(loc_RunThread, empth_init, empth_threadMain, empth_yield)
(empth_select, empth_sleep, empth_wait_for_signal) (empth_sem_wait) [EMPTH_W32]: Add the ability to wait additional event in loc_RunThread() when acquiring the hThread mutex. (empth_rwlock_t, empth_rwlock_create, empth_rwlock_destroy) (empth_rwlock_wrlock, empth_rwlock_rdlock, empth_rwlock_unlock): New. (empth_rwlock_t, empth_rwlock_create, empth_rwlock_destroy) (empth_rwlock_wrlock, empth_rwlock_rdlock, empth_rwlock_unlock) [EMPTH_W32]: WIN32 implementation. (empth_rwlock_t, empth_rwlock_create, empth_rwlock_destroy) (empth_rwlock_wrlock, empth_rwlock_rdlock, empth_rwlock_unlock) (lwp_rwlock, lwp_rwlock_create, lwp_rwlock_destroy) (lwp_rwlock_wrlock, lwp_rwlock_rdlock, lwp_rwlock_unlock) [EMPTH_LWP]: LWP implementation. (empth_rwlock_t, empth_rwlock_create, empth_rwlock_destroy) (empth_rwlock_wrlock, empth_rwlock_rdlock, empth_rwlock_unlock) [EMPTH_POSIX]: pthread implementation.
This commit is contained in:
parent
8c65fbc2be
commit
71e0f98825
6 changed files with 409 additions and 14 deletions
|
@ -31,7 +31,7 @@
|
||||||
* Sasha Mikheev
|
* Sasha Mikheev
|
||||||
* Doug Hay, 1998
|
* Doug Hay, 1998
|
||||||
* Steve McClure, 1998
|
* Steve McClure, 1998
|
||||||
* Markus Armbruster, 2005-2006
|
* Markus Armbruster, 2005-2007
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -74,6 +74,9 @@ typedef struct lwpProc empth_t;
|
||||||
/* empth_sem_t * represents a semaphore */
|
/* empth_sem_t * represents a semaphore */
|
||||||
typedef struct lwpSem empth_sem_t;
|
typedef struct lwpSem empth_sem_t;
|
||||||
|
|
||||||
|
/* empth_rwlock_t * represents a read-write lock */
|
||||||
|
typedef struct lwp_rwlock empth_rwlock_t;
|
||||||
|
|
||||||
/* Flags for empth_select(): whether to sleep on input or output */
|
/* Flags for empth_select(): whether to sleep on input or output */
|
||||||
#define EMPTH_FD_READ LWP_FD_READ
|
#define EMPTH_FD_READ LWP_FD_READ
|
||||||
#define EMPTH_FD_WRITE LWP_FD_WRITE
|
#define EMPTH_FD_WRITE LWP_FD_WRITE
|
||||||
|
@ -95,6 +98,7 @@ typedef struct lwpSem empth_sem_t;
|
||||||
|
|
||||||
typedef struct empth_t empth_t;
|
typedef struct empth_t empth_t;
|
||||||
typedef struct empth_sem_t empth_sem_t;
|
typedef struct empth_sem_t empth_sem_t;
|
||||||
|
typedef struct empth_rwlock_t empth_rwlock_t;
|
||||||
|
|
||||||
#endif /* EMPTH_POSIX */
|
#endif /* EMPTH_POSIX */
|
||||||
|
|
||||||
|
@ -108,6 +112,7 @@ typedef struct empth_sem_t empth_sem_t;
|
||||||
|
|
||||||
typedef struct loc_Thread_t empth_t;
|
typedef struct loc_Thread_t empth_t;
|
||||||
typedef struct loc_Sem_t empth_sem_t;
|
typedef struct loc_Sem_t empth_sem_t;
|
||||||
|
typedef struct loc_RWLock_t empth_rwlock_t;
|
||||||
|
|
||||||
void empth_request_shutdown(void);
|
void empth_request_shutdown(void);
|
||||||
#endif /* EMPTH_W32 */
|
#endif /* EMPTH_W32 */
|
||||||
|
@ -220,6 +225,42 @@ void empth_sem_signal(empth_sem_t *sem);
|
||||||
*/
|
*/
|
||||||
void empth_sem_wait(empth_sem_t *sem);
|
void empth_sem_wait(empth_sem_t *sem);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a read-write lock.
|
||||||
|
* NAME is its name, it is used for debugging.
|
||||||
|
* Return the reade-write lock, or NULL on error.
|
||||||
|
*/
|
||||||
|
empth_rwlock_t *empth_rwlock_create(char *name);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Destroy RWLOCK.
|
||||||
|
*/
|
||||||
|
void empth_rwlock_destroy(empth_rwlock_t *rwlock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lock RWLOCK for writing.
|
||||||
|
* A read-write lock can be locked for writing only when it is
|
||||||
|
* unlocked. If this is not the case, put the current thread to sleep
|
||||||
|
* until it is.
|
||||||
|
*/
|
||||||
|
void empth_rwlock_wrlock(empth_rwlock_t *rwlock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lock RWLOCK for reading.
|
||||||
|
* A read-write lock can be locked for reading only when it is not
|
||||||
|
* locked for writing. If this is not the case, put the current
|
||||||
|
* thread to sleep until it is. Must not starve writers, and may
|
||||||
|
* sleep to avoid that.
|
||||||
|
*/
|
||||||
|
void empth_rwlock_rdlock(empth_rwlock_t *rwlock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unlock read-write lock RWLOCK.
|
||||||
|
* The current thread must hold RWLOCK.
|
||||||
|
* Wake up threads that can now lock it.
|
||||||
|
*/
|
||||||
|
void empth_rwlock_unlock(empth_rwlock_t *rwlock);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stuff for implementations, not for clients.
|
* Stuff for implementations, not for clients.
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
struct lwpProc;
|
struct lwpProc;
|
||||||
struct lwpSem;
|
struct lwpSem;
|
||||||
|
struct lwp_rwlock;
|
||||||
|
|
||||||
#define LWP_FD_READ 0x1
|
#define LWP_FD_READ 0x1
|
||||||
#define LWP_FD_WRITE 0x2
|
#define LWP_FD_WRITE 0x2
|
||||||
|
@ -57,6 +58,12 @@ struct lwpSem *lwpCreateSem(char *name, int count);
|
||||||
void lwpSignal(struct lwpSem *);
|
void lwpSignal(struct lwpSem *);
|
||||||
void lwpWait(struct lwpSem *);
|
void lwpWait(struct lwpSem *);
|
||||||
|
|
||||||
|
struct lwp_rwlock *lwp_rwlock_create(char *);
|
||||||
|
void lwp_rwlock_destroy(struct lwp_rwlock *);
|
||||||
|
void lwp_rwlock_wrlock(struct lwp_rwlock *);
|
||||||
|
void lwp_rwlock_rdlock(struct lwp_rwlock *);
|
||||||
|
void lwp_rwlock_unlock(struct lwp_rwlock *);
|
||||||
|
|
||||||
extern struct lwpProc *LwpCurrent;
|
extern struct lwpProc *LwpCurrent;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
*
|
*
|
||||||
* Known contributors to this file:
|
* Known contributors to this file:
|
||||||
* Sasha Mikheev
|
* Sasha Mikheev
|
||||||
* Markus Armbruster, 2006
|
* Markus Armbruster, 2006-2007
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
@ -149,3 +149,33 @@ empth_sem_wait(empth_sem_t *sm)
|
||||||
{
|
{
|
||||||
lwpWait(sm);
|
lwpWait(sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
empth_rwlock_t *
|
||||||
|
empth_rwlock_create(char *name)
|
||||||
|
{
|
||||||
|
return lwp_rwlock_create(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
empth_rwlock_destroy(empth_rwlock_t *rwlock)
|
||||||
|
{
|
||||||
|
lwp_rwlock_destroy(rwlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
empth_rwlock_wrlock(empth_rwlock_t *rwlock)
|
||||||
|
{
|
||||||
|
lwp_rwlock_wrlock(rwlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
empth_rwlock_rdlock(empth_rwlock_t *rwlock)
|
||||||
|
{
|
||||||
|
lwp_rwlock_rdlock(rwlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
empth_rwlock_unlock(empth_rwlock_t *rwlock)
|
||||||
|
{
|
||||||
|
lwp_rwlock_unlock(rwlock);
|
||||||
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
* Known contributors to this file:
|
* Known contributors to this file:
|
||||||
* Doug Hay, 1998
|
* Doug Hay, 1998
|
||||||
* Steve McClure, 1998
|
* Steve McClure, 1998
|
||||||
* Ron Koenderink, 2004-2005
|
* Ron Koenderink, 2004-2007
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -108,6 +108,53 @@ struct loc_Sem_t {
|
||||||
int count;
|
int count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/************************
|
||||||
|
* loc_RWLock_t
|
||||||
|
*
|
||||||
|
* Invariants
|
||||||
|
* must hold at function call, return, sleep
|
||||||
|
* and resume from sleep.
|
||||||
|
*
|
||||||
|
* any state:
|
||||||
|
* nwrite >= 0
|
||||||
|
* nread >= 0
|
||||||
|
|
||||||
|
* if unlocked:
|
||||||
|
* can_read set
|
||||||
|
* can_write set
|
||||||
|
* nwrite == 0
|
||||||
|
* nread == 0
|
||||||
|
*
|
||||||
|
* if read-locked without writers contending:
|
||||||
|
* can_read set
|
||||||
|
* can_write clear
|
||||||
|
* nwrite == 0
|
||||||
|
* nread > 0
|
||||||
|
*
|
||||||
|
* if read-locked with writers contending:
|
||||||
|
* can_read clear
|
||||||
|
* can_write clear
|
||||||
|
* nwrite > 0 #writers blocked
|
||||||
|
* nread > 0
|
||||||
|
*
|
||||||
|
* if write-locked:
|
||||||
|
* can_read clear
|
||||||
|
* can_write clear
|
||||||
|
* nwrite > 0 #writers blocked + 1
|
||||||
|
* nread == 0
|
||||||
|
*
|
||||||
|
* To ensure consistency, state normally changes only while the
|
||||||
|
* thread changing it holds hThreadMutex.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct loc_RWLock_t {
|
||||||
|
char name[17]; /* The thread name, passed in at create time. */
|
||||||
|
HANDLE can_read; /* Manual event -- allows read locks */
|
||||||
|
HANDLE can_write; /* Auto-reset event -- allows write locks */
|
||||||
|
int nread; /* number of active readers */
|
||||||
|
int nwrite; /* total number of writers (active and waiting) */
|
||||||
|
};
|
||||||
|
|
||||||
/* This is the thread exclusion/non-premption mutex. */
|
/* This is the thread exclusion/non-premption mutex. */
|
||||||
/* The running thread has this MUTEX, and all others are */
|
/* The running thread has this MUTEX, and all others are */
|
||||||
/* either blocked on it, or waiting for some OS response. */
|
/* either blocked on it, or waiting for some OS response. */
|
||||||
|
@ -202,8 +249,10 @@ loc_FreeThreadInfo(empth_t *pThread)
|
||||||
* info, and the thread owns the MUTEX sem.
|
* info, and the thread owns the MUTEX sem.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
loc_RunThisThread(void)
|
loc_RunThisThread(HANDLE hWaitObject)
|
||||||
{
|
{
|
||||||
|
HANDLE hWaitObjects[2];
|
||||||
|
|
||||||
empth_t *pThread = TlsGetValue(dwTLSIndex);
|
empth_t *pThread = TlsGetValue(dwTLSIndex);
|
||||||
|
|
||||||
if (pThread->bKilled) {
|
if (pThread->bKilled) {
|
||||||
|
@ -214,8 +263,11 @@ loc_RunThisThread(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the MUTEX semaphore, wait forever. */
|
hWaitObjects[0] = hThreadMutex;
|
||||||
WaitForSingleObject(hThreadMutex, INFINITE);
|
hWaitObjects[1] = hWaitObject;
|
||||||
|
|
||||||
|
WaitForMultipleObjects(hWaitObject ? 2 : 1, hWaitObjects,
|
||||||
|
TRUE, INFINITE);
|
||||||
|
|
||||||
if (!pCurThread) {
|
if (!pCurThread) {
|
||||||
/* Set the globals to this thread. */
|
/* Set the globals to this thread. */
|
||||||
|
@ -306,7 +358,7 @@ empth_threadMain(void *pvData)
|
||||||
srand(now ^ (unsigned)pThread);
|
srand(now ^ (unsigned)pThread);
|
||||||
|
|
||||||
/* Switch to this thread context */
|
/* Switch to this thread context */
|
||||||
loc_RunThisThread();
|
loc_RunThisThread(NULL);
|
||||||
|
|
||||||
/* Run the thread. */
|
/* Run the thread. */
|
||||||
if (pThread->pfnEntry)
|
if (pThread->pfnEntry)
|
||||||
|
@ -375,7 +427,7 @@ empth_init(void **ctx_ptr, int flags)
|
||||||
TlsSetValue(dwTLSIndex, pThread);
|
TlsSetValue(dwTLSIndex, pThread);
|
||||||
|
|
||||||
/* Make this the running thread. */
|
/* Make this the running thread. */
|
||||||
loc_RunThisThread();
|
loc_RunThisThread(NULL);
|
||||||
|
|
||||||
logerror("NT pthreads initialized");
|
logerror("NT pthreads initialized");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -481,7 +533,7 @@ void
|
||||||
empth_yield(void)
|
empth_yield(void)
|
||||||
{
|
{
|
||||||
loc_BlockThisThread();
|
loc_BlockThisThread();
|
||||||
loc_RunThisThread();
|
loc_RunThisThread(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************
|
/************************
|
||||||
|
@ -534,7 +586,7 @@ empth_select(int fd, int flags)
|
||||||
|
|
||||||
WSACloseEvent(hEventObject[0]);
|
WSACloseEvent(hEventObject[0]);
|
||||||
|
|
||||||
loc_RunThisThread();
|
loc_RunThisThread(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************
|
/************************
|
||||||
|
@ -570,7 +622,7 @@ empth_sleep(time_t until)
|
||||||
|
|
||||||
loc_debug("sleep done. Waiting to run.");
|
loc_debug("sleep done. Waiting to run.");
|
||||||
|
|
||||||
loc_RunThisThread();
|
loc_RunThisThread(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************
|
/************************
|
||||||
|
@ -593,7 +645,7 @@ empth_wait_for_signal(void)
|
||||||
/* Get the MUTEX semaphore, wait the number of MS */
|
/* Get the MUTEX semaphore, wait the number of MS */
|
||||||
WaitForSingleObject(hShutdownEvent, INFINITE);
|
WaitForSingleObject(hShutdownEvent, INFINITE);
|
||||||
|
|
||||||
loc_RunThisThread();
|
loc_RunThisThread(NULL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -670,5 +722,81 @@ empth_sem_wait(empth_sem_t *pSem)
|
||||||
} else
|
} else
|
||||||
ReleaseMutex(pSem->hMutex);
|
ReleaseMutex(pSem->hMutex);
|
||||||
|
|
||||||
loc_RunThisThread();
|
loc_RunThisThread(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
empth_rwlock_t *
|
||||||
|
empth_rwlock_create(char *name)
|
||||||
|
{
|
||||||
|
empth_rwlock_t *rwlock;
|
||||||
|
|
||||||
|
rwlock = malloc(sizeof(*rwlock));
|
||||||
|
if (!rwlock)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memset(rwlock, 0, sizeof(*rwlock));
|
||||||
|
strncpy(rwlock->name, name, sizeof(rwlock->name) - 1);
|
||||||
|
|
||||||
|
if ((rwlock->can_read = CreateEvent(NULL, TRUE, TRUE, NULL)) == NULL) {
|
||||||
|
logerror("rwlock_create: failed to create reader event %s at %s:%d",
|
||||||
|
name, __FILE__, __LINE__);
|
||||||
|
free(rwlock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((rwlock->can_write = CreateEvent(NULL, FALSE, TRUE, NULL)) == NULL) {
|
||||||
|
logerror("rwlock_create: failed to create writer event %s at %s:%d",
|
||||||
|
name, __FILE__, __LINE__);
|
||||||
|
CloseHandle(rwlock->can_read);
|
||||||
|
free(rwlock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return rwlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
empth_rwlock_destroy(empth_rwlock_t *rwlock)
|
||||||
|
{
|
||||||
|
if (CANT_HAPPEN(rwlock->nread || rwlock->nwrite))
|
||||||
|
return;
|
||||||
|
CloseHandle(rwlock->can_read);
|
||||||
|
CloseHandle(rwlock->can_write);
|
||||||
|
free(rwlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
empth_rwlock_wrlock(empth_rwlock_t *rwlock)
|
||||||
|
{
|
||||||
|
/* block any new readers */
|
||||||
|
ResetEvent(rwlock->can_read);
|
||||||
|
rwlock->nwrite++;
|
||||||
|
loc_BlockThisThread();
|
||||||
|
loc_RunThisThread(rwlock->can_write);
|
||||||
|
CANT_HAPPEN(rwlock->nread != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
empth_rwlock_rdlock(empth_rwlock_t *rwlock)
|
||||||
|
{
|
||||||
|
loc_BlockThisThread();
|
||||||
|
loc_RunThisThread(rwlock->can_read);
|
||||||
|
ResetEvent(rwlock->can_write);
|
||||||
|
rwlock->nread++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
empth_rwlock_unlock(empth_rwlock_t *rwlock)
|
||||||
|
{
|
||||||
|
if (CANT_HAPPEN(!rwlock->nread && !rwlock->nwrite))
|
||||||
|
return;
|
||||||
|
if (rwlock->nread) { /* holding read lock */
|
||||||
|
rwlock->nread--;
|
||||||
|
if (rwlock->nread == 0)
|
||||||
|
SetEvent(rwlock->can_write);
|
||||||
|
} else {
|
||||||
|
rwlock->nwrite--;
|
||||||
|
SetEvent(rwlock->can_write);
|
||||||
|
}
|
||||||
|
if (rwlock->nwrite == 0)
|
||||||
|
SetEvent(rwlock->can_read);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,8 @@
|
||||||
* Known contributors to this file:
|
* Known contributors to this file:
|
||||||
* Sasha Mikheev
|
* Sasha Mikheev
|
||||||
* Steve McClure, 1998
|
* Steve McClure, 1998
|
||||||
* Markus Armbruster, 2005-2006
|
* Markus Armbruster, 2005-2007
|
||||||
|
* Ron Koenderink, 2007
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Required for PTHREAD_STACK_MIN on some systems, e.g. Solaris: */
|
/* Required for PTHREAD_STACK_MIN on some systems, e.g. Solaris: */
|
||||||
|
@ -75,6 +76,11 @@ struct empth_sem_t {
|
||||||
pthread_cond_t cnd_sem;
|
pthread_cond_t cnd_sem;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct empth_rwlock_t {
|
||||||
|
char *name;
|
||||||
|
pthread_rwlock_t lock;
|
||||||
|
};
|
||||||
|
|
||||||
/* Thread-specific data key */
|
/* Thread-specific data key */
|
||||||
static pthread_key_t ctx_key;
|
static pthread_key_t ctx_key;
|
||||||
|
|
||||||
|
@ -455,3 +461,52 @@ empth_sem_wait(empth_sem_t *sm)
|
||||||
} else
|
} else
|
||||||
pthread_mutex_unlock(&sm->mtx_update);
|
pthread_mutex_unlock(&sm->mtx_update);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
empth_rwlock_t *
|
||||||
|
empth_rwlock_create(char *name)
|
||||||
|
{
|
||||||
|
empth_rwlock_t *rwlock;
|
||||||
|
|
||||||
|
rwlock = malloc(sizeof(*rwlock));
|
||||||
|
if (!rwlock)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (pthread_rwlock_init(&rwlock->lock, NULL) != 0) {
|
||||||
|
free(rwlock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rwlock->name = strdup(name);
|
||||||
|
return rwlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
empth_rwlock_destroy(empth_rwlock_t *rwlock)
|
||||||
|
{
|
||||||
|
pthread_rwlock_destroy(&rwlock->lock);
|
||||||
|
free(rwlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
empth_rwlock_wrlock(empth_rwlock_t *rwlock)
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&mtx_ctxsw);
|
||||||
|
pthread_rwlock_wrlock(&rwlock->lock);
|
||||||
|
pthread_mutex_lock(&mtx_ctxsw);
|
||||||
|
empth_restorectx();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
empth_rwlock_rdlock(empth_rwlock_t *rwlock)
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&mtx_ctxsw);
|
||||||
|
pthread_rwlock_rdlock(&rwlock->lock);
|
||||||
|
pthread_mutex_lock(&mtx_ctxsw);
|
||||||
|
empth_restorectx();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
empth_rwlock_unlock(empth_rwlock_t *rwlock)
|
||||||
|
{
|
||||||
|
pthread_rwlock_unlock(&rwlock->lock);
|
||||||
|
}
|
||||||
|
|
134
src/lib/lwp/rwlock.c
Normal file
134
src/lib/lwp/rwlock.c
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
/*
|
||||||
|
* Empire - A multi-player, client/server Internet based war game.
|
||||||
|
* Copyright (C) 1994-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
|
||||||
|
* Ken Stevens, Steve McClure
|
||||||
|
* Copyright (C) 1991-3 Stephen Crane
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* ---
|
||||||
|
*
|
||||||
|
* See files README, COPYING and CREDITS in the root of the source
|
||||||
|
* tree for related information and legal notices. It is expected
|
||||||
|
* that future projects/authors will amend these files as needed.
|
||||||
|
*
|
||||||
|
* ---
|
||||||
|
*
|
||||||
|
* rwlock.c: Read-write locks
|
||||||
|
*
|
||||||
|
* Known contributors to this file:
|
||||||
|
* Ron Koenderink, 2007
|
||||||
|
* Markus Armbruster, 2007
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "lwp.h"
|
||||||
|
#include "lwpint.h"
|
||||||
|
|
||||||
|
struct lwp_rwlock {
|
||||||
|
/*
|
||||||
|
* Lock counter
|
||||||
|
* 0: unlocked
|
||||||
|
* -1: locked for writing
|
||||||
|
* >0: locked for reading that many times
|
||||||
|
*/
|
||||||
|
int count;
|
||||||
|
struct lwpQueue rq; /* read lock sleepers */
|
||||||
|
struct lwpQueue wq; /* write lock sleepers */
|
||||||
|
char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lwp_rwlock *
|
||||||
|
lwp_rwlock_create(char *name)
|
||||||
|
{
|
||||||
|
struct lwp_rwlock *rwlock;
|
||||||
|
|
||||||
|
rwlock = malloc(sizeof(*rwlock));
|
||||||
|
if (!rwlock)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memset(rwlock, 0, sizeof(*rwlock));
|
||||||
|
rwlock->name = strdup(name);
|
||||||
|
return rwlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lwp_rwlock_destroy(struct lwp_rwlock *rwlock)
|
||||||
|
{
|
||||||
|
if (CANT_HAPPEN(rwlock->count))
|
||||||
|
return;
|
||||||
|
free(rwlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lwp_rwlock_wrlock(struct lwp_rwlock *rwlock)
|
||||||
|
{
|
||||||
|
if (rwlock->count) {
|
||||||
|
lwpAddTail(&rwlock->wq, LwpCurrent);
|
||||||
|
lwpStatus(LwpCurrent, "blocked to acquire rwlock %s for writing",
|
||||||
|
rwlock->name);
|
||||||
|
lwpReschedule();
|
||||||
|
}
|
||||||
|
CANT_HAPPEN(rwlock->count != 0);
|
||||||
|
rwlock->count = -1;
|
||||||
|
lwpStatus(LwpCurrent, "acquired rwlock %s for writing", rwlock->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lwp_rwlock_rdlock(struct lwp_rwlock *rwlock)
|
||||||
|
{
|
||||||
|
if (rwlock->count < 0 || rwlock->wq.head) {
|
||||||
|
lwpStatus(LwpCurrent, "blocked to acquire rwlock %s for reading",
|
||||||
|
rwlock->name);
|
||||||
|
lwpAddTail(&rwlock->rq, LwpCurrent);
|
||||||
|
lwpReschedule();
|
||||||
|
}
|
||||||
|
CANT_HAPPEN(rwlock->count < 0);
|
||||||
|
rwlock->count++;
|
||||||
|
lwpStatus(LwpCurrent, "acquired rwlock %s for reading", rwlock->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lwp_rwlock_unlock(struct lwp_rwlock *rwlock)
|
||||||
|
{
|
||||||
|
struct lwpProc *p;
|
||||||
|
|
||||||
|
lwpStatus(LwpCurrent, "unlocking rwlock %s", rwlock->name);
|
||||||
|
if (CANT_HAPPEN(rwlock->count == 0))
|
||||||
|
return;
|
||||||
|
if (rwlock->count < 0)
|
||||||
|
rwlock->count = 0;
|
||||||
|
else
|
||||||
|
rwlock->count--;
|
||||||
|
|
||||||
|
if (rwlock->count == 0 && rwlock->wq.head) {
|
||||||
|
p = lwpGetFirst(&rwlock->wq);
|
||||||
|
lwpStatus(p, "wake up next writer of rwlock %s", rwlock->name);
|
||||||
|
} else if (rwlock->count >= 0 && rwlock->rq.head && !rwlock->wq.head) {
|
||||||
|
p = lwpGetFirst(&rwlock->rq);
|
||||||
|
lwpStatus(p, "wake up next reader of rwlock %s", rwlock->name);
|
||||||
|
} else
|
||||||
|
return;
|
||||||
|
|
||||||
|
lwpReady(p);
|
||||||
|
if (LwpCurrent->pri < p->pri) {
|
||||||
|
lwpStatus(LwpCurrent, "yielding to thread with higher priority");
|
||||||
|
lwpYield();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue