241 lines
7.7 KiB
C
241 lines
7.7 KiB
C
/* hookTblLibP.h - Private generic hook management library header */
|
|
|
|
/*
|
|
* Copyright (c) 2012 Wind River Systems, Inc.
|
|
*
|
|
* The right to copy, distribute, modify or otherwise make use
|
|
* of this software may be licensed only pursuant to the terms
|
|
* of an applicable Wind River license agreement.
|
|
*/
|
|
|
|
/*
|
|
modification history
|
|
--------------------
|
|
01b,27nov12,jpb fixed value of HOOK_TABLE_STATUS_BITS (WIND00392252)
|
|
01a,27apr12,cww written
|
|
*/
|
|
|
|
#ifndef __INChookTblLibPh
|
|
#define __INChookTblLibPh
|
|
|
|
#include <vxWorks.h>
|
|
#include <private/qLibP.h>
|
|
#include <hookLib.h>
|
|
#include <semLib.h>
|
|
#include <vxAtomicLib.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#ifndef _ASMLANGUAGE
|
|
|
|
typedef struct
|
|
{
|
|
VX_SEMAPHORE (lockSem);
|
|
int maxEntries;
|
|
int execCnt;
|
|
Q_HEAD updatePendQ;
|
|
void * pActiveTable;
|
|
void ** hookTableA;
|
|
void ** hookTableB;
|
|
} HOOK_TBL;
|
|
|
|
#define HOOK_TBL_DECL(name, maxEntries) \
|
|
void * name##ArrayA[maxEntries+1]; \
|
|
void * name##ArrayB[maxEntries+1]; \
|
|
HOOK_TBL name = {{},maxEntries,0,{},name##ArrayA,name##ArrayA, \
|
|
name##ArrayB};
|
|
|
|
/*
|
|
* Notes on the protection mechanisms used:
|
|
*
|
|
* Table updaters use a mutex (lockSem) to protect the table from simultaneous
|
|
* updates. Two copies of the actual hooks are maintained, one of which is
|
|
* always active and referenced by pActiveTable. Updating the hooks involves
|
|
* first updating the inactive table, flipping pActiveTable, then updating the
|
|
* other (now inactive) table.
|
|
*
|
|
* The mutex is not used for walking the table as we cannot pend when
|
|
* invoking hooks. Instead, bit manipulation of pActiveTable is used to mark
|
|
* when the table is being traversed, also serving to prevent pActiveTable
|
|
* from being swapped during hook invokation. A count (execCnt) is used to
|
|
* track nested and concurrent execution.
|
|
*
|
|
* The following status bits are stored in the least significant bits of
|
|
* pActiveTable and are used to protect the table from updates while it is
|
|
* being traversed. Setting HOOK_TABLE_IN_USE indicates that the table is
|
|
* reserved, while setting HOOK_TABLE_RESERVING indicates that the most recent
|
|
* operation is a reservation. The latter is required to detect the situation
|
|
* where the table is being reserved while an unreserve operation has already
|
|
* decremented execCnt to 0, but before the HOOK_TABLE_IN_USE bit is cleared,
|
|
* in which case the table should stay reserved.
|
|
*/
|
|
|
|
#define HOOK_TABLE_IN_USE 0x01L
|
|
#define HOOK_TABLE_RESERVING 0x02L
|
|
#define HOOK_TABLE_STATUS_BITS (HOOK_TABLE_IN_USE | HOOK_TABLE_RESERVING)
|
|
|
|
/******************************************************************************
|
|
*
|
|
* HOOK_TBL_READ_RESERVE - Reserve the active hook table for walking
|
|
*
|
|
* Marks the given HOOK_TBL as in use and returns a pointer to the active
|
|
* table via <pReservedTable>.
|
|
*
|
|
* \NOMANUAL
|
|
*/
|
|
|
|
#define HOOK_TBL_READ_RESERVE(pReservedTable,pHookTable) \
|
|
{ \
|
|
pReservedTable = (void *) vxAtomicOr ( \
|
|
(atomic_t *) &(pHookTable)->pActiveTable, \
|
|
HOOK_TABLE_STATUS_BITS); \
|
|
vxAtomic32Inc (&(pHookTable)->execCnt); \
|
|
pReservedTable = (void *)((ULONG) pReservedTable & \
|
|
~HOOK_TABLE_STATUS_BITS); \
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* HOOK_TBL_READ_UNRESERVE - Unreserve the active hook table
|
|
*
|
|
* Marks the given HOOK_TBL as not in use and potentially unpends any task
|
|
* waiting to update the table. Note that the CAS only fails if either another
|
|
* task sets the reserving bit, or we were preempted just before the CAS and
|
|
* someone else has unreserved already; in both cases, there is nothing more
|
|
* to do.
|
|
*
|
|
* \NOMANUAL
|
|
*/
|
|
|
|
#define HOOK_TBL_READ_UNRESERVE(pHookTable) \
|
|
{ \
|
|
atomic_t tempVal; \
|
|
\
|
|
tempVal = vxAtomicAnd ((atomic_t *) &(pHookTable)->pActiveTable, \
|
|
~HOOK_TABLE_RESERVING); \
|
|
tempVal &= ~HOOK_TABLE_RESERVING; \
|
|
\
|
|
if (vxAtomic32Dec (&(pHookTable)->execCnt) == 1) \
|
|
{ \
|
|
if (vxAtomicCas ((atomic_t *) &(pHookTable)->pActiveTable, \
|
|
tempVal, \
|
|
tempVal & ~(HOOK_TABLE_STATUS_BITS))) \
|
|
hookTblUpdatersUnpend (pHookTable); \
|
|
} \
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* HOOK_TBL_READ_UNRESERVE_NO_UNPEND - Unreserve the active hook table
|
|
*
|
|
* Marks the given HOOK_TBL as not in use but does not unpend any waiting task.
|
|
* Used only in special cases where we cannot enter the kernel, such as when
|
|
* running reboot hooks. We skip the reserving bit check since in these
|
|
* special cases we either don't care or no concurrent reserve is possible.
|
|
*
|
|
* \NOMANUAL
|
|
*/
|
|
|
|
#define HOOK_TBL_READ_UNRESERVE_NO_UNPEND(pHookTable) \
|
|
{ \
|
|
if (vxAtomic32Dec (&(pHookTable)->execCnt) == 1) \
|
|
{ \
|
|
vxAtomicAnd ((atomic_t *) &(pHookTable)->pActiveTable, \
|
|
~HOOK_TABLE_STATUS_BITS); \
|
|
} \
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* HOOK_TBL_INVOKE_VOID_RETURN - Invoke all hooks in the given table.
|
|
*
|
|
* This macro calls all hook functions added into the given hook table <tbl>.
|
|
* The called functions are not expected to return anything (return values
|
|
* are not checked). The <type> argument is a typecast that is applied to
|
|
* all function pointers in the table. This is done for type checking
|
|
* purposes. The <arglist> argument is a parenthesis-enclosed
|
|
* argument list that is passed verbatim to each hook function called.
|
|
*
|
|
* \NOMANUAL
|
|
*/
|
|
|
|
#define HOOK_TBL_INVOKE_VOID_RETURN(pTbl,type,arglist) \
|
|
{ \
|
|
int ix; \
|
|
void ** pTableCurrent; \
|
|
\
|
|
HOOK_TBL_READ_RESERVE (pTableCurrent,pTbl); \
|
|
\
|
|
for (ix = 0; ix < (pTbl)->maxEntries; ix++) \
|
|
{ \
|
|
if (pTableCurrent[ix] != NULL) \
|
|
(*(type) pTableCurrent[ix]) arglist; \
|
|
else \
|
|
break; \
|
|
} \
|
|
\
|
|
HOOK_TBL_READ_UNRESERVE (pTbl); \
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* HOOK_TBL_INVOKE_CHECK_RETURN - Invoke all hooks in a table, performing
|
|
* return value checking.
|
|
*
|
|
* This macro calls all hook functions added into the given hook table <tbl>.
|
|
* The return value from each called function is saved to <pRetval> and
|
|
* compared with <keepGoing>, and hook execution stops if they differ. In that
|
|
* case, any remaining hooks are not executed. The <type> argument is a
|
|
* typecast that is applied to all function pointers in the table. This is
|
|
* done for type checking purposes. The <arglist> must be a parenthesis-enclosed
|
|
* argument list that is passed verbatim to each hook function called.
|
|
*
|
|
* \NOMANUAL
|
|
*/
|
|
|
|
#define HOOK_TBL_INVOKE_CHECK_RETURN(pTbl,type,keepGoing,pRetval,arglist) \
|
|
{ \
|
|
int ix; \
|
|
void ** pTableCurrent; \
|
|
\
|
|
HOOK_TBL_READ_RESERVE (pTableCurrent,pTbl); \
|
|
\
|
|
for (ix = 0; ix < (pTbl)->maxEntries; ix++) \
|
|
{ \
|
|
if (pTableCurrent[ix] != NULL) \
|
|
{ \
|
|
*(pRetval) = (type) pTableCurrent[ix] arglist; \
|
|
if (*(pRetval) != keepGoing) \
|
|
{ \
|
|
break; \
|
|
} \
|
|
} \
|
|
else \
|
|
break; \
|
|
} \
|
|
\
|
|
HOOK_TBL_READ_UNRESERVE (pTbl); \
|
|
}
|
|
|
|
/* function declarations */
|
|
|
|
STATUS hookTblInit (HOOK_TBL * pTable);
|
|
STATUS hookTblAddToTail (HOOK_TBL * pTable, void * hook);
|
|
STATUS hookTblAddToHead (HOOK_TBL * pTable, void * hook);
|
|
STATUS hookTblDelete (HOOK_TBL * pTable, void * hook);
|
|
BOOL hookTblFind (HOOK_TBL * pTable, void * hook);
|
|
void hookTblUpdatersUnpend (HOOK_TBL * pTable);
|
|
|
|
void hookTblShow (HOOK_TBL * pHookTable);
|
|
|
|
#endif /* _ASMLANGUAGE */
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* __INChookTblLibPh */
|
|
|