/*static char *SCCSID = "@(#)lockdir.c	6.3 92/01/31";*/
#ifndef	 _BTXT
#define	 _BTXT _BTXT
#define	 _THISFILE "LOCKDIR.C"
#include _THISFILE.C
#undef	 _BTXT
#endif

#ifndef HDRS
#define HDRS

#include <os2def.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 "frame.h"
#include "assert.h"
#include "log.h"

#endif

#include "pr_DIR.h"
#include "pr_MISC.h"


/*
 ***	LockDir - Lock Directory
 *
 *	LockDir is called when someone wants to lock a directory.
 *	LockDir waits until the lock can be made and then returns.
 *	Lockdir DOES NOT set the lock.
 *
 *	Note that LockDir is sometimes called when someone is converting
 *	a hold to a lock.  In this case, they typically haven't checked to
 *	see if their decrementing of the HCNT made it go to zero, which
 *	requires a Wakeup.  LockDir checks for this and does the wakeup
 *	if necessary
 *
 *	ENTRY	psbd (eax) = address of SBDIR to lock
 *
 *	EXIT	psbd (eax) = address of SBDIR to lock
 *
 *	10/20/88 -- updated to 10/16/88 assembly
 */

void
LockDir (psbd,pfrm)
PSUBDIR psbd;
PFRAME	pfrm;
{

    ASSERT_SBD(psbd);

    /*
     *	Since we may have decremented the hold count without
     *	waking people up, check that first.
     */
    if ( ((psbd->bFlags & SDF_PND) != 0 ) &&
	 (psbd -> cusHolds == 0) ) {

	/*
	 *  The hold count is zero, and someone may be
	 *  waiting for this directory.  Wake everybody up.
	 */
	WakeupSBD( psbd );
    }

    /*
     *	Get the right to set the pending lock flag.  Wait
     *	until there are no locks or pending locks.
     */
    while (psbd -> bFlags & (SDF_LCK | SDF_PLK)) {

	ASSERT_SBD(psbd);
	/*
	 *  It's locked, or someone else already has
	 *  a lock pending--we have to wait.
	 */
	psbd->cusWaiters += 1;
	BlockOnSBD( psbd,pfrm );
	psbd->cusWaiters -= 1;
    }


    if( psbd->cusHolds == 0 )
	return;


    /* Someone's got it held so indicate that we're the guy pending. */
    SetFlagsSBD(psbd, SDF_PND | SDF_PLK);


#ifdef DEBUG
    if (MAKETYPE (psbd->pWaitChain, ULONG) != 0) {
	    /* We already set the lock bit.  Since we let pending-lock
	     * threads go first, there should currently be no other
	     * threads waiting on this sbd.
	     */
	    INTERR ("LockDir: wait queue must be empty and it isn't");
    }
#endif

    /*
     *	Note that, due to the test above, we know that
     *	the hold count is nonzero.  However, once we block,
     *	we will only get woken up if the hold count is zero,
     *	so this loop should be executed exactly once.  But
     *	we make it a loop just to be on the safe side.
     */

    while ( psbd->cusHolds != 0 ) {

	psbd->cusWaiters += 1;
	BlockOnSBD( psbd,pfrm );
	psbd->cusWaiters -= 1;

	ASSERT_SBD(psbd);
    }

    /*
     * It's ours now.  Since only one instance of LockDir sets
     * the SDF_PND bit, and that instance was us, we'll clear it now.
     */
    ClrFlagsSBD(psbd, SDF_PLK);

    if ( (psbd->bFlags & SDF_PSO) == 0 ) {
	    ClrFlagsSBD(psbd, SDF_PND);
    }

}
