]> git.saurik.com Git - apple/libc.git/blobdiff - pthreads/pthread_rwlock.c
Libc-498.1.7.tar.gz
[apple/libc.git] / pthreads / pthread_rwlock.c
index 3ce5ef260ee2385e5195808a9587ef5e30f76718..35bb6d08522f6d809437426474e656d96faa62d4 100644 (file)
@@ -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
  */
 
 #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 */
-        }
-
-}