992 lines
32 KiB
C
992 lines
32 KiB
C
/****************************************************************************
|
|
|
|
|
| (C) Copyright 1985, 1991, 1993, 1996 Novell, Inc.
|
|
| All Rights Reserved.
|
|
|
|
|
| This program is free software; you can redistribute it and/or
|
|
| modify it under the terms of version 2 of the GNU General Public
|
|
| License as published by the Free Software Foundation.
|
|
|
|
|
| This program is distributed in the hope that it will be useful,
|
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
| GNU General Public License for more details.
|
|
|
|
|
| You should have received a copy of the GNU General Public License
|
|
| along with this program; if not, contact Novell, Inc.
|
|
|
|
|
| To contact Novell about this file by physical or electronic mail,
|
|
| you may find current contact information at www.novell.com
|
|
|
|
|
|***************************************************************************
|
|
|
|
|
| NetWare Advance File Services (NSS) module
|
|
|
|
|
|---------------------------------------------------------------------------
|
|
|
|
|
| $Author: taysom $
|
|
| $Date: 2004-12-31 01:10:58 +0530 (Fri, 31 Dec 2004) $
|
|
|
|
|
| $RCSfile$
|
|
| $Revision: 465 $
|
|
|
|
|
|---------------------------------------------------------------------------
|
|
| This module is used to:
|
|
| NSS Library Routine
|
|
|
|
|
| WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
|
|
|
|
|
| This header file should ONLY be used for NSS internal development.
|
|
| This includes Semantic Agents (SA) and Loadable Storage Services (LSS).
|
|
| Any other use may cause conflicts which NSS will NOT fix.
|
|
+-------------------------------------------------------------------------*/
|
|
#ifndef _LATCH_H_
|
|
#define _LATCH_H_
|
|
|
|
#ifndef _PSSMPK_H_
|
|
# include <include/pssmpk.h>
|
|
#endif
|
|
|
|
#ifndef _QUE_H_
|
|
# include <library/que.h>
|
|
#endif
|
|
|
|
#ifndef _PSSDEBUG_H_
|
|
# include <include/pssDebug.h>
|
|
#endif
|
|
|
|
#ifndef _FSM_H_
|
|
# include <include/fsm.h>
|
|
#endif
|
|
|
|
#ifndef _PARSE_H_
|
|
#include <include/parse.h>
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
|
|
/*
|
|
* A latch allows fair Shared and eXclusive access to the
|
|
* object owning the latch. The latch will block the requesting
|
|
* thread if the mode asked for can not be granted. We use the
|
|
* term latch instead of lock because these are meant to be short
|
|
* term and have no deadlock detection. Code using latches should
|
|
* acquire them in such an order that deadlock is not possible.
|
|
*
|
|
* Besides latches, we define routines for counting semaphores and
|
|
* and waiting for events. Counting semaphores are very much like
|
|
* latches. Rather that starting at 0, the count for a counting
|
|
* semaphore is given some initial value. A requester can then
|
|
* be "grab" some delta on the count as long as the count stays
|
|
* greater than zero. The event routines manage dispatching
|
|
* requesters depending on if they are a FSM or a thread. Threads
|
|
* are distinguished by having their action field set to NULL.
|
|
* When a thread blocks, it sets up an FSM_LITE. The event
|
|
* triggering the dispatch is external to these routines.
|
|
*
|
|
* Latches are granted in FIFO order (see EXCEPTION), so once an
|
|
* exclusive latch is requested, all subsequent latch requests
|
|
* are deferred. Thus, if one or more share latches are held and
|
|
* a request for an exclusive latch is made, all subsequent share
|
|
* latches are deferred until the exclusive latch has been satisfied.
|
|
* (For further details, see the ObjecTime model for a latch.)
|
|
*
|
|
* EXCEPTION: to reduce the number of trains formed and thus reduce
|
|
* the number of context switches, eXclusive latches for threads have
|
|
* two additional states. When a thread releases an eXclusive latch,
|
|
* rather than granting the latch to the next waiter, it checks if
|
|
* if the next waiter is asking for eXclusive access, if so, it dispatches
|
|
* the thread but does not grant the thread. If the current thread
|
|
* reasks for the latch, it is granted the latch and the dispatched
|
|
* waiter gets pushed back on to the wait queue when it asks for the
|
|
* latch.
|
|
*
|
|
* (A train is a situation where several threads line up behind one
|
|
* or more latches. When one thread releases the latch the next thread
|
|
* gets it but when the first thread asks for the latch it goes to the
|
|
* end of the line. The end results, is each thread in the train has to
|
|
* get the latch for a particular segment of an operation before going on
|
|
* to the next segment -- it may be fair, but it is slow.)
|
|
*
|
|
* We have augmented the basic latch code to allow Finite State
|
|
* Machines, FSMs, to use latches. A latch can be used by either
|
|
* threads, FSMs or both. We've also added several different versions
|
|
* of the return to control blocking and return whether the thread/FSMs
|
|
* blocked or would have blocked in the case of a non-blocking call.
|
|
*
|
|
* Note: both macro and function versions of the latch code are provided.
|
|
* Which one is used is selected at compile time. Because of cache hit
|
|
* ratios, the functions may be faster than in-line code though I've
|
|
* tried to separate the code that is always executed from the code for
|
|
* waiting for the latch.
|
|
*
|
|
* The latch structure consists of three fields. The first is a queue for
|
|
* threads waiting for the latch, the second is a count field for how
|
|
* many shared latches held or is set to X_LATCH_STATE to indicate an
|
|
* eXclusive latch, and the third is the last thread to have done an
|
|
* eXclusive latch.
|
|
*
|
|
* The wait queue uses the Singly Linked Circular Queue described in que.h
|
|
* for the wait queue because it uses the least amount of space and it
|
|
* should be a rare event for anything to wait on a latch.
|
|
*
|
|
* Summary:
|
|
*
|
|
* INIT_LATCH Initialize a latch data structure.
|
|
* LATCH_FREE True if nothing is waiting for the latch.
|
|
* LATCH_INUSE True if something is holding latch.
|
|
*
|
|
* S_LATCH Acquire a share latch.
|
|
* X_LATCH Acquire an exclusive latch.
|
|
* UP_LATCH Up-grade a share latch to an exclusive latch.
|
|
* ADD_LATCH Add a share latch to a latch that already has
|
|
* a share latch.
|
|
*
|
|
* DOWN_LATCH Down-grade an exclusive latch to a share latch.
|
|
* UNS_LATCH Release a share latch.
|
|
* UNX_LATCH Release an exclusive latch.
|
|
* UN_LATCH Release a latch regardless of type.
|
|
*
|
|
* Variations on the theme for S, X, and UP latches:
|
|
*
|
|
* INIT_S_LATCH Set an initial shared count for latch.
|
|
* INIT_X_LATCH Set an exclusive latch when initializing latch.
|
|
*
|
|
* S_FORCE Force a share latch (Code knows latch is not held).
|
|
* X_FORCE Force an exclusive latch (Code knows latch is not held).
|
|
*
|
|
* S_NOWAIT Return WAITED if thread/FSM would have blocked.
|
|
* X_NOWAIT Return WAITED if thread/FSM would have blocked.
|
|
* UP_NOWAIT Return WAITED if thread/FSM would have blocked.
|
|
*
|
|
* FSM_S_LATCH Acquire a share latch a Finite State Machine, FSM.
|
|
* FSM_X_LATCH Acquire an exclusive latch for a FSM.
|
|
* FSM_UP_LATCH Up-grade a share latch to an exclusive latch
|
|
*
|
|
* Definitions:
|
|
*
|
|
* Latch_s *latch
|
|
* A pointer to a latch structure is passed to each of
|
|
* these MACROS.
|
|
*
|
|
* INIT_LATCH(latch)
|
|
* Initializes the latch by setting its count to zero and
|
|
* setting the wait queue to empty. Because of the low
|
|
* overhead of the MACRO version, I suggest that only
|
|
* the MACRO version be used.
|
|
*
|
|
* S_LATCH(latch)
|
|
* Request a share latch. A share latch allows multiple threads
|
|
* to access the data structure protected by the latch. It is
|
|
* important that the threads only do read operations of the data
|
|
* structure. If you need to update the data structure either
|
|
* request an eXclusive latch or use an upgrade.
|
|
*
|
|
* X_LATCH(latch)
|
|
* Request an exclusive latch. An exclusive latch only allows
|
|
* one thread to access the data structure protected by the latch.
|
|
* Once an exclusive latch has been requested, no further share
|
|
* latches are allowed. This prevents starvation.
|
|
*
|
|
* DOWN_LATCH(latch)
|
|
* Down-grade an exclusive latch to a share latch. Once finished
|
|
* with the exclusive access portion of an operation, down grading
|
|
* a latch lets other readers in. If the requester already has
|
|
* the latch in shared mode, nothing happens. Note: the thread
|
|
* that asks for a down-grade will not block.
|
|
*
|
|
* UP_LATCH(latch)
|
|
* Up-grade a share latch to an exclusive latch. If a thread needs
|
|
* to gain exclusive access to a resource, it can do an up-latch.
|
|
* It behaves like doing a UNS_LATCH followed by an X_LATCH. Note:
|
|
* that if some other exclusive latch is already pending, it will
|
|
* be granted before the up-grade.
|
|
*
|
|
* ADD_LATCH(latch)
|
|
* Lets the owner of a share latch add another latch to it. Used
|
|
* to let multiple operations on a object proceed in parallel.
|
|
*
|
|
* UNS_LATCH(latch)
|
|
* Release a share latch.
|
|
*
|
|
* UNX_LATCH(latch)
|
|
* Release an exclusive latch.
|
|
*
|
|
* UN_LATCH(latch)
|
|
* Release a latch regardless of type. If one code path could have
|
|
* obtained one type of latch and another code path another type of
|
|
* latch yet they share the same finish code, UN_LATCH figures out
|
|
* the latch mode and releases it.
|
|
*
|
|
* This are the macros for grabbing and releasing resources. They are
|
|
* based on a counting semaphore. It uses the same data structure as a
|
|
* latch but uses the count field differently. To tell the difference
|
|
* between a FSM and a thread, the requested count will be set to a
|
|
* negative number.
|
|
*
|
|
* INIT_COUNT(latch, count)
|
|
* Initializes the counting semaphore to the given count value.
|
|
* This usually represents the number of a particular resource.
|
|
*
|
|
* INC_COUNT(latch, count)
|
|
* Increments the counting semaphore by the given count value.
|
|
* This usually represents the number of a particular resource.
|
|
*
|
|
* INC_COUNT_CHECK(latch, count)
|
|
* Increments the counting semaphore by the given count value.
|
|
* This usually represents the number of a particular resource.
|
|
* Also checks to see if there is someone waiting for resources
|
|
* that can now go.
|
|
*
|
|
* DEC_COUNT(latch, count)
|
|
* Decrements the counting semaphore by the given count value.
|
|
* This usually represents the number of a particular resource.
|
|
*
|
|
* GRAB(latch, count)
|
|
* If count is greater than or equal to the remaining count for latch,
|
|
* the latch is granted, otherwise, we block until the count reaches
|
|
* the number asked for.
|
|
*
|
|
* DROP(latch, count)
|
|
* Add count to the latch's count and check if any requests have now
|
|
* been satisfied.
|
|
*
|
|
* Routines for managing events. The code managing the event may have
|
|
* to have a loop to check the event again after the thread or FSM has
|
|
* been woken up.
|
|
*
|
|
* AWAIT(cirque)
|
|
* Places a thread on a circular queue waiting for some event.
|
|
* FSM_AWAIT(cirque, fsm, action)
|
|
* Places a finite state machine on a circular queue. When it
|
|
* awakes, the action is called.
|
|
* WAKEUP(cirque)
|
|
* Wakes up the next thread or FSM on the circular queue.
|
|
*/
|
|
|
|
enum { WAITED = 0, NOWAIT = 1 };
|
|
|
|
enum
|
|
{
|
|
IDLE_LATCH_STATE = 0,
|
|
LIMBO_LATCH_STATE = -1, /* A user has been dispatched to get eXclusive
|
|
* access but has not yet had a chance to get it.
|
|
* The last user of this latch, can get eXclusive
|
|
* access again without waiting.
|
|
*/
|
|
X_LATCH_STATE = -2, /* User has eXclusive access */
|
|
XX_LATCH_STATE = -3 /* User has eXclusive access and a thread waiting
|
|
* for exclusive access has been dispatched to
|
|
* try and aquire the latch but the current holder
|
|
* of the latch could release and reaquire the
|
|
* latch without having to wait.
|
|
*/
|
|
};
|
|
|
|
typedef struct Latch_s
|
|
{
|
|
CIRhead_t waiting;
|
|
SNINT count;
|
|
ADDR L_thread;
|
|
} Latch_s;
|
|
|
|
#if zNETWARE
|
|
// Under Linux RunningProcess is a macro
|
|
extern ADDR RunningProcess;
|
|
#endif
|
|
#if defined(__linux__) && !defined(__KERNEL__)
|
|
#ifndef _SCHEDULE_H_
|
|
# include <include/schedule.h>
|
|
#endif
|
|
#ifndef RunningProcess
|
|
# define RunningProcess ThreadId()
|
|
#endif
|
|
#endif
|
|
|
|
#define CLEAR_THREAD(_latch) ((_latch)->L_thread = 0)
|
|
#define SET_THREAD(_latch) ((_latch)->L_thread = RunningProcess)
|
|
#define SET_FSM(_latch, _fsm) ((_latch)->L_thread = (ADDR)_fsm | 0x1)
|
|
#define SET_S_THREAD(_latch) ((_latch)->L_thread = \
|
|
(((_latch)->count == 1) ? RunningProcess : 0))
|
|
#define SET_S_FSM(_latch, _fsm) ((_latch)->L_thread = \
|
|
(((_latch)->count == 1) ? ((ADDR)_fsm|0x1) : 0))
|
|
|
|
#if NSS_DEBUG IS_ENABLED
|
|
|
|
/*
|
|
* WARNING: I'm doing something kind-of-tricky with the C preprocessor
|
|
* to optionally add an argument to these functions for debug
|
|
* support. The argument tells from where the function was called.
|
|
*/
|
|
|
|
#define STRING_ARG , char *
|
|
#define WHENCE , WHERE
|
|
#define WHENCE_ARG , char *whencE
|
|
#define WHENCE_PASS , whencE
|
|
|
|
#else
|
|
|
|
#define STRING_ARG
|
|
#define WHENCE
|
|
#define WHENCE_ARG
|
|
#define WHENCE_PASS
|
|
|
|
#endif
|
|
|
|
/*---------------------------------------------------------------------------
|
|
* MACROs without function version
|
|
*---------------------------------------------------------------------------*/
|
|
#define LATCH_FREE(latch) ((latch)->count == IDLE_LATCH_STATE)
|
|
#define LATCH_INUSE(latch) ((latch)->count != IDLE_LATCH_STATE)
|
|
|
|
#define IS_SLATCHED(latch) ((latch)->count > IDLE_LATCH_STATE)
|
|
#define IS_XLATCHED(latch) ((latch)->count < LIMBO_LATCH_STATE)
|
|
#define IS_LATCHED(latch) (IS_SLATCHED(latch) || IS_XLATCHED(latch))
|
|
#define IS_LAST_SLATCH(latch) ((latch)->count == 1)
|
|
|
|
#define ASSERT_LATCH(latch) (zASSERT((latch)->count != IDLE_LATCH_STATE))
|
|
#define ASSERT_SLATCH(latch) (zASSERT((latch)->count > IDLE_LATCH_STATE))
|
|
#define ASSERT_XLATCH(latch) (zASSERT((latch)->count < LIMBO_LATCH_STATE))
|
|
#define ASSERT_NOLATCH(latch) (zASSERT((latch)->count == IDLE_LATCH_STATE))
|
|
|
|
#define S_BARRIER(latch) \
|
|
{ \
|
|
S_LATCH(latch); \
|
|
UNS_LATCH(latch); \
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
* Latch routine where the latch type is a parameter
|
|
*---------------------------------------------------------------------------*/
|
|
#define NOTLATCHED 0
|
|
#define XLATCHED 1
|
|
#define SLATCHED 2 /* any non-zero value will work */
|
|
|
|
#define COND_LATCH(latch,latchType) \
|
|
{ \
|
|
if ((latchType) == XLATCHED) \
|
|
{ \
|
|
X_LATCH(latch); \
|
|
} \
|
|
else if ((latchType) == SLATCHED) \
|
|
{ \
|
|
S_LATCH(latch); \
|
|
} \
|
|
else \
|
|
{ \
|
|
; \
|
|
} \
|
|
}
|
|
|
|
#define COND_UNLATCH(latch,latchType) \
|
|
{ \
|
|
if ((latchType) == XLATCHED) \
|
|
{ \
|
|
UNX_LATCH(latch); \
|
|
} \
|
|
else if ((latchType) == SLATCHED) \
|
|
{ \
|
|
UNS_LATCH(latch); \
|
|
} \
|
|
else \
|
|
{ \
|
|
; \
|
|
} \
|
|
}
|
|
|
|
#define GET_LATCH_TYPE(_latch) \
|
|
(IS_XLATCHED(_latch) ? XLATCHED : \
|
|
((IS_SLATCHED(_latch)) ? SLATCHED : NOTLATCHED))
|
|
|
|
extern NINT LBL_xBarrier(Latch_s * STRING_ARG);
|
|
|
|
extern void LBL_initCount(Latch_s *, SNINT);
|
|
extern void LBL_incCount(Latch_s *, SNINT);
|
|
extern void LBL_incCountAndCheck(Latch_s *, SNINT STRING_ARG);
|
|
extern void LBL_decCount(Latch_s *, SNINT);
|
|
extern void LBL_grab(Latch_s *, SNINT STRING_ARG);
|
|
extern void LBL_drop(Latch_s *, SNINT STRING_ARG);
|
|
extern void LBL_fsmGrab(Latch_s *, SNINT, FsmLite_s *, voidfunc_t STRING_ARG);
|
|
extern NINT LBL_grabNoWait(Latch_s *, SNINT STRING_ARG);
|
|
|
|
#if LATCH_MACRO IS_ENABLED
|
|
/****************************************************************************
|
|
* MACRO versions of latch routines
|
|
* If you change any of these be sure to update the function version.
|
|
*****************************************************************************/
|
|
|
|
extern void LBL_sWait(Latch_s *);
|
|
extern void LBL_xWait(Latch_s *);
|
|
extern void LBL_fsmSwait(Latch_s *, struct FsmLite_s *, voidfunc_t action);
|
|
extern void LBL_fsmXwait(Latch_s *, struct FsmLite_s *, voidfunc_t action);
|
|
extern void LBL_sSignal(Latch_s *);
|
|
extern void LBL_xSignal(Latch_s *);
|
|
|
|
/*---------------------------------------------------------------------------
|
|
* Initialization routines
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
#define ADD_LATCH(latch) (++((latch)->count))
|
|
|
|
#define S_FORCE(latch) (((latch)->count = 1), \
|
|
((latch)->L_thread = RunningProcess))
|
|
#define X_FORCE(latch) (((latch)->count = X_LATCH_STATE), \
|
|
((latch)->L_thread = RunningProcess))
|
|
|
|
#define INIT_LATCH(latch) \
|
|
{ \
|
|
Latch_s *_latch = (latch); \
|
|
\
|
|
CIR_INIT(_latch->waiting); \
|
|
_latch->count = IDLE_LATCH_STATE; \
|
|
CLEAR_THREAD(_latch); \
|
|
}
|
|
|
|
#define INIT_S_LATCH(latch, cnt) \
|
|
{ \
|
|
Latch_s *_latch = (latch); \
|
|
\
|
|
CIR_INIT(_latch->waiting); \
|
|
_latch->count = cnt; \
|
|
SET_S_THREAD(_latch); \
|
|
}
|
|
|
|
#define INIT_X_LATCH(latch) \
|
|
{ \
|
|
Latch_s *_latch = (latch); \
|
|
\
|
|
CIR_INIT(_latch->waiting); \
|
|
_latch->count = X_LATCH_STATE; \
|
|
SET_THREAD(_latch); \
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
* Shared Latch routines
|
|
*---------------------------------------------------------------------------*/
|
|
#define S_LATCH(latch) \
|
|
{ \
|
|
Latch_s *_latch = (latch); \
|
|
\
|
|
if (_latch->count == IDLE_LATCH_STATE) \
|
|
{ \
|
|
_latch->count = 1; \
|
|
SET_THREAD(_latch); \
|
|
} \
|
|
else if ((_latch->count > 0) && (CIR_EMPTY(_latch->waiting))) \
|
|
{ \
|
|
++_latch->count; \
|
|
CLEAR_THREAD(_latch); \
|
|
} \
|
|
else \
|
|
{ \
|
|
LBL_sWait(_latch); \
|
|
} \
|
|
}
|
|
|
|
#define S_NOWAIT(latch, rtn) \
|
|
{ \
|
|
Latch_s *_latch = (latch); \
|
|
\
|
|
if (_latch->count == IDLE_LATCH_STATE) \
|
|
{ \
|
|
_latch->count = 1; \
|
|
rtn = NOWAIT; \
|
|
SET_THREAD(_latch); \
|
|
} \
|
|
else if ((_latch->count > IDLE_LATCH_STATE) \
|
|
&& (CIR_EMPTY(_latch->waiting))) \
|
|
{ \
|
|
++_latch->count; \
|
|
rtn = NOWAIT; \
|
|
CLEAR_THREAD(_latch); \
|
|
} \
|
|
else \
|
|
{ \
|
|
rtn = WAITED; \
|
|
} \
|
|
}
|
|
|
|
#define FSM_S_LATCH(latch, fsm, action) \
|
|
{ \
|
|
Latch_s *_latch = (latch); \
|
|
\
|
|
if (_latch->count == IDLE_LATCH_STATE) \
|
|
{ \
|
|
_latch->count = 1; \
|
|
SET_FSM(_latch, fsm); \
|
|
((void (*)(struct FsmLite_s *))(action))(fsm); \
|
|
} \
|
|
else if ((_latch->count > IDLE_LATCH_STATE) \
|
|
&& (CIR_EMPTY(_latch->waiting))) \
|
|
{ \
|
|
++_latch->count; \
|
|
CLEAR_THREAD(_latch); \
|
|
((void (*)(struct FsmLite_s *))(action))(fsm); \
|
|
} \
|
|
else \
|
|
{ \
|
|
LBL_fsmSwait(_latch, fsm, (voidfunc_t)(action)); \
|
|
} \
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
* Exclusive Latch routines
|
|
*---------------------------------------------------------------------------*/
|
|
#define X_LATCH(latch) \
|
|
{ \
|
|
Latch_s *_latch = (latch); \
|
|
\
|
|
if (_latch->count == IDLE_LATCH_STATE) \
|
|
{ \
|
|
_latch->count = X_LATCH_STATE; \
|
|
SET_THREAD(_latch); \
|
|
} \
|
|
else if ((_latch->count == LIMBO_LATCH_STATE) \
|
|
&& (_latch->L_thread == RunningProcess)) \
|
|
{ \
|
|
_latch->count = XX_LATCH_STATE; \
|
|
/* Don't need to set thread because already set */ \
|
|
} \
|
|
else \
|
|
{ \
|
|
LBL_xWait(_latch); \
|
|
} \
|
|
}
|
|
|
|
#define X_NOWAIT(latch, rtn) \
|
|
{ \
|
|
Latch_s *_latch = (latch); \
|
|
\
|
|
if (_latch->count == IDLE_LATCH_STATE) \
|
|
{ \
|
|
_latch->count = X_LATCH_STATE; \
|
|
SET_THREAD(_latch); \
|
|
rtn = NOWAIT; \
|
|
} \
|
|
else if ((_latch->count == LIMBO_LATCH_STATE) \
|
|
&& (_latch->L_thread == RunningProcess)) \
|
|
{ \
|
|
_latch->count = XX_LATCH_STATE; \
|
|
/* Don't need to set thread because already set */ \
|
|
rtn = NOWAIT; \
|
|
} \
|
|
else \
|
|
{ \
|
|
rtn = WAITED; \
|
|
} \
|
|
}
|
|
|
|
#define FSM_X_LATCH(latch, fsm, action) \
|
|
{ \
|
|
Latch_s *_latch = (latch); \
|
|
\
|
|
if (_latch->count == IDLE_LATCH_STATE) \
|
|
{ \
|
|
_latch->count = X_LATCH_STATE; \
|
|
SET_FSM(_latch, fsm); \
|
|
((void (*)(struct FsmLite_s *))(action))(fsm); \
|
|
} \
|
|
else \
|
|
{ \
|
|
LBL_fsmXwait(_latch, fsm, (voidfunc_t)(action)); \
|
|
} \
|
|
}
|
|
|
|
#define X_BARRIER(latch) \
|
|
{ \
|
|
Latch_s *_latch = (latch); \
|
|
\
|
|
if (_latch->count == IDLE_LATCH_STATE) \
|
|
{ \
|
|
SET_THREAD(_latch); \
|
|
} \
|
|
else \
|
|
{ \
|
|
LBL_xBarrier(_latch); \
|
|
} \
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
* Up-grade Latch routines
|
|
*---------------------------------------------------------------------------*/
|
|
#define UP_LATCH(latch) \
|
|
{ \
|
|
Latch_s *_latch = (Latch_s *)(latch); \
|
|
\
|
|
--_latch->count; \
|
|
if (_latch->count == IDLE_LATCH_STATE) \
|
|
{ \
|
|
if (CIR_EMPTY(_latch->waiting)) \
|
|
{ \
|
|
_latch->count = X_LATCH_STATE; \
|
|
} \
|
|
else \
|
|
{ \
|
|
LBL_sSignal(_latch); \
|
|
LBL_xWait(_latch); \
|
|
} \
|
|
} \
|
|
else \
|
|
{ \
|
|
LBL_xWait(_latch); \
|
|
} \
|
|
SET_THREAD(_latch); \
|
|
}
|
|
|
|
#define UP_NOWAIT(latch, rtn) \
|
|
{ \
|
|
Latch_s *_latch = (Latch_s *)(latch); \
|
|
\
|
|
--_latch->count; \
|
|
if (_latch->count == IDLE_LATCH_STATE) \
|
|
{ \
|
|
if (CIR_EMPTY(_latch->waiting)) \
|
|
{ \
|
|
_latch->count = X_LATCH_STATE; \
|
|
SET_THREAD(_latch); \
|
|
rtn = NOWAIT; \
|
|
} \
|
|
else \
|
|
{ \
|
|
LBL_sSignal(_latch); \
|
|
rtn = WAITED; \
|
|
} \
|
|
} \
|
|
else \
|
|
{ \
|
|
rtn = WAITED; \
|
|
} \
|
|
}
|
|
|
|
#define FSM_UP_LATCH(latch, fsm, action) \
|
|
{ \
|
|
Latch_s *_latch = (Latch_s *)(latch); \
|
|
\
|
|
--_latch->count; \
|
|
\
|
|
if (_latch->count == IDLE_LATCH_STATE) \
|
|
{ \
|
|
if (CIR_EMPTY(_latch->waiting)) \
|
|
{ \
|
|
_latch->count = X_LATCH_STATE; \
|
|
SET_FSM(_latch, fsm); \
|
|
((void (*)(struct FsmLite_s *))(action))(fsm); \
|
|
} \
|
|
else \
|
|
{ \
|
|
LBL_sSignal(_latch); \
|
|
LBL_fsmXwait(_latch, fsm, (voidfunc_t)(action)); \
|
|
} \
|
|
} \
|
|
else \
|
|
{ \
|
|
LBL_fsmXwait(_latch, fsm, (voidfunc_t)(action)); \
|
|
} \
|
|
}
|
|
|
|
/*
|
|
* Routines for releasing latches
|
|
*/
|
|
|
|
#define DOWN_LATCH(latch) \
|
|
{ \
|
|
Latch_s *_latch = (latch); \
|
|
\
|
|
if (IS_XLATCHED(_latch)) \
|
|
{ \
|
|
_latch->count = 1; \
|
|
SET_THREAD(_latch); \
|
|
if (CIR_NOT_EMPTY(_latch->waiting)) \
|
|
{ \
|
|
LBL_xSignal(_latch); \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
#define UNS_LATCH(latch) \
|
|
{ \
|
|
Latch_s *_latch = (latch); \
|
|
\
|
|
--_latch->count; \
|
|
if ((_latch->count == IDLE_LATCH_STATE) \
|
|
&& (CIR_NOT_EMPTY(_latch->waiting))) \
|
|
{ \
|
|
LBL_sSignal(_latch); \
|
|
} \
|
|
}
|
|
|
|
#define UNX_LATCH(latch) \
|
|
{ \
|
|
Latch_s *_latch = (Latch_s *)(latch); \
|
|
\
|
|
if (_latch->count == XX_LATCH_STATE) \
|
|
{ \
|
|
_latch->count = LIMBO_LATCH_STATE; \
|
|
} \
|
|
else \
|
|
{ \
|
|
_latch->count = IDLE_LATCH_STATE; \
|
|
if (CIR_NOT_EMPTY(_latch->waiting)) \
|
|
{ \
|
|
LBL_xSignal(_latch); \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
#define UN_LATCH(latch) \
|
|
{ \
|
|
Latch_s *_unlatch = (latch); \
|
|
\
|
|
if (_unlatch->count >= IDLE_LATCH_STATE) \
|
|
{ \
|
|
UNS_LATCH(_unlatch); \
|
|
} \
|
|
else \
|
|
{ \
|
|
UNX_LATCH(_unlatch); \
|
|
} \
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
* MACROS for counting semaphores
|
|
*---------------------------------------------------------------------------*/
|
|
extern void LBL_cntWait(Latch_s *, SNINT);
|
|
extern void LBL_cntSignal(Latch_s *, SNINT);
|
|
extern void LBL_fsmCntWait(Latch_s *, SNINT, struct FsmLite_s *,voidfunc_t action STRING_ARG);
|
|
//extern void LBL_fsmCntSignal(Latch_s *, SNINT, struct Fsm_s *);
|
|
|
|
#define INIT_COUNT(latch, cnt) \
|
|
{ \
|
|
Latch_s *_latch = (latch); \
|
|
\
|
|
CIR_INIT(_latch->waiting); \
|
|
_latch->count = cnt; \
|
|
}
|
|
|
|
#define INC_COUNT(latch, cnt) \
|
|
{ \
|
|
Latch_s *_latch = (latch); \
|
|
_latch->count += cnt; \
|
|
}
|
|
|
|
#define INC_COUNT_CHECK(latch, cnt) \
|
|
{ \
|
|
Latch_s *_latch = (latch); \
|
|
SNINT _cnt = cnt; \
|
|
\
|
|
_latch->count += _cnt; \
|
|
if (CIR_NOT_EMPTY(_latch->waiting)) \
|
|
{ \
|
|
LBL_cntSignal(_latch, _cnt); \
|
|
} \
|
|
}
|
|
|
|
#define DEC_COUNT(latch, cnt) \
|
|
{ \
|
|
Latch_s *_latch = (latch); \
|
|
zASSERT(_latch->count >= cnt); \
|
|
_latch->count -= cnt; \
|
|
}
|
|
|
|
#define GRAB(latch, cnt) \
|
|
{ \
|
|
Latch_s *_latch = (latch); \
|
|
SNINT _cnt = cnt; \
|
|
\
|
|
if (_cnt > _latch->count) \
|
|
{ \
|
|
LBL_cntWait(_latch, _cnt); \
|
|
} \
|
|
else \
|
|
{ \
|
|
_latch->count -= _cnt; \
|
|
} \
|
|
}
|
|
|
|
#define GRAB_NOWAIT(latch, cnt, rtn) \
|
|
{ \
|
|
Latch_s *_latch = (latch); \
|
|
SNINT _cnt = cnt; \
|
|
\
|
|
if (_cnt > _latch->count) \
|
|
{ \
|
|
rtn = WAITED; \
|
|
} \
|
|
else \
|
|
{ \
|
|
_latch->count -= _cnt; \
|
|
rtn = NOWAIT; \
|
|
} \
|
|
}
|
|
|
|
#define FSM_GRAB(latch, cnt, _fsm, action) \
|
|
{ \
|
|
Latch_s *_latch = (latch); \
|
|
SNINT _cnt = cnt; \
|
|
\
|
|
if (_cnt > _latch->count) \
|
|
{ \
|
|
LBL_fsmCntWait(_latch, _cnt, _fsm, action); \
|
|
} \
|
|
else \
|
|
{ \
|
|
_latch->count -= _cnt; \
|
|
action(_fsm); \
|
|
} \
|
|
}
|
|
|
|
#define DROP(latch, cnt) \
|
|
{ \
|
|
Latch_s *_latch = (latch); \
|
|
SNINT _cnt = cnt; \
|
|
\
|
|
_latch->count += _cnt; \
|
|
if (CIR_NOT_EMPTY(_latch->waiting)) \
|
|
{ \
|
|
LBL_cntSignal(_latch, _cnt); \
|
|
} \
|
|
}
|
|
|
|
#else /* LATCH_MACRO IS_ENABLED */
|
|
|
|
/****************************************************************************
|
|
* Function versions of latch routines
|
|
* If you change any of these be sure to update the MACRO version.
|
|
*****************************************************************************/
|
|
extern void LBL_sForce(Latch_s * STRING_ARG);
|
|
extern void LBL_xForce(Latch_s * STRING_ARG);
|
|
extern void LBL_addLatch(Latch_s * STRING_ARG);
|
|
|
|
extern void LBL_initLatch(Latch_s *);
|
|
extern void LBL_initSlatch(Latch_s *, SNINT STRING_ARG);
|
|
extern void LBL_initXlatch(Latch_s * STRING_ARG);
|
|
|
|
extern NINT LBL_sLatch(Latch_s * STRING_ARG);
|
|
extern NINT LBL_sNoWait(Latch_s * STRING_ARG);
|
|
extern NINT LBL_fsmSlatch(Latch_s *, FsmLite_s *, voidfunc_t STRING_ARG);
|
|
|
|
extern NINT LBL_xLatch(Latch_s * STRING_ARG);
|
|
extern NINT LBL_xNoWait(Latch_s * STRING_ARG);
|
|
extern NINT LBL_fsmXlatch(Latch_s *, FsmLite_s *, voidfunc_t STRING_ARG);
|
|
|
|
extern NINT LBL_upLatch(Latch_s * STRING_ARG);
|
|
extern NINT LBL_upNoWait(Latch_s * STRING_ARG);
|
|
extern NINT LBL_fsmUpLatch(Latch_s *, FsmLite_s *, voidfunc_t STRING_ARG);
|
|
|
|
extern void LBL_downLatch(Latch_s * STRING_ARG);
|
|
extern void LBL_unsLatch(Latch_s * STRING_ARG);
|
|
extern void LBL_unxLatch(Latch_s * STRING_ARG);
|
|
extern void LBL_unLatch(Latch_s * STRING_ARG);
|
|
|
|
#define S_FORCE(latch) LBL_sForce(latch WHENCE)
|
|
#define X_FORCE(latch) LBL_xForce(latch WHENCE)
|
|
#define ADD_LATCH(latch) LBL_addLatch(latch WHENCE)
|
|
|
|
#define INIT_LATCH(latch) LBL_initLatch(latch)
|
|
#define INIT_S_LATCH(latch, cnt) LBL_initSlatch(latch, cnt WHENCE)
|
|
#define INIT_X_LATCH(latch) LBL_initXlatch(latch WHENCE)
|
|
|
|
#define S_LATCH(latch) ((void)LBL_sLatch(latch WHENCE))
|
|
#define S_NOWAIT(latch, rtn) (rtn = LBL_sNoWait(latch WHENCE))
|
|
#define FSM_S_LATCH(latch, fsm, action) \
|
|
((void)LBL_fsmSlatch(latch,fsm,(voidfunc_t)(action) WHENCE))
|
|
|
|
#define X_LATCH(latch) ((void)LBL_xLatch(latch WHENCE))
|
|
#define X_NOWAIT(latch, rtn) (rtn = LBL_xNoWait(latch WHENCE))
|
|
#define FSM_X_LATCH(latch, fsm, action) \
|
|
((void)LBL_fsmXlatch(latch,fsm,(voidfunc_t)(action) WHENCE))
|
|
#define X_BARRIER(latch) ((void)LBL_xBarrier(latch WHENCE))
|
|
|
|
#define UP_LATCH(latch) ((void)LBL_upLatch(latch WHENCE))
|
|
#define UP_NOWAIT(latch, rtn) (rtn = LBL_upNoWait(latch WHENCE))
|
|
#define FSM_UP_LATCH(latch, fsm, action) \
|
|
((void)LBL_fsmUpLatch(latch,fsm,(voidfunc_t)(action) WHENCE))
|
|
|
|
#define DOWN_LATCH(latch) LBL_downLatch(latch WHENCE)
|
|
#define UNS_LATCH(latch) LBL_unsLatch(latch WHENCE)
|
|
#define UNX_LATCH(latch) LBL_unxLatch(latch WHENCE)
|
|
#define UN_LATCH(latch) LBL_unLatch(latch WHENCE)
|
|
|
|
/*---------------------------------------------------------------------------
|
|
* Counting semaphore
|
|
*---------------------------------------------------------------------------*/
|
|
#define INIT_COUNT(latch, cnt) LBL_initCount(latch, cnt)
|
|
#define INC_COUNT(latch, cnt) LBL_incCount(latch, cnt)
|
|
#define INC_COUNT_CHECK(latch, cnt) LBL_incCountAndCheck(latch, cnt WHENCE)
|
|
#define DEC_COUNT(latch, cnt) LBL_decCount(latch, cnt)
|
|
#define GRAB(latch, cnt) LBL_grab(latch, cnt WHENCE)
|
|
#define DROP(latch, cnt) LBL_drop(latch, cnt WHENCE)
|
|
#define FSM_GRAB(latch, cnt, fsm, action) \
|
|
LBL_fsmGrab(latch, cnt, fsm, action WHENCE)
|
|
#define GRAB_NOWAIT(latch, cnt) LBL_grabNoWait(latch, cnt WHENCE)
|
|
|
|
#endif /* LATCH_MACRO IS_ENABLED */
|
|
|
|
|
|
#if NSS_DEBUG IS_ENABLED
|
|
/*-------------------------------------------------------------------------
|
|
* Debugging Support
|
|
*-------------------------------------------------------------------------*/
|
|
typedef struct LatchDbg_s
|
|
{
|
|
NINT hold;
|
|
NINT wait;
|
|
NINT grant;
|
|
NINT release;
|
|
NINT slatch;
|
|
NINT xlatch;
|
|
NINT sunlatch;
|
|
NINT xunlatch;
|
|
NINT unlatch;
|
|
NINT grab;
|
|
NINT drop;
|
|
} LatchDbg_s;
|
|
|
|
extern LatchDbg_s DBGL_LatchDbg;
|
|
|
|
extern void DBGL_latchSetup();
|
|
extern void DBGL_latchCleanup();
|
|
extern void DBGL_DumpLatches(
|
|
struct ScreenStruct *screen,
|
|
char **commandL);
|
|
|
|
#define LATCH_HASH_COUNT (1<<10) /** 1024 **/
|
|
#define LATCH_HASH_MASK (LATCH_HASH_COUNT-1)
|
|
|
|
extern STKtop_t DBGL_LatchPages;
|
|
|
|
|
|
#endif /* NSS_DEBUG */
|
|
|
|
extern NINT Latch_All();
|
|
extern NINT Latch_Free();
|
|
extern NINT Latch_Holder();
|
|
extern NINT Latch_Waiter();
|
|
|
|
STATUS doLatchInstDisplay (
|
|
struct PCLSwitchDef_s *switchDef,
|
|
NINT options,
|
|
void *userParm);
|
|
|
|
STATUS doLatchInstEnable (
|
|
struct PCLSwitchDef_s *switchDef,
|
|
NINT options,
|
|
void *userParm);
|
|
|
|
STATUS doLatchInstReset (
|
|
struct PCLSwitchDef_s *switchDef,
|
|
NINT options,
|
|
void *userParm);
|
|
|
|
extern BOOL RecordLatches;
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|