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

MySQL数据库

开发平台:

Visual C++

  1. /******************************************************
  2. The wait array used in synchronization primitives
  3. (c) 1995 Innobase Oy
  4. Created 9/5/1995 Heikki Tuuri
  5. *******************************************************/
  6. #include "sync0arr.h"
  7. #ifdef UNIV_NONINL
  8. #include "sync0arr.ic"
  9. #endif
  10. #include "sync0sync.h"
  11. #include "sync0rw.h"
  12. #include "os0sync.h"
  13. /*
  14. WAIT ARRAY
  15. ==========
  16. The wait array consists of cells each of which has an
  17. an operating system event object created for it. The threads
  18. waiting for a mutex, for example, can reserve a cell
  19. in the array and suspend themselves to wait for the event
  20. to become signaled. When using the wait array, remember to make
  21. sure that some thread holding the synchronization object
  22. will eventually know that there is a waiter in the array and
  23. signal the object, to prevent infinite wait.
  24. Why we chose to implement a wait array? First, to make
  25. mutexes fast, we had to code our own implementation of them,
  26. which only in usually uncommon cases resorts to using
  27. slow operating system primitives. Then we had the choice of
  28. assigning a unique OS event for each mutex, which would
  29. be simpler, or using a global wait array. In some operating systems,
  30. the global wait array solution is more efficient and flexible,
  31. because we can do with a very small number of OS events,
  32. say 200. In NT 3.51, allocating events seems to be a quadratic
  33. algorithm, because 10 000 events are created fast, but
  34. 100 000 events takes a couple of minutes to create.
  35. */
  36. /* A cell where an individual thread may wait suspended
  37. until a resource is released. The suspending is implemented
  38. using an operating system event semaphore. */
  39. struct sync_cell_struct {
  40.         void*           wait_object;    /* pointer to the object the
  41.                                         thread is waiting for; if NULL
  42.                                         the cell is free for use */
  43.         ulint request_type; /* lock type requested on the
  44.          object */
  45. char* file; /* in debug version file where
  46. requested */
  47. ulint line; /* in debug version line where
  48. requested */
  49. os_thread_id_t thread; /* thread id of this waiting
  50. thread */
  51. ibool waiting; /* TRUE if the thread has already
  52. called sync_array_event_wait
  53. on this cell but not yet
  54. sync_array_free_cell (which
  55. actually resets wait_object and thus
  56. whole cell) */
  57. ibool event_set; /* TRUE if the event is set */
  58.         os_event_t  event;    /* operating system event
  59.                                         semaphore handle */
  60. };
  61. /* NOTE: It is allowed for a thread to wait
  62. for an event allocated for the array without owning the
  63. protecting mutex (depending on the case: OS or database mutex), but
  64. all changes (set or reset) to the state of the event must be made
  65. while owning the mutex. */
  66. struct sync_array_struct {
  67. ulint n_reserved; /* number of currently reserved
  68. cells in the wait array */
  69. ulint n_cells; /* number of cells in the
  70. wait array */
  71. sync_cell_t* array; /* pointer to wait array */
  72. ulint protection; /* this flag tells which
  73. mutex protects the data */
  74. mutex_t mutex; /* possible database mutex
  75. protecting this data structure */
  76. os_mutex_t os_mutex; /* Possible operating system mutex
  77. protecting the data structure.
  78. As this data structure is used in
  79. constructing the database mutex,
  80. to prevent infinite recursion
  81. in implementation, we fall back to
  82. an OS mutex. */
  83. ulint sg_count; /* count of how many times an
  84. object has been signalled */
  85. ulint res_count; /* count of cell reservations
  86. since creation of the array */
  87. };
  88. /**********************************************************************
  89. This function is called only in the debug version. Detects a deadlock
  90. of one or more threads because of waits of semaphores. */
  91. static
  92. ibool
  93. sync_array_detect_deadlock(
  94. /*=======================*/
  95. /* out: TRUE if deadlock detected */
  96.         sync_array_t* arr, /* in: wait array; NOTE! the caller must
  97.          own the mutex to array */
  98. sync_cell_t* start, /* in: cell where recursive search started */
  99. sync_cell_t* cell, /* in: cell to search */
  100. ulint depth); /* in: recursion depth */
  101. /*********************************************************************
  102. Gets the nth cell in array. */
  103. static
  104. sync_cell_t*
  105. sync_array_get_nth_cell(
  106. /*====================*/
  107. /* out: cell */
  108. sync_array_t* arr, /* in: sync array */
  109. ulint n) /* in: index */
  110. {
  111. ut_a(arr);
  112. ut_a(n < arr->n_cells);
  113. return(arr->array + n);
  114. }
  115. /**********************************************************************
  116. Reserves the mutex semaphore protecting a sync array. */
  117. static
  118. void
  119. sync_array_enter(
  120. /*=============*/
  121. sync_array_t* arr) /* in: sync wait array */
  122. {
  123. ulint protection;
  124. protection = arr->protection;
  125. if (protection == SYNC_ARRAY_OS_MUTEX) {
  126. os_mutex_enter(arr->os_mutex);
  127. } else if (protection == SYNC_ARRAY_MUTEX) {
  128. mutex_enter(&(arr->mutex));
  129. } else {
  130. ut_error;
  131. }
  132. }
  133. /**********************************************************************
  134. Releases the mutex semaphore protecting a sync array. */
  135. static
  136. void
  137. sync_array_exit(
  138. /*============*/
  139. sync_array_t* arr) /* in: sync wait array */
  140. {
  141. ulint protection;
  142. protection = arr->protection;
  143. if (protection == SYNC_ARRAY_OS_MUTEX) {
  144. os_mutex_exit(arr->os_mutex);
  145. } else if (protection == SYNC_ARRAY_MUTEX) {
  146. mutex_exit(&(arr->mutex));
  147. } else {
  148. ut_error;
  149. }
  150. }
  151. /***********************************************************************
  152. Creates a synchronization wait array. It is protected by a mutex
  153. which is automatically reserved when the functions operating on it
  154. are called. */
  155. sync_array_t*
  156. sync_array_create(
  157. /*==============*/
  158. /* out, own: created wait array */
  159. ulint n_cells, /* in: number of cells in the array
  160. to create */
  161. ulint protection) /* in: either SYNC_ARRAY_OS_MUTEX or
  162. SYNC_ARRAY_MUTEX: determines the type
  163. of mutex protecting the data structure */
  164. {
  165. sync_array_t* arr;
  166. sync_cell_t* cell_array;
  167. sync_cell_t* cell;
  168. ulint i;
  169. ut_a(n_cells > 0);
  170. /* Allocate memory for the data structures */
  171. arr = ut_malloc(sizeof(sync_array_t));
  172. cell_array = ut_malloc(sizeof(sync_cell_t) * n_cells);
  173. arr->n_cells = n_cells;
  174. arr->n_reserved = 0;
  175. arr->array = cell_array;
  176. arr->protection = protection;
  177. arr->sg_count = 0;
  178. arr->res_count = 0;
  179.         /* Then create the mutex to protect the wait array complex */
  180. if (protection == SYNC_ARRAY_OS_MUTEX) {
  181. arr->os_mutex = os_mutex_create(NULL);
  182. } else if (protection == SYNC_ARRAY_MUTEX) {
  183. mutex_create(&(arr->mutex));
  184. mutex_set_level(&(arr->mutex), SYNC_NO_ORDER_CHECK);
  185. } else {
  186. ut_error;
  187. }
  188.         for (i = 0; i < n_cells; i++) {
  189. cell = sync_array_get_nth_cell(arr, i);        
  190.                 cell->wait_object = NULL;
  191.                 /* Create an operating system event semaphore with no name */
  192.                 cell->event = os_event_create(NULL);
  193. cell->event_set = FALSE; /* it is created in reset state */
  194. }
  195. return(arr);
  196. }
  197. /**********************************************************************
  198. Frees the resources in a wait array. */
  199. void
  200. sync_array_free(
  201. /*============*/
  202. sync_array_t* arr) /* in, own: sync wait array */
  203. {
  204.         ulint           i;
  205.         sync_cell_t*    cell;
  206. ulint protection;
  207.         ut_a(arr->n_reserved == 0);
  208.         
  209. sync_array_validate(arr);
  210.         
  211.         for (i = 0; i < arr->n_cells; i++) {
  212. cell = sync_array_get_nth_cell(arr, i);        
  213. os_event_free(cell->event);
  214.         }
  215. protection = arr->protection;
  216.         /* Release the mutex protecting the wait array complex */
  217. if (protection == SYNC_ARRAY_OS_MUTEX) {
  218. os_mutex_free(arr->os_mutex);
  219. } else if (protection == SYNC_ARRAY_MUTEX) {
  220. mutex_free(&(arr->mutex));
  221. } else {
  222. ut_error;
  223. }
  224. ut_free(arr->array);
  225. ut_free(arr);
  226. }
  227. /************************************************************************
  228. Validates the integrity of the wait array. Checks
  229. that the number of reserved cells equals the count variable. */
  230. void
  231. sync_array_validate(
  232. /*================*/
  233. sync_array_t* arr) /* in: sync wait array */
  234. {
  235.         ulint           i;
  236.         sync_cell_t*    cell;
  237.         ulint           count           = 0;
  238.         
  239.         sync_array_enter(arr);
  240.         for (i = 0; i < arr->n_cells; i++) {
  241. cell = sync_array_get_nth_cell(arr, i);        
  242.                 if (cell->wait_object != NULL) {
  243.                         count++;
  244.                 }
  245.         }
  246.         ut_a(count == arr->n_reserved);
  247.         sync_array_exit(arr);
  248. }
  249. /***********************************************************************
  250. Puts the cell event in set state. */
  251. static
  252. void
  253. sync_cell_event_set(
  254. /*================*/
  255. sync_cell_t* cell) /* in: array cell */
  256. {
  257. os_event_set(cell->event);
  258. cell->event_set = TRUE;
  259. }
  260. /***********************************************************************
  261. Puts the cell event in reset state. */
  262. static
  263. void
  264. sync_cell_event_reset(
  265. /*==================*/
  266. sync_cell_t* cell) /* in: array cell */
  267. {
  268. os_event_reset(cell->event);
  269. cell->event_set = FALSE;
  270. }
  271. /**********************************************************************
  272. Reserves a wait array cell for waiting for an object.
  273. The event of the cell is reset to nonsignalled state. */
  274. void
  275. sync_array_reserve_cell(
  276. /*====================*/
  277.         sync_array_t* arr, /* in: wait array */
  278.         void*    object, /* in: pointer to the object to wait for */
  279.         ulint type, /* in: lock request type */
  280. #ifdef UNIV_SYNC_DEBUG
  281.         char* file, /* in: in debug version file where
  282.          requested */
  283.         ulint line, /* in: in the debug version line where
  284.          requested */
  285. #endif
  286.         ulint*    index)  /* out: index of the reserved cell */
  287. {
  288.         ulint           i;
  289.         sync_cell_t*    cell;
  290.         
  291.         ut_a(object);
  292.         ut_a(index);
  293.         sync_array_enter(arr);
  294.         arr->res_count++;
  295. /* Reserve a new cell. */
  296.         for (i = 0; i < arr->n_cells; i++) {
  297. cell = sync_array_get_nth_cell(arr, i);        
  298.                 if (cell->wait_object == NULL) {
  299.                         /* Make sure the event is reset */
  300. if (cell->event_set) {
  301.                          sync_cell_event_reset(cell);
  302. }
  303. cell->wait_object = object;
  304. cell->request_type = type;
  305. cell->thread = os_thread_get_curr_id();
  306. cell->waiting = FALSE;
  307. #ifdef UNIV_SYNC_DEBUG
  308. cell->file = file;
  309. cell->line = line;
  310. #else
  311. cell->file = "NOT KNOWN";
  312. cell->line = 0;
  313. #endif
  314. arr->n_reserved++;
  315. *index = i;
  316. sync_array_exit(arr);
  317.                         
  318.                         return;
  319.                 }
  320.         }
  321.         ut_error; /* No free cell found */
  322. return;
  323. }
  324. /**********************************************************************
  325. This function should be called when a thread starts to wait on
  326. a wait array cell. In the debug version this function checks
  327. if the wait for a semaphore will result in a deadlock, in which
  328. case prints info and asserts. */
  329. void
  330. sync_array_wait_event(
  331. /*==================*/
  332.         sync_array_t* arr, /* in: wait array */
  333.         ulint    index)  /* in: index of the reserved cell */
  334. {
  335.         sync_cell_t*    cell;
  336.         os_event_t  event;
  337.         
  338.         ut_a(arr);
  339.         sync_array_enter(arr);
  340. cell = sync_array_get_nth_cell(arr, index);        
  341. ut_a(cell->wait_object);
  342. ut_a(!cell->waiting);
  343. ut_ad(os_thread_get_curr_id() == cell->thread);
  344.         event = cell->event;
  345.         cell->waiting = TRUE;
  346. #ifdef UNIV_SYNC_DEBUG
  347.        
  348. /* We use simple enter to the mutex below, because if
  349. we cannot acquire it at once, mutex_enter would call
  350. recursively sync_array routines, leading to trouble.
  351. rw_lock_debug_mutex freezes the debug lists. */
  352. rw_lock_debug_mutex_enter();
  353. if (TRUE == sync_array_detect_deadlock(arr, cell, cell, 0)) {
  354. printf("########################################n");
  355. ut_error;
  356. }
  357. rw_lock_debug_mutex_exit();
  358. #endif
  359.         sync_array_exit(arr);
  360.         os_event_wait(event);
  361.         sync_array_free_cell(arr, index);
  362. }
  363. /**********************************************************************
  364. Reports info of a wait array cell. */
  365. static
  366. void
  367. sync_array_cell_print(
  368. /*==================*/
  369. sync_cell_t* cell) /* in: sync cell */
  370. {
  371. char* str  = NULL;
  372. ulint type;
  373. type = cell->request_type;
  374. if (type == SYNC_MUTEX) {
  375. str = "MUTEX ENTER";
  376. } else if (type == RW_LOCK_EX) {
  377. str = "X-LOCK";
  378. } else if (type == RW_LOCK_SHARED) {
  379. str = "S-LOCK";
  380. } else {
  381. ut_error;
  382. }
  383. printf("%lx waited for by thread %lu op. %s file %s line %lu ",
  384. (ulint)cell->wait_object,
  385. (ulint)cell->thread,
  386. str, cell->file, cell->line);
  387.         if (!cell->waiting) {
  388.            printf("WAIT ENDED ");
  389. }
  390.         if (cell->event_set) {
  391.               printf("EVENT SET");
  392. }
  393. printf("n");
  394. }
  395. /**********************************************************************
  396. Looks for a cell with the given thread id. */
  397. static
  398. sync_cell_t*
  399. sync_array_find_thread(
  400. /*===================*/
  401. /* out: pointer to cell or NULL
  402. if not found */
  403.         sync_array_t* arr, /* in: wait array */
  404. os_thread_id_t thread) /* in: thread id */
  405. {
  406.         ulint           i;
  407.         sync_cell_t*    cell;
  408.         for (i = 0; i < arr->n_cells; i++) {
  409. cell = sync_array_get_nth_cell(arr, i);        
  410.                 if ((cell->wait_object != NULL)
  411.     && (cell->thread == thread)) {
  412.      return(cell); /* Found */
  413.                 }
  414.         }
  415. return(NULL); /* Not found */
  416. }
  417. /**********************************************************************
  418. Recursion step for deadlock detection. */
  419. static
  420. ibool
  421. sync_array_deadlock_step(
  422. /*=====================*/
  423. /* out: TRUE if deadlock detected */
  424.         sync_array_t* arr, /* in: wait array; NOTE! the caller must
  425.          own the mutex to array */
  426. sync_cell_t* start, /* in: cell where recursive search
  427. started */
  428. os_thread_id_t thread, /* in: thread to look at */
  429. ulint pass, /* in: pass value */
  430. ulint depth) /* in: recursion depth */
  431. {
  432. sync_cell_t* new;
  433. ibool ret;
  434. depth++;
  435. if (pass != 0) {
  436. /* If pass != 0, then we do not know which threads are
  437. responsible of releasing the lock, and no deadlock can
  438. be detected. */
  439. return(FALSE);
  440. }
  441.     
  442. new = sync_array_find_thread(arr, thread);
  443. if (new == start) {
  444. /* Stop running of other threads */
  445. ut_dbg_stop_threads = TRUE;
  446. /* Deadlock */
  447. printf("########################################n");
  448. printf("DEADLOCK of threads detected!n");
  449. return(TRUE);
  450. } else if (new) {
  451. ret = sync_array_detect_deadlock(arr, start, new, depth);
  452. if (ret) {
  453. return(TRUE);
  454. }
  455. }
  456. return(FALSE);
  457. }
  458. /**********************************************************************
  459. This function is called only in the debug version. Detects a deadlock
  460. of one or more threads because of waits of semaphores. */
  461. static
  462. ibool
  463. sync_array_detect_deadlock(
  464. /*=======================*/
  465. /* out: TRUE if deadlock detected */
  466.         sync_array_t* arr, /* in: wait array; NOTE! the caller must
  467.          own the mutex to array */
  468. sync_cell_t* start, /* in: cell where recursive search started */
  469. sync_cell_t* cell, /* in: cell to search */
  470. ulint depth) /* in: recursion depth */
  471. {
  472. mutex_t* mutex;
  473. rw_lock_t* lock;
  474. os_thread_id_t thread;
  475. ibool ret;
  476. rw_lock_debug_t* debug;
  477.         ut_a(arr && start && cell);
  478. ut_ad(cell->wait_object);
  479. ut_ad(os_thread_get_curr_id() == start->thread);
  480. ut_ad(depth < 100);
  481. depth++;
  482. if (cell->event_set || !cell->waiting) {
  483. return(FALSE); /* No deadlock here */
  484. }
  485. if (cell->request_type == SYNC_MUTEX) {
  486. mutex = cell->wait_object;
  487. if (mutex_get_lock_word(mutex) != 0) {
  488. thread = mutex->thread_id;
  489. /* Note that mutex->thread_id above may be
  490. also OS_THREAD_ID_UNDEFINED, because the
  491. thread which held the mutex maybe has not
  492. yet updated the value, or it has already
  493. released the mutex: in this case no deadlock
  494. can occur, as the wait array cannot contain
  495. a thread with ID_UNDEFINED value. */
  496. ret = sync_array_deadlock_step(arr, start, thread, 0,
  497. depth);
  498. if (ret) {
  499. printf(
  500. "Mutex %lx owned by thread %lu file %s line %lun",
  501. (ulint)mutex, mutex->thread_id,
  502. mutex->file_name, mutex->line);
  503. sync_array_cell_print(cell);
  504. return(TRUE);
  505. }
  506. }
  507. return(FALSE); /* No deadlock */
  508. } else if (cell->request_type == RW_LOCK_EX) {
  509.    lock = cell->wait_object;
  510.    debug = UT_LIST_GET_FIRST(lock->debug_list);
  511.    while (debug != NULL) {
  512. thread = debug->thread_id;
  513. if (((debug->lock_type == RW_LOCK_EX)
  514.              && (thread != cell->thread))
  515.             || ((debug->lock_type == RW_LOCK_WAIT_EX)
  516. && (thread != cell->thread))
  517.             || (debug->lock_type == RW_LOCK_SHARED)) {
  518. /* The (wait) x-lock request can block infinitely
  519. only if someone (can be also cell thread) is holding
  520. s-lock, or someone (cannot be cell thread) (wait)
  521. x-lock, and he is blocked by start thread */
  522. ret = sync_array_deadlock_step(arr, start, thread,
  523. debug->pass,
  524. depth);
  525. if (ret) {
  526. printf("rw-lock %lx ", (ulint) lock);
  527. rw_lock_debug_print(debug);
  528. sync_array_cell_print(cell);
  529. return(TRUE);
  530. }
  531. }
  532. debug = UT_LIST_GET_NEXT(list, debug);
  533.    }
  534.    return(FALSE);
  535. } else if (cell->request_type == RW_LOCK_SHARED) {
  536.    lock = cell->wait_object;
  537.    debug = UT_LIST_GET_FIRST(lock->debug_list);
  538.    while (debug != NULL) {
  539. thread = debug->thread_id;
  540. if ((debug->lock_type == RW_LOCK_EX)
  541.             || (debug->lock_type == RW_LOCK_WAIT_EX)) {
  542. /* The s-lock request can block infinitely only if
  543. someone (can also be cell thread) is holding (wait)
  544. x-lock, and he is blocked by start thread */
  545. ret = sync_array_deadlock_step(arr, start, thread,
  546. debug->pass,
  547. depth);
  548. if (ret) {
  549. printf("rw-lock %lx ", (ulint) lock);
  550. rw_lock_debug_print(debug);
  551. sync_array_cell_print(cell);
  552. return(TRUE);
  553. }
  554. }
  555. debug = UT_LIST_GET_NEXT(list, debug);
  556.    }
  557.    return(FALSE);
  558. } else {
  559. ut_error;
  560. }
  561. return(TRUE);  /* Execution never reaches this line: for compiler
  562. fooling only */
  563. }
  564. /**********************************************************************
  565. Frees the cell. NOTE! sync_array_wait_event frees the cell
  566. automatically! */
  567. void
  568. sync_array_free_cell(
  569. /*=================*/
  570. sync_array_t* arr, /* in: wait array */
  571.         ulint     index)  /* in: index of the cell in array */
  572. {
  573.         sync_cell_t*    cell;
  574.         
  575.         sync_array_enter(arr);
  576.         cell = sync_array_get_nth_cell(arr, index);
  577.         ut_a(cell->wait_object != NULL);
  578. cell->wait_object =  NULL;
  579. ut_a(arr->n_reserved > 0);
  580. arr->n_reserved--;
  581.         sync_array_exit(arr);
  582. }
  583. /**************************************************************************
  584. Looks for the cells in the wait array which refer
  585. to the wait object specified,
  586. and sets their corresponding events to the signaled state. In this
  587. way releases the threads waiting for the object to contend for the object.
  588. It is possible that no such cell is found, in which case does nothing. */
  589. void
  590. sync_array_signal_object(
  591. /*=====================*/
  592. sync_array_t* arr, /* in: wait array */
  593. void* object) /* in: wait object */
  594. {
  595.         sync_cell_t*    cell;
  596.         ulint           count;
  597.         ulint           i;
  598.         sync_array_enter(arr);
  599. arr->sg_count++;
  600. i = 0;
  601. count = 0;
  602.         while (count < arr->n_reserved) {
  603.          cell = sync_array_get_nth_cell(arr, i);
  604.                 if (cell->wait_object != NULL) {
  605.                         count++;
  606.                         if (cell->wait_object == object) {
  607.                          sync_cell_event_set(cell);
  608.                         }
  609.                 }
  610.                 i++;
  611.         }
  612.         sync_array_exit(arr);
  613. }
  614. /**************************************************************************
  615. Prints info of the wait array. */
  616. static
  617. void
  618. sync_array_output_info(
  619. /*===================*/
  620. sync_array_t* arr) /* in: wait array; NOTE! caller must own the
  621. mutex */
  622. {
  623.         sync_cell_t*    cell;
  624.         ulint           count;
  625. ulint           i;
  626. printf("-----------------------------------------------------n");
  627. printf("SYNC ARRAY INFO: reservation count %ld, signal count %ldn",
  628. arr->res_count, arr->sg_count);
  629. i = 0;
  630. count = 0;
  631.         while (count < arr->n_reserved) {
  632.          cell = sync_array_get_nth_cell(arr, i);
  633.                 if (cell->wait_object != NULL) {
  634.                         count++;
  635. sync_array_cell_print(cell);
  636.                 }
  637.                 i++;
  638.         }
  639. }
  640. /**************************************************************************
  641. Prints info of the wait array. */
  642. void
  643. sync_array_print_info(
  644. /*==================*/
  645. sync_array_t* arr) /* in: wait array */
  646. {
  647.         sync_array_enter(arr);
  648. sync_array_output_info(arr);
  649.         
  650.         sync_array_exit(arr);
  651. }