pthread-rwlocks.c 10 KB

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