* cygwin.din: Add pthread_rwlock_destroy, pthread_rwlock_init,
pthread_rwlock_rdlock, pthread_rwlock_tryrdlock, pthread_rwlock_wrlock, pthread_rwlock_trywrlock, pthread_rwlock_unlock, pthread_rwlockattr_init, pthread_rwlockattr_getpshared, pthread_rwlockattr_setpshared, and pthread_rwlockattr_destroy. * include/cygwin/version.h: Bump API minor number. * include/pthread.h (PTHREAD_RWLOCK_INITIALIZER): Define a reasonable value. Add prototypes for pthread_rwlock_destroy, pthread_rwlock_init, pthread_rwlock_rdlock, pthread_rwlock_tryrdlock, pthread_rwlock_wrlock, pthread_rwlock_trywrlock, pthread_rwlock_unlock, pthread_rwlockattr_init, pthread_rwlockattr_getpshared, pthread_rwlockattr_setpshared, and pthread_rwlockattr_destroy. * thread.h (PTHREAD_ONCE_MAGIC): Remove superflous semicolon. (PTHREAD_RWLOCK_MAGIC): New define. (PTHREAD_RWLOCKATTR_MAGIC): Ditto. (pthread_rwlockattr): New class. (pthread_rwlock): Ditto. (MTinterface::rwlocks): New member. (MTinterface::MTinterface): Initialize rwlocks. Add prototypes for __pthread_rwlock_destroy, __pthread_rwlock_wrlock, __pthread_rwlock_trywrlock, __pthread_rwlock_unlock, __pthread_rwlockattr_init, __pthread_rwlockattr_getpshared, __pthread_rwlockattr_setpshared, and __pthread_rwlockattr_destroy. * thread.cc (MTinterface::Init): Initialize rwlock internal mutex. (MTinterface::fixup_after_fork): Fixup rwlocks after fork. (pthread_rwlockattr::isGoodObject): Implement. (pthread_rwlockattr::pthread_rwlockattr): Ditto. (pthread_rwlockattr::~pthread_rwlockattr): Ditto. (pthread_rwlock::initMutex): Ditto. (pthread_rwlock::pthread_rwlock): Ditto. (pthread_rwlock::~pthread_rwlock): Ditto. (pthread_rwlock::RdLock): Ditto. (pthread_rwlock::TryRdLock): Ditto. (pthread_rwlock::WrLock): Ditto. (pthread_rwlock::TryWrLock): Ditto. (pthread_rwlock::UnLock): Ditto. (pthread_rwlock::addReader): Ditto. (pthread_rwlock::removeReader): Ditto. (pthread_rwlock::lookupReader): Ditto. (pthread_rwlock::RdLockCleanup): Ditto. (pthread_rwlock::WrLockCleanup): Ditto. (pthread_rwlock::fixup_after_fork): Ditto. (pthread_rwlock::isGoodObject): Ditto. (pthread_rwlock::isGoodInitializer): Ditto. (pthread_rwlock::isGoodInitializerOrObject): Ditto. (pthread_rwlock::isGoodInitializerOrBadObject): Ditto. (__pthread_rwlock_destroy): Ditto. (pthread_rwlock::init): Ditto. (__pthread_rwlock_rdlock): Ditto. (__pthread_rwlock_tryrdlock): Ditto. (__pthread_rwlock_wrlock): Ditto. (__pthread_rwlock_trywrlock): Ditto.
This commit is contained in:
		| @@ -1,3 +1,62 @@ | |||||||
|  | 2003-03-18  Thomas Pfaff  <tpfaff@gmx.net> | ||||||
|  |  | ||||||
|  | 	* cygwin.din: Add pthread_rwlock_destroy, pthread_rwlock_init, | ||||||
|  | 	pthread_rwlock_rdlock, pthread_rwlock_tryrdlock, | ||||||
|  | 	pthread_rwlock_wrlock, pthread_rwlock_trywrlock, | ||||||
|  | 	pthread_rwlock_unlock, pthread_rwlockattr_init, | ||||||
|  | 	pthread_rwlockattr_getpshared, pthread_rwlockattr_setpshared, | ||||||
|  | 	and pthread_rwlockattr_destroy. | ||||||
|  | 	* include/cygwin/version.h: Bump API minor number. | ||||||
|  | 	* include/pthread.h (PTHREAD_RWLOCK_INITIALIZER): Define a | ||||||
|  | 	reasonable value. | ||||||
|  | 	Add prototypes for pthread_rwlock_destroy, pthread_rwlock_init, | ||||||
|  | 	pthread_rwlock_rdlock, pthread_rwlock_tryrdlock, | ||||||
|  | 	pthread_rwlock_wrlock, pthread_rwlock_trywrlock, | ||||||
|  | 	pthread_rwlock_unlock, pthread_rwlockattr_init, | ||||||
|  | 	pthread_rwlockattr_getpshared, pthread_rwlockattr_setpshared, | ||||||
|  | 	and pthread_rwlockattr_destroy. | ||||||
|  | 	* thread.h (PTHREAD_ONCE_MAGIC): Remove superflous semicolon. | ||||||
|  | 	(PTHREAD_RWLOCK_MAGIC): New define. | ||||||
|  | 	(PTHREAD_RWLOCKATTR_MAGIC): Ditto. | ||||||
|  | 	(pthread_rwlockattr): New class. | ||||||
|  | 	(pthread_rwlock): Ditto. | ||||||
|  | 	(MTinterface::rwlocks): New member. | ||||||
|  | 	(MTinterface::MTinterface): Initialize rwlocks. | ||||||
|  | 	Add prototypes for __pthread_rwlock_destroy, | ||||||
|  | 	__pthread_rwlock_wrlock, __pthread_rwlock_trywrlock, | ||||||
|  | 	__pthread_rwlock_unlock, __pthread_rwlockattr_init, | ||||||
|  | 	__pthread_rwlockattr_getpshared, __pthread_rwlockattr_setpshared, | ||||||
|  | 	and __pthread_rwlockattr_destroy. | ||||||
|  | 	* thread.cc (MTinterface::Init): Initialize rwlock internal mutex. | ||||||
|  | 	(MTinterface::fixup_after_fork): Fixup rwlocks after fork. | ||||||
|  | 	(pthread_rwlockattr::isGoodObject): Implement. | ||||||
|  | 	(pthread_rwlockattr::pthread_rwlockattr): Ditto. | ||||||
|  | 	(pthread_rwlockattr::~pthread_rwlockattr): Ditto. | ||||||
|  | 	(pthread_rwlock::initMutex): Ditto. | ||||||
|  | 	(pthread_rwlock::pthread_rwlock): Ditto. | ||||||
|  | 	(pthread_rwlock::~pthread_rwlock): Ditto. | ||||||
|  | 	(pthread_rwlock::RdLock): Ditto. | ||||||
|  | 	(pthread_rwlock::TryRdLock): Ditto. | ||||||
|  | 	(pthread_rwlock::WrLock): Ditto. | ||||||
|  | 	(pthread_rwlock::TryWrLock): Ditto. | ||||||
|  | 	(pthread_rwlock::UnLock): Ditto. | ||||||
|  | 	(pthread_rwlock::addReader): Ditto. | ||||||
|  | 	(pthread_rwlock::removeReader): Ditto. | ||||||
|  | 	(pthread_rwlock::lookupReader): Ditto. | ||||||
|  | 	(pthread_rwlock::RdLockCleanup): Ditto. | ||||||
|  | 	(pthread_rwlock::WrLockCleanup): Ditto. | ||||||
|  | 	(pthread_rwlock::fixup_after_fork): Ditto. | ||||||
|  | 	(pthread_rwlock::isGoodObject): Ditto. | ||||||
|  | 	(pthread_rwlock::isGoodInitializer): Ditto. | ||||||
|  | 	(pthread_rwlock::isGoodInitializerOrObject): Ditto. | ||||||
|  | 	(pthread_rwlock::isGoodInitializerOrBadObject): Ditto. | ||||||
|  | 	(__pthread_rwlock_destroy): Ditto. | ||||||
|  | 	(pthread_rwlock::init): Ditto. | ||||||
|  | 	(__pthread_rwlock_rdlock): Ditto. | ||||||
|  | 	(__pthread_rwlock_tryrdlock): Ditto. | ||||||
|  | 	(__pthread_rwlock_wrlock): Ditto. | ||||||
|  | 	(__pthread_rwlock_trywrlock): Ditto. | ||||||
|  |  | ||||||
| 2003-03-18  Thomas Pfaff  <tpfaff@gmx.net> | 2003-03-18  Thomas Pfaff  <tpfaff@gmx.net> | ||||||
|  |  | ||||||
| 	* thread.h (pthread_cond::ExitingWait): Remove. | 	* thread.h (pthread_cond::ExitingWait): Remove. | ||||||
|   | |||||||
| @@ -954,6 +954,17 @@ pthread_mutexattr_setprotocol | |||||||
| pthread_mutexattr_setpshared | pthread_mutexattr_setpshared | ||||||
| pthread_mutexattr_settype | pthread_mutexattr_settype | ||||||
| pthread_once | pthread_once | ||||||
|  | pthread_rwlock_destroy | ||||||
|  | pthread_rwlock_init | ||||||
|  | pthread_rwlock_rdlock | ||||||
|  | pthread_rwlock_tryrdlock | ||||||
|  | pthread_rwlock_wrlock | ||||||
|  | pthread_rwlock_trywrlock | ||||||
|  | pthread_rwlock_unlock | ||||||
|  | pthread_rwlockattr_init | ||||||
|  | pthread_rwlockattr_getpshared | ||||||
|  | pthread_rwlockattr_setpshared | ||||||
|  | pthread_rwlockattr_destroy | ||||||
| pthread_self | pthread_self | ||||||
| pthread_setcancelstate | pthread_setcancelstate | ||||||
| pthread_setcanceltype | pthread_setcanceltype | ||||||
|   | |||||||
| @@ -192,12 +192,13 @@ details. */ | |||||||
| 		  aclsort32 acltomode32 acltopbits32 acltotext32 facl32 | 		  aclsort32 acltomode32 acltopbits32 acltotext32 facl32 | ||||||
| 		  fgetpos64 fopen64 freopen64 fseeko64 fsetpos64 ftello64 | 		  fgetpos64 fopen64 freopen64 fseeko64 fsetpos64 ftello64 | ||||||
| 		  _open64 _lseek64 _fstat64 _stat64 mknod32 | 		  _open64 _lseek64 _fstat64 _stat64 mknod32 | ||||||
|  |        80: Export pthread_rwlock stuff | ||||||
|      */ |      */ | ||||||
|  |  | ||||||
|      /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ |      /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ | ||||||
|  |  | ||||||
| #define CYGWIN_VERSION_API_MAJOR 0 | #define CYGWIN_VERSION_API_MAJOR 0 | ||||||
| #define CYGWIN_VERSION_API_MINOR 79 | #define CYGWIN_VERSION_API_MINOR 80 | ||||||
|  |  | ||||||
|      /* There is also a compatibity version number associated with the |      /* There is also a compatibity version number associated with the | ||||||
| 	shared memory regions.  It is incremented when incompatible | 	shared memory regions.  It is incremented when incompatible | ||||||
|   | |||||||
| @@ -62,7 +62,7 @@ extern "C" | |||||||
| #define PTHREAD_PRIO_PROTECT | #define PTHREAD_PRIO_PROTECT | ||||||
| #define PTHREAD_PROCESS_SHARED 1 | #define PTHREAD_PROCESS_SHARED 1 | ||||||
| #define PTHREAD_PROCESS_PRIVATE 0 | #define PTHREAD_PROCESS_PRIVATE 0 | ||||||
| #define PTHREAD_RWLOCK_INITIALIZER | #define PTHREAD_RWLOCK_INITIALIZER (pthread_rwlock_t)22 | ||||||
| /* process is the default */ | /* process is the default */ | ||||||
| #define PTHREAD_SCOPE_PROCESS 0 | #define PTHREAD_SCOPE_PROCESS 0 | ||||||
| #define PTHREAD_SCOPE_SYSTEM 1 | #define PTHREAD_SCOPE_SYSTEM 1 | ||||||
| @@ -161,6 +161,20 @@ int pthread_mutexattr_setprotocol (pthread_mutexattr_t *, int); | |||||||
| int pthread_mutexattr_setpshared (pthread_mutexattr_t *, int); | int pthread_mutexattr_setpshared (pthread_mutexattr_t *, int); | ||||||
| int pthread_mutexattr_settype (pthread_mutexattr_t *, int); | int pthread_mutexattr_settype (pthread_mutexattr_t *, int); | ||||||
|  |  | ||||||
|  | /* RW Locks */ | ||||||
|  | int pthread_rwlock_destroy (pthread_rwlock_t *rwlock); | ||||||
|  | int pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr); | ||||||
|  | int pthread_rwlock_rdlock (pthread_rwlock_t *rwlock); | ||||||
|  | int pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock); | ||||||
|  | int pthread_rwlock_wrlock (pthread_rwlock_t *rwlock); | ||||||
|  | int pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock); | ||||||
|  | int pthread_rwlock_unlock (pthread_rwlock_t *rwlock); | ||||||
|  | int pthread_rwlockattr_init (pthread_rwlockattr_t *rwlockattr); | ||||||
|  | int pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, | ||||||
|  |                                    int *pshared); | ||||||
|  | int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared); | ||||||
|  | int pthread_rwlockattr_destroy (pthread_rwlockattr_t *rwlockattr); | ||||||
|  |  | ||||||
| int pthread_once (pthread_once_t *, void (*)(void)); | int pthread_once (pthread_once_t *, void (*)(void)); | ||||||
|  |  | ||||||
| /* Concurrency levels - X/Open interface */ | /* Concurrency levels - X/Open interface */ | ||||||
|   | |||||||
| @@ -388,6 +388,74 @@ pthread_condattr_setpshared (pthread_condattr_t * attr, int pshared) | |||||||
|   return __pthread_condattr_setpshared (attr, pshared); |   return __pthread_condattr_setpshared (attr, pshared); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* RW Locks */ | ||||||
|  | int | ||||||
|  | pthread_rwlock_destroy (pthread_rwlock_t *rwlock) | ||||||
|  | { | ||||||
|  |   return __pthread_rwlock_destroy (rwlock); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) | ||||||
|  | { | ||||||
|  |   return pthread_rwlock::init (rwlock, attr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | pthread_rwlock_rdlock (pthread_rwlock_t *rwlock) | ||||||
|  | { | ||||||
|  |   return __pthread_rwlock_rdlock (rwlock); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock) | ||||||
|  | { | ||||||
|  |   return __pthread_rwlock_tryrdlock (rwlock); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | pthread_rwlock_wrlock (pthread_rwlock_t *rwlock) | ||||||
|  | { | ||||||
|  |   return __pthread_rwlock_wrlock (rwlock); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock) | ||||||
|  | { | ||||||
|  |   return __pthread_rwlock_trywrlock (rwlock); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | pthread_rwlock_unlock (pthread_rwlock_t *rwlock) | ||||||
|  | { | ||||||
|  |   return __pthread_rwlock_unlock (rwlock); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | pthread_rwlockattr_init (pthread_rwlockattr_t *rwlockattr) | ||||||
|  | { | ||||||
|  |   return __pthread_rwlockattr_init (rwlockattr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, | ||||||
|  |                                int *pshared) | ||||||
|  | { | ||||||
|  |   return __pthread_rwlockattr_getpshared (attr, pshared); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared) | ||||||
|  | { | ||||||
|  |   return __pthread_rwlockattr_setpshared (attr, pshared); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | pthread_rwlockattr_destroy (pthread_rwlockattr_t *rwlockattr) | ||||||
|  | { | ||||||
|  |   return __pthread_rwlockattr_destroy (rwlockattr); | ||||||
|  | } | ||||||
|  |  | ||||||
| /* Scheduling */ | /* Scheduling */ | ||||||
|  |  | ||||||
| int | int | ||||||
|   | |||||||
| @@ -199,6 +199,7 @@ MTinterface::Init (int forked) | |||||||
|  |  | ||||||
|   pthread_mutex::initMutex (); |   pthread_mutex::initMutex (); | ||||||
|   pthread_cond::initMutex (); |   pthread_cond::initMutex (); | ||||||
|  |   pthread_rwlock::initMutex (); | ||||||
| } | } | ||||||
|  |  | ||||||
| void | void | ||||||
| @@ -230,6 +231,13 @@ MTinterface::fixup_after_fork (void) | |||||||
|       cond->fixup_after_fork (); |       cond->fixup_after_fork (); | ||||||
|       cond = cond->next; |       cond = cond->next; | ||||||
|     } |     } | ||||||
|  |   pthread_rwlock *rwlock = rwlocks; | ||||||
|  |   debug_printf ("rwlocks is %x",rwlocks); | ||||||
|  |   while (rwlock) | ||||||
|  |     { | ||||||
|  |       rwlock->fixup_after_fork (); | ||||||
|  |       rwlock = rwlock->next; | ||||||
|  |     } | ||||||
|   semaphore *sem = semaphores; |   semaphore *sem = semaphores; | ||||||
|   debug_printf ("semaphores is %x",semaphores); |   debug_printf ("semaphores is %x",semaphores); | ||||||
|   while (sem) |   while (sem) | ||||||
| @@ -998,6 +1006,341 @@ pthread_cond::fixup_after_fork () | |||||||
|     api_fatal ("pthread_cond::fixup_after_fork () failed to recreate win32 semaphore"); |     api_fatal ("pthread_cond::fixup_after_fork () failed to recreate win32 semaphore"); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | bool | ||||||
|  | pthread_rwlockattr::isGoodObject (pthread_rwlockattr_t const *attr) | ||||||
|  | { | ||||||
|  |   if (verifyable_object_isvalid (attr, PTHREAD_RWLOCKATTR_MAGIC) != VALID_OBJECT) | ||||||
|  |     return false; | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pthread_rwlockattr::pthread_rwlockattr ():verifyable_object | ||||||
|  |   (PTHREAD_RWLOCKATTR_MAGIC), shared (PTHREAD_PROCESS_PRIVATE) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pthread_rwlockattr::~pthread_rwlockattr () | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* This is used for rwlock creation protection within a single process only */ | ||||||
|  | nativeMutex NO_COPY pthread_rwlock::rwlockInitializationLock; | ||||||
|  |  | ||||||
|  | /* We can only be called once. | ||||||
|  |    TODO: (no rush) use a non copied memory section to | ||||||
|  |    hold an initialization flag.  */ | ||||||
|  | void | ||||||
|  | pthread_rwlock::initMutex () | ||||||
|  | { | ||||||
|  |   if (!rwlockInitializationLock.init ()) | ||||||
|  |     api_fatal ("Could not create win32 Mutex for pthread rwlock static initializer support."); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pthread_rwlock::pthread_rwlock (pthread_rwlockattr *attr) : | ||||||
|  |   verifyable_object (PTHREAD_RWLOCK_MAGIC), | ||||||
|  |   shared (0), waitingReaders (0), waitingWriters (0), writer (NULL), | ||||||
|  |   readers (NULL), mtx (NULL), condReaders (NULL), condWriters (NULL), | ||||||
|  |   next (NULL) | ||||||
|  | { | ||||||
|  |   pthread_mutex *verifyable_mutex_obj = &mtx; | ||||||
|  |   pthread_cond *verifyable_cond_obj; | ||||||
|  |  | ||||||
|  |   if (attr) | ||||||
|  |     if (attr->shared != PTHREAD_PROCESS_PRIVATE) | ||||||
|  |       { | ||||||
|  |         magic = 0; | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |   if (!pthread_mutex::isGoodObject (&verifyable_mutex_obj)) | ||||||
|  |     { | ||||||
|  |       thread_printf ("Internal rwlock mutex is not valid. this %p", this); | ||||||
|  |       magic = 0; | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |   /* Change the mutex type to NORMAL to speed up mutex operations */ | ||||||
|  |   mtx.type = PTHREAD_MUTEX_NORMAL; | ||||||
|  |  | ||||||
|  |   verifyable_cond_obj = &condReaders; | ||||||
|  |   if (!pthread_cond::isGoodObject (&verifyable_cond_obj)) | ||||||
|  |     { | ||||||
|  |       thread_printf ("Internal rwlock readers cond is not valid. this %p", this); | ||||||
|  |       magic = 0; | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   verifyable_cond_obj = &condWriters; | ||||||
|  |   if (!pthread_cond::isGoodObject (&verifyable_cond_obj)) | ||||||
|  |     { | ||||||
|  |       thread_printf ("Internal rwlock writers cond is not valid. this %p", this); | ||||||
|  |       magic = 0; | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   /* threadsafe addition is easy */ | ||||||
|  |   next = (pthread_rwlock *) InterlockedExchangePointer (&MT_INTERFACE->rwlocks, this); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pthread_rwlock::~pthread_rwlock () | ||||||
|  | { | ||||||
|  |   /* I'm not 100% sure the next bit is threadsafe. I think it is... */ | ||||||
|  |   if (MT_INTERFACE->rwlocks == this) | ||||||
|  |     InterlockedExchangePointer (&MT_INTERFACE->rwlocks, this->next); | ||||||
|  |   else | ||||||
|  |     { | ||||||
|  |       pthread_rwlock *temprwlock = MT_INTERFACE->rwlocks; | ||||||
|  |       while (temprwlock->next && temprwlock->next != this) | ||||||
|  | 	temprwlock = temprwlock->next; | ||||||
|  |       /* but there may be a race between the loop above and this statement */ | ||||||
|  |       InterlockedExchangePointer (&temprwlock->next, this->next); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | pthread_rwlock::RdLock () | ||||||
|  | { | ||||||
|  |   int result = 0; | ||||||
|  |   struct RWLOCK_READER *reader; | ||||||
|  |   pthread_t self = pthread::self (); | ||||||
|  |  | ||||||
|  |   mtx.Lock (); | ||||||
|  |  | ||||||
|  |   if (lookupReader (self)) | ||||||
|  |     { | ||||||
|  |       result = EDEADLK; | ||||||
|  |       goto DONE; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   reader = new struct RWLOCK_READER; | ||||||
|  |   if (!reader) | ||||||
|  |     { | ||||||
|  |       result = EAGAIN; | ||||||
|  |       goto DONE; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   while (writer || waitingWriters) | ||||||
|  |     {   | ||||||
|  |       pthread_cleanup_push (pthread_rwlock::RdLockCleanup, this); | ||||||
|  |  | ||||||
|  |       ++waitingReaders; | ||||||
|  |       condReaders.Wait (&mtx); | ||||||
|  |       --waitingReaders; | ||||||
|  |  | ||||||
|  |       pthread_cleanup_pop (0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   reader->thread = self; | ||||||
|  |   addReader (reader); | ||||||
|  |  | ||||||
|  |  DONE: | ||||||
|  |   mtx.UnLock (); | ||||||
|  |  | ||||||
|  |   return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | pthread_rwlock::TryRdLock () | ||||||
|  | { | ||||||
|  |   int result = 0; | ||||||
|  |   pthread_t self = pthread::self (); | ||||||
|  |  | ||||||
|  |   mtx.Lock (); | ||||||
|  |  | ||||||
|  |   if (writer || waitingWriters || lookupReader (self)) | ||||||
|  |     result = EBUSY; | ||||||
|  |   else | ||||||
|  |     { | ||||||
|  |       struct RWLOCK_READER *reader = new struct RWLOCK_READER; | ||||||
|  |       if (reader) | ||||||
|  |         { | ||||||
|  |           reader->thread = self; | ||||||
|  |           addReader (reader); | ||||||
|  |         } | ||||||
|  |       else | ||||||
|  |         result = EAGAIN; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |   mtx.UnLock (); | ||||||
|  |  | ||||||
|  |   return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | pthread_rwlock::WrLock () | ||||||
|  | { | ||||||
|  |   int result = 0; | ||||||
|  |   pthread_t self = pthread::self (); | ||||||
|  |  | ||||||
|  |   mtx.Lock (); | ||||||
|  |  | ||||||
|  |   if (writer == self || lookupReader (self)) | ||||||
|  |     { | ||||||
|  |       result = EDEADLK; | ||||||
|  |       goto DONE; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   while (writer || readers) | ||||||
|  |     {   | ||||||
|  |       pthread_cleanup_push (pthread_rwlock::WrLockCleanup, this); | ||||||
|  |  | ||||||
|  |       ++waitingWriters; | ||||||
|  |       condWriters.Wait (&mtx); | ||||||
|  |       --waitingWriters; | ||||||
|  |  | ||||||
|  |       pthread_cleanup_pop (0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   writer = self; | ||||||
|  |  | ||||||
|  |  DONE: | ||||||
|  |   mtx.UnLock (); | ||||||
|  |  | ||||||
|  |   return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | pthread_rwlock::TryWrLock () | ||||||
|  | { | ||||||
|  |   int result = 0; | ||||||
|  |   pthread_t self = pthread::self (); | ||||||
|  |  | ||||||
|  |   mtx.Lock (); | ||||||
|  |  | ||||||
|  |   if (writer || readers) | ||||||
|  |     result = EBUSY; | ||||||
|  |   else | ||||||
|  |     writer = self; | ||||||
|  |      | ||||||
|  |   mtx.UnLock (); | ||||||
|  |  | ||||||
|  |   return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | pthread_rwlock::UnLock () | ||||||
|  | { | ||||||
|  |   int result = 0; | ||||||
|  |   pthread_t self = pthread::self (); | ||||||
|  |  | ||||||
|  |   mtx.Lock (); | ||||||
|  |  | ||||||
|  |   if (writer) | ||||||
|  |     { | ||||||
|  |       if (writer != self) | ||||||
|  |         { | ||||||
|  |           result = EPERM; | ||||||
|  |           goto DONE; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |       writer = NULL; | ||||||
|  |     } | ||||||
|  |   else | ||||||
|  |     { | ||||||
|  |       struct RWLOCK_READER *reader = lookupReader (self); | ||||||
|  |  | ||||||
|  |       if (!reader) | ||||||
|  |         { | ||||||
|  |           result = EPERM; | ||||||
|  |           goto DONE; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |       removeReader (reader); | ||||||
|  |       delete reader; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   if (waitingWriters) | ||||||
|  |     { | ||||||
|  |       if (!readers) | ||||||
|  |         condWriters.UnBlock (false); | ||||||
|  |     } | ||||||
|  |   else if (waitingReaders) | ||||||
|  |     condReaders.UnBlock (true); | ||||||
|  |  | ||||||
|  |  DONE: | ||||||
|  |   mtx.UnLock (); | ||||||
|  |  | ||||||
|  |   return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | pthread_rwlock::addReader (struct RWLOCK_READER *rd) | ||||||
|  | { | ||||||
|  |   rd->next = (struct RWLOCK_READER *) | ||||||
|  |     InterlockedExchangePointer (&readers, rd); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | pthread_rwlock::removeReader (struct RWLOCK_READER *rd) | ||||||
|  | { | ||||||
|  |   if (readers == rd) | ||||||
|  |     InterlockedExchangePointer (&readers, rd->next); | ||||||
|  |   else | ||||||
|  |     { | ||||||
|  |       struct RWLOCK_READER *temp = readers; | ||||||
|  |       while (temp->next && temp->next != rd) | ||||||
|  | 	temp = temp->next; | ||||||
|  |       /* but there may be a race between the loop above and this statement */ | ||||||
|  |       InterlockedExchangePointer (&temp->next, rd->next); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | struct pthread_rwlock::RWLOCK_READER * | ||||||
|  | pthread_rwlock::lookupReader (pthread_t thread) | ||||||
|  | { | ||||||
|  |   struct RWLOCK_READER *temp = readers; | ||||||
|  |  | ||||||
|  |   while (temp && temp->thread != thread) | ||||||
|  |     temp = temp->next; | ||||||
|  |  | ||||||
|  |   return temp; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | pthread_rwlock::RdLockCleanup (void *arg) | ||||||
|  | { | ||||||
|  |   pthread_rwlock *rwlock = (pthread_rwlock *) arg; | ||||||
|  |  | ||||||
|  |   --(rwlock->waitingReaders); | ||||||
|  |   rwlock->mtx.UnLock (); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | pthread_rwlock::WrLockCleanup (void *arg) | ||||||
|  | { | ||||||
|  |   pthread_rwlock *rwlock = (pthread_rwlock *) arg; | ||||||
|  |  | ||||||
|  |   --(rwlock->waitingWriters); | ||||||
|  |   rwlock->mtx.UnLock (); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | pthread_rwlock::fixup_after_fork () | ||||||
|  | { | ||||||
|  |   pthread_t self = pthread::self (); | ||||||
|  |   struct RWLOCK_READER **temp = &readers; | ||||||
|  |  | ||||||
|  |   waitingReaders = 0; | ||||||
|  |   waitingWriters = 0; | ||||||
|  |  | ||||||
|  |   /* Unlock eventually locked mutex */ | ||||||
|  |   mtx.UnLock (); | ||||||
|  |   /* | ||||||
|  |    * Remove all readers except self | ||||||
|  |    */ | ||||||
|  |   while (*temp) | ||||||
|  |     { | ||||||
|  |       if ((*temp)->thread == self) | ||||||
|  |         temp = &((*temp)->next); | ||||||
|  |       else | ||||||
|  |         { | ||||||
|  |           struct RWLOCK_READER *cur = *temp; | ||||||
|  |           *temp = (*temp)->next; | ||||||
|  |           delete cur; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| /* pthread_key */ | /* pthread_key */ | ||||||
| /* static members */ | /* static members */ | ||||||
| /* This stores pthread_key information across fork() boundaries */ | /* This stores pthread_key information across fork() boundaries */ | ||||||
| @@ -2292,6 +2635,191 @@ __pthread_condattr_destroy (pthread_condattr_t *condattr) | |||||||
|   return 0; |   return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* RW locks */ | ||||||
|  | bool | ||||||
|  | pthread_rwlock::isGoodObject (pthread_rwlock_t const *rwlock) | ||||||
|  | { | ||||||
|  |   if (verifyable_object_isvalid (rwlock, PTHREAD_RWLOCK_MAGIC) != VALID_OBJECT) | ||||||
|  |     return false; | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool | ||||||
|  | pthread_rwlock::isGoodInitializer (pthread_rwlock_t const *rwlock) | ||||||
|  | { | ||||||
|  |   if (verifyable_object_isvalid (rwlock, PTHREAD_RWLOCK_MAGIC, PTHREAD_RWLOCK_INITIALIZER) != VALID_STATIC_OBJECT) | ||||||
|  |     return false; | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool | ||||||
|  | pthread_rwlock::isGoodInitializerOrObject (pthread_rwlock_t const *rwlock) | ||||||
|  | { | ||||||
|  |   if (verifyable_object_isvalid (rwlock, PTHREAD_RWLOCK_MAGIC, PTHREAD_RWLOCK_INITIALIZER) == INVALID_OBJECT) | ||||||
|  |     return false; | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool | ||||||
|  | pthread_rwlock::isGoodInitializerOrBadObject (pthread_rwlock_t const *rwlock) | ||||||
|  | { | ||||||
|  |   verifyable_object_state objectState = verifyable_object_isvalid (rwlock, PTHREAD_RWLOCK_MAGIC, PTHREAD_RWLOCK_INITIALIZER); | ||||||
|  |   if (objectState == VALID_OBJECT) | ||||||
|  | 	return false; | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | __pthread_rwlock_destroy (pthread_rwlock_t *rwlock) | ||||||
|  | { | ||||||
|  |   if (pthread_rwlock::isGoodInitializer (rwlock)) | ||||||
|  |     return 0; | ||||||
|  |   if (!pthread_rwlock::isGoodObject (rwlock)) | ||||||
|  |     return EINVAL; | ||||||
|  |  | ||||||
|  |   if ((*rwlock)->writer || (*rwlock)->readers || | ||||||
|  |       (*rwlock)->waitingReaders || (*rwlock)->waitingWriters) | ||||||
|  |     return EBUSY; | ||||||
|  |  | ||||||
|  |   delete (*rwlock); | ||||||
|  |   *rwlock = NULL; | ||||||
|  |  | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | pthread_rwlock::init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) | ||||||
|  | { | ||||||
|  |   if (attr && !pthread_rwlockattr::isGoodObject (attr)) | ||||||
|  |     return EINVAL; | ||||||
|  |   if (!rwlockInitializationLock.lock ()) | ||||||
|  |     return EINVAL; | ||||||
|  |  | ||||||
|  |   if (!isGoodInitializerOrBadObject (rwlock)) | ||||||
|  |     { | ||||||
|  |       rwlockInitializationLock.unlock (); | ||||||
|  |       return EBUSY; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   *rwlock = new pthread_rwlock (attr ? (*attr) : NULL); | ||||||
|  |   if (!isGoodObject (rwlock)) | ||||||
|  |     { | ||||||
|  |       delete (*rwlock); | ||||||
|  |       *rwlock = NULL; | ||||||
|  |       rwlockInitializationLock.unlock (); | ||||||
|  |       return EAGAIN; | ||||||
|  |     } | ||||||
|  |   rwlockInitializationLock.unlock (); | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | __pthread_rwlock_rdlock (pthread_rwlock_t *rwlock) | ||||||
|  | { | ||||||
|  |   pthread_testcancel (); | ||||||
|  |  | ||||||
|  |   if (pthread_rwlock::isGoodInitializer (rwlock)) | ||||||
|  |     pthread_rwlock::init (rwlock, NULL); | ||||||
|  |   if (!pthread_rwlock::isGoodObject (rwlock)) | ||||||
|  |     return EINVAL; | ||||||
|  |  | ||||||
|  |   return (*rwlock)->RdLock (); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | __pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock) | ||||||
|  | { | ||||||
|  |   if (pthread_rwlock::isGoodInitializer (rwlock)) | ||||||
|  |     pthread_rwlock::init (rwlock, NULL); | ||||||
|  |   if (!pthread_rwlock::isGoodObject (rwlock)) | ||||||
|  |     return EINVAL; | ||||||
|  |  | ||||||
|  |   return (*rwlock)->TryRdLock (); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | __pthread_rwlock_wrlock (pthread_rwlock_t *rwlock) | ||||||
|  | { | ||||||
|  |   pthread_testcancel (); | ||||||
|  |  | ||||||
|  |   if (pthread_rwlock::isGoodInitializer (rwlock)) | ||||||
|  |     pthread_rwlock::init (rwlock, NULL); | ||||||
|  |   if (!pthread_rwlock::isGoodObject (rwlock)) | ||||||
|  |     return EINVAL; | ||||||
|  |  | ||||||
|  |   return (*rwlock)->WrLock (); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | __pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock) | ||||||
|  | { | ||||||
|  |   if (pthread_rwlock::isGoodInitializer (rwlock)) | ||||||
|  |     pthread_rwlock::init (rwlock, NULL); | ||||||
|  |   if (!pthread_rwlock::isGoodObject (rwlock)) | ||||||
|  |     return EINVAL; | ||||||
|  |  | ||||||
|  |   return (*rwlock)->TryWrLock (); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | __pthread_rwlock_unlock (pthread_rwlock_t *rwlock) | ||||||
|  | { | ||||||
|  |   if (pthread_rwlock::isGoodInitializer (rwlock)) | ||||||
|  |     return 0; | ||||||
|  |   if (!pthread_rwlock::isGoodObject (rwlock)) | ||||||
|  |     return EINVAL; | ||||||
|  |  | ||||||
|  |   return (*rwlock)->UnLock (); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | __pthread_rwlockattr_init (pthread_rwlockattr_t *rwlockattr) | ||||||
|  | { | ||||||
|  |   if (check_valid_pointer (rwlockattr)) | ||||||
|  |     return EINVAL; | ||||||
|  |   *rwlockattr = new pthread_rwlockattr; | ||||||
|  |   if (!pthread_rwlockattr::isGoodObject (rwlockattr)) | ||||||
|  |     { | ||||||
|  |       delete (*rwlockattr); | ||||||
|  |       *rwlockattr = NULL; | ||||||
|  |       return EAGAIN; | ||||||
|  |     } | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | __pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, int *pshared) | ||||||
|  | { | ||||||
|  |   if (!pthread_rwlockattr::isGoodObject (attr)) | ||||||
|  |     return EINVAL; | ||||||
|  |   *pshared = (*attr)->shared; | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | __pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared) | ||||||
|  | { | ||||||
|  |   if (!pthread_rwlockattr::isGoodObject (attr)) | ||||||
|  |     return EINVAL; | ||||||
|  |   if ((pshared < 0) || (pshared > 1)) | ||||||
|  |     return EINVAL; | ||||||
|  |   /* shared rwlock vars not currently supported */ | ||||||
|  |   if (pshared != PTHREAD_PROCESS_PRIVATE) | ||||||
|  |     return EINVAL; | ||||||
|  |   (*attr)->shared = pshared; | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | __pthread_rwlockattr_destroy (pthread_rwlockattr_t *rwlockattr) | ||||||
|  | { | ||||||
|  |   if (!pthread_rwlockattr::isGoodObject (rwlockattr)) | ||||||
|  |     return EINVAL; | ||||||
|  |   delete (*rwlockattr); | ||||||
|  |   *rwlockattr = NULL; | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
| /* Thread signal */ | /* Thread signal */ | ||||||
| int | int | ||||||
| __pthread_kill (pthread_t thread, int sig) | __pthread_kill (pthread_t thread, int sig) | ||||||
|   | |||||||
| @@ -163,6 +163,8 @@ private: | |||||||
| #define PTHREAD_CONDATTR_MAGIC PTHREAD_MAGIC+6 | #define PTHREAD_CONDATTR_MAGIC PTHREAD_MAGIC+6 | ||||||
| #define SEM_MAGIC PTHREAD_MAGIC+7 | #define SEM_MAGIC PTHREAD_MAGIC+7 | ||||||
| #define PTHREAD_ONCE_MAGIC PTHREAD_MAGIC+8 | #define PTHREAD_ONCE_MAGIC PTHREAD_MAGIC+8 | ||||||
|  | #define PTHREAD_RWLOCK_MAGIC PTHREAD_MAGIC+9 | ||||||
|  | #define PTHREAD_RWLOCKATTR_MAGIC PTHREAD_MAGIC+10 | ||||||
|  |  | ||||||
| #define MUTEX_OWNER_ANONYMOUS        ((pthread_t) -1) | #define MUTEX_OWNER_ANONYMOUS        ((pthread_t) -1) | ||||||
|  |  | ||||||
| @@ -517,6 +519,67 @@ private: | |||||||
|   static nativeMutex condInitializationLock; |   static nativeMutex condInitializationLock; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | class pthread_rwlockattr:public verifyable_object | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |   static bool isGoodObject(pthread_rwlockattr_t const *); | ||||||
|  |   int shared; | ||||||
|  |  | ||||||
|  |   pthread_rwlockattr (); | ||||||
|  |   ~pthread_rwlockattr (); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class pthread_rwlock:public verifyable_object | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |   static bool isGoodObject (pthread_rwlock_t const *); | ||||||
|  |   static bool isGoodInitializer (pthread_rwlock_t const *); | ||||||
|  |   static bool isGoodInitializerOrObject (pthread_rwlock_t const *); | ||||||
|  |   static bool isGoodInitializerOrBadObject (pthread_rwlock_t const *); | ||||||
|  |   static void initMutex (); | ||||||
|  |   static int init (pthread_rwlock_t *, const pthread_rwlockattr_t *); | ||||||
|  |  | ||||||
|  |   int shared; | ||||||
|  |  | ||||||
|  |   unsigned long waitingReaders; | ||||||
|  |   unsigned long waitingWriters; | ||||||
|  |   pthread_t writer; | ||||||
|  |   struct RWLOCK_READER | ||||||
|  |   { | ||||||
|  |     struct RWLOCK_READER *next; | ||||||
|  |     pthread_t thread; | ||||||
|  |   } *readers; | ||||||
|  |  | ||||||
|  |   int RdLock (); | ||||||
|  |   int TryRdLock (); | ||||||
|  |  | ||||||
|  |   int WrLock (); | ||||||
|  |   int TryWrLock (); | ||||||
|  |  | ||||||
|  |   int UnLock (); | ||||||
|  |  | ||||||
|  |   pthread_mutex mtx; | ||||||
|  |   pthread_cond condReaders; | ||||||
|  |   pthread_cond condWriters; | ||||||
|  |  | ||||||
|  |   class pthread_rwlock * next; | ||||||
|  |  | ||||||
|  |   void fixup_after_fork (); | ||||||
|  |  | ||||||
|  |   pthread_rwlock (pthread_rwlockattr *); | ||||||
|  |   ~pthread_rwlock (); | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |   void addReader (struct RWLOCK_READER *rd); | ||||||
|  |   void removeReader (struct RWLOCK_READER *rd); | ||||||
|  |   struct RWLOCK_READER *lookupReader (pthread_t thread); | ||||||
|  |  | ||||||
|  |   static void RdLockCleanup (void *arg); | ||||||
|  |   static void WrLockCleanup (void *arg); | ||||||
|  |  | ||||||
|  |   static nativeMutex rwlockInitializationLock; | ||||||
|  | }; | ||||||
|  |  | ||||||
| class pthread_once | class pthread_once | ||||||
| { | { | ||||||
| public: | public: | ||||||
| @@ -574,6 +637,7 @@ public: | |||||||
|   // lists of pthread objects. USE THREADSAFE INSERTS AND DELETES. |   // lists of pthread objects. USE THREADSAFE INSERTS AND DELETES. | ||||||
|   class pthread_mutex * mutexs; |   class pthread_mutex * mutexs; | ||||||
|   class pthread_cond  * conds; |   class pthread_cond  * conds; | ||||||
|  |   class pthread_rwlock * rwlocks; | ||||||
|   class semaphore     * semaphores; |   class semaphore     * semaphores; | ||||||
|  |  | ||||||
|   pthread_key reent_key; |   pthread_key reent_key; | ||||||
| @@ -586,7 +650,7 @@ public: | |||||||
|   MTinterface () : |   MTinterface () : | ||||||
|     concurrency (0), threadcount (1), |     concurrency (0), threadcount (1), | ||||||
|     pthread_prepare (NULL), pthread_child (NULL), pthread_parent (NULL), |     pthread_prepare (NULL), pthread_child (NULL), pthread_parent (NULL), | ||||||
|     mutexs (NULL), conds (NULL), semaphores (NULL), |     mutexs (NULL), conds (NULL), rwlocks (NULL), semaphores (NULL), | ||||||
|     reent_key (NULL), thread_self_key (NULL) |     reent_key (NULL), thread_self_key (NULL) | ||||||
|   { |   { | ||||||
|   } |   } | ||||||
| @@ -632,6 +696,19 @@ int __pthread_condattr_getpshared (const pthread_condattr_t * attr, | |||||||
| 				   int *pshared); | 				   int *pshared); | ||||||
| int __pthread_condattr_setpshared (pthread_condattr_t * attr, int pshared); | int __pthread_condattr_setpshared (pthread_condattr_t * attr, int pshared); | ||||||
|  |  | ||||||
|  | /* RW locks */ | ||||||
|  | int __pthread_rwlock_destroy (pthread_rwlock_t *rwlock); | ||||||
|  | int __pthread_rwlock_rdlock (pthread_rwlock_t *rwlock); | ||||||
|  | int __pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock); | ||||||
|  | int __pthread_rwlock_wrlock (pthread_rwlock_t *rwlock); | ||||||
|  | int __pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock); | ||||||
|  | int __pthread_rwlock_unlock (pthread_rwlock_t *rwlock); | ||||||
|  | int __pthread_rwlockattr_init (pthread_rwlockattr_t *rwlockattr); | ||||||
|  | int __pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, | ||||||
|  |                                      int *pshared); | ||||||
|  | int __pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared); | ||||||
|  | int __pthread_rwlockattr_destroy (pthread_rwlockattr_t *rwlockattr); | ||||||
|  |  | ||||||
| /* Thread signal */ | /* Thread signal */ | ||||||
| int __pthread_kill (pthread_t thread, int sig); | int __pthread_kill (pthread_t thread, int sig); | ||||||
| int __pthread_sigmask (int operation, const sigset_t * set, | int __pthread_sigmask (int operation, const sigset_t * set, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user