CCAFFEINE  0.8.8
pth_rwlock.h
00001 /****************************************************************************
00002  *
00003  *
00004  * File:  pth_rwlock.h
00005  *
00006  * Public functions for pth_rwlock.lib
00007  *
00008  * PURPOSE
00009  *
00010  * This package implements a readers/writer lock facility, using the POSIX
00011  * threads package. This is very similar to readers/writer lock facility
00012  * that is part of Solaris native threads, so do 'man rwlock_init' for a
00013  * description. I have tried to name calls similarly, adding a "pth_" prefix
00014  * to indicate that this is associated with, but not part of, the POSIX thread
00015  * package.
00016  *
00017  * This package does not prevent a thread from acquiring the read lock twice,
00018  * such as when a function in your package that holds the lock calls another
00019  * function which tries to acquire the lock. It is important to ensure that
00020  * your application does not do this, as a deadlock can result.
00021  * 
00022  * It happens in this way: a thread first takes a read lock, and subsequently
00023  * another thread attempts to acquire a write lock. The writer must wait for
00024  * all readers to yield the lock before proceeding. When the reader tries to
00025  * acquire the read lock again, it notices that a writer is pending, and waits
00026  * to let the write occur. Since it is holding a read lock already, the write
00027  * cannot proceed, and the threads deadlock.
00028  *
00029  * Therefore, you can recognize the deadlock in this way: there are one or
00030  * more active readers, pending readers and pending writers, and the total
00031  * will be more than the number of threads that share the data structure.
00032  *
00033  *****************************************************************************
00034  */
00035 #ifndef PTH_RWLOCK_H
00036 #define PTH_RWLOCK_H
00037 
00038 #include <pthread.h>
00039 
00040 #define pthread_rwlockattr_t void
00041 
00042 #ifdef __cplusplus
00043 extern "C" {
00044 #endif
00045 
00046 
00047 typedef struct pth_rwlock
00048 {
00049   int    active_readers;/*  -1 when writer active */
00050   int    pending_readers;
00051   int    pending_writers;
00052 
00053   pthread_mutex_t mutex;
00054   pthread_cond_t  ok_to_read;
00055   pthread_cond_t  ok_to_write; 
00056 } pth_rwlock_t;
00057 
00058 
00059 /* Initialize a readers/writer lock.
00060  */
00061 void pth_rwlock_init(pth_rwlock_t * lock, const pthread_rwlockattr_t * attr);
00062 
00063 
00064 /* Destroy a readers/writer lock. The space used by the rwlock is not freed.
00065  */
00066 void pth_rwlock_destroy(pth_rwlock_t * lock);
00067 
00068 
00069 /* Acquire a read-only lock.
00070  */
00071 void pth_rwlock_rdlock(pth_rwlock_t *lock);
00072 
00073 
00074 /* Release a read-only lock.
00075  */
00076 void pth_rwlock_rdunlock(pth_rwlock_t * lock);
00077 
00078 
00079 /* Acquire a write lock.
00080  */  
00081 void pth_rwlock_wrlock(pth_rwlock_t * lock);
00082 
00083 
00084 /* Try to get a write lock, without waiting.
00085  * As with pthread_mutex_trylock(), returns 0 on success.
00086  */
00087 int pth_rwlock_wrtrylock(pth_rwlock_t * lock);
00088 
00089 
00090 /* pth_rwlock_tryupgrade
00091  *
00092  * Try to upgrade a read lock to a write lock. 
00093  * Returns 0 on success, and -1 if there are other active readers.
00094  */  
00095 int pth_rwlock_tryupgrade(pth_rwlock_t * lock);
00096 
00097 
00098 /* Release a write lock.
00099  */
00100 void pth_rwlock_wrunlock(pth_rwlock_t * lock);
00101 
00102 
00103 /* Release a read-only or write lock.
00104  */
00105 void pth_rwlock_unlock(pth_rwlock_t * lock);
00106 
00107 #ifdef __cplusplus
00108 }
00109 #endif
00110 
00111 
00112 /*
00113  * Some useful macros to put in assert()s.
00114  */
00115 #define READ_LOCK_HELD(lock)(lock.active_readers > 0)
00116 
00117 #define WRITE_LOCK_HELD(lock)(lock.active_readers == -1)
00118 
00119 /*
00120  * define pthread_XXX to appropriate symbol defined above
00121  */
00122 
00123 #endif