#include "pthread_internals.h"
#define MAX_READ_LOCKS (INT_MAX - 1)
int
pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
{
if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
return(EINVAL);
} else {
pthread_mutex_destroy(&rwlock->lock);
pthread_cond_destroy(&rwlock->read_signal);
pthread_cond_destroy(&rwlock->write_signal);
rwlock->sig = _PTHREAD_NO_SIG;
return(ESUCCESS);
}
}
int
pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
{
int ret;
if ((ret = pthread_mutex_init(&rwlock->lock, NULL)) != 0)
return(ret);
else {
ret = pthread_cond_init(&rwlock->read_signal, NULL);
if (ret != 0) {
pthread_mutex_destroy(&rwlock->lock);
return(ret);
} else {
ret = pthread_cond_init(&rwlock->write_signal, NULL);
if (ret != 0) {
pthread_cond_destroy(&rwlock->read_signal);
pthread_mutex_destroy(&rwlock->lock);
return(ret);
} else {
rwlock->state = 0;
rwlock->blocked_writers = 0;
rwlock->sig = _PTHREAD_RWLOCK_SIG;
return(ESUCCESS);
}
}
}
}
int
pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
{
int ret;
if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
return(ret);
}
}
if (rwlock->sig != _PTHREAD_RWLOCK_SIG)
return(EINVAL);
if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0)
return(ret);
while (rwlock->blocked_writers || rwlock->state < 0) {
ret = pthread_cond_wait(&rwlock->read_signal, &rwlock->lock);
if (ret != 0) {
pthread_mutex_unlock(&rwlock->lock);
return(ret);
}
}
if (rwlock->state == MAX_READ_LOCKS)
ret = EAGAIN;
else
++rwlock->state;
pthread_mutex_unlock(&rwlock->lock);
return(ret);
}
int
pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
{
int ret;
if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
return(ret);
}
}
if (rwlock->sig != _PTHREAD_RWLOCK_SIG)
return(EINVAL);
if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0)
return(ret);
if (rwlock->blocked_writers || rwlock->state < 0)
ret = EBUSY;
else if (rwlock->state == MAX_READ_LOCKS)
ret = EAGAIN;
else
++rwlock->state;
pthread_mutex_unlock(&rwlock->lock);
return(ret);
}
int
pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
{
int ret;
if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
return(ret);
}
}
if (rwlock->sig != _PTHREAD_RWLOCK_SIG)
return(EINVAL);
if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0)
return(ret);
if (rwlock->state != 0)
ret = EBUSY;
else
rwlock->state = -1;
pthread_mutex_unlock(&rwlock->lock);
return(ret);
}
int
pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
{
int ret;
if (rwlock->sig != _PTHREAD_RWLOCK_SIG)
return(EINVAL);
if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0)
return(ret);
if (rwlock->state > 0) {
if (--rwlock->state == 0 && rwlock->blocked_writers)
ret = pthread_cond_signal(&rwlock->write_signal);
} else if (rwlock->state < 0) {
rwlock->state = 0;
if (rwlock->blocked_writers)
ret = pthread_cond_signal(&rwlock->write_signal);
else
ret = pthread_cond_broadcast(&rwlock->read_signal);
} else
ret = EINVAL;
pthread_mutex_unlock(&rwlock->lock);
return(ret);
}
int
pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
{
int ret;
if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
return(ret);
}
}
if (rwlock->sig != _PTHREAD_RWLOCK_SIG)
return(EINVAL);
if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0)
return(ret);
while (rwlock->state != 0) {
++rwlock->blocked_writers;
ret = pthread_cond_wait(&rwlock->write_signal, &rwlock->lock);
if (ret != 0) {
--rwlock->blocked_writers;
pthread_mutex_unlock(&rwlock->lock);
return(ret);
}
--rwlock->blocked_writers;
}
rwlock->state = -1;
pthread_mutex_unlock(&rwlock->lock);
return(ret);
}
int
pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
{
attr->sig = _PTHREAD_RWLOCK_ATTR_SIG;
attr->pshared = PTHREAD_PROCESS_PRIVATE;
return (ESUCCESS);
}
int
pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
{
attr->sig = _PTHREAD_NO_SIG;
attr->pshared = 0;
return (ESUCCESS);
}
int
pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr,
int *pshared)
{
if (attr->sig == _PTHREAD_RWLOCK_ATTR_SIG)
{
*pshared = (int)PTHREAD_PROCESS_PRIVATE;
return (ESUCCESS);
} else
{
return (EINVAL);
}
}
int
pthread_rwlockattr_setpshared(pthread_rwlockattr_t * attr, int pshared)
{
if (attr->sig == _PTHREAD_RWLOCK_ATTR_SIG)
{
if ( pshared == PTHREAD_PROCESS_PRIVATE)
{
attr->pshared = pshared ;
return (ESUCCESS);
} else
{
return (EINVAL);
}
} else
{
return (EINVAL);
}
}