/*static char *SCCSID = "@(#)lockswap.c	6.1 90/11/18";*/
/*static char *SCCSID = "@(#)lockswap.c    13.4 90/03/13";*/

#if !defined(_BTXT) && !defined(INIT2)

#define  _BTXT _BTXT
#define  _THISFILE "LOCKSWAP.C"
#include _THISFILE.C
#undef	 _BTXT

#define  INIT2 INIT2
#define  _THISFILE "LOCKSWAP.C"
#include _THISFILE.C
#undef	 INIT2

#endif


#ifndef HDRS
#define HDRS

#define INCL_DOSERRORS
#include <os2.h>
#include <fsh.h>
#include <strat2.h>
#include "const.h"
#include "misc.h"
#include "chain.h"
#include "buf.h"
#include "dir.h"
#include "storage.h"
#include "volume.h"
#include "tables.h"
#include "lw.h"
#include "frame.h"
#include "fsdata.h"
#include "pbmacros.h"
#include "pbmsg.h"

#endif

#include "pr_misc.h"
#include "pr_misc.seg"
#include "pr_debug.h"
#include "pr_debug.seg"

/*
 *	HISTORY
 *	    02-Mar-1990 by JR (John Rogers, JohnRo@Microsoft)
 *		- PTR B788315: put routines in INIT2 so we can init earlier.
 */

/*
 * Must define all these macros since MAYBLOCK won't accept #ifdef's
 * within it.
 */
#ifdef USE_VMLOCK
#undef	NOSWAPF
/* 0x14L = 0x4L (below 16M) | 0x10L (long term) */
#define NOSWAPF  VMLock(0x14L,pswap->pModAddress,(ULONG) pswap->usModSize, \
			((void far *) -1L),pswap->LockHandle,((PUINT) -1L))
#undef	MAYSWAPF
#define MAYSWAPF VMUnlock(pswap->LockHandle)
#else
#ifdef DEBUG
#undef	NOSWAPF
#define NOSWAPF  (((*((LHANDLE *) pswap->LockHandle) = SegLock( \
		    SELECTOROF(pswap->pModAddress),0,0)) != 0) ? 0 : 1)
#undef	MAYSWAPF
#define MAYSWAPF SegUnlock(*((LHANDLE *) pswap->LockHandle))
#else

#undef	NOSWAPF
#define NOSWAPF  0

#undef	MAYSWAPF
#define MAYSWAPF 0

#endif
#endif


#ifdef DEBUG

#undef	LOGLOCK
#define LOGLOCK(op) dprintf(op " Module %x At %p size %d -",   \
				  pswap,pswap->pModAddress,pswap->usModSize);

#undef	LOGHANDLE
#define LOGHANDLE   dprintf(" Handle %lx:%lx:%lx\n",		\
			    ((ULONG *) pswap->LockHandle)[0],	\
			    ((ULONG *) pswap->LockHandle)[1],	\
			    ((ULONG *) pswap->LockHandle)[2]	\
			   );

#undef	CHKLOCKCNT
#define CHKLOCKCNT				       \
	if (pswap->usLockCnt == 0)		       \
	    INTERR(__FILE__ " : usLockCnt already 0"); \
	else

#else

#undef	LOGLOCK
#define LOGLOCK(op)

#undef	LOGHANDLE
#define LOGHANDLE

#undef	CHKLOCKCNT
#define CHKLOCKCNT

#endif



/*
 * LockSwap is a captive of LOCKSWAP.  It is called to swap in a module
 * when we determine it hasn't been swapped in by another thread.
 * If the module is not resident, it will be swapped in and we'll block.
 * We use semaphore to avoid race condition.
 * on entry pswap->usLockCnt is 0.
 *
 */
void LockSwap(PSWAP pswap)
{
    MAYBLOCK(
	/* Make sure no one else is going to swap this module */
	while (FSH_SEMREQUEST(&pswap->semChgState,TO_FOREVER) != NO_ERROR);

	/*
	 * If usLckCnt != 0 someone else already swaped in the module
	 * while we blocked on the semaphore; do what LOCKSWAP does.
	 */
	if (pswap->usLockCnt == 0) {
	    LOGLOCK("Locking  ")

	    if (NOSWAPF) /* Make module resident */
		INTERR(PBMSG_LOCKSWAP_FORCEERR);

	    LOGHANDLE
	}

	pswap->usLockCnt++; /* This thread uses the module */
	FSH_SEMCLEAR(&pswap->semChgState);
    )
}

/*
 * UnLockSwap is a captive of UNLOCKSWAP.  It is called to allow swaping
 * out of a module when we don't need it and we determine it is used only
 * by us. We might block. We use semaphore to avoid race condition.
 * on entry pswap->usLockCnt is 1.
 *
 */

void UnLockSwap(PSWAP pswap)
{
    MAYBLOCK(

	/* Make sure no one else is going to swap this module */
	while (FSH_SEMREQUEST(&pswap->semChgState,TO_FOREVER) != NO_ERROR);

	/*
	 * If usLockCnt > 1 Called LOCKSWAP while we blocked on semaphore.
	 * Since other thread(s) are using the module don't release it.
	 * If usLockCnt == 0 there are two threads doing UNLOCKSWAP
	 * while only one of them did LOCKSWAP; this is an internal error.
	 */

	CHKLOCKCNT

	if (pswap->usLockCnt == 1) {
	    LOGLOCK("UnLocking")
	    LOGHANDLE

	    if (MAYSWAPF) /* Allow module to be swapped out */
		INTERR(PBMSG_LOCKSWAP_RELEASEERR);
	}

	pswap->usLockCnt--; /* This thread no longer uses the module */
	FSH_SEMCLEAR(&pswap->semChgState);
    )
}
