rdwr.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. /* $OpenLDAP$ */
  2. /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  3. *
  4. * Copyright 1998-2022 The OpenLDAP Foundation.
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted only as authorized by the OpenLDAP
  9. * Public License.
  10. *
  11. * A copy of this license is available in file LICENSE in the
  12. * top-level directory of the distribution or, alternatively, at
  13. * <http://www.OpenLDAP.org/license.html>.
  14. */
  15. /* This work was initially developed by Kurt D. Zeilenga for inclusion
  16. * in OpenLDAP Software. Additional significant contributors include:
  17. * Stuart Lynne
  18. */
  19. /*
  20. * This is an improved implementation of Reader/Writer locks does
  21. * not protect writers from starvation. That is, if a writer is
  22. * currently waiting on a reader, any new reader will get
  23. * the lock before the writer.
  24. *
  25. * Does not support cancellation nor does any status checking.
  26. */
  27. /* Adapted from publicly available examples for:
  28. * "Programming with Posix Threads"
  29. * by David R Butenhof, Addison-Wesley
  30. * http://cseng.aw.com/bookpage.taf?ISBN=0-201-63392-2
  31. */
  32. #include "portable.h"
  33. #include <ac/stdlib.h>
  34. #include <ac/errno.h>
  35. #include <ac/string.h>
  36. #include <ac/time.h>
  37. #include "ldap-int.h"
  38. #ifdef LDAP_R_COMPILE
  39. #include "ldap_pvt_thread.h" /* Get the thread interface */
  40. #define LDAP_THREAD_RDWR_IMPLEMENTATION
  41. #include "ldap_thr_debug.h" /* May rename the symbols defined below */
  42. /*
  43. * implementations that provide their own compatible
  44. * reader/writer locks define LDAP_THREAD_HAVE_RDWR
  45. * in ldap_pvt_thread.h
  46. */
  47. #ifndef LDAP_THREAD_HAVE_RDWR
  48. struct ldap_int_thread_rdwr_s {
  49. ldap_pvt_thread_mutex_t ltrw_mutex;
  50. ldap_pvt_thread_cond_t ltrw_read; /* wait for read */
  51. ldap_pvt_thread_cond_t ltrw_write; /* wait for write */
  52. int ltrw_valid;
  53. #define LDAP_PVT_THREAD_RDWR_VALID 0x0bad
  54. int ltrw_r_active;
  55. int ltrw_w_active;
  56. int ltrw_r_wait;
  57. int ltrw_w_wait;
  58. #ifdef LDAP_RDWR_DEBUG
  59. /* keep track of who has these locks */
  60. #define MAX_READERS 32
  61. int ltrw_more_readers; /* Set if ltrw_readers[] is incomplete */
  62. ldap_pvt_thread_t ltrw_readers[MAX_READERS];
  63. ldap_pvt_thread_t ltrw_writer;
  64. #endif
  65. };
  66. int
  67. ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rwlock )
  68. {
  69. struct ldap_int_thread_rdwr_s *rw;
  70. assert( rwlock != NULL );
  71. rw = (struct ldap_int_thread_rdwr_s *) LDAP_CALLOC( 1,
  72. sizeof( struct ldap_int_thread_rdwr_s ) );
  73. if ( !rw )
  74. return LDAP_NO_MEMORY;
  75. /* we should check return results */
  76. ldap_pvt_thread_mutex_init( &rw->ltrw_mutex );
  77. ldap_pvt_thread_cond_init( &rw->ltrw_read );
  78. ldap_pvt_thread_cond_init( &rw->ltrw_write );
  79. rw->ltrw_valid = LDAP_PVT_THREAD_RDWR_VALID;
  80. *rwlock = rw;
  81. return 0;
  82. }
  83. int
  84. ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rwlock )
  85. {
  86. struct ldap_int_thread_rdwr_s *rw;
  87. assert( rwlock != NULL );
  88. rw = *rwlock;
  89. assert( rw != NULL );
  90. assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
  91. if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
  92. return LDAP_PVT_THREAD_EINVAL;
  93. ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
  94. assert( rw->ltrw_w_active >= 0 );
  95. assert( rw->ltrw_w_wait >= 0 );
  96. assert( rw->ltrw_r_active >= 0 );
  97. assert( rw->ltrw_r_wait >= 0 );
  98. /* active threads? */
  99. if( rw->ltrw_r_active > 0 || rw->ltrw_w_active > 0) {
  100. ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
  101. return LDAP_PVT_THREAD_EBUSY;
  102. }
  103. /* waiting threads? */
  104. if( rw->ltrw_r_wait > 0 || rw->ltrw_w_wait > 0) {
  105. ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
  106. return LDAP_PVT_THREAD_EBUSY;
  107. }
  108. rw->ltrw_valid = 0;
  109. ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
  110. ldap_pvt_thread_mutex_destroy( &rw->ltrw_mutex );
  111. ldap_pvt_thread_cond_destroy( &rw->ltrw_read );
  112. ldap_pvt_thread_cond_destroy( &rw->ltrw_write );
  113. LDAP_FREE(rw);
  114. *rwlock = NULL;
  115. return 0;
  116. }
  117. int ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rwlock )
  118. {
  119. struct ldap_int_thread_rdwr_s *rw;
  120. assert( rwlock != NULL );
  121. rw = *rwlock;
  122. assert( rw != NULL );
  123. assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
  124. if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
  125. return LDAP_PVT_THREAD_EINVAL;
  126. ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
  127. assert( rw->ltrw_w_active >= 0 );
  128. assert( rw->ltrw_w_wait >= 0 );
  129. assert( rw->ltrw_r_active >= 0 );
  130. assert( rw->ltrw_r_wait >= 0 );
  131. if( rw->ltrw_w_active > 0 ) {
  132. /* writer is active */
  133. rw->ltrw_r_wait++;
  134. do {
  135. ldap_pvt_thread_cond_wait(
  136. &rw->ltrw_read, &rw->ltrw_mutex );
  137. } while( rw->ltrw_w_active > 0 );
  138. rw->ltrw_r_wait--;
  139. assert( rw->ltrw_r_wait >= 0 );
  140. }
  141. #ifdef LDAP_RDWR_DEBUG
  142. if( rw->ltrw_r_active < MAX_READERS )
  143. rw->ltrw_readers[rw->ltrw_r_active] = ldap_pvt_thread_self();
  144. else
  145. rw->ltrw_more_readers = 1;
  146. #endif
  147. rw->ltrw_r_active++;
  148. ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
  149. return 0;
  150. }
  151. int ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rwlock )
  152. {
  153. struct ldap_int_thread_rdwr_s *rw;
  154. assert( rwlock != NULL );
  155. rw = *rwlock;
  156. assert( rw != NULL );
  157. assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
  158. if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
  159. return LDAP_PVT_THREAD_EINVAL;
  160. ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
  161. assert( rw->ltrw_w_active >= 0 );
  162. assert( rw->ltrw_w_wait >= 0 );
  163. assert( rw->ltrw_r_active >= 0 );
  164. assert( rw->ltrw_r_wait >= 0 );
  165. if( rw->ltrw_w_active > 0) {
  166. ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
  167. return LDAP_PVT_THREAD_EBUSY;
  168. }
  169. #ifdef LDAP_RDWR_DEBUG
  170. if( rw->ltrw_r_active < MAX_READERS )
  171. rw->ltrw_readers[rw->ltrw_r_active] = ldap_pvt_thread_self();
  172. else
  173. rw->ltrw_more_readers = 1;
  174. #endif
  175. rw->ltrw_r_active++;
  176. ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
  177. return 0;
  178. }
  179. int ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rwlock )
  180. {
  181. struct ldap_int_thread_rdwr_s *rw;
  182. assert( rwlock != NULL );
  183. rw = *rwlock;
  184. assert( rw != NULL );
  185. assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
  186. if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
  187. return LDAP_PVT_THREAD_EINVAL;
  188. ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
  189. rw->ltrw_r_active--;
  190. #ifdef LDAP_RDWR_DEBUG
  191. /* Remove us from the list of readers */
  192. {
  193. ldap_pvt_thread_t self = ldap_pvt_thread_self();
  194. int i, j;
  195. for( i = j = rw->ltrw_r_active; i >= 0; i--) {
  196. if (rw->ltrw_readers[i] == self) {
  197. rw->ltrw_readers[i] = rw->ltrw_readers[j];
  198. rw->ltrw_readers[j] = 0;
  199. break;
  200. }
  201. }
  202. if( !rw->ltrw_more_readers )
  203. assert( i >= 0 );
  204. else if( j == 0 )
  205. rw->ltrw_more_readers = 0;
  206. }
  207. #endif
  208. assert( rw->ltrw_w_active >= 0 );
  209. assert( rw->ltrw_w_wait >= 0 );
  210. assert( rw->ltrw_r_active >= 0 );
  211. assert( rw->ltrw_r_wait >= 0 );
  212. if (rw->ltrw_r_active == 0 && rw->ltrw_w_wait > 0 ) {
  213. ldap_pvt_thread_cond_signal( &rw->ltrw_write );
  214. }
  215. ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
  216. return 0;
  217. }
  218. int ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rwlock )
  219. {
  220. struct ldap_int_thread_rdwr_s *rw;
  221. assert( rwlock != NULL );
  222. rw = *rwlock;
  223. assert( rw != NULL );
  224. assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
  225. if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
  226. return LDAP_PVT_THREAD_EINVAL;
  227. ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
  228. assert( rw->ltrw_w_active >= 0 );
  229. assert( rw->ltrw_w_wait >= 0 );
  230. assert( rw->ltrw_r_active >= 0 );
  231. assert( rw->ltrw_r_wait >= 0 );
  232. if ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 ) {
  233. rw->ltrw_w_wait++;
  234. do {
  235. ldap_pvt_thread_cond_wait(
  236. &rw->ltrw_write, &rw->ltrw_mutex );
  237. } while ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 );
  238. rw->ltrw_w_wait--;
  239. assert( rw->ltrw_w_wait >= 0 );
  240. }
  241. #ifdef LDAP_RDWR_DEBUG
  242. rw->ltrw_writer = ldap_pvt_thread_self();
  243. #endif
  244. rw->ltrw_w_active++;
  245. ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
  246. return 0;
  247. }
  248. int ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rwlock )
  249. {
  250. struct ldap_int_thread_rdwr_s *rw;
  251. assert( rwlock != NULL );
  252. rw = *rwlock;
  253. assert( rw != NULL );
  254. assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
  255. if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
  256. return LDAP_PVT_THREAD_EINVAL;
  257. ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
  258. assert( rw->ltrw_w_active >= 0 );
  259. assert( rw->ltrw_w_wait >= 0 );
  260. assert( rw->ltrw_r_active >= 0 );
  261. assert( rw->ltrw_r_wait >= 0 );
  262. if ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 ) {
  263. ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
  264. return LDAP_PVT_THREAD_EBUSY;
  265. }
  266. #ifdef LDAP_RDWR_DEBUG
  267. rw->ltrw_writer = ldap_pvt_thread_self();
  268. #endif
  269. rw->ltrw_w_active++;
  270. ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
  271. return 0;
  272. }
  273. int ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rwlock )
  274. {
  275. struct ldap_int_thread_rdwr_s *rw;
  276. assert( rwlock != NULL );
  277. rw = *rwlock;
  278. assert( rw != NULL );
  279. assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
  280. if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
  281. return LDAP_PVT_THREAD_EINVAL;
  282. ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
  283. rw->ltrw_w_active--;
  284. assert( rw->ltrw_w_active >= 0 );
  285. assert( rw->ltrw_w_wait >= 0 );
  286. assert( rw->ltrw_r_active >= 0 );
  287. assert( rw->ltrw_r_wait >= 0 );
  288. if (rw->ltrw_r_wait > 0) {
  289. ldap_pvt_thread_cond_broadcast( &rw->ltrw_read );
  290. } else if (rw->ltrw_w_wait > 0) {
  291. ldap_pvt_thread_cond_signal( &rw->ltrw_write );
  292. }
  293. #ifdef LDAP_RDWR_DEBUG
  294. assert( rw->ltrw_writer == ldap_pvt_thread_self() );
  295. rw->ltrw_writer = 0;
  296. #endif
  297. ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
  298. return 0;
  299. }
  300. #ifdef LDAP_RDWR_DEBUG
  301. /* just for testing,
  302. * return 0 if false, suitable for assert(ldap_pvt_thread_rdwr_Xchk(rdwr))
  303. *
  304. * Currently they don't check if the calling thread is the one
  305. * that has the lock, just that there is a reader or writer.
  306. *
  307. * Basically sufficient for testing that places that should have
  308. * a lock are caught.
  309. */
  310. int ldap_pvt_thread_rdwr_readers(ldap_pvt_thread_rdwr_t *rwlock)
  311. {
  312. struct ldap_int_thread_rdwr_s *rw;
  313. assert( rwlock != NULL );
  314. rw = *rwlock;
  315. assert( rw != NULL );
  316. assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
  317. assert( rw->ltrw_w_active >= 0 );
  318. assert( rw->ltrw_w_wait >= 0 );
  319. assert( rw->ltrw_r_active >= 0 );
  320. assert( rw->ltrw_r_wait >= 0 );
  321. return( rw->ltrw_r_active );
  322. }
  323. int ldap_pvt_thread_rdwr_writers(ldap_pvt_thread_rdwr_t *rwlock)
  324. {
  325. struct ldap_int_thread_rdwr_s *rw;
  326. assert( rwlock != NULL );
  327. rw = *rwlock;
  328. assert( rw != NULL );
  329. assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
  330. assert( rw->ltrw_w_active >= 0 );
  331. assert( rw->ltrw_w_wait >= 0 );
  332. assert( rw->ltrw_r_active >= 0 );
  333. assert( rw->ltrw_r_wait >= 0 );
  334. return( rw->ltrw_w_active );
  335. }
  336. int ldap_pvt_thread_rdwr_active(ldap_pvt_thread_rdwr_t *rwlock)
  337. {
  338. struct ldap_int_thread_rdwr_s *rw;
  339. assert( rwlock != NULL );
  340. rw = *rwlock;
  341. assert( rw != NULL );
  342. assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
  343. assert( rw->ltrw_w_active >= 0 );
  344. assert( rw->ltrw_w_wait >= 0 );
  345. assert( rw->ltrw_r_active >= 0 );
  346. assert( rw->ltrw_r_wait >= 0 );
  347. return(ldap_pvt_thread_rdwr_readers(rwlock) +
  348. ldap_pvt_thread_rdwr_writers(rwlock));
  349. }
  350. #endif /* LDAP_RDWR_DEBUG */
  351. #endif /* LDAP_THREAD_HAVE_RDWR */
  352. #endif /* LDAP_R_COMPILE */