ptw32_OLL_lock.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734
  1. /*
  2. * ptw32_OLL_lock.c
  3. *
  4. * Description:
  5. * This translation unit implements extended reader/writer queue-based locks.
  6. *
  7. * --------------------------------------------------------------------------
  8. *
  9. * Pthreads-win32 - POSIX Threads Library for Win32
  10. * Copyright(C) 1998 John E. Bossom
  11. * Copyright(C) 1999,2005 Pthreads-win32 contributors
  12. *
  13. * Contact Email: [email protected]
  14. *
  15. * The current list of contributors is contained
  16. * in the file CONTRIBUTORS included with the source
  17. * code distribution. The list can also be seen at the
  18. * following World Wide Web location:
  19. * http://sources.redhat.com/pthreads-win32/contributors.html
  20. *
  21. * This library is free software; you can redistribute it and/or
  22. * modify it under the terms of the GNU Lesser General Public
  23. * License as published by the Free Software Foundation; either
  24. * version 2 of the License, or (at your option) any later version.
  25. *
  26. * This library is distributed in the hope that it will be useful,
  27. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  28. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  29. * Lesser General Public License for more details.
  30. *
  31. * You should have received a copy of the GNU Lesser General Public
  32. * License along with this library in the file COPYING.LIB;
  33. * if not, write to the Free Software Foundation, Inc.,
  34. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  35. */
  36. /*
  37. * About the OLL lock (Scalable Reader-Writer Lock):
  38. *
  39. * OLL locks are queue-based locks similar to the MCS queue lock, where the queue
  40. * nodes are local to the thread but where reader threads can enter the critical
  41. * section immediately without going through a central guard lock if there are
  42. * already readers holding the lock.
  43. *
  44. * Covered by United States Patent Application 20100241774 (Oracle)
  45. */
  46. #include "pthread.h"
  47. #include "sched.h"
  48. #include "implement.h"
  49. /*
  50. * C-SNZI support
  51. */
  52. typedef union ptw32_oll_counter_t_ ptw32_oll_counter_t;
  53. typedef struct ptw32_oll_snziRoot_t_ ptw32_oll_snziRoot_t;
  54. typedef struct ptw32_oll_snziNode_t_ ptw32_oll_snziNode_t;
  55. typedef union ptw32_oll_snziNodeOrRoot_t_ ptw32_oll_snziNodeOrRoot_t;
  56. typedef struct ptw32_oll_queryResult_t_ ptw32_oll_queryResult_t;
  57. typedef struct ptw32_oll_ticket_t_ ptw32_oll_ticket_t;
  58. typedef struct ptw32_oll_csnzi_t_ ptw32_oll_csnzi_t;
  59. enum
  60. {
  61. ptw32_archWidth = sizeof(size_t)*8,
  62. ptw32_oll_countWidth = ptw32_archWidth-2
  63. };
  64. #define PTW32_OLL_MAXREADERS (((size_t)2<<(ptw32_oll_countWidth-1))-1)
  65. union ptw32_oll_counter_t_
  66. {
  67. size_t word : ptw32_archWidth;
  68. struct
  69. {
  70. /*
  71. * This needs to be a single word
  72. *
  73. * ------------------------------------
  74. * | STATE | ROOT | COUNT (readers) |
  75. * ------------------------------------
  76. * 63 / 31 62 / 30 61 / 29 .. 0
  77. */
  78. size_t count : ptw32_oll_countWidth;
  79. size_t root : 1; /* ROOT or NODE */
  80. size_t state : 1; /* OPEN or CLOSED (root only) */
  81. } internal;
  82. };
  83. struct ptw32_oll_snziRoot_t_
  84. {
  85. /*
  86. * "counter" must be at same offset in both
  87. * ptw32_oll_snziNode_t and ptw32_oll_snziRoot_t
  88. */
  89. ptw32_oll_counter_t counter;
  90. };
  91. enum
  92. {
  93. ptw32_oll_snziRoot_open = 0,
  94. ptw32_oll_snziRoot_closed = 1
  95. };
  96. enum
  97. {
  98. ptw32_oll_snzi_root = 0,
  99. ptw32_oll_snzi_node = 1
  100. };
  101. /*
  102. * Some common SNZI root whole-word states that can be used to set or compare
  103. * root words with a single operation.
  104. */
  105. ptw32_oll_snziRoot_t ptw32_oll_snziRoot_openAndZero = {.counter.internal.count = 0,
  106. .counter.internal.root = ptw32_oll_snzi_root,
  107. .counter.internal.state = ptw32_oll_snziRoot_open};
  108. ptw32_oll_snziRoot_t ptw32_oll_snziRoot_closedAndZero = {.counter.internal.count = 0,
  109. .counter.internal.root = ptw32_oll_snzi_root,
  110. .counter.internal.state = ptw32_oll_snziRoot_closed};
  111. struct ptw32_oll_queryResult_t_
  112. {
  113. BOOL nonZero;
  114. BOOL open;
  115. };
  116. union ptw32_oll_snziNodeOrRoot_t_
  117. {
  118. ptw32_oll_snziRoot_t* rootPtr;
  119. ptw32_oll_snziNode_t* nodePtr;
  120. };
  121. struct ptw32_oll_snziNode_t_
  122. {
  123. /* "counter" must be at same offset in both
  124. * ptw32_oll_snziNode_t and ptw32_oll_snziRoot_t
  125. */
  126. ptw32_oll_counter_t counter;
  127. ptw32_oll_snziNodeOrRoot_t parentPtr;
  128. };
  129. struct ptw32_oll_ticket_t_
  130. {
  131. ptw32_oll_snziNodeOrRoot_t snziNodeOrRoot;
  132. };
  133. ptw32_oll_ticket_t ptw32_oll_ticket_null = {NULL};
  134. struct ptw32_oll_csnzi_t_
  135. {
  136. ptw32_oll_snziRoot_t proxyRoot;
  137. ptw32_oll_snziNode_t leafs[];
  138. };
  139. /*
  140. * FOLL lock support
  141. */
  142. typedef struct ptw32_foll_node_t_ ptw32_foll_node_t;
  143. typedef struct ptw32_foll_local_t_ ptw32_foll_local_t;
  144. typedef struct ptw32_foll_rwlock_t_ ptw32_foll_rwlock_t;
  145. enum
  146. {
  147. ptw32_srwl_reader,
  148. ptw32_srwl_writer
  149. };
  150. enum
  151. {
  152. ptw32_srwl_free,
  153. ptw32_srwl_in_use
  154. };
  155. struct ptw32_foll_node_t_
  156. {
  157. ptw32_foll_node_t* qNextPtr;
  158. ptw32_oll_csnzi_t* csnziPtr;
  159. ptw32_foll_node_t* nextPtr;
  160. int kind;
  161. int allocState;
  162. BOOL spin;
  163. };
  164. struct ptw32_foll_local_t_
  165. {
  166. ptw32_foll_node_t* rNodePtr; // Default read node. Immutable
  167. ptw32_foll_node_t* wNodePtr; // Write node. Immutable.
  168. ptw32_foll_node_t* departFromPtr; // List node we last arrived at.
  169. ptw32_oll_ticket_t ticket; // C-SNZI ticket
  170. };
  171. struct ptw32_foll_rwlock_t_
  172. {
  173. ptw32_foll_node_t* tailPtr;
  174. ptw32_foll_node_t* rNodesPtr; // Head of reader node
  175. };
  176. /*
  177. * ShouldArriveAtTree() returns true if:
  178. * the compare_exchange in Arrive() fails too often under read access; or
  179. * ??
  180. * Note that this is measured across all access to
  181. * this lock, not just this attempt, so that highly
  182. * read-contended locks will use C-SNZI. Lightly
  183. * read-contended locks can reduce memory usage and some
  184. * processing by using the root directly.
  185. */
  186. BOOL
  187. ptw32_oll_ShouldArriveAtTree()
  188. {
  189. return PTW32_FALSE;
  190. }
  191. size_t
  192. ptw32_oll_GetLeafForThread()
  193. {
  194. return 0;
  195. }
  196. /*
  197. * Only readers call ptw32_oll_Arrive()
  198. *
  199. * Checks whether the C-SNZI state is OPEN, and if so,
  200. * increments the surplus of the C-SNZI by either directly
  201. * arriving at the root node, or calling TreeArrive on one
  202. * of the leaf nodes. Returns a ticket pointing to the node
  203. * that was arrived at. If the state is CLOSED, makes no
  204. * change and returns a ticket that contains no pointer.
  205. */
  206. ptw32_oll_ticket_t
  207. ptw32_oll_Arrive(ptw32_oll_csnzi_t* csnzi)
  208. {
  209. for (;;)
  210. {
  211. ptw32_oll_ticket_t ticket;
  212. ptw32_oll_snziRoot_t oldProxy = csnzi->proxyRoot;
  213. if (oldProxy.counter.internal.state != ptw32_oll_snziRoot_open)
  214. {
  215. ticket.snziNodeOrRoot.rootPtr = (ptw32_oll_snziRoot_t*)NULL;
  216. return ticket;
  217. }
  218. if (!ptw32_oll_ShouldArriveAtTree())
  219. {
  220. ptw32_oll_snziRoot_t newProxy = oldProxy;
  221. newProxy.counter.internal.count++;
  222. if (PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE(
  223. (PTW32_INTERLOCKED_SIZEPTR)&csnzi->proxyRoot.counter,
  224. (PTW32_INTERLOCKED_SIZE)newProxy.counter.word,
  225. (PTW32_INTERLOCKED_SIZE)oldProxy.counter.word)
  226. == (PTW32_INTERLOCKED_SIZE)oldProxy.counter.word)
  227. {
  228. /* Exchange successful */
  229. ticket.snziNodeOrRoot.rootPtr = &csnzi->proxyRoot;
  230. return ticket;
  231. }
  232. }
  233. else
  234. {
  235. ptw32_oll_snziNode_t* leafPtr = &csnzi->leafs[ptw32_oll_GetLeafForThread()];
  236. ticket.snziNodeOrRoot.nodePtr = (ptw32_oll_TreeArrive(leafPtr) ? leafPtr : (ptw32_oll_snziNode_t*)NULL);
  237. return ticket;
  238. }
  239. }
  240. }
  241. /*
  242. * Decrements the C-SNZI surplus. Returns false iff the
  243. * resulting state is CLOSED and the surplus is zero.
  244. * Ticket must have been returned by an arrival. Must have
  245. * received this ticket from Arrive more times than Depart
  246. * has been called with the ticket. (Thus, the surplus
  247. * must be greater than zero.)
  248. */
  249. BOOL
  250. ptw32_oll_Depart(ptw32_oll_ticket_t ticket)
  251. {
  252. return ptw32_oll_TreeDepart(ticket.snziNodeOrRoot);
  253. }
  254. /*
  255. * Increments the C-SNZI surplus and returns true if the
  256. * C-SNZI is open or has a surplus. Calls TreeArrive
  257. * recursively on the node’s parent if needed.
  258. * Otherwise, returns false without making any changes.
  259. */
  260. BOOL
  261. ptw32_oll_TreeArrive(ptw32_oll_snziNodeOrRoot_t snziNodeOrRoot)
  262. {
  263. if (snziNodeOrRoot.nodePtr->counter.internal.root != ptw32_oll_snzi_root)
  264. {
  265. /* Non-root node */
  266. ptw32_oll_counter_t newCounter, oldCounter;
  267. BOOL arrivedAtParent = PTW32_FALSE;
  268. do
  269. {
  270. oldCounter = snziNodeOrRoot.nodePtr->counter;
  271. if (0 == oldCounter.internal.count && !arrivedAtParent)
  272. {
  273. if (ptw32_oll_TreeArrive(snziNodeOrRoot.nodePtr->parentPtr))
  274. arrivedAtParent = PTW32_TRUE;
  275. else
  276. return PTW32_FALSE;
  277. }
  278. newCounter = oldCounter;
  279. newCounter.internal.count++;
  280. } while (PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE(
  281. (PTW32_INTERLOCKED_SIZEPTR)&snziNodeOrRoot.nodePtr->counter,
  282. (PTW32_INTERLOCKED_SIZE)newCounter.word,
  283. (PTW32_INTERLOCKED_SIZE)oldCounter.word)
  284. != (PTW32_INTERLOCKED_SIZE)oldCounter.word);
  285. if (newCounter.internal.count != 0 && arrivedAtParent)
  286. ptw32_oll_TreeDepart(snziNodeOrRoot.nodePtr->parentPtr);
  287. return PTW32_TRUE;
  288. }
  289. else
  290. {
  291. /* Root node */
  292. ptw32_oll_snziRoot_t newRoot, oldRoot;
  293. do
  294. {
  295. oldRoot = *(ptw32_oll_snziRoot_t*)snziNodeOrRoot.rootPtr;
  296. if (oldRoot.counter.word == ptw32_oll_snziRoot_closedAndZero.counter.word)
  297. return PTW32_FALSE;
  298. newRoot = oldRoot;
  299. newRoot.counter.internal.count++;
  300. } while (PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE(
  301. (PTW32_INTERLOCKED_SIZEPTR)&snziNodeOrRoot.rootPtr->counter,
  302. (PTW32_INTERLOCKED_SIZE)newRoot.counter.word,
  303. (PTW32_INTERLOCKED_SIZE)oldRoot.counter.word)
  304. != (PTW32_INTERLOCKED_SIZE)oldRoot.counter.word);
  305. return PTW32_TRUE;
  306. }
  307. }
  308. /*
  309. * Decrements the C-SNZI surplus, calling TreeDepart
  310. * recursively on the node’s parent if needed. Returns
  311. * false iff the resulting state of the C-SNZI is CLOSED
  312. * and the surplus is zero. Otherwise, returns true.
  313. */
  314. BOOL
  315. ptw32_oll_TreeDepart(ptw32_oll_snziNodeOrRoot_t snziNodeOrRoot)
  316. {
  317. if (snziNodeOrRoot.nodePtr->counter.internal.root != ptw32_oll_snzi_root)
  318. {
  319. /* Non-root node */
  320. ptw32_oll_counter_t newCounter, oldCounter;
  321. do
  322. {
  323. newCounter = oldCounter = snziNodeOrRoot.nodePtr->counter;
  324. newCounter.internal.count--;
  325. } while (PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE(
  326. (PTW32_INTERLOCKED_SIZEPTR)&snziNodeOrRoot.nodePtr->counter,
  327. (PTW32_INTERLOCKED_SIZE)newCounter.word,
  328. (PTW32_INTERLOCKED_SIZE)oldCounter.word)
  329. != (PTW32_INTERLOCKED_SIZE)oldCounter.word);
  330. return (0 == newCounter.internal.count)
  331. ? ptw32_oll_TreeDepart(snziNodeOrRoot.nodePtr->parentPtr)
  332. : PTW32_TRUE;
  333. }
  334. else
  335. {
  336. /* Root node */
  337. ptw32_oll_snziRoot_t newRoot, oldRoot;
  338. do
  339. {
  340. newRoot = oldRoot = *(ptw32_oll_snziRoot_t*)snziNodeOrRoot.rootPtr;
  341. newRoot.counter.internal.count--;
  342. } while (PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE(
  343. (PTW32_INTERLOCKED_SIZEPTR)&snziNodeOrRoot.rootPtr->counter,
  344. (PTW32_INTERLOCKED_SIZE)newRoot.counter.word,
  345. (PTW32_INTERLOCKED_SIZE)oldRoot.counter.word)
  346. != (PTW32_INTERLOCKED_SIZE)oldRoot.counter.word);
  347. return (newRoot.counter.word != ptw32_oll_snziRoot_closedAndZero.counter.word);
  348. }
  349. }
  350. /*
  351. * Opens a C-SNZI object. Requires C-SNZI state to be
  352. * CLOSED and the surplus to be zero.
  353. */
  354. void
  355. ptw32_oll_Open(ptw32_oll_csnzi_t* csnziPtr)
  356. {
  357. csnziPtr->proxyRoot = ptw32_oll_snziRoot_openAndZero;
  358. }
  359. /*
  360. * Opens a C-SNZI object while atomically performing count
  361. * arrivals. Requires C-SNZI state to be CLOSED and
  362. * the surplus to be zero.
  363. */
  364. void
  365. ptw32_oll_OpenWithArrivals(ptw32_oll_csnzi_t* csnziPtr, size_t count, BOOL close)
  366. {
  367. csnziPtr->proxyRoot.counter.internal.count = count;
  368. csnziPtr->proxyRoot.counter.internal.state = (close ? ptw32_oll_snziRoot_closed : ptw32_oll_snziRoot_open);
  369. }
  370. /*
  371. * Closes a C-SNZI object. Returns true iff the C-SNZI
  372. * state changed from OPEN to CLOSED and the surplus is
  373. * zero.
  374. */
  375. BOOL
  376. ptw32_oll_Close(ptw32_oll_csnzi_t* csnziPtr)
  377. {
  378. ptw32_oll_snziRoot_t newProxy, oldProxy;
  379. do
  380. {
  381. oldProxy = csnziPtr->proxyRoot;
  382. if (oldProxy.counter.internal.state != ptw32_oll_snziRoot_open)
  383. {
  384. return PTW32_FALSE;
  385. }
  386. newProxy = oldProxy;
  387. newProxy.counter.internal.state = ptw32_oll_snziRoot_closed;
  388. } while (PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE(
  389. (PTW32_INTERLOCKED_SIZEPTR)&csnziPtr->proxyRoot.counter,
  390. (PTW32_INTERLOCKED_SIZE)newProxy.counter.word,
  391. (PTW32_INTERLOCKED_SIZE)oldProxy.counter.word)
  392. != (PTW32_INTERLOCKED_SIZE)oldProxy.counter.word);
  393. return (newProxy.counter.word == ptw32_oll_snziRoot_closedAndZero.counter.word);
  394. }
  395. /*
  396. * Closes a C-SNZI if its surplus is zero. Otherwise, does
  397. * nothing. Returns true iff C-SNZI state changed from
  398. * OPEN to CLOSED.
  399. */
  400. BOOL
  401. ptw32_oll_CloseIfEmpty(ptw32_oll_csnzi_t* csnziPtr)
  402. {
  403. ptw32_oll_snziRoot_t newProxy, oldProxy;
  404. do
  405. {
  406. oldProxy = csnziPtr->proxyRoot;
  407. if (oldProxy.counter.word != ptw32_oll_snziRoot_openAndZero.counter.word)
  408. {
  409. return PTW32_FALSE;
  410. }
  411. newProxy = ptw32_oll_snziRoot_closedAndZero;
  412. } while (PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE(
  413. (PTW32_INTERLOCKED_SIZEPTR)&csnziPtr->proxyRoot.counter,
  414. (PTW32_INTERLOCKED_SIZE)newProxy.counter.word,
  415. (PTW32_INTERLOCKED_SIZE)oldProxy.counter.word)
  416. != (PTW32_INTERLOCKED_SIZE)oldProxy.counter.word);
  417. return PTW32_TRUE;
  418. }
  419. /*
  420. * Returns whether the C-SNZI has a nonzero surplus and
  421. * whether the C-SNZI is open.
  422. * "nonZero" doesn't appear to be used anywhere in the algorithms.
  423. */
  424. ptw32_oll_queryResult_t
  425. ptw32_oll_Query(ptw32_oll_csnzi_t* csnziPtr)
  426. {
  427. ptw32_oll_queryResult_t query;
  428. ptw32_oll_snziRoot_t proxy = csnziPtr->proxyRoot;
  429. query.nonZero = (proxy.counter.internal.count > 0);
  430. query.open = (proxy.counter.internal.state == ptw32_oll_snziRoot_open);
  431. return query;
  432. }
  433. /*
  434. * Returns whether the Arrive operation that returned
  435. * the ticket succeeded.
  436. */
  437. BOOL
  438. ptw32_oll_Arrived(ptw32_oll_ticket_t t)
  439. {
  440. return (t.snziNodeOrRoot.nodePtr != NULL);
  441. }
  442. /*
  443. * Constructs and returns a ticket that can be used to
  444. * depart from the root node.
  445. */
  446. ptw32_oll_ticket_t
  447. ptw32_oll_DirectTicket(ptw32_oll_csnzi_t* csnziPtr)
  448. {
  449. ptw32_oll_ticket_t ticket;
  450. ticket.snziNodeOrRoot.rootPtr = &csnziPtr->proxyRoot;
  451. return ticket;
  452. }
  453. /* Scalable RW Locks */
  454. typedef struct ptw32_srwl_rwlock_t_ ptw32_srwl_rwlock_t;
  455. typedef struct ptw32_srwl_node_t_ ptw32_srwl_node_t;
  456. typedef struct ptw32_srwl_local_t_ ptw32_srwl_local_t;
  457. enum
  458. {
  459. ptw32_srwl_reader = 0,
  460. ptw32_srwl_writer = 1
  461. };
  462. enum
  463. {
  464. ptw32_srwl_free = 0,
  465. ptw32_srwl_in_use = 1
  466. };
  467. struct ptw32_srwl_rwlock_t_
  468. {
  469. ptw32_srwl_node_t* tailPtr;
  470. ptw32_srwl_node_t* readerNodePtr;
  471. };
  472. struct ptw32_srwl_node_t_
  473. {
  474. ptw32_srwl_node_t* qNextPtr;
  475. ptw32_oll_csnzi_t* csnziPtr;
  476. ptw32_srwl_node_t* nextReaderPtr;
  477. int kind; /* ptw32_srwl_reader, ptw32_srwl_writer */
  478. int allocState; /* ptw32_srwl_free, ptw32_srwl_in_use */
  479. BOOL spin;
  480. };
  481. /*
  482. * When a ptw32_srwl_local_t is instantiated the "kind" of each of
  483. * rNode and wNode must be set as appropriate. This is the only
  484. * time "kind" is set.
  485. */
  486. struct ptw32_srwl_local_t_
  487. {
  488. ptw32_srwl_node_t* rNodePtr;
  489. ptw32_srwl_node_t* wNodePtr;
  490. ptw32_srwl_node_t* departFromPtr;
  491. ptw32_oll_ticket_t ticket;
  492. };
  493. /* Allocates a new reader node. */
  494. ptw32_srwl_node_t*
  495. ptw32_srwl_AllocReaderNode(ptw32_srwl_local_t* local)
  496. {
  497. ptw32_srwl_node_t* currNodePtr = local->rNodePtr;
  498. for (;;)
  499. {
  500. if (currNodePtr->allocState == ptw32_srwl_free)
  501. {
  502. if (PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG(
  503. (PTW32_INTERLOCKED_LONGPTR)&currNodePtr->allocState,
  504. (PTW32_INTERLOCKED_LONG)ptw32_srwl_in_use,
  505. (PTW32_INTERLOCKED_LONG)ptw32_srwl_free)
  506. == (PTW32_INTERLOCKED_LONG)ptw32_srwl_in_use)
  507. {
  508. return currNodePtr;
  509. }
  510. }
  511. currNodePtr = currNodePtr->next;
  512. }
  513. }
  514. /*
  515. * Frees a reader node. Requires that its allocState
  516. * is ptw32_srwl_in_use.
  517. */
  518. void
  519. ptw32_srwl_FreeReaderNode(ptw32_srwl_node_t* nodePtr)
  520. {
  521. nodePtr->allocState := ptw32_srwl_free;
  522. }
  523. void
  524. ptw32_srwl_WriterLock(ptw32_srwl_rwlock_t* lockPtr, ptw32_srwl_local_t* localPtr)
  525. {
  526. oldTailPtr = (ptw32_srwl_rwlock_t*)PTW32_INTERLOCKED_EXCHANGE_PTR(
  527. (PTW32_INTERLOCKED_PVOID_PTR)&lockPtr->tailPtr,
  528. (PTW32_INTERLOCKED_PVOID)localPtr->wNodePtr);
  529. if (oldTailPtr != NULL)
  530. {
  531. localPtr->wNodePtr->spin := PTW32_TRUE;
  532. oldTailPtr->qNextPtr = localPtr->wNodePtr;
  533. if (oldTailPtr->kind == ptw32_srwl_writer)
  534. {
  535. while (localPtr->wNodePtr->spin);
  536. }
  537. else
  538. {
  539. /* Wait until node is properly recycled */
  540. while (ptw32_oll_Query(oldTailPtr->csnzi).open);
  541. /*
  542. * Close C-SNZI of previous reader node.
  543. * If there are no readers to signal us, spin on
  544. * previous node and free it before entering
  545. * critical section.
  546. */
  547. if (ptw32_oll_Close(oldTailPtr->csnzi))
  548. {
  549. while (oldTailPtr->spin);
  550. ptw32_srwl_FreeReaderNode(oldTailPtr);
  551. }
  552. else
  553. {
  554. while (localPtr->wNodePtr->spin);
  555. }
  556. }
  557. }
  558. }
  559. void
  560. ptw32_srwl_WriterUnlock(ptw32_srwl_rwlock_t* lockPtr, ptw32_srwl_local_t* localPtr)
  561. {
  562. if (localPtr->wNodePtr->qNextPtr == NULL)
  563. {
  564. if (PTW32_INTERLOCKED_COMPARE_EXCHANGE_PTR(
  565. (PTW32_INTERLOCKED_PVOIDPTR)&lockPtr->tailPtr,
  566. (PTW32_INTERLOCKED_PVOID)NULL,
  567. (PTW32_INTERLOCKED_PVOID)localPtr->wNodePtr)
  568. == (PTW32_INTERLOCKED_PVOID)NULL)
  569. {
  570. return;
  571. }
  572. else
  573. {
  574. while (localPtr->wNodePtr->qNextPtr == NULL);
  575. }
  576. }
  577. /* Clean up */
  578. localPtr->wNodePtr->qNextPtr->spin = PTW32_FALSE;
  579. localPtr->wNodePtr->qNextPtr = NULL;
  580. }
  581. void
  582. ptw32_srwl_ReaderLock(ptw32_srwl_rwlock_t* lockPtr, ptw32_srwl_local_t* localPtr)
  583. {
  584. ptw32_srwl_node_t* rNodePtr = NULL;
  585. for (;;)
  586. {
  587. ptw32_srwl_node_t* tailPtr = lockPtr->tailPtr;
  588. /* If no nodes are in the queue */
  589. if (tailPtr == NULL)
  590. {
  591. if (rNodePtr == NULL)
  592. {
  593. rNodePtr = ptw32_srwl_AllocReaderNode(localPtr);
  594. }
  595. rNodePtr->spin = PTW32_FALSE;
  596. if (PTW32_INTERLOCKED_COMPARE_EXCHANGE_PTR(
  597. (PTW32_INTERLOCKED_PVOIDPTR)&lockPtr->tailPtr,
  598. (PTW32_INTERLOCKED_PVOID)rNodePtr,
  599. (PTW32_INTERLOCKED_PVOID)NULL)
  600. == (PTW32_INTERLOCKED_PVOID)rNodePtr)
  601. {
  602. ptw32_oll_Open(rNodePtr->csnzi);
  603. localPtr->ticket = ptw32_oll_Arrive(rNodePtr->csnzi);
  604. if (ptw32_oll_Arrived(localPtr->ticket))
  605. {
  606. localPtr->departFromPtr = rNodePtr;
  607. return;
  608. }
  609. /* Avoid reusing inserted node */
  610. rNodePtr = NULL;
  611. }
  612. }
  613. /* Otherwise, there is a node in the queue */
  614. else
  615. {
  616. /* Is last node a writer node? */
  617. if (tailPtr->kind == ptw32_srwl_writer)
  618. {
  619. if (rNodePtr == NULL)
  620. {
  621. rNodePtr = ptw32_srwl_AllocReaderNode(localPtr);
  622. }
  623. rNodePtr->spin = PTW32_TRUE;
  624. if (PTW32_INTERLOCKED_COMPARE_EXCHANGE_PTR(
  625. (PTW32_INTERLOCKED_PVOIDPTR)&lockPtr->tailPtr,
  626. (PTW32_INTERLOCKED_PVOID)rNodePtr,
  627. (PTW32_INTERLOCKED_PVOID)tailPtr)
  628. == (PTW32_INTERLOCKED_PVOID)rNodePtr)
  629. {
  630. tailPtr->qNextPtr = rNodePtr;
  631. localPtr->ticket = ptw32_oll_Arrive(rNodePtr->csnzi);
  632. if (ptw32_oll_Arrived(localPtr->ticket))
  633. {
  634. localPtr->departFromPtr = rNodePtr;
  635. while (rNodePtr->spin);
  636. return;
  637. }
  638. /* Avoid reusing inserted node */
  639. rNodePtr = NULL;
  640. }
  641. }
  642. /*
  643. * Otherwise, last node is a reader node.
  644. * (tailPtr->kind == ptw32_srwl_reader)
  645. */
  646. else
  647. {
  648. localPtr->ticket = ptw32_oll_Arrive(tailPtr->csnzi);
  649. if (ptw32_oll_Arrived(localPtr->ticket))
  650. {
  651. if (rNodePtr != NULL)
  652. {
  653. ptw32_srwl_FreeReaderNode(rNodePtr);
  654. }
  655. localPtr->departFromPtr = tailPtr;
  656. while (tailPtr->spin);
  657. return;
  658. }
  659. }
  660. }
  661. }
  662. }
  663. void
  664. ptw32_srwl_ReaderUnlock(ptw32_srwl_rwlock_t* lockPtr, ptw32_srwl_local_t* localPtr)
  665. {
  666. if (ptw32_oll_Depart(localPtr->departFromPtr->csnzi, localPtr->ticket))
  667. {
  668. return;
  669. }
  670. /* Clean up */
  671. localPtr->departFromPtr->qNextPtr->spin = PTW32_FALSE;
  672. localPtr->departFromPtr->qNextPtr = NULL;
  673. ptw32_srwl_FreeReaderNode(localPtr->departFromPtr);
  674. }
  675. #include <stdio.h>
  676. int main()
  677. {
  678. printf("%lx\n", PTW32_OLL_MAXREADERS);
  679. return 0;
  680. }