00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00033 #include "sync0arr.h"
00034 #ifdef UNIV_NONINL
00035 #include "sync0arr.ic"
00036 #endif
00037
00038 #include "sync0sync.h"
00039 #include "sync0rw.h"
00040 #include "os0sync.h"
00041 #include "os0file.h"
00042 #include "srv0srv.h"
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00080 struct sync_cell_struct {
00081 void* wait_object;
00084 mutex_t* old_wait_mutex;
00085 rw_lock_t* old_wait_rw_lock;
00088 ulint request_type;
00090 const char* file;
00092 ulint line;
00094 os_thread_id_t thread;
00096 ibool waiting;
00099 ib_int64_t signal_count;
00107 time_t reservation_time;
00109 };
00110
00111
00112
00113
00114
00115
00116
00118 struct sync_array_struct {
00119 ulint n_reserved;
00121 ulint n_cells;
00123 sync_cell_t* array;
00124 ulint protection;
00126 mutex_t mutex;
00128 os_mutex_t os_mutex;
00135 ulint sg_count;
00137 ulint res_count;
00139 };
00140
00141 #ifdef UNIV_PFS_MUTEX
00142
00143 UNIV_INTERN mysql_pfs_key_t syn_arr_mutex_key;
00144 #endif
00145
00146 #ifdef UNIV_SYNC_DEBUG
00147
00151 static
00152 ibool
00153 sync_array_detect_deadlock(
00154
00155 sync_array_t* arr,
00157 sync_cell_t* start,
00158 sync_cell_t* cell,
00159 ulint depth);
00160 #endif
00161
00162
00165 static
00166 sync_cell_t*
00167 sync_array_get_nth_cell(
00168
00169 sync_array_t* arr,
00170 ulint n)
00171 {
00172 ut_a(arr);
00173 ut_a(n < arr->n_cells);
00174
00175 return(arr->array + n);
00176 }
00177
00178
00180 static
00181 void
00182 sync_array_enter(
00183
00184 sync_array_t* arr)
00185 {
00186 ulint protection;
00187
00188 protection = arr->protection;
00189
00190 if (protection == SYNC_ARRAY_OS_MUTEX) {
00191 os_mutex_enter(arr->os_mutex);
00192 } else if (protection == SYNC_ARRAY_MUTEX) {
00193 mutex_enter(&(arr->mutex));
00194 } else {
00195 ut_error;
00196 }
00197 }
00198
00199
00201 static
00202 void
00203 sync_array_exit(
00204
00205 sync_array_t* arr)
00206 {
00207 ulint protection;
00208
00209 protection = arr->protection;
00210
00211 if (protection == SYNC_ARRAY_OS_MUTEX) {
00212 os_mutex_exit(arr->os_mutex);
00213 } else if (protection == SYNC_ARRAY_MUTEX) {
00214 mutex_exit(&(arr->mutex));
00215 } else {
00216 ut_error;
00217 }
00218 }
00219
00220
00225 UNIV_INTERN
00226 sync_array_t*
00227 sync_array_create(
00228
00229 ulint n_cells,
00231 ulint protection)
00234 {
00235 ulint sz;
00236 sync_array_t* arr;
00237
00238 ut_a(n_cells > 0);
00239
00240
00241 arr = static_cast<sync_array_t *>(ut_malloc(sizeof(sync_array_t)));
00242 memset(arr, 0x0, sizeof(*arr));
00243
00244 sz = sizeof(sync_cell_t) * n_cells;
00245 arr->array = static_cast<sync_cell_t *>(ut_malloc(sz));
00246 memset(arr->array, 0x0, sz);
00247
00248 arr->n_cells = n_cells;
00249 arr->protection = protection;
00250
00251
00252 if (protection == SYNC_ARRAY_OS_MUTEX) {
00253 arr->os_mutex = os_mutex_create();
00254 } else if (protection == SYNC_ARRAY_MUTEX) {
00255 mutex_create(syn_arr_mutex_key,
00256 &arr->mutex, SYNC_NO_ORDER_CHECK);
00257 } else {
00258 ut_error;
00259 }
00260
00261 return(arr);
00262 }
00263
00264
00266 UNIV_INTERN
00267 void
00268 sync_array_free(
00269
00270 sync_array_t* arr)
00271 {
00272 ulint protection;
00273
00274 ut_a(arr->n_reserved == 0);
00275
00276 sync_array_validate(arr);
00277
00278 protection = arr->protection;
00279
00280
00281
00282 if (protection == SYNC_ARRAY_OS_MUTEX) {
00283 os_mutex_free(arr->os_mutex);
00284 } else if (protection == SYNC_ARRAY_MUTEX) {
00285 mutex_free(&(arr->mutex));
00286 } else {
00287 ut_error;
00288 }
00289
00290 ut_free(arr->array);
00291 ut_free(arr);
00292 }
00293
00294
00297 UNIV_INTERN
00298 void
00299 sync_array_validate(
00300
00301 sync_array_t* arr)
00302 {
00303 ulint i;
00304 sync_cell_t* cell;
00305 ulint count = 0;
00306
00307 sync_array_enter(arr);
00308
00309 for (i = 0; i < arr->n_cells; i++) {
00310 cell = sync_array_get_nth_cell(arr, i);
00311 if (cell->wait_object != NULL) {
00312 count++;
00313 }
00314 }
00315
00316 ut_a(count == arr->n_reserved);
00317
00318 sync_array_exit(arr);
00319 }
00320
00321
00323 static
00324 os_event_t
00325 sync_cell_get_event(
00326
00327 sync_cell_t* cell)
00328 {
00329 ulint type = cell->request_type;
00330
00331 if (type == SYNC_MUTEX) {
00332 return(((mutex_t *) cell->wait_object)->event);
00333 } else if (type == RW_LOCK_WAIT_EX) {
00334 return(((rw_lock_t *) cell->wait_object)->wait_ex_event);
00335 } else {
00336 return(((rw_lock_t *) cell->wait_object)->event);
00337 }
00338 }
00339
00340
00343 UNIV_INTERN
00344 void
00345 sync_array_reserve_cell(
00346
00347 sync_array_t* arr,
00348 void* object,
00349 ulint type,
00350 const char* file,
00351 ulint line,
00352 ulint* index)
00353 {
00354 sync_cell_t* cell;
00355 os_event_t event;
00356 ulint i;
00357
00358 ut_a(object);
00359 ut_a(index);
00360
00361 sync_array_enter(arr);
00362
00363 arr->res_count++;
00364
00365
00366 for (i = 0; i < arr->n_cells; i++) {
00367 cell = sync_array_get_nth_cell(arr, i);
00368
00369 if (cell->wait_object == NULL) {
00370
00371 cell->waiting = FALSE;
00372 cell->wait_object = object;
00373
00374 if (type == SYNC_MUTEX) {
00375 cell->old_wait_mutex = static_cast<mutex_struct *>(object);
00376 } else {
00377 cell->old_wait_rw_lock = static_cast<rw_lock_struct *>(object);
00378 }
00379
00380 cell->request_type = type;
00381
00382 cell->file = file;
00383 cell->line = line;
00384
00385 arr->n_reserved++;
00386
00387 *index = i;
00388
00389 sync_array_exit(arr);
00390
00391
00392
00393
00394 event = sync_cell_get_event(cell);
00395 cell->signal_count = os_event_reset(event);
00396
00397 cell->reservation_time = time(NULL);
00398
00399 cell->thread = os_thread_get_curr_id();
00400
00401 return;
00402 }
00403 }
00404
00405 ut_error;
00406
00407 return;
00408 }
00409
00410
00415 UNIV_INTERN
00416 void
00417 sync_array_wait_event(
00418
00419 sync_array_t* arr,
00420 ulint index)
00421 {
00422 sync_cell_t* cell;
00423 os_event_t event;
00424
00425 ut_a(arr);
00426
00427 sync_array_enter(arr);
00428
00429 cell = sync_array_get_nth_cell(arr, index);
00430
00431 ut_a(cell->wait_object);
00432 ut_a(!cell->waiting);
00433 ut_ad(os_thread_get_curr_id() == cell->thread);
00434
00435 event = sync_cell_get_event(cell);
00436 cell->waiting = TRUE;
00437
00438 #ifdef UNIV_SYNC_DEBUG
00439
00440
00441
00442
00443
00444
00445 rw_lock_debug_mutex_enter();
00446
00447 if (TRUE == sync_array_detect_deadlock(arr, cell, cell, 0)) {
00448
00449 fputs("########################################\n", stderr);
00450 ut_error;
00451 }
00452
00453 rw_lock_debug_mutex_exit();
00454 #endif
00455 sync_array_exit(arr);
00456
00457 os_event_wait_low(event, cell->signal_count);
00458
00459 sync_array_free_cell(arr, index);
00460 }
00461
00462
00464 static
00465 void
00466 sync_array_cell_print(
00467
00468 FILE* file,
00469 sync_cell_t* cell)
00470 {
00471 mutex_t* mutex;
00472 rw_lock_t* rwlock;
00473 ulint type;
00474 ulint writer;
00475
00476 type = cell->request_type;
00477
00478 fprintf(file,
00479 "--Thread %lu has waited at %s line %lu"
00480 " for %.2f seconds the semaphore:\n",
00481 (ulong) os_thread_pf(cell->thread), cell->file,
00482 (ulong) cell->line,
00483 difftime(time(NULL), cell->reservation_time));
00484
00485 if (type == SYNC_MUTEX) {
00486
00487
00488 mutex = cell->old_wait_mutex;
00489
00490 fprintf(file,
00491 "Mutex at %p created file %s line %lu, lock var %lu\n"
00492 #ifdef UNIV_SYNC_DEBUG
00493 "Last time reserved in file %s line %lu, "
00494 #endif
00495 "waiters flag %lu\n",
00496 (void*) mutex, mutex->cfile_name, (ulong) mutex->cline,
00497 (ulong) mutex->lock_word,
00498 #ifdef UNIV_SYNC_DEBUG
00499 mutex->file_name, (ulong) mutex->line,
00500 #endif
00501 (ulong) mutex->waiters);
00502
00503 } else if (type == RW_LOCK_EX
00504 || type == RW_LOCK_WAIT_EX
00505 || type == RW_LOCK_SHARED) {
00506
00507 fputs(type == RW_LOCK_EX ? "X-lock on"
00508 : type == RW_LOCK_WAIT_EX ? "X-lock (wait_ex) on"
00509 : "S-lock on", file);
00510
00511 rwlock = cell->old_wait_rw_lock;
00512
00513 fprintf(file,
00514 " RW-latch at %p created in file %s line %lu\n",
00515 (void*) rwlock, rwlock->cfile_name,
00516 (ulong) rwlock->cline);
00517 writer = rw_lock_get_writer(rwlock);
00518 if (writer != RW_LOCK_NOT_LOCKED) {
00519 fprintf(file,
00520 "a writer (thread id %lu) has"
00521 " reserved it in mode %s",
00522 (ulong) os_thread_pf(rwlock->writer_thread),
00523 writer == RW_LOCK_EX
00524 ? " exclusive\n"
00525 : " wait exclusive\n");
00526 }
00527
00528 fprintf(file,
00529 "number of readers %lu, waiters flag %lu, "
00530 "lock_word: %lx\n"
00531 "Last time read locked in file %s line %lu\n"
00532 "Last time write locked in file %s line %lu\n",
00533 (ulong) rw_lock_get_reader_count(rwlock),
00534 (ulong) rwlock->waiters,
00535 rwlock->lock_word,
00536 rwlock->last_s_file_name,
00537 (ulong) rwlock->last_s_line,
00538 rwlock->last_x_file_name,
00539 (ulong) rwlock->last_x_line);
00540 } else {
00541 ut_error;
00542 }
00543
00544 if (!cell->waiting) {
00545 fputs("wait has ended\n", file);
00546 }
00547 }
00548
00549 #ifdef UNIV_SYNC_DEBUG
00550
00553 static
00554 sync_cell_t*
00555 sync_array_find_thread(
00556
00557 sync_array_t* arr,
00558 os_thread_id_t thread)
00559 {
00560 ulint i;
00561 sync_cell_t* cell;
00562
00563 for (i = 0; i < arr->n_cells; i++) {
00564
00565 cell = sync_array_get_nth_cell(arr, i);
00566
00567 if (cell->wait_object != NULL
00568 && os_thread_eq(cell->thread, thread)) {
00569
00570 return(cell);
00571 }
00572 }
00573
00574 return(NULL);
00575 }
00576
00577
00580 static
00581 ibool
00582 sync_array_deadlock_step(
00583
00584 sync_array_t* arr,
00586 sync_cell_t* start,
00588 os_thread_id_t thread,
00589 ulint pass,
00590 ulint depth)
00591 {
00592 sync_cell_t* new;
00593 ibool ret;
00594
00595 depth++;
00596
00597 if (pass != 0) {
00598
00599
00600
00601
00602 return(FALSE);
00603 }
00604
00605 new = sync_array_find_thread(arr, thread);
00606
00607 if (new == start) {
00608
00609
00610 ut_dbg_stop_threads = TRUE;
00611
00612
00613 fputs("########################################\n"
00614 "DEADLOCK of threads detected!\n", stderr);
00615
00616 return(TRUE);
00617
00618 } else if (new) {
00619 ret = sync_array_detect_deadlock(arr, start, new, depth);
00620
00621 if (ret) {
00622 return(TRUE);
00623 }
00624 }
00625 return(FALSE);
00626 }
00627
00628
00632 static
00633 ibool
00634 sync_array_detect_deadlock(
00635
00636 sync_array_t* arr,
00638 sync_cell_t* start,
00639 sync_cell_t* cell,
00640 ulint depth)
00641 {
00642 mutex_t* mutex;
00643 rw_lock_t* lock;
00644 os_thread_id_t thread;
00645 ibool ret;
00646 rw_lock_debug_t*debug;
00647
00648 ut_a(arr);
00649 ut_a(start);
00650 ut_a(cell);
00651 ut_ad(cell->wait_object);
00652 ut_ad(os_thread_get_curr_id() == start->thread);
00653 ut_ad(depth < 100);
00654
00655 depth++;
00656
00657 if (!cell->waiting) {
00658
00659 return(FALSE);
00660 }
00661
00662 if (cell->request_type == SYNC_MUTEX) {
00663
00664 mutex = cell->wait_object;
00665
00666 if (mutex_get_lock_word(mutex) != 0) {
00667
00668 thread = mutex->thread_id;
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678 ret = sync_array_deadlock_step(arr, start, thread, 0,
00679 depth);
00680 if (ret) {
00681 fprintf(stderr,
00682 "Mutex %p owned by thread %lu file %s line %lu\n",
00683 mutex, (ulong) os_thread_pf(mutex->thread_id),
00684 mutex->file_name, (ulong) mutex->line);
00685 sync_array_cell_print(stderr, cell);
00686
00687 return(TRUE);
00688 }
00689 }
00690
00691 return(FALSE);
00692
00693 } else if (cell->request_type == RW_LOCK_EX
00694 || cell->request_type == RW_LOCK_WAIT_EX) {
00695
00696 lock = cell->wait_object;
00697
00698 debug = UT_LIST_GET_FIRST(lock->debug_list);
00699
00700 while (debug != NULL) {
00701
00702 thread = debug->thread_id;
00703
00704 if (((debug->lock_type == RW_LOCK_EX)
00705 && !os_thread_eq(thread, cell->thread))
00706 || ((debug->lock_type == RW_LOCK_WAIT_EX)
00707 && !os_thread_eq(thread, cell->thread))
00708 || (debug->lock_type == RW_LOCK_SHARED)) {
00709
00710
00711
00712
00713
00714
00715
00716 ret = sync_array_deadlock_step(
00717 arr, start, thread, debug->pass,
00718 depth);
00719 if (ret) {
00720 print:
00721 fprintf(stderr, "rw-lock %p ",
00722 (void*) lock);
00723 sync_array_cell_print(stderr, cell);
00724 rw_lock_debug_print(debug);
00725 return(TRUE);
00726 }
00727 }
00728
00729 debug = UT_LIST_GET_NEXT(list, debug);
00730 }
00731
00732 return(FALSE);
00733
00734 } else if (cell->request_type == RW_LOCK_SHARED) {
00735
00736 lock = cell->wait_object;
00737 debug = UT_LIST_GET_FIRST(lock->debug_list);
00738
00739 while (debug != NULL) {
00740
00741 thread = debug->thread_id;
00742
00743 if ((debug->lock_type == RW_LOCK_EX)
00744 || (debug->lock_type == RW_LOCK_WAIT_EX)) {
00745
00746
00747
00748
00749
00750
00751 ret = sync_array_deadlock_step(
00752 arr, start, thread, debug->pass,
00753 depth);
00754 if (ret) {
00755 goto print;
00756 }
00757 }
00758
00759 debug = UT_LIST_GET_NEXT(list, debug);
00760 }
00761
00762 return(FALSE);
00763
00764 } else {
00765 ut_error;
00766 }
00767
00768 return(TRUE);
00769
00770 }
00771 #endif
00772
00773
00775 static
00776 ibool
00777 sync_arr_cell_can_wake_up(
00778
00779 sync_cell_t* cell)
00780 {
00781 mutex_t* mutex;
00782 rw_lock_t* lock;
00783
00784 if (cell->request_type == SYNC_MUTEX) {
00785
00786 mutex = static_cast<mutex_t *>(cell->wait_object);
00787
00788 if (mutex_get_lock_word(mutex) == 0) {
00789
00790 return(TRUE);
00791 }
00792
00793 } else if (cell->request_type == RW_LOCK_EX) {
00794
00795 lock = static_cast<rw_lock_t *>(cell->wait_object);
00796
00797 if (lock->lock_word > 0) {
00798
00799
00800 return(TRUE);
00801 }
00802
00803 } else if (cell->request_type == RW_LOCK_WAIT_EX) {
00804
00805 lock = static_cast<rw_lock_t *>(cell->wait_object);
00806
00807
00808 if (lock->lock_word == 0) {
00809
00810 return(TRUE);
00811 }
00812 } else if (cell->request_type == RW_LOCK_SHARED) {
00813 lock = static_cast<rw_lock_t *>(cell->wait_object);
00814
00815
00816 if (lock->lock_word > 0) {
00817
00818 return(TRUE);
00819 }
00820 }
00821
00822 return(FALSE);
00823 }
00824
00825
00828 UNIV_INTERN
00829 void
00830 sync_array_free_cell(
00831
00832 sync_array_t* arr,
00833 ulint index)
00834 {
00835 sync_cell_t* cell;
00836
00837 sync_array_enter(arr);
00838
00839 cell = sync_array_get_nth_cell(arr, index);
00840
00841 ut_a(cell->wait_object != NULL);
00842
00843 cell->waiting = FALSE;
00844 cell->wait_object = NULL;
00845 cell->signal_count = 0;
00846
00847 ut_a(arr->n_reserved > 0);
00848 arr->n_reserved--;
00849
00850 sync_array_exit(arr);
00851 }
00852
00853
00855 UNIV_INTERN
00856 void
00857 sync_array_object_signalled(
00858
00859 sync_array_t* arr)
00860 {
00861 #ifdef HAVE_ATOMIC_BUILTINS
00862 (void) os_atomic_increment_ulint(&arr->sg_count, 1);
00863 #else
00864 sync_array_enter(arr);
00865
00866 arr->sg_count++;
00867
00868 sync_array_exit(arr);
00869 #endif
00870 }
00871
00872
00880 UNIV_INTERN
00881 void
00882 sync_arr_wake_threads_if_sema_free(void)
00883
00884 {
00885 sync_array_t* arr = sync_primary_wait_array;
00886 sync_cell_t* cell;
00887 ulint count;
00888 ulint i;
00889 os_event_t event;
00890
00891 sync_array_enter(arr);
00892
00893 i = 0;
00894 count = 0;
00895
00896 while (count < arr->n_reserved) {
00897
00898 cell = sync_array_get_nth_cell(arr, i);
00899 i++;
00900
00901 if (cell->wait_object == NULL) {
00902 continue;
00903 }
00904 count++;
00905
00906 if (sync_arr_cell_can_wake_up(cell)) {
00907
00908 event = sync_cell_get_event(cell);
00909
00910 os_event_set(event);
00911 }
00912
00913 }
00914
00915 sync_array_exit(arr);
00916 }
00917
00918
00921 UNIV_INTERN
00922 ibool
00923 sync_array_print_long_waits(void)
00924
00925 {
00926 sync_cell_t* cell;
00927 ibool old_val;
00928 ibool noticed = FALSE;
00929 ulint i;
00930 ulint fatal_timeout = srv_fatal_semaphore_wait_threshold;
00931 ibool fatal = FALSE;
00932
00933 for (i = 0; i < sync_primary_wait_array->n_cells; i++) {
00934
00935 cell = sync_array_get_nth_cell(sync_primary_wait_array, i);
00936
00937 if (cell->wait_object != NULL && cell->waiting
00938 && difftime(time(NULL), cell->reservation_time) > 240) {
00939 fputs("InnoDB: Warning: a long semaphore wait:\n",
00940 stderr);
00941 sync_array_cell_print(stderr, cell);
00942 noticed = TRUE;
00943 }
00944
00945 if (cell->wait_object != NULL && cell->waiting
00946 && difftime(time(NULL), cell->reservation_time)
00947 > fatal_timeout) {
00948 fatal = TRUE;
00949 }
00950 }
00951
00952 if (noticed) {
00953 fprintf(stderr,
00954 "InnoDB: ###### Starts InnoDB Monitor"
00955 " for 30 secs to print diagnostic info:\n");
00956 old_val = srv_print_innodb_monitor;
00957
00958
00959
00960
00961
00962
00963
00964 fprintf(stderr,
00965 "InnoDB: Pending preads %lu, pwrites %lu\n",
00966 (ulong)os_file_n_pending_preads,
00967 (ulong)os_file_n_pending_pwrites);
00968
00969 srv_print_innodb_monitor = TRUE;
00970 os_event_set(srv_lock_timeout_thread_event);
00971
00972 os_thread_sleep(30000000);
00973
00974 srv_print_innodb_monitor = old_val;
00975 fprintf(stderr,
00976 "InnoDB: ###### Diagnostic info printed"
00977 " to the standard error stream\n");
00978 }
00979
00980 return(fatal);
00981 }
00982
00983
00985 static
00986 void
00987 sync_array_output_info(
00988
00989 FILE* file,
00990 sync_array_t* arr)
00992 {
00993 sync_cell_t* cell;
00994 ulint count;
00995 ulint i;
00996
00997 fprintf(file,
00998 "OS WAIT ARRAY INFO: reservation count %ld, signal count %ld\n",
00999 (long) arr->res_count, (long) arr->sg_count);
01000 i = 0;
01001 count = 0;
01002
01003 while (count < arr->n_reserved) {
01004
01005 cell = sync_array_get_nth_cell(arr, i);
01006
01007 if (cell->wait_object != NULL) {
01008 count++;
01009 sync_array_cell_print(file, cell);
01010 }
01011
01012 i++;
01013 }
01014 }
01015
01016
01018 UNIV_INTERN
01019 void
01020 sync_array_print_info(
01021
01022 FILE* file,
01023 sync_array_t* arr)
01024 {
01025 sync_array_enter(arr);
01026
01027 sync_array_output_info(file, arr);
01028
01029 sync_array_exit(arr);
01030 }