rwlock.h (5073B)
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20#ifndef __GUAC_RWLOCK_H 21#define __GUAC_RWLOCK_H 22 23#include <pthread.h> 24 25/** 26 * This file implements reentrant read-write locks using thread-local storage 27 * to keep track of how locks are held and released by the current thread, 28 * since the pthread locks do not support reentrant behavior. 29 * 30 * A thread will attempt to acquire the requested lock on the first acquire 31 * function call, and will release it once the number of unlock requests 32 * matches the number of lock requests. Therefore, it is safe to aquire a lock 33 * and then call a function that also acquires the same lock, provided that 34 * the caller and the callee request to unlock the lock when done with it. 35 * 36 * Any lock that's locked using one of the functions defined in this file 37 * must _only_ be unlocked using the unlock function defined here to avoid 38 * unexpected behavior. 39 */ 40 41/** 42 * A structure packaging together a pthread rwlock along with a key to a 43 * thread-local property to keep track of the current status of the lock, 44 * allowing the functions defined in this header to provide reentrant behavior. 45 * Note that both the lock and key must be initialized before being provided 46 * to any of these functions. 47 */ 48typedef struct guac_rwlock { 49 50 /** 51 * A non-reentrant pthread rwlock to be wrapped by the local lock, 52 * functions providing reentrant behavior. 53 */ 54 pthread_rwlock_t lock; 55 56 /** 57 * A key to access a thread-local property tracking any ownership of the 58 * lock by the current thread. 59 */ 60 pthread_key_t key; 61 62} guac_rwlock; 63 64/** 65 * Initialize the provided guac reentrant rwlock. The lock will be configured to be 66 * visible to child processes. 67 * 68 * @param lock 69 * The guac reentrant rwlock to be initialized. 70 */ 71void guac_rwlock_init(guac_rwlock* lock); 72 73/** 74 * Clean up and destroy the provided guac reentrant rwlock. 75 * 76 * @param lock 77 * The guac reentrant rwlock to be destroyed. 78 */ 79void guac_rwlock_destroy(guac_rwlock* lock); 80 81/** 82 * Aquire the write lock for the provided guac reentrant rwlock, if the key does not 83 * indicate that the write lock is already acquired. If the key indicates that 84 * the read lock is already acquired, the read lock will be dropped before the 85 * write lock is acquired. The thread local property associated with the key 86 * will be updated as necessary to track the thread's ownership of the lock. 87 * 88 * If an error occurs while attempting to acquire the lock, a non-zero value is 89 * returned, and guac_error is set appropriately. 90 * 91 * @param reentrant_rwlock 92 * The guac reentrant rwlock for which the write lock should be acquired 93 * reentrantly. 94 * 95 * @return 96 * Zero if the lock is succesfully acquired, or a non-zero value if an 97 * error occured. 98 */ 99int guac_rwlock_acquire_write_lock(guac_rwlock* reentrant_rwlock); 100 101/** 102 * Aquire the read lock for the provided guac reentrant rwlock, if the key does not 103 * indicate that the read or write lock is already acquired. The thread local 104 * property associated with the key will be updated as necessary to track the 105 * thread's ownership of the lock. 106 * 107 * If an error occurs while attempting to acquire the lock, a non-zero value is 108 * returned, and guac_error is set appropriately. 109 * 110 * @param reentrant_rwlock 111 * The guac reentrant rwlock for which the read lock should be acquired 112 * reentrantly. 113 * 114 * @return 115 * Zero if the lock is succesfully acquired, or a non-zero value if an 116 * error occured. 117 */ 118int guac_rwlock_acquire_read_lock(guac_rwlock* reentrant_rwlock); 119 120/** 121 * Release the the rwlock associated with the provided guac reentrant rwlock if this 122 * is the last level of the lock held by this thread. Otherwise, the thread 123 * local property associated with the key will be updated as needed to ensure 124 * that the correct number of release requests will finally release the lock. 125 * 126 * If an error occurs while attempting to release the lock, a non-zero value is 127 * returned, and guac_error is set appropriately. 128 * 129 * @param reentrant_rwlock 130 * The guac reentrant rwlock that should be released. 131 * 132 * @return 133 * Zero if the lock is succesfully released, or a non-zero value if an 134 * error occured. 135 */ 136int guac_rwlock_release_lock(guac_rwlock* reentrant_rwlock); 137 138#endif 139