diff options
Diffstat (limited to 'linuxthreads/rwlock.c')
-rw-r--r-- | linuxthreads/rwlock.c | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/linuxthreads/rwlock.c b/linuxthreads/rwlock.c new file mode 100644 index 0000000000..c6b281551a --- /dev/null +++ b/linuxthreads/rwlock.c @@ -0,0 +1,276 @@ +/* Read-write lock implementation. + Copyright (C) 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Xavier Leroy <Xavier.Leroy@inria.fr> + and Ulrich Drepper <drepper@cygnus.com>, 1998. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <pthread.h> +#include "internals.h" +#include "queue.h" +#include "restart.h" +#include "spinlock.h" + +int +pthread_rwlock_init (pthread_rwlock_t *rwlock, + const pthread_rwlockattr_t *attr) +{ + rwlock->rw_spinlock = 0; + rwlock->rw_readers = 0; + rwlock->rw_writer = NULL; + + queue_init(&rwlock->rw_read_waiting); + queue_init(&rwlock->rw_write_waiting); + + if (attr == NULL) + { + rwlock->rw_kind = PTHREAD_RWLOCK_DEFAULT_NP; + rwlock->rw_pshared = PTHREAD_PROCESS_PRIVATE; + } + else + { + rwlock->rw_kind = attr->lockkind; + rwlock->rw_pshared = attr->pshared; + } + + return 0; +} + + +int +pthread_rwlock_destroy (pthread_rwlock_t *rwlock) +{ + int readers; + _pthread_descr writer; + + acquire (&rwlock->rw_spinlock); + readers = rwlock->rw_readers; + writer = rwlock->rw_writer; + release (&rwlock->rw_spinlock); + + if (readers > 0 || writer != NULL) + return EBUSY; + + return 0; +} + + +int +pthread_rwlock_rdlock (pthread_rwlock_t *rwlock) +{ + pthread_descr self; + + while (1) + { + acquire (&rwlock->rw_spinlock); + if (rwlock->rw_writer == NULL + || (rwlock->rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP + && rwlock->rw_readers != 0)) + /* We can add a reader lock. */ + break; + + /* Suspend ourselves, then try again */ + self = thread_self (); + enqueue (&rwlock->rw_read_waiting, self); + release (&rwlock->rw_spinlock); + suspend (self); /* This is not a cancellation point */ + } + + ++rwlock->rw_readers; + release (&rwlock->rw_spinlock); + + return 0; +} + + +int +pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock) +{ + int result = EBUSY; + + acquire (&rwlock->rw_spinlock); + if (rwlock->rw_writer == NULL + || (rwlock->rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP + && rwlock->rw_readers != 0)) + { + ++rwlock->rw_readers; + result = 0; + } + release (&rwlock->rw_spinlock); + + return result; +} + + +int +pthread_rwlock_wrlock (pthread_rwlock_t *rwlock) +{ + pthread_descr self = thread_self (); + + while(1) + { + acquire (&rwlock->rw_spinlock); + if (rwlock->rw_readers == 0 && rwlock->rw_writer == NULL) + { + rwlock->rw_writer = self; + release (&rwlock->rw_spinlock); + return 0; + } + + /* Suspend ourselves, then try again */ + enqueue (&rwlock->rw_write_waiting, self); + release (&rwlock->rw_spinlock); + suspend (self); /* This is not a cancellation point */ + } +} + + +int +pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock) +{ + int result = EBUSY; + + acquire (&rwlock->rw_spinlock); + if (rwlock->rw_readers == 0 && rwlock->rw_writer == NULL) + { + rwlock->rw_writer = thread_self (); + result = 0; + } + release (&rwlock->rw_spinlock); + + return result; +} + + +int +pthread_rwlock_unlock (pthread_rwlock_t *rwlock) +{ + struct _pthread_queue torestart; + pthread_descr th; + + acquire (&rwlock->rw_spinlock); + if (rwlock->rw_writer != NULL) + { + /* Unlocking a write lock. */ + if (rwlock->rw_writer != thread_self ()) + { + release (&rwlock->rw_spinlock); + return EPERM; + } + rwlock->rw_writer = NULL; + + if (rwlock->rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP + || (th = dequeue (&rwlock->rw_write_waiting)) == NULL) + { + /* Restart all waiting readers. */ + torestart = rwlock->rw_read_waiting; + queue_init (&rwlock->rw_read_waiting); + release (&rwlock->rw_spinlock); + while ((th = dequeue (&torestart)) != NULL) + restart (th); + } + else + { + /* Restart one waiting writer. */ + release (&rwlock->rw_spinlock); + restart (th); + } + } + else + { + /* Unlocking a read lock. */ + if (rwlock->rw_readers == 0) + { + release (&rwlock->rw_spinlock); + return EPERM; + } + + --rwlock->rw_readers; + if (rwlock->rw_readers == 0) + /* Restart one waiting writer, if any. */ + th = dequeue (&rwlock->rw_write_waiting); + else + th = NULL; + + release (&rwlock->rw_spinlock); + if (th != NULL) + restart (th); + } + + return 0; +} + + + +int +pthread_rwlockattr_init (pthread_rwlockattr_t *attr) +{ + attr->lockkind = 0; + attr->pshared = 0; + + return 0; +} + + +int +pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr) +{ + return 0; +} + + +int +pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, int *pshared) +{ + *pshared = attr->pshared; + return 0; +} + + +int +pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared) +{ + if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED) + return EINVAL; + + attr->pshared = pshared; + + return 0; +} + + +int +pthread_rwlockattr_getkind_np (const pthread_rwlockattr_t *attr, int *pref) +{ + *pref = attr->lockkind; + return 0; +} + + +int +pthread_rwlockattr_setkind_np (pthread_rwlockattr_t *attr, int pref) +{ + if (pref != PTHREAD_RWLOCK_PREFER_READER_NP + && pref != PTHREAD_RWLOCK_PREFER_WRITER_NP + && pref != PTHREAD_RWLOCK_DEFAULT_NP) + return EINVAL; + + attr->lockkind = pref; + + return 0; +} |