/*static char *SCCSID = "@(#)frame.h    6.2 92/01/31";*/
/***    frame.h - instance variables for FSD calls
 *
 *      There are a number of variables that are passed in to pinball
 *      that we'd rather not pass via stack parms.  These are rarely
 *      used, but the cost in terms of stack allocation and stack usage
 *      is prohibitive.
 *
 *      As a result, we allocate a separate frame structure from the heap
 *      upon entry, store the address in a global variable, use that variable
 *      to address the object when needed, and be sure to save it  across
 *      known context switches.
 *
 *      NOTE: we must have some kind of valid heap frame before trying to
 *            allocate a new frame from the heap.  It does not have to contain
 *            any valid data; it just has to be a valid pointer so that if GHS
 *            blocks, MAYBLOCK has a valid pfrmHeap to use.  We initialize
 *            pfrmHeap to point to the global data frame (pfrm) for both
 *            INIT_READ_FRAME & INIT_WRITE_FRAME.  Since pfrm is not needed by
 *            any other thread (they are all blocked), it is ok for us to use.
 *            If GHS blocks, MAYBLOCK will copy *pfrm to *pfrmHeap, which
 *            happen to be the same pointer in this case.
 *
 *      We must be careful to handle unknown context switches!  In v1.2, these
 *      are caused by using not-present segments, while in later releases
 *      they are caused by using not-present pages.  We solve this by
 *      locking the object down beforehand (and saving it across the blocking
 *      lock call!).
 *
 *      Another wrinkle is introduced because the shutdown code needs to wait
 *      for any write threads which are currently in progress.  The macros to
 *      handle that include INCR_WRITE_THREAD and DECR_WRITE_THREAD.  The users
 *      of the frame macros must invoke the appropriate version (e.g. a write
 *      thread would invoke INIT_WRITE_FRAME).  Failure to do so may cause the
 *      system to hang during shutdown.  See "shutdown.h" for details.
 *
 *      HISTORY
 *          08-Dec-89 by RamonSA
 *              - Eliminated (unnecessary) use of pfrmTemp.
 *          19-Sep-89 by JR (John Rogers, JohnRo@Microsoft)
 *              - Avoid warnings from Microsoft C 5.2 (on slash-slash comments).
 *          26-May-1989 by JR (John Rogers, JohnRo@Microsoft)
 *              - DCR 259.2: added counting of write threads for shutdown.
 */

typedef struct FRAME {          /* frame */
    PVOLTAB pvol;               /*  pointer to vol table entry */
    PSUBDIR psbd;               /*  pointer to locked SBDIR */
    USHORT  flDMask;            /*  bit mask for current file (see buf.h) */
    USHORT  usHardErr;          /*  hard error code */
    BYTE    fRecheckAddr;       /*  flag:  need to re-verify user addr */
    BYTE    iCP;                /*  index of current code page (into global
                                 *  code page array) - used in LDECreate. */
    PBYTE   pbLastName;         /*  ptr to mixed-case last name in path -
                                 *  used in LDECreate, Move, and CrackPath. */
    BYTE    fFlag;              //  @129233 Frame flags (FFL_XXXX)
    union {                     /*  Part of frame used differently  by  *
                                 *  different parts of the filesystem   */
        BOOL    fWrtThru;       /*      write thru flags for EA stuff   */
#if defined(PERFVIEW) && defined(RAHEAD)
        BOOL    fReadAhead;     /* Updated by Read() before calling SDR() */
#endif
    } u;
#if defined (DEBUG) || defined (LOGGING) || defined (LOG_PRINT)
    USHORT  ostkStart;          /*  start of stack for depth noting */
    USHORT  usID;               /*  slot id */
    PVOID   pData;              /* values to check in ProbeAddress */
    USHORT  usOp;
    USHORT  cbData;
    SHORT   cusHolds;           /* hold count for all SBDs (this thread only) */
#endif

} FRAME;

typedef FRAME far *PFRAME;

// Values for fFlag:
#define FFL_NOLZREAD  0x0001  // DON'T LAZY READ ANY I/O   @129233


#define GetHardErr(error)   (pfrm->usHardErr ? pfrm->usHardErr : (error))

#define FS_GetHardErr(error)   (frm.usHardErr ? frm.usHardErr : (error))

#define GetHrdErr_()        GetHardErr( ERROR_READ_FAULT )

#define SETHARDERR(usErr)               \
    {                                   \
        pfrm->usHardErr = usErr;        \
    }

#define FS_SETHARDERR(usErr)            \
    {                                   \
        frm.usHardErr = usErr;          \
    }

#define INIT_DEBUG_FRAME


#define CHECK_MAYBLOCK


/*  MAYBLOCK - perform bookkeeping around a potentially blocking call.
 *
 *  The second performance concern is in terms of verifying the validity
 *  of a user transfer address.  We do not want to repeatedly call
 *  FSH_PROBEBUF nor we do not wish to lock the data down at the outset.
 *  As a result, we note whether we've blocked (thus invalidating any
 *  verification of legality).  When it comes time to probe the address,
 *  we check to see if we've blocked since the last probe.  If so, we
 *  reverify the address.
 */

#define NOTESTACKDEPTH
#define STARTSTACKDEPTH

#define CLOBBERFRAME
#define CHECKFRAME(pfrmSave)

#ifdef ZAPPING  // @76193
#define MAYBLOCK(s)                                                     \
        {                                                               \
            DoZap(pfrm);                                                \
            s;                                                          \
            pfrm->fRecheckAddr = TRUE;                                  \
        }

#define FS_MAYBLOCK(s)                                                  \
        {                                                               \
            DoZap(&frm);                                                \
            s;                                                          \
            frm.fRecheckAddr = TRUE;                                    \
        }
#else
#define MAYBLOCK(s)                                                     \
        {                                                               \
            s;                                                          \
            pfrm->fRecheckAddr = TRUE;                                  \
        }

#define FS_MAYBLOCK(s)                                                  \
        {                                                               \
            s;                                                          \
            frm.fRecheckAddr = TRUE;                                    \
        }
#endif
