sync0rw.ic
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:13k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /******************************************************
  2. The read-write lock (for threads)
  3. (c) 1995 Innobase Oy
  4. Created 9/11/1995 Heikki Tuuri
  5. *******************************************************/
  6. /**********************************************************************
  7. Lock an rw-lock in shared mode for the current thread. If the rw-lock is
  8. locked in exclusive mode, or there is an exclusive lock request waiting,
  9. the function spins a preset time (controlled by SYNC_SPIN_ROUNDS),
  10. waiting for the lock before suspending the thread. */
  11. void
  12. rw_lock_s_lock_spin(
  13. /*================*/
  14.         rw_lock_t*    lock   /* in: pointer to rw-lock */
  15. #ifdef UNIV_SYNC_DEBUG
  16. ,ulint pass, /* in: pass value; != 0, if the lock will
  17. be passed to another thread to unlock */
  18. char* file_name, /* in: file name where lock requested */
  19. ulint line /* in: line where requested */
  20. #endif
  21. );
  22. /**********************************************************************
  23. Inserts the debug information for an rw-lock. */
  24. void
  25. rw_lock_add_debug_info(
  26. /*===================*/
  27. rw_lock_t* lock, /* in: rw-lock */
  28. ulint pass, /* in: pass value */
  29. ulint lock_type, /* in: lock type */
  30. char* file_name, /* in: file where requested */
  31. ulint line); /* in: line where requested */
  32. /**********************************************************************
  33. Removes a debug information struct for an rw-lock. */
  34. void
  35. rw_lock_remove_debug_info(
  36. /*======================*/
  37. rw_lock_t* lock, /* in: rw-lock */
  38. ulint pass, /* in: pass value */
  39. ulint lock_type); /* in: lock type */
  40. /************************************************************************
  41. Accessor functions for rw lock. */
  42. UNIV_INLINE
  43. ulint
  44. rw_lock_get_waiters(
  45. /*================*/
  46. rw_lock_t* lock)
  47. {
  48. return(lock->waiters);
  49. }
  50. UNIV_INLINE
  51. void
  52. rw_lock_set_waiters(
  53. /*================*/
  54. rw_lock_t* lock,
  55. ulint flag)
  56. {
  57. lock->waiters = flag;
  58. }
  59. UNIV_INLINE
  60. ulint
  61. rw_lock_get_writer(
  62. /*===============*/
  63. rw_lock_t* lock)
  64. {
  65. return(lock->writer);
  66. }
  67. UNIV_INLINE
  68. void
  69. rw_lock_set_writer(
  70. /*===============*/
  71. rw_lock_t* lock,
  72. ulint flag)
  73. {
  74. lock->writer = flag;
  75. }
  76. UNIV_INLINE
  77. ulint
  78. rw_lock_get_reader_count(
  79. /*=====================*/
  80. rw_lock_t* lock)
  81. {
  82. return(lock->reader_count);
  83. }
  84. UNIV_INLINE
  85. void
  86. rw_lock_set_reader_count(
  87. /*=====================*/
  88. rw_lock_t* lock,
  89. ulint count)
  90. {
  91. lock->reader_count = count;
  92. }
  93. UNIV_INLINE
  94. mutex_t*
  95. rw_lock_get_mutex(
  96. /*==============*/
  97. rw_lock_t* lock)
  98. {
  99. return(&(lock->mutex));
  100. }
  101. /**********************************************************************
  102. Returns the value of writer_count for the lock. Does not reserve the lock
  103. mutex, so the caller must be sure it is not changed during the call. */
  104. UNIV_INLINE
  105. ulint
  106. rw_lock_get_x_lock_count(
  107. /*=====================*/
  108. /* out: value of writer_count */
  109. rw_lock_t* lock) /* in: rw-lock */
  110. {
  111. return(lock->writer_count);
  112. }
  113. /**********************************************************************
  114. Low-level function which tries to lock an rw-lock in s-mode. Performs no
  115. spinning. */
  116. UNIV_INLINE
  117. ibool
  118. rw_lock_s_lock_low(
  119. /*===============*/
  120. /* out: TRUE if success */
  121.         rw_lock_t*    lock   /* in: pointer to rw-lock */
  122. #ifdef UNIV_SYNC_DEBUG
  123. ,ulint pass, /* in: pass value; != 0, if the lock will be
  124. passed to another thread to unlock */
  125. char* file_name, /* in: file name where lock requested */
  126. ulint line /* in: line where requested */
  127. #endif
  128. )
  129. {
  130. ut_ad(mutex_own(rw_lock_get_mutex(lock)));
  131. /* Check if the writer field is free */
  132. if (lock->writer == RW_LOCK_NOT_LOCKED) {
  133. /* Set the shared lock by incrementing the reader count */
  134. lock->reader_count++;
  135. #ifdef UNIV_SYNC_DEBUG
  136. rw_lock_add_debug_info(lock, pass, RW_LOCK_SHARED, file_name,
  137. line);
  138. #endif
  139. return(TRUE); /* locking succeeded */
  140. }
  141. return(FALSE); /* locking did not succeed */
  142. }
  143. /**********************************************************************
  144. Low-level function which locks an rw-lock in s-mode when we know that it
  145. is possible and none else is currently accessing the rw-lock structure.
  146. Then we can do the locking without reserving the mutex. */
  147. UNIV_INLINE
  148. void
  149. rw_lock_s_lock_direct(
  150. /*==================*/
  151.         rw_lock_t*    lock   /* in: pointer to rw-lock */
  152. #ifdef UNIV_SYNC_DEBUG
  153. ,char* file_name, /* in: file name where lock requested */
  154. ulint line /* in: line where requested */
  155. #endif
  156. )
  157. {
  158. ut_ad(lock->writer == RW_LOCK_NOT_LOCKED);
  159. ut_ad(rw_lock_get_reader_count(lock) == 0);
  160. /* Set the shared lock by incrementing the reader count */
  161. lock->reader_count++;
  162. #ifdef UNIV_SYNC_DEBUG
  163. rw_lock_add_debug_info(lock, 0, RW_LOCK_SHARED, file_name, line);
  164. #endif
  165. }
  166. /**********************************************************************
  167. Low-level function which locks an rw-lock in x-mode when we know that it
  168. is not locked and none else is currently accessing the rw-lock structure.
  169. Then we can do the locking without reserving the mutex. */
  170. UNIV_INLINE
  171. void
  172. rw_lock_x_lock_direct(
  173. /*==================*/
  174.         rw_lock_t*    lock   /* in: pointer to rw-lock */
  175. #ifdef UNIV_SYNC_DEBUG
  176. ,char* file_name, /* in: file name where lock requested */
  177. ulint line /* in: line where requested */
  178. #endif
  179. )
  180. {
  181.         ut_ad(rw_lock_validate(lock));
  182. ut_ad(rw_lock_get_reader_count(lock) == 0);
  183. ut_ad(rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED);
  184. rw_lock_set_writer(lock, RW_LOCK_EX);
  185. lock->writer_thread = os_thread_get_curr_id();
  186. lock->writer_count++;
  187. lock->pass = 0;
  188. #ifdef UNIV_SYNC_DEBUG
  189. rw_lock_add_debug_info(lock, 0, RW_LOCK_EX, file_name, line);
  190. #endif
  191. }
  192. /**********************************************************************
  193. NOTE! Use the corresponding macro, not directly this function! Lock an
  194. rw-lock in shared mode for the current thread. If the rw-lock is locked
  195. in exclusive mode, or there is an exclusive lock request waiting, the
  196. function spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting for
  197. the lock, before suspending the thread. */
  198. UNIV_INLINE
  199. void
  200. rw_lock_s_lock_func(
  201. /*================*/
  202.         rw_lock_t*    lock   /* in: pointer to rw-lock */
  203. #ifdef UNIV_SYNC_DEBUG
  204. ,ulint pass, /* in: pass value; != 0, if the lock will
  205. be passed to another thread to unlock */
  206. char* file_name, /* in: file name where lock requested */
  207. ulint line /* in: line where requested */
  208. #endif
  209. )
  210. {
  211. /* NOTE: As we do not know the thread ids for threads which have
  212. s-locked a latch, and s-lockers will be served only after waiting
  213. x-lock requests have been fulfilled, then if this thread already
  214. owns an s-lock here, it may end up in a deadlock with another thread
  215. which requests an x-lock here. Therefore, we will forbid recursive
  216. s-locking of a latch: the following assert will warn the programmer
  217. of the possibility of a tjis kind of deadlock. If we want to implement
  218. safe recursive s-locking, we should keep in a list the thread ids of
  219. the threads which have s-locked a latch. This would use some CPU
  220. time. */
  221. ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); /* see NOTE above */
  222. mutex_enter(rw_lock_get_mutex(lock));
  223. if (TRUE == rw_lock_s_lock_low(lock
  224. #ifdef UNIV_SYNC_DEBUG
  225. ,pass, file_name, line
  226. #endif
  227.    )) {
  228. mutex_exit(rw_lock_get_mutex(lock));
  229. return; /* Success */
  230. } else {
  231. /* Did not succeed, try spin wait */
  232. mutex_exit(rw_lock_get_mutex(lock));
  233. rw_lock_s_lock_spin(lock
  234. #ifdef UNIV_SYNC_DEBUG
  235. ,pass, file_name, line
  236. #endif
  237.     );
  238. return;
  239. }
  240. }
  241. /**********************************************************************
  242. NOTE! Use the corresponding macro, not directly this function! Lock an
  243. rw-lock in shared mode for the current thread if the lock can be acquired
  244. immediately. */
  245. UNIV_INLINE
  246. ibool
  247. rw_lock_s_lock_func_nowait(
  248. /*=======================*/
  249. /* out: TRUE if success */
  250.         rw_lock_t*    lock   /* in: pointer to rw-lock */
  251. #ifdef UNIV_SYNC_DEBUG
  252. ,char* file_name, /* in: file name where lock requested */
  253. ulint line /* in: line where requested */
  254. #endif
  255. )
  256. {
  257. ibool success = FALSE;
  258. mutex_enter(rw_lock_get_mutex(lock));
  259. if (lock->writer == RW_LOCK_NOT_LOCKED) {
  260. /* Set the shared lock by incrementing the reader count */
  261. lock->reader_count++;
  262. #ifdef UNIV_SYNC_DEBUG
  263. rw_lock_add_debug_info(lock, 0, RW_LOCK_SHARED, file_name,
  264. line);
  265. #endif
  266. success = TRUE;
  267. }
  268. mutex_exit(rw_lock_get_mutex(lock));
  269. return(success);
  270. }
  271. /**********************************************************************
  272. NOTE! Use the corresponding macro, not directly this function! Lock an
  273. rw-lock in exclusive mode for the current thread if the lock can be
  274. obtained immediately. */
  275. UNIV_INLINE
  276. ibool
  277. rw_lock_x_lock_func_nowait(
  278. /*=======================*/
  279. /* out: TRUE if success */
  280.         rw_lock_t*    lock   /* in: pointer to rw-lock */
  281. #ifdef UNIV_SYNC_DEBUG
  282. ,char* file_name, /* in: file name where lock requested */
  283. ulint line /* in: line where requested */
  284. #endif
  285. )
  286. {
  287. ibool success = FALSE;
  288. mutex_enter(rw_lock_get_mutex(lock));
  289. if ((rw_lock_get_reader_count(lock) == 0)
  290.      && ((rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED)
  291.        || ((rw_lock_get_writer(lock) == RW_LOCK_EX)
  292.            && (lock->pass == 0)
  293.            && (lock->writer_thread == os_thread_get_curr_id())))) {
  294. rw_lock_set_writer(lock, RW_LOCK_EX);
  295. lock->writer_thread = os_thread_get_curr_id();
  296. lock->writer_count++;
  297. lock->pass = 0;
  298. #ifdef UNIV_SYNC_DEBUG
  299. rw_lock_add_debug_info(lock, 0, RW_LOCK_EX, file_name, line);
  300. #endif
  301. success = TRUE;
  302. }
  303. mutex_exit(rw_lock_get_mutex(lock));
  304.         ut_ad(rw_lock_validate(lock));
  305. return(success);
  306. }
  307. /**********************************************************************
  308. Releases a shared mode lock. */
  309. UNIV_INLINE
  310. void
  311. rw_lock_s_unlock_func(
  312. /*==================*/
  313. rw_lock_t* lock /* in: rw-lock */
  314. #ifdef UNIV_SYNC_DEBUG
  315. ,ulint pass /* in: pass value; != 0, if the lock may have
  316. been passed to another thread to unlock */
  317. #endif
  318. )
  319. {
  320. mutex_t* mutex = &(lock->mutex);
  321. ibool sg  = FALSE;
  322.         /* Acquire the mutex protecting the rw-lock fields */
  323. mutex_enter(mutex);
  324. /* Reset the shared lock by decrementing the reader count */
  325. ut_ad(lock->reader_count > 0);
  326. lock->reader_count--;
  327. #ifdef UNIV_SYNC_DEBUG
  328. rw_lock_remove_debug_info(lock, pass, RW_LOCK_SHARED);
  329. #endif
  330. /* If there may be waiters and this was the last s-lock,
  331. signal the object */
  332. if (lock->waiters && (lock->reader_count == 0)) {
  333.         sg = TRUE;
  334. rw_lock_set_waiters(lock, 0);
  335. }
  336. mutex_exit(mutex);
  337. if (sg == TRUE) {
  338. sync_array_signal_object(sync_primary_wait_array, lock);
  339. }
  340.         ut_ad(rw_lock_validate(lock));
  341. #ifdef UNIV_SYNC_PERF_STAT
  342. rw_s_exit_count++;
  343. #endif
  344. }
  345. /**********************************************************************
  346. Releases a shared mode lock when we know there are no waiters and none
  347. else will access the lock during the time this function is executed. */
  348. UNIV_INLINE
  349. void
  350. rw_lock_s_unlock_direct(
  351. /*====================*/
  352. rw_lock_t* lock) /* in: rw-lock */
  353. {
  354. /* Reset the shared lock by decrementing the reader count */
  355. ut_ad(lock->reader_count > 0);
  356. lock->reader_count--;
  357. #ifdef UNIV_SYNC_DEBUG
  358. rw_lock_remove_debug_info(lock, 0, RW_LOCK_SHARED);
  359. #endif
  360. ut_ad(!lock->waiters);
  361.         ut_ad(rw_lock_validate(lock));
  362. #ifdef UNIV_SYNC_PERF_STAT
  363. rw_s_exit_count++;
  364. #endif
  365. }
  366. /**********************************************************************
  367. Releases an exclusive mode lock. */
  368. UNIV_INLINE
  369. void
  370. rw_lock_x_unlock_func(
  371. /*==================*/
  372. rw_lock_t* lock /* in: rw-lock */
  373. #ifdef UNIV_SYNC_DEBUG
  374. ,ulint pass /* in: pass value; != 0, if the lock may have
  375. been passed to another thread to unlock */
  376. #endif
  377. )
  378. {
  379. ibool sg  = FALSE;
  380.         /* Acquire the mutex protecting the rw-lock fields */
  381. mutex_enter(&(lock->mutex));
  382. /* Reset the exclusive lock if this thread no longer has an x-mode
  383. lock */
  384. ut_ad(lock->writer_count > 0);
  385. lock->writer_count--;
  386. if (lock->writer_count == 0) {
  387. rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED);
  388. }
  389. #ifdef UNIV_SYNC_DEBUG
  390. rw_lock_remove_debug_info(lock, pass, RW_LOCK_EX);
  391. #endif
  392. /* If there may be waiters, signal the lock */
  393. if (lock->waiters && (lock->writer_count == 0)) {
  394.         sg = TRUE;
  395. rw_lock_set_waiters(lock, 0);
  396. }
  397. mutex_exit(&(lock->mutex));
  398. if (sg == TRUE) {
  399. sync_array_signal_object(sync_primary_wait_array, lock);
  400. }
  401.         ut_ad(rw_lock_validate(lock));
  402. #ifdef UNIV_SYNC_PERF_STAT
  403. rw_x_exit_count++;
  404. #endif
  405. }
  406. /**********************************************************************
  407. Releases an exclusive mode lock when we know there are no waiters, and
  408. none else will access the lock durint the time this function is executed. */
  409. UNIV_INLINE
  410. void
  411. rw_lock_x_unlock_direct(
  412. /*====================*/
  413. rw_lock_t* lock) /* in: rw-lock */
  414. {
  415. /* Reset the exclusive lock if this thread no longer has an x-mode
  416. lock */
  417. ut_ad(lock->writer_count > 0);
  418. lock->writer_count--;
  419. if (lock->writer_count == 0) {
  420. rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED);
  421. }
  422. #ifdef UNIV_SYNC_DEBUG
  423. rw_lock_remove_debug_info(lock, 0, RW_LOCK_EX);
  424. #endif
  425. ut_ad(!lock->waiters);
  426.         ut_ad(rw_lock_validate(lock));
  427. #ifdef UNIV_SYNC_PERF_STAT
  428. rw_x_exit_count++;
  429. #endif
  430. }