pthread_rwlock.cpp revision a418c3b8370cae1c80fbe9a06e7e53025da5d6f0
1a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner/* 2a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * Copyright (C) 2010 The Android Open Source Project 3a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * All rights reserved. 4a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * 5a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * Redistribution and use in source and binary forms, with or without 6a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * modification, are permitted provided that the following conditions 7a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * are met: 8a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * * Redistributions of source code must retain the above copyright 9a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * notice, this list of conditions and the following disclaimer. 10a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * * Redistributions in binary form must reproduce the above copyright 11a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * notice, this list of conditions and the following disclaimer in 12a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * the documentation and/or other materials provided with the 13a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * distribution. 14a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * 15a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * SUCH DAMAGE. 27a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner */ 28a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 29a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner#include "pthread_internal.h" 30a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner#include <errno.h> 31a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 32a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner/* Technical note: 33a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * 34a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * Possible states of a read/write lock: 35a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * 36a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * - no readers and no writer (unlocked) 37a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * - one or more readers sharing the lock at the same time (read-locked) 38a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * - one writer holding the lock (write-lock) 39a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * 40a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * Additionally: 41a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * - trying to get the write-lock while there are any readers blocks 42a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * - trying to get the read-lock while there is a writer blocks 43a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * - a single thread can acquire the lock multiple times in the same mode 44a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * 45a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * - Posix states that behaviour is undefined it a thread tries to acquire 46a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * the lock in two distinct modes (e.g. write after read, or read after write). 47a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * 48a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * - This implementation tries to avoid writer starvation by making the readers 49a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * block as soon as there is a waiting writer on the lock. However, it cannot 50a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * completely eliminate it: each time the lock is unlocked, all waiting threads 51a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * are woken and battle for it, which one gets it depends on the kernel scheduler 52a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * and is semi-random. 53a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * 54a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner */ 55a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 56a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner#define __likely(cond) __builtin_expect(!!(cond), 1) 57a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner#define __unlikely(cond) __builtin_expect(!!(cond), 0) 58a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 59a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner#define RWLOCKATTR_DEFAULT 0 60a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner#define RWLOCKATTR_SHARED_MASK 0x0010 61a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 62a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turnerextern pthread_internal_t* __get_thread(void); 63a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 64a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner/* Return a global kernel ID for the current thread */ 65a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turnerstatic int __get_thread_id(void) 66a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner{ 67a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return __get_thread()->kernel_id; 68a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner} 69a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 70a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turnerint pthread_rwlockattr_init(pthread_rwlockattr_t *attr) 71a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner{ 72a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (!attr) 73a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return EINVAL; 74a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 75a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner *attr = PTHREAD_PROCESS_PRIVATE; 76a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return 0; 77a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner} 78a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 79a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turnerint pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr) 80a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner{ 81a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (!attr) 82a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return EINVAL; 83a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 84a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner *attr = -1; 85a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return 0; 86a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner} 87a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 88a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turnerint pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared) 89a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner{ 90a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (!attr) 91a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return EINVAL; 92a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 93a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner switch (pshared) { 94a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner case PTHREAD_PROCESS_PRIVATE: 95a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner case PTHREAD_PROCESS_SHARED: 96a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner *attr = pshared; 97a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return 0; 98a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner default: 99a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return EINVAL; 100a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner } 101a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner} 102a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 103a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turnerint pthread_rwlockattr_getpshared(pthread_rwlockattr_t *attr, int *pshared) 104a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner{ 105a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (!attr || !pshared) 106a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return EINVAL; 107a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 108a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner *pshared = *attr; 109a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return 0; 110a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner} 111a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 112a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turnerint pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) 113a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner{ 114a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner pthread_mutexattr_t* lock_attr = NULL; 115a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner pthread_condattr_t* cond_attr = NULL; 116a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner pthread_mutexattr_t lock_attr0; 117a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner pthread_condattr_t cond_attr0; 118a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner int ret; 119a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 120a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (rwlock == NULL) 121a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return EINVAL; 122a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 123a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (attr && *attr == PTHREAD_PROCESS_SHARED) { 124a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner lock_attr = &lock_attr0; 125a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner pthread_mutexattr_init(lock_attr); 126a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner pthread_mutexattr_setpshared(lock_attr, PTHREAD_PROCESS_SHARED); 127a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 128a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner cond_attr = &cond_attr0; 129a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner pthread_condattr_init(cond_attr); 130a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner pthread_condattr_setpshared(cond_attr, PTHREAD_PROCESS_SHARED); 131a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner } 132a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 133a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner ret = pthread_mutex_init(&rwlock->lock, lock_attr); 134a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (ret != 0) 135a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return ret; 136a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 137a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner ret = pthread_cond_init(&rwlock->cond, cond_attr); 138a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (ret != 0) { 139a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner pthread_mutex_destroy(&rwlock->lock); 140a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return ret; 141a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner } 142a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 143a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner rwlock->numLocks = 0; 144a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner rwlock->pendingReaders = 0; 145a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner rwlock->pendingWriters = 0; 146a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner rwlock->writerThreadId = 0; 147a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 148a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return 0; 149a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner} 150a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 151a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turnerint pthread_rwlock_destroy(pthread_rwlock_t *rwlock) 152a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner{ 153a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner int ret; 154a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 155a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (rwlock == NULL) 156a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return EINVAL; 157a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 158a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (rwlock->numLocks > 0) 159a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return EBUSY; 160a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 161a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner pthread_cond_destroy(&rwlock->cond); 162a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner pthread_mutex_destroy(&rwlock->lock); 163a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return 0; 164a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner} 165a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 166a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner/* Returns TRUE iff we can acquire a read lock. */ 167a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turnerstatic __inline__ int read_precondition(pthread_rwlock_t *rwlock, int thread_id) 168a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner{ 169a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner /* We can't have the lock if any writer is waiting for it (writer bias). 170a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * This tries to avoid starvation when there are multiple readers racing. 171a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner */ 172a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (rwlock->pendingWriters > 0) 173a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return 0; 174a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 175a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner /* We can have the lock if there is no writer, or if we write-own it */ 176a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner /* The second test avoids a self-dead lock in case of buggy code. */ 177a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (rwlock->writerThreadId == 0 || rwlock->writerThreadId == thread_id) 178a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return 1; 179a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 180a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner /* Otherwise, we can't have it */ 181a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return 0; 182a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner} 183a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 184a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner/* returns TRUE iff we can acquire a write lock. */ 185a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turnerstatic __inline__ int write_precondition(pthread_rwlock_t *rwlock, int thread_id) 186a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner{ 187a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner /* We can get the lock if nobody has it */ 188a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (rwlock->numLocks == 0) 189a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return 1; 190a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 191a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner /* Or if we already own it */ 192a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (rwlock->writerThreadId == thread_id) 193a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return 1; 194a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 195a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner /* Otherwise, not */ 196a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return 0; 197a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner} 198a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 199a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner/* This function is used to waken any waiting thread contending 200a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * for the lock. One of them should be able to grab it after 201a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * that. 202a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner */ 203a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turnerstatic void _pthread_rwlock_pulse(pthread_rwlock_t *rwlock) 204a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner{ 205a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (rwlock->pendingReaders > 0 || rwlock->pendingWriters > 0) 206a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner pthread_cond_broadcast(&rwlock->cond); 207a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner} 208a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 209a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 210a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turnerint pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) 211a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner{ 212a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return pthread_rwlock_timedrdlock(rwlock, NULL); 213a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner} 214a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 215a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turnerint pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) 216a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner{ 217a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner int ret = 0; 218a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 219a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (rwlock == NULL) 220a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return EINVAL; 221a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 222a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner pthread_mutex_lock(&rwlock->lock); 223a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (__unlikely(!read_precondition(rwlock, __get_thread_id()))) 224a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner ret = EBUSY; 225a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner else 226a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner rwlock->numLocks ++; 227a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner pthread_mutex_unlock(&rwlock->lock); 228a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 229a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return ret; 230a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner} 231a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 232a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turnerint pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, const struct timespec *abs_timeout) 233a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner{ 234a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner int thread_id, ret = 0; 235a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 236a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (rwlock == NULL) 237a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return EINVAL; 238a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 239a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner pthread_mutex_lock(&rwlock->lock); 240a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner thread_id = __get_thread_id(); 241a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (__unlikely(!read_precondition(rwlock, thread_id))) { 242a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner rwlock->pendingReaders += 1; 243a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner do { 244a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner ret = pthread_cond_timedwait(&rwlock->cond, &rwlock->lock, abs_timeout); 245a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner } while (ret == 0 && !read_precondition(rwlock, thread_id)); 246a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner rwlock->pendingReaders -= 1; 247a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (ret != 0) 248a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner goto EXIT; 249a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner } 250a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner rwlock->numLocks ++; 251a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' TurnerEXIT: 252a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner pthread_mutex_unlock(&rwlock->lock); 253a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return ret; 254a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner} 255a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 256a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 257a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turnerint pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) 258a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner{ 259a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return pthread_rwlock_timedwrlock(rwlock, NULL); 260a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner} 261a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 262a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turnerint pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) 263a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner{ 264a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner int thread_id, ret = 0; 265a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 266a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (rwlock == NULL) 267a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return EINVAL; 268a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 269a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner pthread_mutex_lock(&rwlock->lock); 270a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner thread_id = __get_thread_id(); 271a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (__unlikely(!write_precondition(rwlock, thread_id))) { 272a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner ret = EBUSY; 273a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner } else { 274a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner rwlock->numLocks ++; 275a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner rwlock->writerThreadId = thread_id; 276a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner } 277a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner pthread_mutex_unlock(&rwlock->lock); 278a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return ret; 279a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner} 280a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 281a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turnerint pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, const struct timespec *abs_timeout) 282a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner{ 283a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner int thread_id, ret = 0; 284a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 285a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (rwlock == NULL) 286a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return EINVAL; 287a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 288a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner pthread_mutex_lock(&rwlock->lock); 289a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner thread_id = __get_thread_id(); 290a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (__unlikely(!write_precondition(rwlock, thread_id))) { 291a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner /* If we can't read yet, wait until the rwlock is unlocked 292a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * and try again. Increment pendingReaders to get the 293a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * cond broadcast when that happens. 294a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner */ 295a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner rwlock->pendingWriters += 1; 296a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner do { 297a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner ret = pthread_cond_timedwait(&rwlock->cond, &rwlock->lock, abs_timeout); 298a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner } while (ret == 0 && !write_precondition(rwlock, thread_id)); 299a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner rwlock->pendingWriters -= 1; 300a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (ret != 0) 301a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner goto EXIT; 302a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner } 303a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner rwlock->numLocks ++; 304a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner rwlock->writerThreadId = thread_id; 305a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' TurnerEXIT: 306a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner pthread_mutex_unlock(&rwlock->lock); 307a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return ret; 308a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner} 309a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 310a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 311a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turnerint pthread_rwlock_unlock(pthread_rwlock_t *rwlock) 312a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner{ 313a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner int ret = 0; 314a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 315a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (rwlock == NULL) 316a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return EINVAL; 317a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 318a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner pthread_mutex_lock(&rwlock->lock); 319a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 320a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner /* The lock must be held */ 321a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (rwlock->numLocks == 0) { 322a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner ret = EPERM; 323a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner goto EXIT; 324a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner } 325a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner 326a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner /* If it has only readers, writerThreadId is 0 */ 327a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (rwlock->writerThreadId == 0) { 328a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (--rwlock->numLocks == 0) 329a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner _pthread_rwlock_pulse(rwlock); 330a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner } 331a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner /* Otherwise, it has only a single writer, which 332a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner * must be ourselves. 333a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner */ 334a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner else { 335a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (rwlock->writerThreadId != __get_thread_id()) { 336a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner ret = EPERM; 337a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner goto EXIT; 338a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner } 339a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner if (--rwlock->numLocks == 0) { 340a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner rwlock->writerThreadId = 0; 341a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner _pthread_rwlock_pulse(rwlock); 342a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner } 343a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner } 344a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' TurnerEXIT: 345a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner pthread_mutex_unlock(&rwlock->lock); 346a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner return ret; 347a418c3b8370cae1c80fbe9a06e7e53025da5d6f0David 'Digit' Turner} 348