#include "pthread_internals.h"
extern int __unix_conforming;
#include "plockstat.h"
#define READ_LOCK_PLOCKSTAT 0
#define WRITE_LOCK_PLOCKSTAT 1
#define BLOCK_FAIL_PLOCKSTAT 0
#define BLOCK_SUCCESS_PLOCKSTAT 1
#define MAX_READ_LOCKS (INT_MAX - 1)
#ifndef BUILDING_VARIANT
int
pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
{
attr->sig = _PTHREAD_RWLOCK_ATTR_SIG;
attr->pshared = _PTHREAD_DEFAULT_PSHARED;
return (0);
}
int
pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
{
attr->sig = _PTHREAD_NO_SIG;
attr->pshared = 0;
return (0);
}
int
pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr,
int *pshared)
{
if (attr->sig == _PTHREAD_RWLOCK_ATTR_SIG)
{
*pshared = (int)attr->pshared;
return (0);
} else
{
return (EINVAL);
}
}
#ifdef PR_5243343
extern int PR_5243343_flag;
#endif
int
pthread_rwlockattr_setpshared(pthread_rwlockattr_t * attr, int pshared)
{
if (attr->sig == _PTHREAD_RWLOCK_ATTR_SIG)
{
#if __DARWIN_UNIX03
#ifdef PR_5243343
if (( pshared == PTHREAD_PROCESS_PRIVATE) || (pshared == PTHREAD_PROCESS_SHARED && PR_5243343_flag))
#else
if (( pshared == PTHREAD_PROCESS_PRIVATE) || (pshared == PTHREAD_PROCESS_SHARED))
#endif
#else
if ( pshared == PTHREAD_PROCESS_PRIVATE)
#endif
{
attr->pshared = pshared ;
return (0);
} else
{
return (EINVAL);
}
} else
{
return (EINVAL);
}
}
#endif
int
pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
{
int ret;
if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
return(EINVAL);
} else {
#if __DARWIN_UNIX03
if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0)
return(ret);
if (rwlock->state != 0) {
pthread_mutex_unlock(&rwlock->lock);
return(EBUSY);
}
pthread_mutex_unlock(&rwlock->lock);
#endif
pthread_mutex_destroy(&rwlock->lock);
pthread_cond_destroy(&rwlock->read_signal);
pthread_cond_destroy(&rwlock->write_signal);
rwlock->sig = _PTHREAD_NO_SIG;
return(0);
}
}
int
pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
{
int ret;
#if __DARWIN_UNIX03
if (attr && (attr->sig != _PTHREAD_RWLOCK_ATTR_SIG)) {
return(EINVAL);
}
if ((rwlock->sig == _PTHREAD_RWLOCK_SIG) && (rwlock->state !=0 )) {
return(EBUSY);
}
#endif
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->owner = (pthread_t)0;
rwlock->blocked_writers = 0;
if (attr)
rwlock->pshared = attr->pshared;
else
rwlock->pshared = _PTHREAD_DEFAULT_PSHARED;
rwlock->sig = _PTHREAD_RWLOCK_SIG;
return(0);
}
}
}
}
int
pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
{
int ret;
#if __DARWIN_UNIX03
pthread_t self = pthread_self();
#endif
if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
return(ret);
}
}
if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, EINVAL);
return(EINVAL);
}
if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) {
PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
return(ret);
}
#if __DARWIN_UNIX03
if ((rwlock->state < 0) && (rwlock->owner == self)) {
pthread_mutex_unlock(&rwlock->lock);
PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, EDEADLK);
return(EDEADLK);
}
#endif
#if __DARWIN_UNIX03
while (rwlock->blocked_writers || ((rwlock->state < 0) && (rwlock->owner != self)))
#else
while (rwlock->blocked_writers || rwlock->state < 0)
#endif
{
PLOCKSTAT_RW_BLOCK(rwlock, READ_LOCK_PLOCKSTAT);
ret = pthread_cond_wait(&rwlock->read_signal, &rwlock->lock);
if (ret != 0) {
pthread_mutex_unlock(&rwlock->lock);
PLOCKSTAT_RW_BLOCKED(rwlock, READ_LOCK_PLOCKSTAT, BLOCK_FAIL_PLOCKSTAT);
PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
return(ret);
}
PLOCKSTAT_RW_BLOCKED(rwlock, READ_LOCK_PLOCKSTAT, BLOCK_SUCCESS_PLOCKSTAT);
}
if (rwlock->state == MAX_READ_LOCKS) {
ret = EAGAIN;
PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
}
else {
++rwlock->state;
PLOCKSTAT_RW_ACQUIRE(rwlock, READ_LOCK_PLOCKSTAT);
}
pthread_mutex_unlock(&rwlock->lock);
return(ret);
}
int
pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
{
int ret;
#if __DARWIN_UNIX03
pthread_t self = pthread_self();
#endif
if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
return(ret);
}
}
if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, EINVAL);
return(EINVAL);
}
if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) {
PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
return(ret);
}
if (rwlock->blocked_writers || rwlock->state < 0) {
ret = EBUSY;
PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
}
else if (rwlock->state == MAX_READ_LOCKS) {
ret = EAGAIN;
PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
}
else {
++rwlock->state;
PLOCKSTAT_RW_ACQUIRE(rwlock, READ_LOCK_PLOCKSTAT);
}
pthread_mutex_unlock(&rwlock->lock);
return(ret);
}
int
pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
{
int ret;
#if __DARWIN_UNIX03
pthread_t self = pthread_self();
#endif
if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret);
return(ret);
}
}
if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, EINVAL);
return(EINVAL);
}
if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) {
PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret);
return(ret);
}
if (rwlock->state != 0) {
ret = EBUSY;
PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret);
}
else {
rwlock->state = -1;
#if __DARWIN_UNIX03
rwlock->owner = self;
#endif
PLOCKSTAT_RW_ACQUIRE(rwlock, WRITE_LOCK_PLOCKSTAT);
}
pthread_mutex_unlock(&rwlock->lock);
return(ret);
}
int
pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
{
int ret;
int writer = (rwlock < 0) ? 1:0;
#if __DARWIN_UNIX03
pthread_t self = pthread_self();
#endif
if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
PLOCKSTAT_RW_ERROR(rwlock, writer, EINVAL);
return(EINVAL);
}
if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) {
PLOCKSTAT_RW_ERROR(rwlock, writer, ret);
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 __DARWIN_UNIX03
rwlock->owner = (pthread_t)0;
#endif
if (rwlock->blocked_writers)
ret = pthread_cond_signal(&rwlock->write_signal);
else
ret = pthread_cond_broadcast(&rwlock->read_signal);
} else
ret = EINVAL;
if (ret == 0) {
PLOCKSTAT_RW_RELEASE(rwlock, writer);
} else {
PLOCKSTAT_RW_ERROR(rwlock, writer, ret);
}
pthread_mutex_unlock(&rwlock->lock);
return(ret);
}
int
pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
{
int ret;
#if __DARWIN_UNIX03
pthread_t self = pthread_self();
#endif
if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret);
return(ret);
}
}
if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, EINVAL);
return(EINVAL);
}
if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) {
PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret);
return(ret);
}
#if __DARWIN_UNIX03
if ((rwlock->state < 0) && (rwlock->owner == self)) {
pthread_mutex_unlock(&rwlock->lock);
PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, EDEADLK);
return(EDEADLK);
}
#endif
while (rwlock->state != 0) {
++rwlock->blocked_writers;
PLOCKSTAT_RW_BLOCK(rwlock, WRITE_LOCK_PLOCKSTAT);
ret = pthread_cond_wait(&rwlock->write_signal, &rwlock->lock);
if (ret != 0) {
--rwlock->blocked_writers;
pthread_mutex_unlock(&rwlock->lock);
PLOCKSTAT_RW_BLOCKED(rwlock, WRITE_LOCK_PLOCKSTAT, BLOCK_FAIL_PLOCKSTAT);
PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret);
return(ret);
}
PLOCKSTAT_RW_BLOCKED(rwlock, WRITE_LOCK_PLOCKSTAT, BLOCK_SUCCESS_PLOCKSTAT);
--rwlock->blocked_writers;
}
rwlock->state = -1;
#if __DARWIN_UNIX03
rwlock->owner = self;
#endif
PLOCKSTAT_RW_ACQUIRE(rwlock, WRITE_LOCK_PLOCKSTAT);
pthread_mutex_unlock(&rwlock->lock);
return(ret);
}