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.

632 lines
18 KiB

17 years ago
17 years ago
17 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
17 years ago
16 years ago
16 years ago
16 years ago
17 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
15 years ago
15 years ago
16 years ago
16 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
  1. /*****************************************************************************
  2. Copyright (c) 1995, 2009, Oracle and/or its affiliates. All Rights Reserved.
  3. Copyright (c) 2008, Google Inc.
  4. Portions of this file contain modifications contributed and copyrighted by
  5. Google, Inc. Those modifications are gratefully acknowledged and are described
  6. briefly in the InnoDB documentation. The contributions by Google are
  7. incorporated with their permission, and subject to the conditions contained in
  8. the file COPYING.Google.
  9. This program is free software; you can redistribute it and/or modify it under
  10. the terms of the GNU General Public License as published by the Free Software
  11. Foundation; version 2 of the License.
  12. This program is distributed in the hope that it will be useful, but WITHOUT
  13. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  14. FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License along with
  16. this program; if not, write to the Free Software Foundation, Inc.,
  17. 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
  18. *****************************************************************************/
  19. /**************************************************//**
  20. @file include/sync0sync.ic
  21. Mutex, the basic synchronization primitive
  22. Created 9/5/1995 Heikki Tuuri
  23. *******************************************************/
  24. /******************************************************************//**
  25. Sets the waiters field in a mutex. */
  26. UNIV_INTERN
  27. void
  28. mutex_set_waiters(
  29. /*==============*/
  30. ib_mutex_t* mutex, /*!< in: mutex */
  31. ulint n); /*!< in: value to set */
  32. /******************************************************************//**
  33. Reserves a mutex or a priority mutex for the current thread. If the mutex is
  34. reserved, the function spins a preset time (controlled by SYNC_SPIN_ROUNDS)
  35. waiting for the mutex before suspending the thread. */
  36. UNIV_INTERN
  37. void
  38. mutex_spin_wait(
  39. /*============*/
  40. void* _mutex, /*!< in: pointer to mutex */
  41. bool high_priority, /*!< in: whether the mutex is a
  42. priority mutex with high priority
  43. specified */
  44. const char* file_name, /*!< in: file name where mutex
  45. requested */
  46. ulint line); /*!< in: line where requested */
  47. #ifdef UNIV_SYNC_DEBUG
  48. /******************************************************************//**
  49. Sets the debug information for a reserved mutex. */
  50. UNIV_INTERN
  51. void
  52. mutex_set_debug_info(
  53. /*=================*/
  54. ib_mutex_t* mutex, /*!< in: mutex */
  55. const char* file_name, /*!< in: file where requested */
  56. ulint line); /*!< in: line where requested */
  57. #endif /* UNIV_SYNC_DEBUG */
  58. /******************************************************************//**
  59. Releases the threads waiting in the primary wait array for this mutex. */
  60. UNIV_INTERN
  61. void
  62. mutex_signal_object(
  63. /*================*/
  64. ib_mutex_t* mutex); /*!< in: mutex */
  65. /******************************************************************//**
  66. Performs an atomic test-and-set instruction to the lock_word field of a
  67. mutex.
  68. @return the previous value of lock_word: 0 or 1 */
  69. UNIV_INLINE
  70. byte
  71. ib_mutex_test_and_set(
  72. /*===============*/
  73. ib_mutex_t* mutex) /*!< in: mutex */
  74. {
  75. #if defined(HAVE_ATOMIC_BUILTINS)
  76. return(os_atomic_test_and_set_byte(&mutex->lock_word, 1));
  77. #else
  78. ibool ret;
  79. ret = os_fast_mutex_trylock(&(mutex->os_fast_mutex));
  80. if (ret == 0) {
  81. /* We check that os_fast_mutex_trylock does not leak
  82. and allow race conditions */
  83. ut_a(mutex->lock_word == 0);
  84. mutex->lock_word = 1;
  85. }
  86. return((byte) ret);
  87. #endif
  88. }
  89. /******************************************************************//**
  90. Performs a reset instruction to the lock_word field of a mutex. This
  91. instruction also serializes memory operations to the program order. */
  92. UNIV_INLINE
  93. void
  94. mutex_reset_lock_word(
  95. /*==================*/
  96. ib_mutex_t* mutex) /*!< in: mutex */
  97. {
  98. #if defined(HAVE_ATOMIC_BUILTINS)
  99. /* In theory __sync_lock_release should be used to release the lock.
  100. Unfortunately, it does not work properly alone. The workaround is
  101. that more conservative __sync_lock_test_and_set is used instead. */
  102. os_atomic_test_and_set_byte(&mutex->lock_word, 0);
  103. #else
  104. mutex->lock_word = 0;
  105. os_fast_mutex_unlock(&(mutex->os_fast_mutex));
  106. #endif
  107. }
  108. /******************************************************************//**
  109. Gets the value of the lock word. */
  110. UNIV_INLINE
  111. lock_word_t
  112. mutex_get_lock_word(
  113. /*================*/
  114. const ib_mutex_t* mutex) /*!< in: mutex */
  115. {
  116. ut_ad(mutex);
  117. return(mutex->lock_word);
  118. }
  119. /******************************************************************//**
  120. Gets the waiters field in a mutex.
  121. @return value to set */
  122. UNIV_INLINE
  123. ulint
  124. mutex_get_waiters(
  125. /*==============*/
  126. const ib_mutex_t* mutex) /*!< in: mutex */
  127. {
  128. const volatile ulint* ptr; /*!< declared volatile to ensure that
  129. the value is read from memory */
  130. ut_ad(mutex);
  131. ptr = &(mutex->waiters);
  132. return(*ptr); /* Here we assume that the read of a single
  133. word from memory is atomic */
  134. }
  135. /******************************************************************//**
  136. NOTE! Use the corresponding macro mutex_exit(), not directly this function!
  137. Unlocks a mutex owned by the current thread. */
  138. UNIV_INLINE
  139. void
  140. mutex_exit_func(
  141. /*============*/
  142. ib_mutex_t* mutex) /*!< in: pointer to mutex */
  143. {
  144. ut_ad(mutex_own(mutex));
  145. ut_d(mutex->thread_id = (os_thread_id_t) ULINT_UNDEFINED);
  146. #ifdef UNIV_SYNC_DEBUG
  147. sync_thread_reset_level(mutex);
  148. #endif
  149. mutex_reset_lock_word(mutex);
  150. /* A problem: we assume that mutex_reset_lock word
  151. is a memory barrier, that is when we read the waiters
  152. field next, the read must be serialized in memory
  153. after the reset. A speculative processor might
  154. perform the read first, which could leave a waiting
  155. thread hanging indefinitely.
  156. Our current solution call every second
  157. sync_arr_wake_threads_if_sema_free()
  158. to wake up possible hanging threads if
  159. they are missed in mutex_signal_object. */
  160. if (mutex_get_waiters(mutex) != 0) {
  161. mutex_signal_object(mutex);
  162. }
  163. #ifdef UNIV_SYNC_PERF_STAT
  164. mutex_exit_count++;
  165. #endif
  166. }
  167. /******************************************************************//**
  168. NOTE! Use the corresponding macro mutex_exit(), not directly this function!
  169. Unlocks a priority mutex owned by the current thread. */
  170. UNIV_INLINE
  171. void
  172. mutex_exit_func(
  173. /*============*/
  174. ib_prio_mutex_t* mutex) /*!< in: pointer to mutex */
  175. {
  176. ut_ad(mutex_own(mutex));
  177. ut_d(mutex->base_mutex.thread_id = (os_thread_id_t) ULINT_UNDEFINED);
  178. #ifdef UNIV_SYNC_DEBUG
  179. sync_thread_reset_level(&mutex->base_mutex);
  180. #endif
  181. mutex_reset_lock_word(&mutex->base_mutex);
  182. /* A problem: we assume that mutex_reset_lock word
  183. is a memory barrier, that is when we read the waiters
  184. field next, the read must be serialized in memory
  185. after the reset. A speculative processor might
  186. perform the read first, which could leave a waiting
  187. thread hanging indefinitely.
  188. Our current solution call every second
  189. sync_arr_wake_threads_if_sema_free()
  190. to wake up possible hanging threads if
  191. they are missed in mutex_signal_object. */
  192. /* Wake up any high priority waiters first. */
  193. if (mutex->high_priority_waiters != 0) {
  194. mutex->high_priority_waiters = 0;
  195. os_event_set(mutex->high_priority_event);
  196. sync_array_object_signalled();
  197. } else if (mutex_get_waiters(&mutex->base_mutex) != 0) {
  198. mutex_signal_object(&mutex->base_mutex);
  199. }
  200. #ifdef UNIV_SYNC_PERF_STAT
  201. mutex_exit_count++;
  202. #endif
  203. }
  204. /******************************************************************//**
  205. Locks a mutex for the current thread. If the mutex is reserved, the function
  206. spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting for the mutex
  207. before suspending the thread. */
  208. UNIV_INLINE
  209. void
  210. mutex_enter_func(
  211. /*=============*/
  212. ib_mutex_t* mutex, /*!< in: pointer to mutex */
  213. const char* file_name, /*!< in: file name where locked */
  214. ulint line) /*!< in: line where locked */
  215. {
  216. ut_ad(mutex_validate(mutex));
  217. ut_ad(!mutex_own(mutex));
  218. /* Note that we do not peek at the value of lock_word before trying
  219. the atomic test_and_set; we could peek, and possibly save time. */
  220. if (!ib_mutex_test_and_set(mutex)) {
  221. ut_d(mutex->thread_id = os_thread_get_curr_id());
  222. #ifdef UNIV_SYNC_DEBUG
  223. mutex_set_debug_info(mutex, file_name, line);
  224. #endif
  225. return; /* Succeeded! */
  226. }
  227. mutex_spin_wait(mutex, false, file_name, line);
  228. }
  229. /******************************************************************//**
  230. NOTE! Use the corresponding macro in the header file, not this function
  231. directly. Locks a priority mutex for the current thread. If the mutex is
  232. reserved the function spins a preset time (controlled by SYNC_SPIN_ROUNDS)
  233. waiting for the mutex before suspending the thread. If the thread is suspended,
  234. the priority argument value determines the relative order for its wake up. Any
  235. IB_HIGH_PRIO waiters will be woken up before any IB_LOW_PRIO waiters. In case
  236. of IB_DEFAULT_PRIO, the relative priority will be set according to
  237. srv_current_thread_priority. */
  238. UNIV_INLINE
  239. void
  240. mutex_enter_func(
  241. /*=============*/
  242. ib_prio_mutex_t* mutex, /*!< in: pointer to mutex */
  243. const char* file_name, /*!< in: file name where
  244. locked */
  245. ulint line, /*!< in: line where locked */
  246. enum ib_sync_priority priority)
  247. /*!<in: mutex acquisition
  248. priority */
  249. {
  250. bool high_priority;
  251. ut_ad(mutex_validate(&mutex->base_mutex));
  252. ut_ad(!mutex_own(mutex));
  253. /* Note that we do not peek at the value of lock_word before trying
  254. the atomic test_and_set; we could peek, and possibly save time. */
  255. if (!ib_mutex_test_and_set(&mutex->base_mutex)) {
  256. ut_d(mutex->base_mutex.thread_id = os_thread_get_curr_id());
  257. #ifdef UNIV_SYNC_DEBUG
  258. mutex_set_debug_info(&mutex->base_mutex, file_name, line);
  259. #endif
  260. return; /* Succeeded! */
  261. }
  262. if (UNIV_LIKELY(priority == IB_DEFAULT_PRIO)) {
  263. high_priority = srv_current_thread_priority;
  264. } else {
  265. high_priority = (priority == IB_HIGH_PRIO);
  266. }
  267. mutex_spin_wait(mutex, high_priority, file_name, line);
  268. }
  269. #ifdef UNIV_PFS_MUTEX
  270. /******************************************************************//**
  271. NOTE! Please use the corresponding macro mutex_enter(), not directly
  272. this function!
  273. This is a performance schema instrumented wrapper function for
  274. mutex_enter_func(). */
  275. UNIV_INLINE
  276. void
  277. pfs_mutex_enter_func(
  278. /*=================*/
  279. ib_mutex_t* mutex, /*!< in: pointer to mutex */
  280. const char* file_name, /*!< in: file name where locked */
  281. ulint line) /*!< in: line where locked */
  282. {
  283. if (mutex->pfs_psi != NULL) {
  284. PSI_mutex_locker* locker;
  285. PSI_mutex_locker_state state;
  286. locker = PSI_MUTEX_CALL(start_mutex_wait)(
  287. &state, mutex->pfs_psi,
  288. PSI_MUTEX_LOCK, file_name, line);
  289. mutex_enter_func(mutex, file_name, line);
  290. if (locker != NULL) {
  291. PSI_MUTEX_CALL(end_mutex_wait)(locker, 0);
  292. }
  293. } else {
  294. mutex_enter_func(mutex, file_name, line);
  295. }
  296. }
  297. /******************************************************************//**
  298. NOTE! Please use the corresponding macro mutex_enter(), not directly
  299. this function!
  300. This is a performance schema instrumented wrapper function for
  301. mutex_enter_func(). */
  302. UNIV_INLINE
  303. void
  304. pfs_mutex_enter_func(
  305. /*=================*/
  306. ib_prio_mutex_t* mutex, /*!< in: pointer to mutex */
  307. const char* file_name, /*!< in: file name where
  308. locked */
  309. ulint line, /*!< in: line where locked */
  310. enum ib_sync_priority priority) /*!<in: mutex acquisition
  311. priority */
  312. {
  313. if (mutex->base_mutex.pfs_psi != NULL) {
  314. PSI_mutex_locker* locker;
  315. PSI_mutex_locker_state state;
  316. locker = PSI_MUTEX_CALL(start_mutex_wait)(
  317. &state, mutex->base_mutex.pfs_psi,
  318. PSI_MUTEX_LOCK, file_name, line);
  319. mutex_enter_func(mutex, file_name, line, priority);
  320. if (locker != NULL) {
  321. PSI_MUTEX_CALL(end_mutex_wait)(locker, 0);
  322. }
  323. } else {
  324. mutex_enter_func(mutex, file_name, line, priority);
  325. }
  326. }
  327. /********************************************************************//**
  328. NOTE! Please use the corresponding macro mutex_enter_nowait(), not directly
  329. this function!
  330. This is a performance schema instrumented wrapper function for
  331. mutex_enter_nowait_func.
  332. @return 0 if succeed, 1 if not */
  333. UNIV_INLINE
  334. ulint
  335. pfs_mutex_enter_nowait_func(
  336. /*========================*/
  337. ib_mutex_t* mutex, /*!< in: pointer to mutex */
  338. const char* file_name, /*!< in: file name where mutex
  339. requested */
  340. ulint line) /*!< in: line where requested */
  341. {
  342. ulint ret;
  343. if (mutex->pfs_psi != NULL) {
  344. PSI_mutex_locker* locker;
  345. PSI_mutex_locker_state state;
  346. locker = PSI_MUTEX_CALL(start_mutex_wait)(
  347. &state, mutex->pfs_psi,
  348. PSI_MUTEX_TRYLOCK, file_name, line);
  349. ret = mutex_enter_nowait_func(mutex, file_name, line);
  350. if (locker != NULL) {
  351. PSI_MUTEX_CALL(end_mutex_wait)(locker, (int) ret);
  352. }
  353. } else {
  354. ret = mutex_enter_nowait_func(mutex, file_name, line);
  355. }
  356. return(ret);
  357. }
  358. /********************************************************************//**
  359. NOTE! Please use the corresponding macro mutex_enter_nowait(), not directly
  360. this function!
  361. This is a performance schema instrumented wrapper function for
  362. mutex_enter_nowait_func.
  363. @return 0 if succeed, 1 if not */
  364. UNIV_INLINE
  365. ulint
  366. pfs_mutex_enter_nowait_func(
  367. /*========================*/
  368. ib_prio_mutex_t* mutex, /*!< in: pointer to mutex */
  369. const char* file_name, /*!< in: file name where mutex
  370. requested */
  371. ulint line) /*!< in: line where
  372. requested */
  373. {
  374. return pfs_mutex_enter_nowait_func(&mutex->base_mutex, file_name,
  375. line);
  376. }
  377. /******************************************************************//**
  378. NOTE! Please use the corresponding macro mutex_exit(), not directly
  379. this function!
  380. A wrap function of mutex_exit_func() with performance schema instrumentation.
  381. Unlocks a mutex owned by the current thread. */
  382. UNIV_INLINE
  383. void
  384. pfs_mutex_exit_func(
  385. /*================*/
  386. ib_mutex_t* mutex) /*!< in: pointer to mutex */
  387. {
  388. if (mutex->pfs_psi != NULL) {
  389. PSI_MUTEX_CALL(unlock_mutex)(mutex->pfs_psi);
  390. }
  391. mutex_exit_func(mutex);
  392. }
  393. /******************************************************************//**
  394. NOTE! Please use the corresponding macro mutex_exit(), not directly
  395. this function!
  396. A wrap function of mutex_exit_func() with peformance schema instrumentation.
  397. Unlocks a priority mutex owned by the current thread. */
  398. UNIV_INLINE
  399. void
  400. pfs_mutex_exit_func(
  401. /*================*/
  402. ib_prio_mutex_t* mutex) /*!< in: pointer to mutex */
  403. {
  404. if (mutex->base_mutex.pfs_psi != NULL) {
  405. PSI_MUTEX_CALL(unlock_mutex)(mutex->base_mutex.pfs_psi);
  406. }
  407. mutex_exit_func(mutex);
  408. }
  409. /******************************************************************//**
  410. NOTE! Please use the corresponding macro mutex_create(), not directly
  411. this function!
  412. A wrapper function for mutex_create_func(), registers the mutex
  413. with performance schema if "UNIV_PFS_MUTEX" is defined when
  414. creating the mutex */
  415. UNIV_INLINE
  416. void
  417. pfs_mutex_create_func(
  418. /*==================*/
  419. mysql_pfs_key_t key, /*!< in: Performance Schema key */
  420. ib_mutex_t* mutex, /*!< in: pointer to memory */
  421. # ifdef UNIV_DEBUG
  422. # ifdef UNIV_SYNC_DEBUG
  423. ulint level, /*!< in: level */
  424. # endif /* UNIV_SYNC_DEBUG */
  425. const char* cfile_name, /*!< in: file name where created */
  426. ulint cline, /*!< in: file line where created */
  427. # endif /* UNIV_DEBUG */
  428. const char* cmutex_name) /*!< in: mutex name */
  429. {
  430. mutex->pfs_psi = PSI_MUTEX_CALL(init_mutex)(key, mutex);
  431. mutex_create_func(mutex,
  432. # ifdef UNIV_DEBUG
  433. # ifdef UNIV_SYNC_DEBUG
  434. level,
  435. # endif /* UNIV_SYNC_DEBUG */
  436. cfile_name,
  437. cline,
  438. # endif /* UNIV_DEBUG */
  439. cmutex_name);
  440. }
  441. /******************************************************************//**
  442. NOTE! Please use the corresponding macro mutex_create(), not directly
  443. this function!
  444. A wrapper function for mutex_create_func(), registers the mutex
  445. with peformance schema if "UNIV_PFS_MUTEX" is defined when
  446. creating the performance mutex */
  447. UNIV_INLINE
  448. void
  449. pfs_mutex_create_func(
  450. /*==================*/
  451. PSI_mutex_key key, /*!< in: Performance Schema
  452. key */
  453. ib_prio_mutex_t* mutex, /*!< in: pointer to memory */
  454. # ifdef UNIV_DEBUG
  455. # ifdef UNIV_SYNC_DEBUG
  456. ulint level, /*!< in: level */
  457. # endif /* UNIV_SYNC_DEBUG */
  458. const char* cfile_name, /*!< in: file name where
  459. created */
  460. ulint cline, /*!< in: file line where
  461. created */
  462. # endif /* UNIV_DEBUG */
  463. const char* cmutex_name)
  464. {
  465. mutex->base_mutex.pfs_psi = PSI_MUTEX_CALL(init_mutex)(key, mutex);
  466. mutex_create_func(mutex,
  467. # ifdef UNIV_DEBUG
  468. # ifdef UNIV_SYNC_DEBUG
  469. level,
  470. # endif /* UNIV_SYNC_DEBUG */
  471. cfile_name,
  472. cline,
  473. # endif /* UNIV_DEBUG */
  474. cmutex_name);
  475. }
  476. /******************************************************************//**
  477. NOTE! Please use the corresponding macro mutex_free(), not directly
  478. this function!
  479. Wrapper function for mutex_free_func(). Also destroys the performance
  480. schema probes when freeing the mutex */
  481. UNIV_INLINE
  482. void
  483. pfs_mutex_free_func(
  484. /*================*/
  485. ib_mutex_t* mutex) /*!< in: mutex */
  486. {
  487. if (mutex->pfs_psi != NULL) {
  488. PSI_MUTEX_CALL(destroy_mutex)(mutex->pfs_psi);
  489. mutex->pfs_psi = NULL;
  490. }
  491. mutex_free_func(mutex);
  492. }
  493. /******************************************************************//**
  494. NOTE! Please use the corresponding macro mutex_free(), not directly
  495. this function!
  496. Wrapper function for mutex_free_func(). Also destroys the performance
  497. schema probes when freeing the priority mutex */
  498. UNIV_INLINE
  499. void
  500. pfs_mutex_free_func(
  501. /*================*/
  502. ib_prio_mutex_t* mutex) /*!< in: mutex */
  503. {
  504. if (mutex->base_mutex.pfs_psi != NULL) {
  505. PSI_MUTEX_CALL(destroy_mutex)(mutex->base_mutex.pfs_psi);
  506. mutex->base_mutex.pfs_psi = NULL;
  507. }
  508. mutex_free_func(mutex);
  509. }
  510. #endif /* UNIV_PFS_MUTEX */
  511. #ifndef HAVE_ATOMIC_BUILTINS
  512. /**********************************************************//**
  513. Function that uses a mutex to decrement a variable atomically */
  514. UNIV_INLINE
  515. void
  516. os_atomic_dec_ulint_func(
  517. /*=====================*/
  518. ib_mutex_t* mutex, /*!< in: mutex guarding the dec */
  519. volatile ulint* var, /*!< in/out: variable to decrement */
  520. ulint delta) /*!< in: delta to decrement */
  521. {
  522. mutex_enter(mutex);
  523. /* I don't think we will encounter a situation where
  524. this check will not be required. */
  525. ut_ad(*var >= delta);
  526. *var -= delta;
  527. mutex_exit(mutex);
  528. }
  529. /**********************************************************//**
  530. Function that uses a mutex to increment a variable atomically */
  531. UNIV_INLINE
  532. void
  533. os_atomic_inc_ulint_func(
  534. /*=====================*/
  535. ib_mutex_t* mutex, /*!< in: mutex guarding the increment */
  536. volatile ulint* var, /*!< in/out: variable to increment */
  537. ulint delta) /*!< in: delta to increment */
  538. {
  539. mutex_enter(mutex);
  540. *var += delta;
  541. mutex_exit(mutex);
  542. }
  543. #endif /* !HAVE_ATOMIC_BUILTINS */