]> git.saurik.com Git - apple/libc.git/blobdiff - pthreads/pthread_rwlock.c
Libc-262.tar.gz
[apple/libc.git] / pthreads / pthread_rwlock.c
diff --git a/pthreads/pthread_rwlock.c b/pthreads/pthread_rwlock.c
new file mode 100644 (file)
index 0000000..978ed80
--- /dev/null
@@ -0,0 +1,319 @@
+/*-
+ * Copyright (c) 1998 Alex Nash
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libc_r/uthread/uthread_rwlock.c,v 1.6 2001/04/10 04:19:20 deischen Exp $
+ */
+
+/* 
+ * POSIX Pthread Library 
+ * -- Read Write Lock support
+ * 4/24/02: A. Ramesh
+ *        Ported from FreeBSD
+ */
+
+#include "pthread_internals.h"
+
+/* maximum number of times a read lock may be obtained */
+#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;
+
+       /* initialize the lock */
+       if ((ret = pthread_mutex_init(&rwlock->lock, NULL)) != 0)
+               return(ret);
+       else {
+               /* initialize the read condition signal */
+               ret = pthread_cond_init(&rwlock->read_signal, NULL);
+
+               if (ret != 0) {
+                       pthread_mutex_destroy(&rwlock->lock);
+                       return(ret);
+               } else {
+                       /* initialize the write condition signal */
+                       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 {
+                               /* success */
+                               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);
+       /* grab the monitor lock */
+       if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0)
+               return(ret);
+
+       /* give writers priority over readers */
+       while (rwlock->blocked_writers || rwlock->state < 0) {
+               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);
+                       return(ret);
+               }
+       }
+
+       /* check lock count */
+       if (rwlock->state == MAX_READ_LOCKS)
+               ret = EAGAIN;
+       else
+               ++rwlock->state; /* indicate we are locked for reading */
+
+       /*
+        * Something is really wrong if this call fails.  Returning
+        * error won't do because we've already obtained the read
+        * lock.  Decrementing 'state' is no good because we probably
+        * don't have the monitor lock.
+        */
+       pthread_mutex_unlock(&rwlock->lock);
+
+       return(ret);
+}
+
+int
+pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
+{
+       int                     ret;
+
+       /* check for static initialization */
+       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);
+       /* grab the monitor lock */
+       if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0)
+               return(ret);
+
+       /* give writers priority over readers */
+       if (rwlock->blocked_writers || rwlock->state < 0)
+               ret = EBUSY;
+       else if (rwlock->state == MAX_READ_LOCKS)
+               ret = EAGAIN; /* too many read locks acquired */
+       else
+               ++rwlock->state; /* indicate we are locked for reading */
+
+       /* see the comment on this in pthread_rwlock_rdlock */
+       pthread_mutex_unlock(&rwlock->lock);
+
+       return(ret);
+}
+
+int
+pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
+{
+       int                     ret;
+
+       /* check for static initialization */
+       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);
+       /* grab the monitor lock */
+       if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0)
+               return(ret);
+
+       if (rwlock->state != 0)
+               ret = EBUSY;
+       else
+               /* indicate we are locked for writing */
+               rwlock->state = -1;
+
+       /* see the comment on this in pthread_rwlock_rdlock */
+       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);
+       /* grab the monitor lock */
+       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;
+
+       /* see the comment on this in pthread_rwlock_rdlock */
+       pthread_mutex_unlock(&rwlock->lock);
+
+       return(ret);
+}
+
+int
+pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
+{
+       int                     ret;
+
+       /* check for static initialization */
+       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);
+       /* grab the monitor lock */
+       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;
+       }
+
+       /* indicate we are locked for writing */
+       rwlock->state = -1;
+
+       /* see the comment on this in pthread_rwlock_rdlock */
+       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;  /* 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 */
+        }
+
+}
+