2004-06-24 21:10:31 +00:00
|
|
|
/*
|
|
|
|
* File : rw.c
|
|
|
|
*
|
|
|
|
* Title : Demo Readers/Writer.
|
|
|
|
*
|
|
|
|
* Short : A solution to the multi-reader's, one writer problem.
|
|
|
|
*
|
|
|
|
* Long :
|
|
|
|
*
|
|
|
|
* Author : Andrae Muys
|
|
|
|
*
|
|
|
|
* Date : 18 September 1997
|
|
|
|
*
|
2009-05-30 02:22:04 +00:00
|
|
|
* Revised : 4-7-04 Shamelessly stolen and adapted by Rusty Sears.
|
2010-05-27 01:48:27 +00:00
|
|
|
* Found the contents of rw.c at this url:
|
2004-06-24 21:10:31 +00:00
|
|
|
* http://www.cs.nmsu.edu/~jcook/Tools/pthreads/rw.c
|
2010-05-27 01:48:27 +00:00
|
|
|
*
|
|
|
|
* Revised : (date?): Converted to thin wrapper over pthread_rwlock.
|
|
|
|
* Revised : 5-26 Added rwlc locks, which can wait for condition variables (assuming they hold a write lock)
|
2004-06-24 21:10:31 +00:00
|
|
|
*/
|
2004-07-04 00:46:49 +00:00
|
|
|
#ifndef __LIBDFA_RW_H
|
|
|
|
#define __LIBDFA_RW_H
|
2007-08-24 23:01:08 +00:00
|
|
|
|
2010-01-21 00:03:17 +00:00
|
|
|
#include <stasis/common.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
2007-08-24 23:01:08 +00:00
|
|
|
BEGIN_C_DECLS
|
2010-01-21 00:03:17 +00:00
|
|
|
|
|
|
|
|
2009-10-13 00:29:35 +00:00
|
|
|
#define HAVE_PTHREAD_RWLOCK
|
|
|
|
#ifdef HAVE_PTHREAD_RWLOCK
|
|
|
|
typedef pthread_rwlock_t rwl;
|
2007-08-24 23:01:08 +00:00
|
|
|
|
2009-10-13 00:29:35 +00:00
|
|
|
static inline rwl* initlock(void) {
|
|
|
|
rwl* ret = (rwl*)malloc(sizeof(*ret));
|
|
|
|
int err = pthread_rwlock_init(ret, 0);
|
|
|
|
if(err) { perror("couldn't init rwlock"); abort(); }
|
2010-08-05 23:07:52 +00:00
|
|
|
DEBUG("initlock(%llx)\n", (long long)ret);
|
2009-10-13 00:29:35 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
static inline void readlock(rwl *lock, int d) {
|
2010-08-05 23:07:52 +00:00
|
|
|
DEBUG("readlock(%llx)\n", (long long)lock);
|
2009-10-13 00:29:35 +00:00
|
|
|
pthread_rwlock_rdlock(lock);
|
|
|
|
}
|
|
|
|
static inline int tryreadlock(rwl *lock, int d) {
|
2010-08-05 23:07:52 +00:00
|
|
|
DEBUG("? = tryreadlock(%llx)\n", (long long)lock);
|
|
|
|
int ret = (0 == pthread_rwlock_tryrdlock(lock));
|
|
|
|
DEBUG("%d = tryreadlock(%llx)\n", ret, (long long)lock);
|
|
|
|
return ret;
|
2009-10-13 00:29:35 +00:00
|
|
|
}
|
|
|
|
static inline void writelock(rwl *lock, int d) {
|
2010-08-05 23:07:52 +00:00
|
|
|
DEBUG("writelock(%llx)\n", (long long)lock);
|
2009-10-13 00:29:35 +00:00
|
|
|
pthread_rwlock_wrlock(lock);
|
|
|
|
}
|
|
|
|
static inline int trywritelock(rwl *lock, int d) {
|
2010-08-05 23:07:52 +00:00
|
|
|
DEBUG("? = trywritelock(%llx)\n", (long long)lock);
|
|
|
|
int ret = (0 == pthread_rwlock_trywrlock(lock));
|
|
|
|
DEBUG("%d = trywritelock(%llx)\n", ret, (long long)lock);
|
|
|
|
return ret;
|
2009-10-13 00:29:35 +00:00
|
|
|
}
|
|
|
|
static inline void assertlocked(rwl * lock) { }
|
|
|
|
static inline void assertunlocked(rwl * lock) { }
|
|
|
|
static inline void unlock(rwl *lock) {
|
2010-08-05 23:07:52 +00:00
|
|
|
DEBUG("unlock(%llx)\n", (long long)lock);
|
2009-10-13 00:29:35 +00:00
|
|
|
pthread_rwlock_unlock(lock);
|
|
|
|
}
|
|
|
|
static inline void readunlock(rwl *lock) { unlock(lock); }
|
|
|
|
static inline void writeunlock(rwl *lock) { unlock(lock); }
|
|
|
|
static inline void deletelock(rwl *lock) {
|
|
|
|
pthread_rwlock_destroy(lock);
|
2010-08-05 23:07:52 +00:00
|
|
|
DEBUG("deletelock(%llx)\n", (long long)lock);
|
2009-10-13 00:29:35 +00:00
|
|
|
free(lock);
|
|
|
|
}
|
|
|
|
#else
|
2004-06-24 21:10:31 +00:00
|
|
|
typedef struct {
|
|
|
|
pthread_mutex_t *mut;
|
|
|
|
int writers;
|
|
|
|
int readers;
|
|
|
|
int waiting;
|
|
|
|
pthread_cond_t *writeOK, *readOK;
|
|
|
|
} rwl;
|
|
|
|
|
|
|
|
rwl *initlock (void);
|
|
|
|
void readlock (rwl *lock, int d);
|
2007-03-08 07:36:02 +00:00
|
|
|
int tryreadlock(rwl *lock, int d);
|
2004-06-24 21:10:31 +00:00
|
|
|
void writelock (rwl *lock, int d);
|
2007-03-08 07:36:02 +00:00
|
|
|
int trywritelock(rwl *lock, int d);
|
2007-06-01 21:32:33 +00:00
|
|
|
/** aborts if called when no thread holds this latch. */
|
|
|
|
void assertlocked(rwl *lock);
|
2009-05-30 02:22:04 +00:00
|
|
|
/** aborts if called when a thread holds this latch. */
|
|
|
|
void assertunlocked(rwl *lock);
|
2004-07-20 00:15:17 +00:00
|
|
|
void downgradelock(rwl * lock);
|
|
|
|
void unlock(rwl * lock);
|
|
|
|
/** @deprecated in favor of unlock() */
|
2004-06-24 21:10:31 +00:00
|
|
|
void readunlock (rwl *lock);
|
2004-07-20 00:15:17 +00:00
|
|
|
/** @deprecated in favor of unlock() */
|
2004-06-24 21:10:31 +00:00
|
|
|
void writeunlock (rwl *lock);
|
|
|
|
void deletelock (rwl *lock);
|
|
|
|
/*
|
|
|
|
typedef struct {
|
|
|
|
rwl *lock;
|
|
|
|
int id;
|
|
|
|
long delay;
|
|
|
|
} rwargs;
|
|
|
|
|
|
|
|
rwargs *newRWargs (rwl *l, int i, long d);
|
|
|
|
void *reader (void *args);
|
|
|
|
void *writer (void *args);
|
|
|
|
*/
|
2009-10-13 00:29:35 +00:00
|
|
|
#endif
|
2007-08-24 23:01:08 +00:00
|
|
|
END_C_DECLS
|
|
|
|
|
2010-05-27 01:48:27 +00:00
|
|
|
/** A rwl with support for condition variables. */
|
|
|
|
typedef struct rwlc {
|
|
|
|
rwl * rw;
|
|
|
|
pthread_mutex_t mut;
|
|
|
|
int is_writelocked;
|
|
|
|
} rwlc;
|
|
|
|
|
|
|
|
static inline rwlc* rwlc_initlock(void) {
|
|
|
|
rwlc* ret = (rwlc*)malloc(sizeof(*ret));
|
|
|
|
ret->rw = initlock();
|
|
|
|
int err = pthread_mutex_init(&ret->mut, 0);
|
|
|
|
ret->is_writelocked = 0;
|
|
|
|
if(err) { perror("couldn't init rwlclock's mutex"); abort(); }
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
static inline void rwlc_readlock(rwlc *lock) {
|
|
|
|
readlock(lock->rw, 0);
|
|
|
|
}
|
|
|
|
static inline int rwlc_tryreadlock(rwlc *lock) {
|
|
|
|
return tryreadlock(lock->rw, 0);
|
|
|
|
}
|
|
|
|
static inline void rwlc_writelock(rwlc *lock) {
|
|
|
|
pthread_mutex_lock(&lock->mut); // need to get this here, since the lock order is dictated by pthread_cond_wait's API.
|
|
|
|
writelock(lock->rw, 0);
|
|
|
|
lock->is_writelocked = 1;
|
|
|
|
}
|
|
|
|
static inline int rwlc_trywritelock(rwlc *lock) {
|
|
|
|
int ret = pthread_mutex_trylock(&lock->mut);
|
|
|
|
if(ret == EBUSY) { return 0; }
|
|
|
|
ret = trywritelock(lock->rw, 0); // will fail if someone is holding a readlock.
|
|
|
|
if(!ret) {
|
|
|
|
pthread_mutex_unlock(&lock->mut);
|
|
|
|
} else {
|
|
|
|
lock->is_writelocked = 1;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
static inline void rwlc_assertlocked(rwlc * lock) {
|
|
|
|
assertlocked(lock->rw);
|
|
|
|
}
|
|
|
|
static inline void rwlc_assertunlocked(rwlc * lock) {
|
|
|
|
assertunlocked(lock->rw);
|
|
|
|
}
|
|
|
|
static inline void rwlc_readunlock(rwlc *lock) { readunlock(lock->rw); }
|
|
|
|
static inline void rwlc_cond_wait(pthread_cond_t * cond, rwlc *lock) {
|
2010-07-13 18:17:25 +00:00
|
|
|
if(!lock->is_writelocked) { abort(); }
|
2010-05-27 01:48:27 +00:00
|
|
|
lock->is_writelocked = 0;
|
|
|
|
writeunlock(lock->rw);
|
|
|
|
pthread_cond_wait(cond, &lock->mut);
|
|
|
|
// already have mutex; reacquire the writelock.
|
|
|
|
writelock(lock->rw, 0);
|
|
|
|
lock->is_writelocked = 1;
|
|
|
|
}
|
|
|
|
static inline int rwlc_cond_timedwait(pthread_cond_t * cond, rwlc *lock, struct timespec * ts) {
|
2010-07-13 18:17:25 +00:00
|
|
|
if(!lock->is_writelocked) { abort(); }
|
2010-05-27 01:48:27 +00:00
|
|
|
lock->is_writelocked = 0;
|
|
|
|
writeunlock(lock->rw);
|
|
|
|
int ret = pthread_cond_timedwait(cond, &lock->mut, ts);
|
|
|
|
// already have mutex; reacquire the writelock.
|
|
|
|
writelock(lock->rw, 0);
|
|
|
|
lock->is_writelocked = 1;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
static inline void rwlc_writeunlock(rwlc *lock) {
|
|
|
|
lock->is_writelocked = 0;
|
|
|
|
writeunlock(lock->rw);
|
|
|
|
pthread_mutex_unlock(&lock->mut);
|
|
|
|
}
|
|
|
|
static inline void rwlc_unlock(rwlc *lock) {
|
|
|
|
if(lock->is_writelocked) {
|
|
|
|
rwlc_writeunlock(lock);
|
|
|
|
} else {
|
|
|
|
rwlc_readunlock(lock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static inline void rwlc_deletelock(rwlc *lock) {
|
|
|
|
deletelock(lock->rw);
|
|
|
|
pthread_mutex_destroy(&lock->mut);
|
|
|
|
free(lock);
|
|
|
|
}
|
2004-07-04 00:46:49 +00:00
|
|
|
#endif /* rw.h */
|