rwlock.h (3586B)
1 #ifndef __RWLOCK_H 2 #define __RWLOCK_H 3 4 #include <inttypes.h> 5 #include <semaphore.h> 6 7 /* Readers-Writer lock 8 * Implemented with 'Passing the Baton' locking technique. 9 * 10 * Priority rules: 11 * 1) if we have an awakened writer or writers in the waiting queue 12 * then a new reader will be added in readers' waiting queue. 13 * 2) if all awakened readers are released then we awake a writer, 14 * even if readers are waiting in the queue. 15 * 3) if the awakened writer and all writers in the waiting queue are 16 * released then we awake all the readers. */ 17 typedef struct { 18 mutex_t lock; 19 mutex_t writer_wait; 20 mutex_t reader_wait; 21 u32 nr_writers; 22 u32 nr_readers; 23 u32 nr_writers_queue; 24 u32 nr_readers_queue; 25 } rwlock_t; 26 27 #define RWLOCK_INIT { \ 28 MUTEX_INIT, \ 29 MUTEX_INIT_LOCKED, \ 30 MUTEX_INIT_LOCKED, \ 31 0, \ 32 0, \ 33 0, \ 34 0 \ 35 } 36 37 static inline void 38 rwlock_init(rwlock_t *rwl) 39 { 40 mutex_init(&rwl->lock); 41 mutex_init(&rwl->writer_wait); 42 mutex_lock(&rwl->writer_wait); 43 mutex_init(&rwl->reader_wait); 44 mutex_lock(&rwl->reader_wait); 45 rwl->nr_writers = 0; 46 rwl->nr_readers = 0; 47 rwl->nr_writers_queue = 0; 48 rwl->nr_readers_queue = 0; 49 } 50 51 static inline void 52 rwlock_rdlock(rwlock_t *rwl) 53 { 54 mutex_lock(&rwl->lock); 55 /* if we have awakened writer or writers in the queue then wait */ 56 if (rwl->nr_writers > 0 || rwl->nr_writers_queue > 0) { 57 rwl->nr_readers_queue++; 58 mutex_unlock(&rwl->lock); 59 /* wait */ 60 mutex_lock(&rwl->reader_wait); 61 } 62 63 rwl->nr_readers++; 64 65 /* if there is at least one reader in the queue, 66 * awake it (i.e. awake the next reader) */ 67 if (rwl->nr_readers_queue > 0) { 68 rwl->nr_readers_queue--; 69 mutex_unlock(&rwl->reader_wait); 70 } else { 71 mutex_unlock(&rwl->lock); 72 } 73 } 74 75 /* returns 1 if managed to lock 76 * returns 0 if not */ 77 static inline int 78 rwlock_tryrdlock(rwlock_t *rwl) 79 { 80 mutex_lock(&rwl->lock); 81 /* if we have awakened writer or writers in the queue then we can't lock */ 82 if (rwl->nr_writers > 0 || rwl->nr_writers_queue > 0) { 83 mutex_unlock(&rwl->lock); 84 return 0; 85 } 86 87 rwl->nr_readers++; 88 mutex_unlock(&rwl->lock); 89 return 1; 90 } 91 92 static inline void 93 rwlock_wrlock(rwlock_t *rwl) 94 { 95 mutex_lock(&rwl->lock); 96 /* if we have an awakened writer or awakened readers then wait */ 97 if (rwl->nr_writers > 0 || rwl->nr_readers > 0) { 98 rwl->nr_writers_queue++; 99 mutex_unlock(&rwl->lock); 100 /* wait */ 101 mutex_lock(&rwl->writer_wait); 102 } 103 104 rwl->nr_writers++; 105 mutex_unlock(&rwl->lock); 106 } 107 108 /* returns 1 if managed to lock 109 * returns 0 if not */ 110 static inline int 111 rwlock_trywrlock(rwlock_t *rwl) 112 { 113 mutex_lock(&rwl->lock); 114 /* if we have an awakened writer or awakened readers then we can't lock */ 115 if (rwl->nr_writers > 0 || rwl->nr_readers > 0) { 116 mutex_unlock(&rwl->lock); 117 return 0; 118 } 119 120 rwl->nr_writers++; 121 mutex_unlock(&rwl->lock); 122 return 1; 123 } 124 125 static inline void 126 rwlock_unlock(rwlock_t *rwl) 127 { 128 mutex_lock(&rwl->lock); 129 130 /* release reader */ 131 if (rwl->nr_readers > 0) { 132 rwl->nr_readers--; 133 /* release writer */ 134 } else if (rwl->nr_writers > 0) { 135 rwl->nr_writers--; 136 } 137 138 /* if all awakened readers are released and we have writers in the queue 139 * then awake a writer */ 140 if (rwl->nr_readers == 0 && rwl->nr_writers_queue > 0) { 141 rwl->nr_writers_queue--; 142 mutex_unlock(&rwl->writer_wait); 143 /* if the awakened writer and all writers from the queue are released 144 * then awake a reader */ 145 } else if (rwl->nr_writers == 0 && rwl->nr_writers_queue == 0 && 146 rwl->nr_readers_queue > 0) { 147 rwl->nr_readers_queue--; 148 mutex_unlock(&rwl->reader_wait); 149 } else { 150 mutex_unlock(&rwl->lock); 151 } 152 } 153 154 #endif /* __RWLOCK_H */