X-Git-Url: https://git.saurik.com/apple/libc.git/blobdiff_plain/59e0d9fe772464b93d835d2a2964457702469a43..5f4d86c1219d56604890d932a3152b3b5dd15b55:/pthreads/pthread_rwlock.c?ds=sidebyside diff --git a/pthreads/pthread_rwlock.c b/pthreads/pthread_rwlock.c index 3ce5ef2..35bb6d0 100644 --- a/pthreads/pthread_rwlock.c +++ b/pthreads/pthread_rwlock.c @@ -1,10 +1,8 @@ /* - * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2003, 2007, 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -58,22 +56,122 @@ */ #include "pthread_internals.h" +extern int __unix_conforming; + +#ifdef PLOCKSTAT +#include "plockstat.h" +#else /* !PLOCKSTAT */ +#define PLOCKSTAT_RW_ERROR(x, y, z) +#define PLOCKSTAT_RW_BLOCK(x, y) +#define PLOCKSTAT_RW_BLOCKED(x, y, z) +#define PLOCKSTAT_RW_ACQUIRE(x, y) +#define PLOCKSTAT_RW_RELEASE(x, y) +#endif /* PLOCKSTAT */ + +#define READ_LOCK_PLOCKSTAT 0 +#define WRITE_LOCK_PLOCKSTAT 1 + +#define BLOCK_FAIL_PLOCKSTAT 0 +#define BLOCK_SUCCESS_PLOCKSTAT 1 /* maximum number of times a read lock may be obtained */ -#define MAX_READ_LOCKS (INT_MAX - 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; /* Uninitialized */ + 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); /* Not an initialized 'attribute' structure */ + } +} + +/* Temp: untill pshared is fixed right */ +#ifdef PR_5243343 +/* 5243343 - temporary hack to detect if we are running the conformance test */ +extern int PR_5243343_flag; +#endif /* PR_5243343 */ + +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 /* !PR_5243343 */ + if (( pshared == PTHREAD_PROCESS_PRIVATE) || (pshared == PTHREAD_PROCESS_SHARED)) +#endif /* PR_5243343 */ +#else /* __DARWIN_UNIX03 */ + if ( pshared == PTHREAD_PROCESS_PRIVATE) +#endif /* __DARWIN_UNIX03 */ + { + attr->pshared = pshared ; + return (0); + } else + { + return (EINVAL); /* Invalid parameter */ + } + } else + { + return (EINVAL); /* Not an initialized 'attribute' structure */ + } + +} + +#endif /* !BUILDING_VARIANT ] */ int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) { + int ret; if (rwlock->sig != _PTHREAD_RWLOCK_SIG) { return(EINVAL); } else { +#if __DARWIN_UNIX03 + /* grab the monitor lock */ + 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 /* __DARWIN_UNIX03 */ + pthread_mutex_destroy(&rwlock->lock); pthread_cond_destroy(&rwlock->read_signal); pthread_cond_destroy(&rwlock->write_signal); rwlock->sig = _PTHREAD_NO_SIG; - return(ESUCCESS); + return(0); } } @@ -81,6 +179,15 @@ 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 already inited check whether it is in use, then return EBUSY */ + if ((rwlock->sig == _PTHREAD_RWLOCK_SIG) && (rwlock->state !=0 )) { + return(EBUSY); + } +#endif /* __DARWIN_UNIX03 */ /* initialize the lock */ if ((ret = pthread_mutex_init(&rwlock->lock, NULL)) != 0) @@ -103,9 +210,15 @@ pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) } else { /* success */ 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(ESUCCESS); + return(0); } } } @@ -115,35 +228,66 @@ 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) + if (rwlock->sig != _PTHREAD_RWLOCK_SIG) { + PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, EINVAL); return(EINVAL); + } /* grab the monitor lock */ - if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) + 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 /* __DARWIN_UNIX03 */ + +#if __DARWIN_UNIX03 + while (rwlock->blocked_writers || ((rwlock->state < 0) && (rwlock->owner != self))) +#else /* __DARWIN_UNIX03 */ + while (rwlock->blocked_writers || rwlock->state < 0) + +#endif /* __DARWIN_UNIX03 */ + { /* give writers priority over readers */ - while (rwlock->blocked_writers || rwlock->state < 0) { + PLOCKSTAT_RW_BLOCK(rwlock, READ_LOCK_PLOCKSTAT); ret = pthread_cond_wait(&rwlock->read_signal, &rwlock->lock); if (ret != 0) { /* can't do a whole lot if this fails */ 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); } /* check lock count */ - if (rwlock->state == MAX_READ_LOCKS) + if (rwlock->state == MAX_READ_LOCKS) { ret = EAGAIN; - else + PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret); + } + else { ++rwlock->state; /* indicate we are locked for reading */ + PLOCKSTAT_RW_ACQUIRE(rwlock, READ_LOCK_PLOCKSTAT); + } /* * Something is really wrong if this call fails. Returning @@ -160,27 +304,41 @@ int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) { int ret; +#if __DARWIN_UNIX03 + pthread_t self = pthread_self(); +#endif /* check for static initialization */ 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) + if (rwlock->sig != _PTHREAD_RWLOCK_SIG) { + PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, EINVAL); return(EINVAL); + } /* grab the monitor lock */ - if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) + if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) { + PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret); return(ret); + } /* give writers priority over readers */ - if (rwlock->blocked_writers || rwlock->state < 0) + if (rwlock->blocked_writers || rwlock->state < 0) { ret = EBUSY; - else if (rwlock->state == MAX_READ_LOCKS) + PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret); + } + else if (rwlock->state == MAX_READ_LOCKS) { ret = EAGAIN; /* too many read locks acquired */ - else + PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret); + } + else { ++rwlock->state; /* indicate we are locked for reading */ + PLOCKSTAT_RW_ACQUIRE(rwlock, READ_LOCK_PLOCKSTAT); + } /* see the comment on this in pthread_rwlock_rdlock */ pthread_mutex_unlock(&rwlock->lock); @@ -192,25 +350,41 @@ int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) { int ret; +#if __DARWIN_UNIX03 + pthread_t self = pthread_self(); +#endif /* __DARWIN_UNIX03 */ /* check for static initialization */ 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) + if (rwlock->sig != _PTHREAD_RWLOCK_SIG) { + PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, EINVAL); return(EINVAL); + } /* grab the monitor lock */ - if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) + if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) { + PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret); return(ret); + } - if (rwlock->state != 0) + + if (rwlock->state != 0) { ret = EBUSY; - else + PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret); + } + else { /* indicate we are locked for writing */ rwlock->state = -1; +#if __DARWIN_UNIX03 + rwlock->owner = self; +#endif /* __DARWIN_UNIX03 */ + PLOCKSTAT_RW_ACQUIRE(rwlock, WRITE_LOCK_PLOCKSTAT); + } /* see the comment on this in pthread_rwlock_rdlock */ pthread_mutex_unlock(&rwlock->lock); @@ -222,18 +396,29 @@ 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 /* __DARWIN_UNIX03 */ - if (rwlock->sig != _PTHREAD_RWLOCK_SIG) + if (rwlock->sig != _PTHREAD_RWLOCK_SIG) { + PLOCKSTAT_RW_ERROR(rwlock, writer, EINVAL); return(EINVAL); + } /* grab the monitor lock */ - if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) + 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 /* __DARWIN_UNIX03 */ if (rwlock->blocked_writers) ret = pthread_cond_signal(&rwlock->write_signal); @@ -242,6 +427,12 @@ pthread_rwlock_unlock(pthread_rwlock_t *rwlock) } else ret = EINVAL; + if (ret == 0) { + PLOCKSTAT_RW_RELEASE(rwlock, writer); + } else { + PLOCKSTAT_RW_ERROR(rwlock, writer, ret); + } + /* see the comment on this in pthread_rwlock_rdlock */ pthread_mutex_unlock(&rwlock->lock); @@ -252,36 +443,60 @@ int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) { int ret; +#if __DARWIN_UNIX03 + pthread_t self = pthread_self(); +#endif /* __DARWIN_UNIX03 */ /* check for static initialization */ 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) + if (rwlock->sig != _PTHREAD_RWLOCK_SIG) { + PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, EINVAL); return(EINVAL); + } /* grab the monitor lock */ - if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) + 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 /* __DARWIN_UNIX03 */ 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; } /* indicate we are locked for writing */ rwlock->state = -1; +#if __DARWIN_UNIX03 + rwlock->owner = self; +#endif /* __DARWIN_UNIX03 */ + PLOCKSTAT_RW_ACQUIRE(rwlock, WRITE_LOCK_PLOCKSTAT); /* see the comment on this in pthread_rwlock_rdlock */ pthread_mutex_unlock(&rwlock->lock); @@ -289,55 +504,4 @@ pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) 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; /* Uninitialized */ - 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)attr->pshared; */ - *pshared = (int)PTHREAD_PROCESS_PRIVATE; - return (ESUCCESS); - } else - { - return (EINVAL); /* Not an initialized 'attribute' structure */ - } -} - - -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); /* Invalid parameter */ - } - } else - { - return (EINVAL); /* Not an initialized 'attribute' structure */ - } - -}