You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

506 lines
18 KiB

20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
  1. /******************************************************
  2. The read-write lock (for threads, not for database transactions)
  3. (c) 1995 Innobase Oy
  4. Created 9/11/1995 Heikki Tuuri
  5. *******************************************************/
  6. #ifndef sync0rw_h
  7. #define sync0rw_h
  8. #include "univ.i"
  9. #include "ut0lst.h"
  10. #include "sync0sync.h"
  11. #include "os0sync.h"
  12. /* The following undef is to prevent a name conflict with a macro
  13. in MySQL: */
  14. #undef rw_lock_t
  15. /* Latch types; these are used also in btr0btr.h: keep the numerical values
  16. smaller than 30 and the order of the numerical values like below! */
  17. #define RW_S_LATCH 1
  18. #define RW_X_LATCH 2
  19. #define RW_NO_LATCH 3
  20. typedef struct rw_lock_struct rw_lock_t;
  21. #ifdef UNIV_SYNC_DEBUG
  22. typedef struct rw_lock_debug_struct rw_lock_debug_t;
  23. #endif /* UNIV_SYNC_DEBUG */
  24. typedef UT_LIST_BASE_NODE_T(rw_lock_t) rw_lock_list_t;
  25. extern rw_lock_list_t rw_lock_list;
  26. extern mutex_t rw_lock_list_mutex;
  27. #ifdef UNIV_SYNC_DEBUG
  28. /* The global mutex which protects debug info lists of all rw-locks.
  29. To modify the debug info list of an rw-lock, this mutex has to be
  30. acquired in addition to the mutex protecting the lock. */
  31. extern mutex_t rw_lock_debug_mutex;
  32. extern os_event_t rw_lock_debug_event; /* If deadlock detection does
  33. not get immediately the mutex it
  34. may wait for this event */
  35. extern ibool rw_lock_debug_waiters; /* This is set to TRUE, if
  36. there may be waiters for the event */
  37. #endif /* UNIV_SYNC_DEBUG */
  38. extern ulint rw_s_system_call_count;
  39. extern ulint rw_s_spin_wait_count;
  40. extern ulint rw_s_exit_count;
  41. extern ulint rw_s_os_wait_count;
  42. extern ulint rw_x_system_call_count;
  43. extern ulint rw_x_spin_wait_count;
  44. extern ulint rw_x_os_wait_count;
  45. extern ulint rw_x_exit_count;
  46. /**********************************************************************
  47. Creates, or rather, initializes an rw-lock object in a specified memory
  48. location (which must be appropriately aligned). The rw-lock is initialized
  49. to the non-locked state. Explicit freeing of the rw-lock with rw_lock_free
  50. is necessary only if the memory block containing it is freed. */
  51. #ifdef UNIV_DEBUG
  52. # ifdef UNIV_SYNC_DEBUG
  53. # define rw_lock_create(L, level) \
  54. rw_lock_create_func((L), (level), #L, __FILE__, __LINE__)
  55. # else /* UNIV_SYNC_DEBUG */
  56. # define rw_lock_create(L, level) \
  57. rw_lock_create_func((L), #L, __FILE__, __LINE__)
  58. # endif /* UNIV_SYNC_DEBUG */
  59. #else /* UNIV_DEBUG */
  60. # define rw_lock_create(L, level) \
  61. rw_lock_create_func((L), __FILE__, __LINE__)
  62. #endif /* UNIV_DEBUG */
  63. /**********************************************************************
  64. Creates, or rather, initializes an rw-lock object in a specified memory
  65. location (which must be appropriately aligned). The rw-lock is initialized
  66. to the non-locked state. Explicit freeing of the rw-lock with rw_lock_free
  67. is necessary only if the memory block containing it is freed. */
  68. void
  69. rw_lock_create_func(
  70. /*================*/
  71. rw_lock_t* lock, /* in: pointer to memory */
  72. #ifdef UNIV_DEBUG
  73. # ifdef UNIV_SYNC_DEBUG
  74. ulint level, /* in: level */
  75. # endif /* UNIV_SYNC_DEBUG */
  76. const char* cmutex_name, /* in: mutex name */
  77. #endif /* UNIV_DEBUG */
  78. const char* cfile_name, /* in: file name where created */
  79. ulint cline); /* in: file line where created */
  80. /**********************************************************************
  81. Calling this function is obligatory only if the memory buffer containing
  82. the rw-lock is freed. Removes an rw-lock object from the global list. The
  83. rw-lock is checked to be in the non-locked state. */
  84. void
  85. rw_lock_free(
  86. /*=========*/
  87. rw_lock_t* lock); /* in: rw-lock */
  88. #ifdef UNIV_DEBUG
  89. /**********************************************************************
  90. Checks that the rw-lock has been initialized and that there are no
  91. simultaneous shared and exclusive locks. */
  92. ibool
  93. rw_lock_validate(
  94. /*=============*/
  95. rw_lock_t* lock);
  96. #endif /* UNIV_DEBUG */
  97. /******************************************************************
  98. NOTE! The following macros should be used in rw s-locking, not the
  99. corresponding function. */
  100. #define rw_lock_s_lock(M) rw_lock_s_lock_func(\
  101. (M), 0, __FILE__, __LINE__)
  102. /******************************************************************
  103. NOTE! The following macros should be used in rw s-locking, not the
  104. corresponding function. */
  105. #define rw_lock_s_lock_gen(M, P) rw_lock_s_lock_func(\
  106. (M), (P), __FILE__, __LINE__)
  107. /******************************************************************
  108. NOTE! The following macros should be used in rw s-locking, not the
  109. corresponding function. */
  110. #define rw_lock_s_lock_nowait(M) rw_lock_s_lock_func_nowait(\
  111. (M), __FILE__, __LINE__)
  112. /**********************************************************************
  113. NOTE! Use the corresponding macro, not directly this function, except if
  114. you supply the file name and line number. Lock an rw-lock in shared mode
  115. for the current thread. If the rw-lock is locked in exclusive mode, or
  116. there is an exclusive lock request waiting, the function spins a preset
  117. time (controlled by SYNC_SPIN_ROUNDS), waiting for the lock, before
  118. suspending the thread. */
  119. UNIV_INLINE
  120. void
  121. rw_lock_s_lock_func(
  122. /*================*/
  123. rw_lock_t* lock, /* in: pointer to rw-lock */
  124. ulint pass, /* in: pass value; != 0, if the lock will
  125. be passed to another thread to unlock */
  126. const char* file_name,/* in: file name where lock requested */
  127. ulint line); /* in: line where requested */
  128. /**********************************************************************
  129. NOTE! Use the corresponding macro, not directly this function, except if
  130. you supply the file name and line number. Lock an rw-lock in shared mode
  131. for the current thread if the lock can be acquired immediately. */
  132. UNIV_INLINE
  133. ibool
  134. rw_lock_s_lock_func_nowait(
  135. /*=======================*/
  136. /* out: TRUE if success */
  137. rw_lock_t* lock, /* in: pointer to rw-lock */
  138. const char* file_name,/* in: file name where lock requested */
  139. ulint line); /* in: line where requested */
  140. /**********************************************************************
  141. NOTE! Use the corresponding macro, not directly this function! Lock an
  142. rw-lock in exclusive mode for the current thread if the lock can be
  143. obtained immediately. */
  144. UNIV_INLINE
  145. ibool
  146. rw_lock_x_lock_func_nowait(
  147. /*=======================*/
  148. /* out: TRUE if success */
  149. rw_lock_t* lock, /* in: pointer to rw-lock */
  150. const char* file_name,/* in: file name where lock requested */
  151. ulint line); /* in: line where requested */
  152. /**********************************************************************
  153. Releases a shared mode lock. */
  154. UNIV_INLINE
  155. void
  156. rw_lock_s_unlock_func(
  157. /*==================*/
  158. rw_lock_t* lock /* in: rw-lock */
  159. #ifdef UNIV_SYNC_DEBUG
  160. ,ulint pass /* in: pass value; != 0, if the lock may have
  161. been passed to another thread to unlock */
  162. #endif
  163. );
  164. /***********************************************************************
  165. Releases a shared mode lock. */
  166. #ifdef UNIV_SYNC_DEBUG
  167. #define rw_lock_s_unlock(L) rw_lock_s_unlock_func(L, 0)
  168. #else
  169. #define rw_lock_s_unlock(L) rw_lock_s_unlock_func(L)
  170. #endif
  171. /***********************************************************************
  172. Releases a shared mode lock. */
  173. #ifdef UNIV_SYNC_DEBUG
  174. #define rw_lock_s_unlock_gen(L, P) rw_lock_s_unlock_func(L, P)
  175. #else
  176. #define rw_lock_s_unlock_gen(L, P) rw_lock_s_unlock_func(L)
  177. #endif
  178. /******************************************************************
  179. NOTE! The following macro should be used in rw x-locking, not the
  180. corresponding function. */
  181. #define rw_lock_x_lock(M) rw_lock_x_lock_func(\
  182. (M), 0, __FILE__, __LINE__)
  183. /******************************************************************
  184. NOTE! The following macro should be used in rw x-locking, not the
  185. corresponding function. */
  186. #define rw_lock_x_lock_gen(M, P) rw_lock_x_lock_func(\
  187. (M), (P), __FILE__, __LINE__)
  188. /******************************************************************
  189. NOTE! The following macros should be used in rw x-locking, not the
  190. corresponding function. */
  191. #define rw_lock_x_lock_nowait(M) rw_lock_x_lock_func_nowait(\
  192. (M), __FILE__, __LINE__)
  193. /**********************************************************************
  194. NOTE! Use the corresponding macro, not directly this function! Lock an
  195. rw-lock in exclusive mode for the current thread. If the rw-lock is locked
  196. in shared or exclusive mode, or there is an exclusive lock request waiting,
  197. the function spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting
  198. for the lock, before suspending the thread. If the same thread has an x-lock
  199. on the rw-lock, locking succeed, with the following exception: if pass != 0,
  200. only a single x-lock may be taken on the lock. NOTE: If the same thread has
  201. an s-lock, locking does not succeed! */
  202. void
  203. rw_lock_x_lock_func(
  204. /*================*/
  205. rw_lock_t* lock, /* in: pointer to rw-lock */
  206. ulint pass, /* in: pass value; != 0, if the lock will
  207. be passed to another thread to unlock */
  208. const char* file_name,/* in: file name where lock requested */
  209. ulint line); /* in: line where requested */
  210. /**********************************************************************
  211. Releases an exclusive mode lock. */
  212. UNIV_INLINE
  213. void
  214. rw_lock_x_unlock_func(
  215. /*==================*/
  216. rw_lock_t* lock /* in: rw-lock */
  217. #ifdef UNIV_SYNC_DEBUG
  218. ,ulint pass /* in: pass value; != 0, if the lock may have
  219. been passed to another thread to unlock */
  220. #endif
  221. );
  222. /***********************************************************************
  223. Releases an exclusive mode lock. */
  224. #ifdef UNIV_SYNC_DEBUG
  225. #define rw_lock_x_unlock(L) rw_lock_x_unlock_func(L, 0)
  226. #else
  227. #define rw_lock_x_unlock(L) rw_lock_x_unlock_func(L)
  228. #endif
  229. /***********************************************************************
  230. Releases an exclusive mode lock. */
  231. #ifdef UNIV_SYNC_DEBUG
  232. #define rw_lock_x_unlock_gen(L, P) rw_lock_x_unlock_func(L, P)
  233. #else
  234. #define rw_lock_x_unlock_gen(L, P) rw_lock_x_unlock_func(L)
  235. #endif
  236. /**********************************************************************
  237. Low-level function which locks an rw-lock in s-mode when we know that it
  238. is possible and none else is currently accessing the rw-lock structure.
  239. Then we can do the locking without reserving the mutex. */
  240. UNIV_INLINE
  241. void
  242. rw_lock_s_lock_direct(
  243. /*==================*/
  244. rw_lock_t* lock, /* in: pointer to rw-lock */
  245. const char* file_name, /* in: file name where requested */
  246. ulint line /* in: line where lock requested */
  247. );
  248. /**********************************************************************
  249. Low-level function which locks an rw-lock in x-mode when we know that it
  250. is not locked and none else is currently accessing the rw-lock structure.
  251. Then we can do the locking without reserving the mutex. */
  252. UNIV_INLINE
  253. void
  254. rw_lock_x_lock_direct(
  255. /*==================*/
  256. rw_lock_t* lock, /* in: pointer to rw-lock */
  257. const char* file_name, /* in: file name where requested */
  258. ulint line /* in: line where lock requested */
  259. );
  260. /**********************************************************************
  261. This function is used in the insert buffer to move the ownership of an
  262. x-latch on a buffer frame to the current thread. The x-latch was set by
  263. the buffer read operation and it protected the buffer frame while the
  264. read was done. The ownership is moved because we want that the current
  265. thread is able to acquire a second x-latch which is stored in an mtr.
  266. This, in turn, is needed to pass the debug checks of index page
  267. operations. */
  268. void
  269. rw_lock_x_lock_move_ownership(
  270. /*==========================*/
  271. rw_lock_t* lock); /* in: lock which was x-locked in the
  272. buffer read */
  273. /**********************************************************************
  274. Releases a shared mode lock when we know there are no waiters and none
  275. else will access the lock during the time this function is executed. */
  276. UNIV_INLINE
  277. void
  278. rw_lock_s_unlock_direct(
  279. /*====================*/
  280. rw_lock_t* lock); /* in: rw-lock */
  281. /**********************************************************************
  282. Releases an exclusive mode lock when we know there are no waiters, and
  283. none else will access the lock durint the time this function is executed. */
  284. UNIV_INLINE
  285. void
  286. rw_lock_x_unlock_direct(
  287. /*====================*/
  288. rw_lock_t* lock); /* in: rw-lock */
  289. /**********************************************************************
  290. Returns the value of writer_count for the lock. Does not reserve the lock
  291. mutex, so the caller must be sure it is not changed during the call. */
  292. UNIV_INLINE
  293. ulint
  294. rw_lock_get_x_lock_count(
  295. /*=====================*/
  296. /* out: value of writer_count */
  297. rw_lock_t* lock); /* in: rw-lock */
  298. /************************************************************************
  299. Accessor functions for rw lock. */
  300. UNIV_INLINE
  301. ulint
  302. rw_lock_get_waiters(
  303. /*================*/
  304. rw_lock_t* lock);
  305. UNIV_INLINE
  306. ulint
  307. rw_lock_get_writer(
  308. /*===============*/
  309. rw_lock_t* lock);
  310. UNIV_INLINE
  311. ulint
  312. rw_lock_get_reader_count(
  313. /*=====================*/
  314. rw_lock_t* lock);
  315. #ifdef UNIV_SYNC_DEBUG
  316. /**********************************************************************
  317. Checks if the thread has locked the rw-lock in the specified mode, with
  318. the pass value == 0. */
  319. ibool
  320. rw_lock_own(
  321. /*========*/
  322. rw_lock_t* lock, /* in: rw-lock */
  323. ulint lock_type); /* in: lock type: RW_LOCK_SHARED,
  324. RW_LOCK_EX */
  325. #endif /* UNIV_SYNC_DEBUG */
  326. /**********************************************************************
  327. Checks if somebody has locked the rw-lock in the specified mode. */
  328. ibool
  329. rw_lock_is_locked(
  330. /*==============*/
  331. rw_lock_t* lock, /* in: rw-lock */
  332. ulint lock_type); /* in: lock type: RW_LOCK_SHARED,
  333. RW_LOCK_EX */
  334. #ifdef UNIV_SYNC_DEBUG
  335. /*******************************************************************
  336. Prints debug info of an rw-lock. */
  337. void
  338. rw_lock_print(
  339. /*==========*/
  340. rw_lock_t* lock); /* in: rw-lock */
  341. /*******************************************************************
  342. Prints debug info of currently locked rw-locks. */
  343. void
  344. rw_lock_list_print_info(
  345. /*====================*/
  346. FILE* file); /* in: file where to print */
  347. /*******************************************************************
  348. Returns the number of currently locked rw-locks.
  349. Works only in the debug version. */
  350. ulint
  351. rw_lock_n_locked(void);
  352. /*==================*/
  353. /*#####################################################################*/
  354. /**********************************************************************
  355. Acquires the debug mutex. We cannot use the mutex defined in sync0sync,
  356. because the debug mutex is also acquired in sync0arr while holding the OS
  357. mutex protecting the sync array, and the ordinary mutex_enter might
  358. recursively call routines in sync0arr, leading to a deadlock on the OS
  359. mutex. */
  360. void
  361. rw_lock_debug_mutex_enter(void);
  362. /*==========================*/
  363. /**********************************************************************
  364. Releases the debug mutex. */
  365. void
  366. rw_lock_debug_mutex_exit(void);
  367. /*==========================*/
  368. /*************************************************************************
  369. Prints info of a debug struct. */
  370. void
  371. rw_lock_debug_print(
  372. /*================*/
  373. rw_lock_debug_t* info); /* in: debug struct */
  374. #endif /* UNIV_SYNC_DEBUG */
  375. /* NOTE! The structure appears here only for the compiler to know its size.
  376. Do not use its fields directly! The structure used in the spin lock
  377. implementation of a read-write lock. Several threads may have a shared lock
  378. simultaneously in this lock, but only one writer may have an exclusive lock,
  379. in which case no shared locks are allowed. To prevent starving of a writer
  380. blocked by readers, a writer may queue for the lock by setting the writer
  381. field. Then no new readers are allowed in. */
  382. struct rw_lock_struct {
  383. os_event_t event; /* Used by sync0arr.c for thread queueing */
  384. #ifdef __WIN__
  385. os_event_t wait_ex_event; /* This windows specific event is
  386. used by the thread which has set the
  387. lock state to RW_LOCK_WAIT_EX. The
  388. rw_lock design guarantees that this
  389. thread will be the next one to proceed
  390. once the current the event gets
  391. signalled. See LEMMA 2 in sync0sync.c */
  392. #endif
  393. ulint reader_count; /* Number of readers who have locked this
  394. lock in the shared mode */
  395. ulint writer; /* This field is set to RW_LOCK_EX if there
  396. is a writer owning the lock (in exclusive
  397. mode), RW_LOCK_WAIT_EX if a writer is
  398. queueing for the lock, and
  399. RW_LOCK_NOT_LOCKED, otherwise. */
  400. os_thread_id_t writer_thread;
  401. /* Thread id of a possible writer thread */
  402. ulint writer_count; /* Number of times the same thread has
  403. recursively locked the lock in the exclusive
  404. mode */
  405. mutex_t mutex; /* The mutex protecting rw_lock_struct */
  406. ulint pass; /* Default value 0. This is set to some
  407. value != 0 given by the caller of an x-lock
  408. operation, if the x-lock is to be passed to
  409. another thread to unlock (which happens in
  410. asynchronous i/o). */
  411. ulint waiters; /* This ulint is set to 1 if there are
  412. waiters (readers or writers) in the global
  413. wait array, waiting for this rw_lock.
  414. Otherwise, == 0. */
  415. UT_LIST_NODE_T(rw_lock_t) list;
  416. /* All allocated rw locks are put into a
  417. list */
  418. #ifdef UNIV_SYNC_DEBUG
  419. UT_LIST_BASE_NODE_T(rw_lock_debug_t) debug_list;
  420. /* In the debug version: pointer to the debug
  421. info list of the lock */
  422. ulint level; /* Level in the global latching order. */
  423. #endif /* UNIV_SYNC_DEBUG */
  424. const char* cfile_name;/* File name where lock created */
  425. const char* last_s_file_name;/* File name where last s-locked */
  426. const char* last_x_file_name;/* File name where last x-locked */
  427. ibool writer_is_wait_ex;
  428. /* This is TRUE if the writer field is
  429. RW_LOCK_WAIT_EX; this field is located far
  430. from the memory update hotspot fields which
  431. are at the start of this struct, thus we can
  432. peek this field without causing much memory
  433. bus traffic */
  434. unsigned cline:14; /* Line where created */
  435. unsigned last_s_line:14; /* Line number where last time s-locked */
  436. unsigned last_x_line:14; /* Line number where last time x-locked */
  437. ulint magic_n;
  438. };
  439. #define RW_LOCK_MAGIC_N 22643
  440. #ifdef UNIV_SYNC_DEBUG
  441. /* The structure for storing debug info of an rw-lock */
  442. struct rw_lock_debug_struct {
  443. os_thread_id_t thread_id; /* The thread id of the thread which
  444. locked the rw-lock */
  445. ulint pass; /* Pass value given in the lock operation */
  446. ulint lock_type; /* Type of the lock: RW_LOCK_EX,
  447. RW_LOCK_SHARED, RW_LOCK_WAIT_EX */
  448. const char* file_name;/* File name where the lock was obtained */
  449. ulint line; /* Line where the rw-lock was locked */
  450. UT_LIST_NODE_T(rw_lock_debug_t) list;
  451. /* Debug structs are linked in a two-way
  452. list */
  453. };
  454. #endif /* UNIV_SYNC_DEBUG */
  455. #ifndef UNIV_NONINL
  456. #include "sync0rw.ic"
  457. #endif
  458. #endif