/*static char *SCCSID = "@(#)codelckc.c	6.1 90/11/17";*/
#define SCCSID "@(#)codelckc.c     13.01 90/07/17"
/********************************************************/
/*							*/
/*	 IBM/Microsoft Confidential			*/
/*							*/
/*	 Copyright (c) IBM Corporation 1987, 1989	*/
/*	 Copyright (c) Microsoft Corporation 1987, 1989	*/
/*							*/
/*	 All Rights Reserved				*/
/********************************************************/

#define INCL_TYPES			// for basedef.h typedefs
#define FNO_NUM FNO_CODELCKC_C
#include <basemac.h>
#include <basedef.h>
#include <osconst.h>
#include <ostypes.h>
#include <fnofs.h>
#include <osmac.h>
#include <basemac.h>
#include <error.h>
#include <error2.h>
#include <mi.h>
#include <vmexport.h>
#include <selxport.h>
#include <pgexport.h>
#include <tkexport.h>
#include <smexport.h>
#include <kutil.h>
#include <tom.h>
#include <kmode.h>
#include <fslocal.h>
#include <codelock.h>


PHOOK	phookCodeLock;
BOOL	bCodeLockHookArmed;
extern	CodeLock_t CodeLockArray;

/***LP	FSTomCodeUnlock - timer routine for code unlocking
 *
 *	TOMCodeUnlock is run when a codelock timer expires.  It is
 *	called from the Timeout Manager, as a worker routine.  The
 *	semantics of TOM workers states that routine is called with
 *	interrupts enabled, and that interrupts will be enabled
 *	between each call.  Therefore, there is no corresponding
 *	_enable() call here.
 *
 *	Note also that a toe is the first element of codelock_t.
 *	This fact is used to reference the other fields of the codelock
 *	structure from the ptoe arguement to this function.
 *
 *	ENTRY	ptoe - pointer to timeout element for codelock region
 *
 *	EXIT	NONE
 */

void
FSTomCodeUnlock (toe_t *ptoe)
{
    _disable();
    ((CodeLock_t *)ptoe)->cl_flags |= CL_UNLOCKPENDING;
    ((CodeLock_t *)ptoe)->cl_flags &= ~CL_TOESET;
    if (!bCodeLockHookArmed) {
	KMArmContextHook (phookCodeLock,KM_GLOBAL_CONTEXT);
	bCodeLockHookArmed = TRUE;
    }
}



/***LP	CodeLockHook - context hook unlocking file system code regions
 *
 *	CodeLockHook is armed when one or more code regions needs to
 *	be unlocked.  This routine walks through the list of code lock
 *	regions and unlocks any regions that have pending unlocks.
 *
 *	ENTRY	pRefData - pointer to reference data (unused)
 *		pContext - pointer to context of execution (-1, global)
 *
 *	EXIT	NONE
 */

void
CodeLockHook (void *pRefData, void *pContext)
{
    ULONG	i;
    ULONG	rc;
    CodeLock_t	*pCodeLock;

    bCodeLockHookArmed = FALSE;
    pCodeLock = &CodeLockArray;
    for  (i = 0; i < NUMCODELOCKGROUPS; i++, pCodeLock++) {
	if (pCodeLock->cl_flags & CL_UNLOCKPENDING) {
	    KSEMRequestMutex ((HKSEM)&(pCodeLock->cl_semaphore), -1);
	    if (pCodeLock->cl_flags & CL_UNLOCKPENDING) {
		fsAssert(pCodeLock->cl_flags & CL_ISLOCKED);
		while((rc=VMUnlock(&pCodeLock->cl_lhand))==ERROR_INTERRUPT);
		fsAssert(!rc);
		pCodeLock->cl_flags &= ~(CL_UNLOCKPENDING | CL_ISLOCKED);
	    }
	    KSEMReleaseMutex ((HKSEM)&(pCodeLock->cl_semaphore));
	}
    }
}
