Files
mars-nwe/include/nwnss/include/latch.h
Mario Fetka 1808464145
Some checks failed
Source release / source-package (push) Failing after 1m17s
move to new lib
2026-06-14 21:47:50 +02:00

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