| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
|
|
| #include <config.h> |
|
|
| #include "glthread/lock.h" |
|
|
| |
|
|
| #if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS |
|
|
| |
|
|
| int |
| glthread_lock_init (gl_lock_t *lock) |
| { |
| if (mtx_init (&lock->mutex, mtx_plain) != thrd_success) |
| return ENOMEM; |
| lock->init_needed = 0; |
| return 0; |
| } |
|
|
| int |
| glthread_lock_lock (gl_lock_t *lock) |
| { |
| if (lock->init_needed) |
| call_once (&lock->init_once, lock->init_func); |
| if (mtx_lock (&lock->mutex) != thrd_success) |
| return EAGAIN; |
| return 0; |
| } |
|
|
| int |
| glthread_lock_unlock (gl_lock_t *lock) |
| { |
| if (lock->init_needed) |
| call_once (&lock->init_once, lock->init_func); |
| if (mtx_unlock (&lock->mutex) != thrd_success) |
| return EINVAL; |
| return 0; |
| } |
|
|
| int |
| glthread_lock_destroy (gl_lock_t *lock) |
| { |
| if (lock->init_needed) |
| call_once (&lock->init_once, lock->init_func); |
| mtx_destroy (&lock->mutex); |
| return 0; |
| } |
|
|
| |
|
|
| int |
| glthread_rwlock_init (gl_rwlock_t *lock) |
| { |
| if (mtx_init (&lock->lock, mtx_plain) != thrd_success |
| || cnd_init (&lock->waiting_readers) != thrd_success |
| || cnd_init (&lock->waiting_writers) != thrd_success) |
| return ENOMEM; |
| lock->waiting_writers_count = 0; |
| lock->runcount = 0; |
| lock->init_needed = 0; |
| return 0; |
| } |
|
|
| int |
| glthread_rwlock_rdlock (gl_rwlock_t *lock) |
| { |
| if (lock->init_needed) |
| call_once (&lock->init_once, lock->init_func); |
| if (mtx_lock (&lock->lock) != thrd_success) |
| return EAGAIN; |
| |
| |
| |
| |
| while (!(lock->runcount + 1 > 0 && lock->waiting_writers_count == 0)) |
| { |
| |
| |
| if (cnd_wait (&lock->waiting_readers, &lock->lock) != thrd_success) |
| { |
| mtx_unlock (&lock->lock); |
| return EINVAL; |
| } |
| } |
| lock->runcount++; |
| if (mtx_unlock (&lock->lock) != thrd_success) |
| return EINVAL; |
| return 0; |
| } |
|
|
| int |
| glthread_rwlock_wrlock (gl_rwlock_t *lock) |
| { |
| if (lock->init_needed) |
| call_once (&lock->init_once, lock->init_func); |
| if (mtx_lock (&lock->lock) != thrd_success) |
| return EAGAIN; |
| |
| while (!(lock->runcount == 0)) |
| { |
| |
| |
| lock->waiting_writers_count++; |
| if (cnd_wait (&lock->waiting_writers, &lock->lock) != thrd_success) |
| { |
| lock->waiting_writers_count--; |
| mtx_unlock (&lock->lock); |
| return EINVAL; |
| } |
| lock->waiting_writers_count--; |
| } |
| lock->runcount--; |
| if (mtx_unlock (&lock->lock) != thrd_success) |
| return EINVAL; |
| return 0; |
| } |
|
|
| int |
| glthread_rwlock_unlock (gl_rwlock_t *lock) |
| { |
| if (lock->init_needed) |
| call_once (&lock->init_once, lock->init_func); |
| if (mtx_lock (&lock->lock) != thrd_success) |
| return EAGAIN; |
| if (lock->runcount < 0) |
| { |
| |
| if (!(lock->runcount == -1)) |
| { |
| mtx_unlock (&lock->lock); |
| return EINVAL; |
| } |
| lock->runcount = 0; |
| } |
| else |
| { |
| |
| if (!(lock->runcount > 0)) |
| { |
| mtx_unlock (&lock->lock); |
| return EINVAL; |
| } |
| lock->runcount--; |
| } |
| if (lock->runcount == 0) |
| { |
| |
| |
| if (lock->waiting_writers_count > 0) |
| { |
| |
| if (cnd_signal (&lock->waiting_writers) != thrd_success) |
| { |
| mtx_unlock (&lock->lock); |
| return EINVAL; |
| } |
| } |
| else |
| { |
| |
| if (cnd_broadcast (&lock->waiting_readers) != thrd_success) |
| { |
| mtx_unlock (&lock->lock); |
| return EINVAL; |
| } |
| } |
| } |
| if (mtx_unlock (&lock->lock) != thrd_success) |
| return EINVAL; |
| return 0; |
| } |
|
|
| int |
| glthread_rwlock_destroy (gl_rwlock_t *lock) |
| { |
| if (lock->init_needed) |
| call_once (&lock->init_once, lock->init_func); |
| mtx_destroy (&lock->lock); |
| cnd_destroy (&lock->waiting_readers); |
| cnd_destroy (&lock->waiting_writers); |
| return 0; |
| } |
|
|
| |
|
|
| int |
| glthread_recursive_lock_init (gl_recursive_lock_t *lock) |
| { |
| if (mtx_init (&lock->mutex, mtx_plain | mtx_recursive) != thrd_success) |
| return ENOMEM; |
| lock->init_needed = 0; |
| return 0; |
| } |
|
|
| int |
| glthread_recursive_lock_lock (gl_recursive_lock_t *lock) |
| { |
| if (lock->init_needed) |
| call_once (&lock->init_once, lock->init_func); |
| if (mtx_lock (&lock->mutex) != thrd_success) |
| return EAGAIN; |
| return 0; |
| } |
|
|
| int |
| glthread_recursive_lock_unlock (gl_recursive_lock_t *lock) |
| { |
| if (lock->init_needed) |
| call_once (&lock->init_once, lock->init_func); |
| if (mtx_unlock (&lock->mutex) != thrd_success) |
| return EINVAL; |
| return 0; |
| } |
|
|
| int |
| glthread_recursive_lock_destroy (gl_recursive_lock_t *lock) |
| { |
| if (lock->init_needed) |
| call_once (&lock->init_once, lock->init_func); |
| mtx_destroy (&lock->mutex); |
| return 0; |
| } |
|
|
| #endif |
|
|
| |
|
|
| #if USE_POSIX_THREADS |
|
|
| |
|
|
| |
|
|
| # if HAVE_PTHREAD_RWLOCK && (HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER || (defined PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP && (__GNU_LIBRARY__ > 1))) |
|
|
| # if defined PTHREAD_RWLOCK_INITIALIZER || defined PTHREAD_RWLOCK_INITIALIZER_NP |
|
|
| # if !HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER |
| |
|
|
| int |
| glthread_rwlock_init_for_glibc (pthread_rwlock_t *lock) |
| { |
| pthread_rwlockattr_t attributes; |
| int err; |
|
|
| err = pthread_rwlockattr_init (&attributes); |
| if (err != 0) |
| return err; |
| |
| |
| |
| |
| err = pthread_rwlockattr_setkind_np (&attributes, |
| PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); |
| if (err == 0) |
| err = pthread_rwlock_init(lock, &attributes); |
| |
| |
| pthread_rwlockattr_destroy (&attributes); |
| return err; |
| } |
|
|
| # endif |
| # else |
|
|
| int |
| glthread_rwlock_init_multithreaded (gl_rwlock_t *lock) |
| { |
| int err; |
|
|
| err = pthread_rwlock_init (&lock->rwlock, NULL); |
| if (err != 0) |
| return err; |
| lock->initialized = 1; |
| return 0; |
| } |
|
|
| int |
| glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock) |
| { |
| if (!lock->initialized) |
| { |
| int err; |
|
|
| err = pthread_mutex_lock (&lock->guard); |
| if (err != 0) |
| return err; |
| if (!lock->initialized) |
| { |
| err = glthread_rwlock_init_multithreaded (lock); |
| if (err != 0) |
| { |
| pthread_mutex_unlock (&lock->guard); |
| return err; |
| } |
| } |
| err = pthread_mutex_unlock (&lock->guard); |
| if (err != 0) |
| return err; |
| } |
| return pthread_rwlock_rdlock (&lock->rwlock); |
| } |
|
|
| int |
| glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock) |
| { |
| if (!lock->initialized) |
| { |
| int err; |
|
|
| err = pthread_mutex_lock (&lock->guard); |
| if (err != 0) |
| return err; |
| if (!lock->initialized) |
| { |
| err = glthread_rwlock_init_multithreaded (lock); |
| if (err != 0) |
| { |
| pthread_mutex_unlock (&lock->guard); |
| return err; |
| } |
| } |
| err = pthread_mutex_unlock (&lock->guard); |
| if (err != 0) |
| return err; |
| } |
| return pthread_rwlock_wrlock (&lock->rwlock); |
| } |
|
|
| int |
| glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock) |
| { |
| if (!lock->initialized) |
| return EINVAL; |
| return pthread_rwlock_unlock (&lock->rwlock); |
| } |
|
|
| int |
| glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock) |
| { |
| int err; |
|
|
| if (!lock->initialized) |
| return EINVAL; |
| err = pthread_rwlock_destroy (&lock->rwlock); |
| if (err != 0) |
| return err; |
| lock->initialized = 0; |
| return 0; |
| } |
|
|
| # endif |
|
|
| # else |
|
|
| int |
| glthread_rwlock_init_multithreaded (gl_rwlock_t *lock) |
| { |
| int err; |
|
|
| err = pthread_mutex_init (&lock->lock, NULL); |
| if (err != 0) |
| return err; |
| err = pthread_cond_init (&lock->waiting_readers, NULL); |
| if (err != 0) |
| return err; |
| err = pthread_cond_init (&lock->waiting_writers, NULL); |
| if (err != 0) |
| return err; |
| lock->waiting_writers_count = 0; |
| lock->runcount = 0; |
| return 0; |
| } |
|
|
| int |
| glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock) |
| { |
| int err; |
|
|
| err = pthread_mutex_lock (&lock->lock); |
| if (err != 0) |
| return err; |
| |
| |
| |
| |
| while (!(lock->runcount + 1 > 0 && lock->waiting_writers_count == 0)) |
| { |
| |
| |
| err = pthread_cond_wait (&lock->waiting_readers, &lock->lock); |
| if (err != 0) |
| { |
| pthread_mutex_unlock (&lock->lock); |
| return err; |
| } |
| } |
| lock->runcount++; |
| return pthread_mutex_unlock (&lock->lock); |
| } |
|
|
| int |
| glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock) |
| { |
| int err; |
|
|
| err = pthread_mutex_lock (&lock->lock); |
| if (err != 0) |
| return err; |
| |
| while (!(lock->runcount == 0)) |
| { |
| |
| |
| lock->waiting_writers_count++; |
| err = pthread_cond_wait (&lock->waiting_writers, &lock->lock); |
| if (err != 0) |
| { |
| lock->waiting_writers_count--; |
| pthread_mutex_unlock (&lock->lock); |
| return err; |
| } |
| lock->waiting_writers_count--; |
| } |
| lock->runcount--; |
| return pthread_mutex_unlock (&lock->lock); |
| } |
|
|
| int |
| glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock) |
| { |
| int err; |
|
|
| err = pthread_mutex_lock (&lock->lock); |
| if (err != 0) |
| return err; |
| if (lock->runcount < 0) |
| { |
| |
| if (!(lock->runcount == -1)) |
| { |
| pthread_mutex_unlock (&lock->lock); |
| return EINVAL; |
| } |
| lock->runcount = 0; |
| } |
| else |
| { |
| |
| if (!(lock->runcount > 0)) |
| { |
| pthread_mutex_unlock (&lock->lock); |
| return EINVAL; |
| } |
| lock->runcount--; |
| } |
| if (lock->runcount == 0) |
| { |
| |
| |
| if (lock->waiting_writers_count > 0) |
| { |
| |
| err = pthread_cond_signal (&lock->waiting_writers); |
| if (err != 0) |
| { |
| pthread_mutex_unlock (&lock->lock); |
| return err; |
| } |
| } |
| else |
| { |
| |
| err = pthread_cond_broadcast (&lock->waiting_readers); |
| if (err != 0) |
| { |
| pthread_mutex_unlock (&lock->lock); |
| return err; |
| } |
| } |
| } |
| return pthread_mutex_unlock (&lock->lock); |
| } |
|
|
| int |
| glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock) |
| { |
| int err; |
|
|
| err = pthread_mutex_destroy (&lock->lock); |
| if (err != 0) |
| return err; |
| err = pthread_cond_destroy (&lock->waiting_readers); |
| if (err != 0) |
| return err; |
| err = pthread_cond_destroy (&lock->waiting_writers); |
| if (err != 0) |
| return err; |
| return 0; |
| } |
|
|
| # endif |
|
|
| |
|
|
| # if HAVE_PTHREAD_MUTEX_RECURSIVE |
|
|
| # if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP |
|
|
| int |
| glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock) |
| { |
| pthread_mutexattr_t attributes; |
| int err; |
|
|
| err = pthread_mutexattr_init (&attributes); |
| if (err != 0) |
| return err; |
| err = pthread_mutexattr_settype (&attributes, PTHREAD_MUTEX_RECURSIVE); |
| if (err != 0) |
| { |
| pthread_mutexattr_destroy (&attributes); |
| return err; |
| } |
| err = pthread_mutex_init (lock, &attributes); |
| if (err != 0) |
| { |
| pthread_mutexattr_destroy (&attributes); |
| return err; |
| } |
| err = pthread_mutexattr_destroy (&attributes); |
| if (err != 0) |
| return err; |
| return 0; |
| } |
|
|
| # else |
|
|
| int |
| glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock) |
| { |
| pthread_mutexattr_t attributes; |
| int err; |
|
|
| err = pthread_mutexattr_init (&attributes); |
| if (err != 0) |
| return err; |
| err = pthread_mutexattr_settype (&attributes, PTHREAD_MUTEX_RECURSIVE); |
| if (err != 0) |
| { |
| pthread_mutexattr_destroy (&attributes); |
| return err; |
| } |
| err = pthread_mutex_init (&lock->recmutex, &attributes); |
| if (err != 0) |
| { |
| pthread_mutexattr_destroy (&attributes); |
| return err; |
| } |
| err = pthread_mutexattr_destroy (&attributes); |
| if (err != 0) |
| return err; |
| lock->initialized = 1; |
| return 0; |
| } |
|
|
| int |
| glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock) |
| { |
| if (!lock->initialized) |
| { |
| int err; |
|
|
| err = pthread_mutex_lock (&lock->guard); |
| if (err != 0) |
| return err; |
| if (!lock->initialized) |
| { |
| err = glthread_recursive_lock_init_multithreaded (lock); |
| if (err != 0) |
| { |
| pthread_mutex_unlock (&lock->guard); |
| return err; |
| } |
| } |
| err = pthread_mutex_unlock (&lock->guard); |
| if (err != 0) |
| return err; |
| } |
| return pthread_mutex_lock (&lock->recmutex); |
| } |
|
|
| int |
| glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock) |
| { |
| if (!lock->initialized) |
| return EINVAL; |
| return pthread_mutex_unlock (&lock->recmutex); |
| } |
|
|
| int |
| glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock) |
| { |
| int err; |
|
|
| if (!lock->initialized) |
| return EINVAL; |
| err = pthread_mutex_destroy (&lock->recmutex); |
| if (err != 0) |
| return err; |
| lock->initialized = 0; |
| return 0; |
| } |
|
|
| # endif |
|
|
| # else |
|
|
| int |
| glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock) |
| { |
| int err; |
|
|
| err = pthread_mutex_init (&lock->mutex, NULL); |
| if (err != 0) |
| return err; |
| lock->owner = (pthread_t) 0; |
| lock->depth = 0; |
| return 0; |
| } |
|
|
| int |
| glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock) |
| { |
| pthread_t self = pthread_self (); |
| if (lock->owner != self) |
| { |
| int err; |
|
|
| err = pthread_mutex_lock (&lock->mutex); |
| if (err != 0) |
| return err; |
| lock->owner = self; |
| } |
| if (++(lock->depth) == 0) |
| { |
| lock->depth--; |
| return EAGAIN; |
| } |
| return 0; |
| } |
|
|
| int |
| glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock) |
| { |
| if (lock->owner != pthread_self ()) |
| return EPERM; |
| if (lock->depth == 0) |
| return EINVAL; |
| if (--(lock->depth) == 0) |
| { |
| lock->owner = (pthread_t) 0; |
| return pthread_mutex_unlock (&lock->mutex); |
| } |
| else |
| return 0; |
| } |
|
|
| int |
| glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock) |
| { |
| if (lock->owner != (pthread_t) 0) |
| return EBUSY; |
| return pthread_mutex_destroy (&lock->mutex); |
| } |
|
|
| # endif |
|
|
| #endif |
|
|
| |
|
|
| #if USE_WINDOWS_THREADS |
|
|
| #endif |
|
|
| |
|
|