Files
m241Neelima/vxworks-6.9/target/h/dshm/adapt/refl.h
T
2026-07-30 11:19:44 +05:30

305 lines
7.4 KiB
C

/* refl.h - local one-modifier/several-user lock */
/*
* Copyright (c) 2007~2008, 2010 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
--------------------
01f,29apr10,pad Moved extern C statement after include statements.
01e,05sep08,cwu add static declaration for DSHM_INLINE related function
01d,05sep07,bwa changed intLockKey into a stack variable (103613)
01c,17jun07,bwa updated following code review.
01b,03apr07,bwa added comments.
01a,15mar07,bwa written.
*/
/* This module implements a read-write lock (use-modify) with a reference
* count, used for local data structures. It is primarily used to protect
* service data structures and driver data structures that are mostly accessed
* in read mode.
*
* This type of lock should be used sparingly, since the data structure is
* relatively heavy, using two semaphores.
*/
#ifndef __INCdshmReflh
#define __INCdshmReflh
#include <dshm/dshm.h>
#include <private/semLibP.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct __REF_LOCK
{
int nReaders; /* number of read takes */
BOOL isWriter; /* modifier wants or has the lock */
SEMAPHORE wlock; /* writer signal */
SEMAPHORE rlock; /* reader signal */
} _REF_LOCK;
/*******************************************************************************
*
* reflInit - initialize a reference count lock
*
* RETURNS: N/A
*/
static DSHM_INLINE void reflInit (_REF_LOCK *pLock)
{
pLock->nReaders = 0;
pLock->isWriter = FALSE;
(void)semBInit (&pLock->rlock, SEM_Q_FIFO, SEM_EMPTY);
(void)semBInit (&pLock->wlock, SEM_Q_FIFO, SEM_EMPTY);
}
/*******************************************************************************
*
* reflUseTake - obtain a reference count lock in 'use' mode
*
* This routine tries to obtain the lock in 'use' mode. It can block the current
* thread of control if the lock is currently taken in 'modify' mode. After
* being unblocked, the thread will retry taking the lock.
*
* RETURNS: TRUE, always
*/
static DSHM_INLINE BOOL reflUseTake (_REF_LOCK *pLock)
{
FOREVER
{
int intLockKey = DSHM_INTLOCK ();
if (!pLock->isWriter)
{
++pLock->nReaders;
DSHM_INTUNLOCK (intLockKey);
return TRUE;
}
else
{
DSHM_INTUNLOCK (intLockKey);
semTake (&pLock->rlock, WAIT_FOREVER);
}
}
}
/*******************************************************************************
*
* reflUseGive - give a lock that was previously taken in 'use' mode.
*
* This routine gives a lock taken in 'use' mode. Care must be taken to only
* call this routine if the lock had previously been acquired in 'use' mode,
* since no verification is done. If this is not observed, the lock will end up
* in an incorrect state, will most probably cause deadlocks.
*
* RETURNS: N/A
*/
static DSHM_INLINE void reflUseGive (_REF_LOCK *pLock)
{
int intLockKey = DSHM_INTLOCK ();
if (--pLock->nReaders == 0)
{
if (pLock->isWriter)
{
DSHM_INTUNLOCK (intLockKey);
semGive (&pLock->wlock);
return;
}
}
DSHM_INTUNLOCK (intLockKey);
}
/*******************************************************************************
*
* reflModTake - obtain a lock in 'modify' mode
*
* This routine tries to obtain the lock in 'modify' mode. If the lock is
* currently held in this mode, the operation will fail. If the lock is
* held in 'use' mode, the thread will block until the lock is released by all
* threads owning it.
*
* When a thread tries to obtain the lock in 'modify' mode, all further attempts
* to take it in 'use' mode will block until the lock is acquired and released
* in 'modify' mode.
*
* RETURNS: TRUE on success, FALSE on failure.
*/
static DSHM_INLINE BOOL reflModTake (_REF_LOCK *pLock)
{
int intLockKey = DSHM_INTLOCK ();
/* someone is already making changes */
if (pLock->isWriter)
{
DSHM_INTUNLOCK (intLockKey);
return FALSE;
}
pLock->isWriter = TRUE;
if (pLock->nReaders)
{
DSHM_INTUNLOCK(intLockKey);
semTake (&pLock->wlock, WAIT_FOREVER);
return TRUE;
}
DSHM_INTUNLOCK(intLockKey);
return TRUE;
}
/*******************************************************************************
*
* reflDemote - turn a lock held in 'modify' mode to a lock held in 'use' mode
*
* This routine demotes a 'modify' lock to a 'use' lock. If threads are waiting
* to acquire it in 'use' mode, they will awaken.
*
* Care must be taken to only
* call this routine if the lock had previously been acquired in 'modify' mode,
* since no verification is done. If this is not observed, the lock will end up
* in an incorrect state, will most probably cause deadlocks.
*
* RETURNS: N/A
*/
static DSHM_INLINE void reflDemote (_REF_LOCK *pLock)
{
int intLockKey = DSHM_INTLOCK ();
pLock->isWriter = FALSE;
pLock->nReaders = 1;
DSHM_INTUNLOCK (intLockKey);
semFlush (&pLock->rlock);
}
/*******************************************************************************
*
* reflModGive - release a lock that was held in 'modify' mode
*
* Give a lock held in 'modify' mode. Threads waiting to acquire the lock in
* 'use' mode will be unblocked and will obtain the lock.
*
* Care must be taken to only
* call this routine if the lock had previously been acquired in 'modify' mode,
* since no verification is done. If this is not observed, the lock will end up
* in an incorrect state, will most probably cause deadlocks.
*
* RETURNS: N/A
*/
static DSHM_INLINE void reflModGive (_REF_LOCK *pLock)
{
int intLockKey = DSHM_INTLOCK ();
pLock->isWriter = FALSE;
DSHM_INTUNLOCK(intLockKey);
semFlush (&pLock->rlock);
}
#ifdef __cplusplus
}
#endif
#endif /* __INCdshmReflh */
/* test cases */
#if 0
void __helper (_REF_LOCK *pLock)
{
printf ("__helper spawned\n");
if (reflModTake (pLock))
{
printf ("__helper: got lock\n");
}
else
{
printf ("error helper 1\n");
return;
}
if (!reflModTake (pLock))
{
printf ("__helper: failed taking lock twice, GOOD\n");
}
else
{
printf ("error helper 2\n");
return;
}
printf ("__helper: releasing\n");
reflModGive (pLock);
printf ("__helper: released\n");
printf ("__helper: done\n");
}
void __test (void)
{
_REF_LOCK lock;
reflInit (&lock);
if (reflUseTake (&lock))
printf ("got ref lock once\n");
else
{
printf ("error 1\n");
return;
}
if (reflUseTake (&lock))
printf ("got ref lock twice\n");
else
{
printf ("error 2\n");
return;
}
if (reflUseTake (&lock))
printf ("got ref lock thrice\n");
else
{
printf ("error 3\n");
return;
}
reflUseGive (&lock);
printf ("gave ref lock once\n");
reflUseGive (&lock);
printf ("gave ref lock twice\n");
{
int prio;
taskPriorityGet (taskIdSelf(), &prio);
printf ("spawning task @ priority %d\n", prio);
if (ERROR == taskSpawn (NULL, prio-1, 0, 20000, (FUNCPTR)__helper, (int)&lock, 0,0,0,0,0,0,0,0,0))
{
printf ("can't spawn task\n");
taskSuspend (taskIdSelf());
}
printf ("spawned helper\n");
}
reflUseGive (&lock);
printf ("gave ref lock thrice\n");
if (reflUseTake (&lock))
printf ("got ref final lock\n");
else
{
printf ("error 7\n");
return;
}
reflUseGive (&lock);
printf ("gave ref final lock\n");
}
#endif