rwlock.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. /* Read-write lock implementation.
  2. Copyright (C) 1998 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. Contributed by Xavier Leroy <Xavier.Leroy@inria.fr>
  5. and Ulrich Drepper <drepper@cygnus.com>, 1998.
  6. The GNU C Library is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU Library General Public License as
  8. published by the Free Software Foundation; either version 2 of the
  9. License, or (at your option) any later version.
  10. The GNU C Library is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. Library General Public License for more details.
  14. You should have received a copy of the GNU Library General Public
  15. License along with the GNU C Library; see the file COPYING.LIB. If not,
  16. write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  17. Boston, MA 02111-1307, USA. */
  18. #include <errno.h>
  19. #include <pthread.h>
  20. #include <stdlib.h>
  21. #include "internals.h"
  22. #include "queue.h"
  23. #include "spinlock.h"
  24. #include "restart.h"
  25. /*
  26. * Check whether the calling thread already owns one or more read locks on the
  27. * specified lock. If so, return a pointer to the read lock info structure
  28. * corresponding to that lock.
  29. */
  30. static pthread_readlock_info *
  31. rwlock_is_in_list(pthread_descr self, pthread_rwlock_t *rwlock)
  32. {
  33. pthread_readlock_info *info;
  34. for (info = self->p_readlock_list; info != NULL; info = info->pr_next)
  35. {
  36. if (info->pr_lock == rwlock)
  37. return info;
  38. }
  39. return NULL;
  40. }
  41. /*
  42. * Add a new lock to the thread's list of locks for which it has a read lock.
  43. * A new info node must be allocated for this, which is taken from the thread's
  44. * free list, or by calling malloc. If malloc fails, a null pointer is
  45. * returned. Otherwise the lock info structure is initialized and pushed
  46. * onto the thread's list.
  47. */
  48. static pthread_readlock_info *
  49. rwlock_add_to_list(pthread_descr self, pthread_rwlock_t *rwlock)
  50. {
  51. pthread_readlock_info *info = self->p_readlock_free;
  52. if (info != NULL)
  53. self->p_readlock_free = info->pr_next;
  54. else
  55. info = malloc(sizeof *info);
  56. if (info == NULL)
  57. return NULL;
  58. info->pr_lock_count = 1;
  59. info->pr_lock = rwlock;
  60. info->pr_next = self->p_readlock_list;
  61. self->p_readlock_list = info;
  62. return info;
  63. }
  64. /*
  65. * If the thread owns a read lock over the given pthread_rwlock_t,
  66. * and this read lock is tracked in the thread's lock list,
  67. * this function returns a pointer to the info node in that list.
  68. * It also decrements the lock count within that node, and if
  69. * it reaches zero, it removes the node from the list.
  70. * If nothing is found, it returns a null pointer.
  71. */
  72. static pthread_readlock_info *
  73. rwlock_remove_from_list(pthread_descr self, pthread_rwlock_t *rwlock)
  74. {
  75. pthread_readlock_info **pinfo;
  76. for (pinfo = &self->p_readlock_list; *pinfo != NULL; pinfo = &(*pinfo)->pr_next)
  77. {
  78. if ((*pinfo)->pr_lock == rwlock)
  79. {
  80. pthread_readlock_info *info = *pinfo;
  81. if (--info->pr_lock_count == 0)
  82. *pinfo = info->pr_next;
  83. return info;
  84. }
  85. }
  86. return NULL;
  87. }
  88. /*
  89. * This function checks whether the conditions are right to place a read lock.
  90. * It returns 1 if so, otherwise zero. The rwlock's internal lock must be
  91. * locked upon entry.
  92. */
  93. static int
  94. rwlock_can_rdlock(pthread_rwlock_t *rwlock, int have_lock_already)
  95. {
  96. /* Can't readlock; it is write locked. */
  97. if (rwlock->__rw_writer != NULL)
  98. return 0;
  99. /* Lock prefers readers; get it. */
  100. if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
  101. return 1;
  102. /* Lock prefers writers, but none are waiting. */
  103. if (queue_is_empty(&rwlock->__rw_write_waiting))
  104. return 1;
  105. /* Writers are waiting, but this thread already has a read lock */
  106. if (have_lock_already)
  107. return 1;
  108. /* Writers are waiting, and this is a new lock */
  109. return 0;
  110. }
  111. /*
  112. * This function helps support brain-damaged recursive read locking
  113. * semantics required by Unix 98, while maintaining write priority.
  114. * This basically determines whether this thread already holds a read lock
  115. * already. It returns 1 if so, otherwise it returns 0.
  116. *
  117. * If the thread has any ``untracked read locks'' then it just assumes
  118. * that this lock is among them, just to be safe, and returns 1.
  119. *
  120. * Also, if it finds the thread's lock in the list, it sets the pointer
  121. * referenced by pexisting to refer to the list entry.
  122. *
  123. * If the thread has no untracked locks, and the lock is not found
  124. * in its list, then it is added to the list. If this fails,
  125. * then *pout_of_mem is set to 1.
  126. */
  127. static int
  128. rwlock_have_already(pthread_descr *pself, pthread_rwlock_t *rwlock,
  129. pthread_readlock_info **pexisting, int *pout_of_mem)
  130. {
  131. pthread_readlock_info *existing = NULL;
  132. int out_of_mem = 0, have_lock_already = 0;
  133. pthread_descr self = *pself;
  134. if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_WRITER_NP)
  135. {
  136. if (!self)
  137. self = thread_self();
  138. existing = rwlock_is_in_list(self, rwlock);
  139. if (existing != NULL || self->p_untracked_readlock_count > 0)
  140. have_lock_already = 1;
  141. else
  142. {
  143. existing = rwlock_add_to_list(self, rwlock);
  144. if (existing == NULL)
  145. out_of_mem = 1;
  146. }
  147. }
  148. *pout_of_mem = out_of_mem;
  149. *pexisting = existing;
  150. *pself = self;
  151. return have_lock_already;
  152. }
  153. int
  154. pthread_rwlock_init (pthread_rwlock_t *rwlock,
  155. const pthread_rwlockattr_t *attr)
  156. {
  157. __pthread_init_lock(&rwlock->__rw_lock);
  158. rwlock->__rw_readers = 0;
  159. rwlock->__rw_writer = NULL;
  160. rwlock->__rw_read_waiting = NULL;
  161. rwlock->__rw_write_waiting = NULL;
  162. if (attr == NULL)
  163. {
  164. rwlock->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
  165. rwlock->__rw_pshared = PTHREAD_PROCESS_PRIVATE;
  166. }
  167. else
  168. {
  169. rwlock->__rw_kind = attr->__lockkind;
  170. rwlock->__rw_pshared = attr->__pshared;
  171. }
  172. return 0;
  173. }
  174. int
  175. pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
  176. {
  177. int readers;
  178. _pthread_descr writer;
  179. __pthread_lock (&rwlock->__rw_lock, NULL);
  180. readers = rwlock->__rw_readers;
  181. writer = rwlock->__rw_writer;
  182. __pthread_unlock (&rwlock->__rw_lock);
  183. if (readers > 0 || writer != NULL)
  184. return EBUSY;
  185. return 0;
  186. }
  187. int
  188. pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
  189. {
  190. pthread_descr self = NULL;
  191. pthread_readlock_info *existing;
  192. int out_of_mem, have_lock_already;
  193. have_lock_already = rwlock_have_already(&self, rwlock,
  194. &existing, &out_of_mem);
  195. for (;;)
  196. {
  197. if (self == NULL)
  198. self = thread_self ();
  199. __pthread_lock (&rwlock->__rw_lock, self);
  200. if (rwlock_can_rdlock(rwlock, have_lock_already))
  201. break;
  202. enqueue (&rwlock->__rw_read_waiting, self);
  203. __pthread_unlock (&rwlock->__rw_lock);
  204. suspend (self); /* This is not a cancellation point */
  205. }
  206. ++rwlock->__rw_readers;
  207. __pthread_unlock (&rwlock->__rw_lock);
  208. if (have_lock_already || out_of_mem)
  209. {
  210. if (existing != NULL)
  211. existing->pr_lock_count++;
  212. else
  213. self->p_untracked_readlock_count++;
  214. }
  215. return 0;
  216. }
  217. int
  218. pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
  219. {
  220. pthread_descr self = thread_self();
  221. pthread_readlock_info *existing;
  222. int out_of_mem, have_lock_already;
  223. int retval = EBUSY;
  224. have_lock_already = rwlock_have_already(&self, rwlock,
  225. &existing, &out_of_mem);
  226. __pthread_lock (&rwlock->__rw_lock, self);
  227. /* 0 is passed to here instead of have_lock_already.
  228. This is to meet Single Unix Spec requirements:
  229. if writers are waiting, pthread_rwlock_tryrdlock
  230. does not acquire a read lock, even if the caller has
  231. one or more read locks already. */
  232. if (rwlock_can_rdlock(rwlock, 0))
  233. {
  234. ++rwlock->__rw_readers;
  235. retval = 0;
  236. }
  237. __pthread_unlock (&rwlock->__rw_lock);
  238. if (retval == 0)
  239. {
  240. if (have_lock_already || out_of_mem)
  241. {
  242. if (existing != NULL)
  243. existing->pr_lock_count++;
  244. else
  245. self->p_untracked_readlock_count++;
  246. }
  247. }
  248. return retval;
  249. }
  250. int
  251. pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
  252. {
  253. pthread_descr self = thread_self ();
  254. while(1)
  255. {
  256. __pthread_lock (&rwlock->__rw_lock, self);
  257. if (rwlock->__rw_readers == 0 && rwlock->__rw_writer == NULL)
  258. {
  259. rwlock->__rw_writer = self;
  260. __pthread_unlock (&rwlock->__rw_lock);
  261. return 0;
  262. }
  263. /* Suspend ourselves, then try again */
  264. enqueue (&rwlock->__rw_write_waiting, self);
  265. __pthread_unlock (&rwlock->__rw_lock);
  266. suspend (self); /* This is not a cancellation point */
  267. }
  268. }
  269. int
  270. pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
  271. {
  272. int result = EBUSY;
  273. __pthread_lock (&rwlock->__rw_lock, NULL);
  274. if (rwlock->__rw_readers == 0 && rwlock->__rw_writer == NULL)
  275. {
  276. rwlock->__rw_writer = thread_self ();
  277. result = 0;
  278. }
  279. __pthread_unlock (&rwlock->__rw_lock);
  280. return result;
  281. }
  282. int
  283. pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
  284. {
  285. pthread_descr torestart;
  286. pthread_descr th;
  287. __pthread_lock (&rwlock->__rw_lock, NULL);
  288. if (rwlock->__rw_writer != NULL)
  289. {
  290. /* Unlocking a write lock. */
  291. if (rwlock->__rw_writer != thread_self ())
  292. {
  293. __pthread_unlock (&rwlock->__rw_lock);
  294. return EPERM;
  295. }
  296. rwlock->__rw_writer = NULL;
  297. if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP
  298. || (th = dequeue (&rwlock->__rw_write_waiting)) == NULL)
  299. {
  300. /* Restart all waiting readers. */
  301. torestart = rwlock->__rw_read_waiting;
  302. rwlock->__rw_read_waiting = NULL;
  303. __pthread_unlock (&rwlock->__rw_lock);
  304. while ((th = dequeue (&torestart)) != NULL)
  305. restart (th);
  306. }
  307. else
  308. {
  309. /* Restart one waiting writer. */
  310. __pthread_unlock (&rwlock->__rw_lock);
  311. restart (th);
  312. }
  313. }
  314. else
  315. {
  316. /* Unlocking a read lock. */
  317. if (rwlock->__rw_readers == 0)
  318. {
  319. __pthread_unlock (&rwlock->__rw_lock);
  320. return EPERM;
  321. }
  322. --rwlock->__rw_readers;
  323. if (rwlock->__rw_readers == 0)
  324. /* Restart one waiting writer, if any. */
  325. th = dequeue (&rwlock->__rw_write_waiting);
  326. else
  327. th = NULL;
  328. __pthread_unlock (&rwlock->__rw_lock);
  329. if (th != NULL)
  330. restart (th);
  331. /* Recursive lock fixup */
  332. if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_WRITER_NP)
  333. {
  334. pthread_descr self = thread_self();
  335. pthread_readlock_info *victim = rwlock_remove_from_list(self, rwlock);
  336. if (victim != NULL)
  337. {
  338. if (victim->pr_lock_count == 0)
  339. {
  340. victim->pr_next = self->p_readlock_free;
  341. self->p_readlock_free = victim;
  342. }
  343. }
  344. else
  345. {
  346. if (self->p_untracked_readlock_count > 0)
  347. self->p_untracked_readlock_count--;
  348. }
  349. }
  350. }
  351. return 0;
  352. }
  353. int
  354. pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
  355. {
  356. attr->__lockkind = 0;
  357. attr->__pshared = 0;
  358. return 0;
  359. }
  360. int
  361. pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr attribute_unused)
  362. {
  363. return 0;
  364. }
  365. int
  366. pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, int *pshared)
  367. {
  368. *pshared = attr->__pshared;
  369. return 0;
  370. }
  371. int
  372. pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared)
  373. {
  374. if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
  375. return EINVAL;
  376. attr->__pshared = pshared;
  377. return 0;
  378. }
  379. int
  380. pthread_rwlockattr_getkind_np (const pthread_rwlockattr_t *attr, int *pref)
  381. {
  382. *pref = attr->__lockkind;
  383. return 0;
  384. }
  385. int
  386. pthread_rwlockattr_setkind_np (pthread_rwlockattr_t *attr, int pref)
  387. {
  388. if (pref != PTHREAD_RWLOCK_PREFER_READER_NP
  389. && pref != PTHREAD_RWLOCK_PREFER_WRITER_NP
  390. && pref != PTHREAD_RWLOCK_DEFAULT_NP)
  391. return EINVAL;
  392. attr->__lockkind = pref;
  393. return 0;
  394. }