163 lines
3.8 KiB
C
163 lines
3.8 KiB
C
/*
|
|
SST_ReadWriteLock.c
|
|
|
|
License:
|
|
|
|
This program is free software. It comes without any warranty, to
|
|
the extent permitted by applicable law. You can redistribute it
|
|
and/or modify it under the terms of the Do What The Fuck You Want
|
|
To Public License, Version 2, as published by Sam Hocevar. See
|
|
http://sam.zoy.org/wtfpl/COPYING for more details.
|
|
*/
|
|
#ifndef __APPLE_CC__
|
|
#include <malloc.h>
|
|
#else
|
|
#include <stdlib.h>
|
|
#endif
|
|
|
|
#include <SST/SST_Build.h>
|
|
#include <SST/SST_Concurrency.h>
|
|
|
|
/* Leading (negative) bit is used to signal write lock */
|
|
#define SST_RWL_WRITE_BIT (0x80000000u)
|
|
|
|
/* ReadWriteLock implementation structure */
|
|
typedef struct SST_ReadWriteLockImpl {
|
|
volatile uint32_t state; /* state flag in the form 0xWRRRRRRR, i.e., write flag and then number of readers */
|
|
} SST_ReadWriteLockImpl;
|
|
|
|
/*************************************************************************/
|
|
|
|
extern SST_ReadWriteLock SST_Concurrency_CreateReadWriteLock( void )
|
|
{
|
|
SST_ReadWriteLockImpl *lock_impl = (SST_ReadWriteLockImpl*)malloc(sizeof(SST_ReadWriteLockImpl));
|
|
|
|
/* Check for allocation failure */
|
|
if (lock_impl == NULL)
|
|
return NULL;
|
|
|
|
/* Initialize the impl */
|
|
lock_impl->state = 0;
|
|
|
|
/* Make sure that goes out to memory */
|
|
SST_Concurrency_MemoryBarrier();
|
|
|
|
return lock_impl;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
extern void SST_Concurrency_DestroyReadWriteLock( SST_ReadWriteLock lock )
|
|
{
|
|
SST_ReadWriteLockImpl* lock_impl;
|
|
|
|
if (lock == NULL)
|
|
return;
|
|
|
|
lock_impl = (SST_ReadWriteLockImpl*)lock;
|
|
|
|
free(lock_impl);
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
extern int SST_Concurrency_LockForReading( SST_ReadWriteLock lock, uint32_t ticks )
|
|
{
|
|
uint64_t startTicks, currentTicks;
|
|
SST_ReadWriteLockImpl* lock_impl;
|
|
|
|
if (lock == NULL)
|
|
return 0;
|
|
|
|
startTicks = (uint32_t)SST_Concurrency_GetTicks();
|
|
|
|
lock_impl = (SST_ReadWriteLockImpl*)lock;
|
|
|
|
/* Spin (and yield) until we are not writing */
|
|
while (lock_impl->state & SST_RWL_WRITE_BIT)
|
|
{
|
|
if (ticks != SST_WAIT_INFINITE)
|
|
{
|
|
currentTicks = SST_Concurrency_GetTicks();
|
|
|
|
if ((uint32_t)(currentTicks - startTicks) > ticks)
|
|
return 0;
|
|
}
|
|
|
|
SST_Concurrency_YieldThread();
|
|
}
|
|
|
|
/* Increment the reader count by incrementing the state variable */
|
|
SST_Atomic_Inc(&lock_impl->state);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
extern int SST_Concurrency_LockForWriting( SST_ReadWriteLock lock, uint32_t ticks )
|
|
{
|
|
uint64_t startTicks, currentTicks;
|
|
SST_ReadWriteLockImpl* lock_impl;
|
|
|
|
if (lock == NULL)
|
|
return 0;
|
|
|
|
startTicks = SST_Concurrency_GetTicks();
|
|
|
|
lock_impl = (SST_ReadWriteLockImpl*)lock;
|
|
|
|
/* If we are already locked for writing, return */
|
|
if (lock_impl->state & SST_RWL_WRITE_BIT)
|
|
return 0;
|
|
|
|
/* Set the write flag */
|
|
SST_Atomic_Or((volatile int*)&lock_impl->state, SST_RWL_WRITE_BIT);
|
|
|
|
/* Spin (and yield) until we have no more readers */
|
|
while (lock_impl->state & ~SST_RWL_WRITE_BIT)
|
|
{
|
|
if (ticks != SST_WAIT_INFINITE)
|
|
{
|
|
currentTicks = SST_Concurrency_GetTicks();
|
|
|
|
if ((uint32_t)(currentTicks - startTicks) > ticks)
|
|
return 0;
|
|
}
|
|
|
|
SST_Concurrency_YieldThread();
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
extern void SST_Concurrency_EndReading( SST_ReadWriteLock lock )
|
|
{
|
|
SST_ReadWriteLockImpl* lock_impl;
|
|
|
|
if (lock == NULL)
|
|
return;
|
|
|
|
lock_impl = (SST_ReadWriteLockImpl*)lock;
|
|
|
|
/* Decrement the readers counter */
|
|
SST_Atomic_Dec(&lock_impl->state);
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
extern void SST_Concurrency_EndWriting( SST_ReadWriteLock lock )
|
|
{
|
|
SST_ReadWriteLockImpl* lock_impl;
|
|
|
|
if (lock == NULL)
|
|
return;
|
|
|
|
lock_impl = (SST_ReadWriteLockImpl*)lock;
|
|
|
|
/* Signal that we are free to read */
|
|
SST_Atomic_And((volatile int*)&lock_impl->state, ~SST_RWL_WRITE_BIT);
|
|
}
|