📄 sync0arr.c
字号:
rwlock->last_x_file_name, (ulong) rwlock->last_x_line); } else { ut_error; } if (!cell->waiting) { fputs("wait has ended\n", file); } if (cell->event_set) { fputs("wait is ending\n", file); }}#ifdef UNIV_SYNC_DEBUG/**********************************************************************Looks for a cell with the given thread id. */staticsync_cell_t*sync_array_find_thread(/*===================*/ /* out: pointer to cell or NULL if not found */ sync_array_t* arr, /* in: wait array */ os_thread_id_t thread) /* in: thread id */{ ulint i; sync_cell_t* cell; for (i = 0; i < arr->n_cells; i++) { cell = sync_array_get_nth_cell(arr, i); if (cell->wait_object != NULL && os_thread_eq(cell->thread, thread)) { return(cell); /* Found */ } } return(NULL); /* Not found */}/**********************************************************************Recursion step for deadlock detection. */staticiboolsync_array_deadlock_step(/*=====================*/ /* out: TRUE if deadlock detected */ sync_array_t* arr, /* in: wait array; NOTE! the caller must own the mutex to array */ sync_cell_t* start, /* in: cell where recursive search started */ os_thread_id_t thread, /* in: thread to look at */ ulint pass, /* in: pass value */ ulint depth) /* in: recursion depth */{ sync_cell_t* new; ibool ret; depth++; if (pass != 0) { /* If pass != 0, then we do not know which threads are responsible of releasing the lock, and no deadlock can be detected. */ return(FALSE); } new = sync_array_find_thread(arr, thread); if (new == start) { /* Stop running of other threads */ ut_dbg_stop_threads = TRUE; /* Deadlock */ fputs("########################################\n" "DEADLOCK of threads detected!\n", stderr); return(TRUE); } else if (new) { ret = sync_array_detect_deadlock(arr, start, new, depth); if (ret) { return(TRUE); } } return(FALSE);}/**********************************************************************This function is called only in the debug version. Detects a deadlockof one or more threads because of waits of semaphores. */staticiboolsync_array_detect_deadlock(/*=======================*/ /* out: TRUE if deadlock detected */ sync_array_t* arr, /* in: wait array; NOTE! the caller must own the mutex to array */ sync_cell_t* start, /* in: cell where recursive search started */ sync_cell_t* cell, /* in: cell to search */ ulint depth) /* in: recursion depth */{ mutex_t* mutex; rw_lock_t* lock; os_thread_id_t thread; ibool ret; rw_lock_debug_t*debug; ut_a(arr && start && cell); ut_ad(cell->wait_object); ut_ad(os_thread_get_curr_id() == start->thread); ut_ad(depth < 100); depth++; if (cell->event_set || !cell->waiting) { return(FALSE); /* No deadlock here */ } if (cell->request_type == SYNC_MUTEX) { mutex = cell->wait_object; if (mutex_get_lock_word(mutex) != 0) { thread = mutex->thread_id; /* Note that mutex->thread_id above may be also OS_THREAD_ID_UNDEFINED, because the thread which held the mutex maybe has not yet updated the value, or it has already released the mutex: in this case no deadlock can occur, as the wait array cannot contain a thread with ID_UNDEFINED value. */ ret = sync_array_deadlock_step(arr, start, thread, 0, depth); if (ret) { fprintf(stderr, "Mutex %p owned by thread %lu file %s line %lu\n", mutex, (ulong) os_thread_pf(mutex->thread_id), mutex->file_name, (ulong) mutex->line); sync_array_cell_print(stderr, cell); return(TRUE); } } return(FALSE); /* No deadlock */ } else if (cell->request_type == RW_LOCK_EX) { lock = cell->wait_object; debug = UT_LIST_GET_FIRST(lock->debug_list); while (debug != NULL) { thread = debug->thread_id; if (((debug->lock_type == RW_LOCK_EX) && !os_thread_eq(thread, cell->thread)) || ((debug->lock_type == RW_LOCK_WAIT_EX) && !os_thread_eq(thread, cell->thread)) || (debug->lock_type == RW_LOCK_SHARED)) { /* The (wait) x-lock request can block infinitely only if someone (can be also cell thread) is holding s-lock, or someone (cannot be cell thread) (wait) x-lock, and he is blocked by start thread */ ret = sync_array_deadlock_step(arr, start, thread, debug->pass, depth); if (ret) { print: fprintf(stderr, "rw-lock %p ", lock); sync_array_cell_print(stderr, cell); rw_lock_debug_print(debug); return(TRUE); } } debug = UT_LIST_GET_NEXT(list, debug); } return(FALSE); } else if (cell->request_type == RW_LOCK_SHARED) { lock = cell->wait_object; debug = UT_LIST_GET_FIRST(lock->debug_list); while (debug != NULL) { thread = debug->thread_id; if ((debug->lock_type == RW_LOCK_EX) || (debug->lock_type == RW_LOCK_WAIT_EX)) { /* The s-lock request can block infinitely only if someone (can also be cell thread) is holding (wait) x-lock, and he is blocked by start thread */ ret = sync_array_deadlock_step(arr, start, thread, debug->pass, depth); if (ret) { goto print; } } debug = UT_LIST_GET_NEXT(list, debug); } return(FALSE); } else { ut_error; } return(TRUE); /* Execution never reaches this line: for compiler fooling only */}#endif /* UNIV_SYNC_DEBUG *//**********************************************************************Determines if we can wake up the thread waiting for a sempahore. */staticiboolsync_arr_cell_can_wake_up(/*======================*/ sync_cell_t* cell) /* in: cell to search */{ mutex_t* mutex; rw_lock_t* lock; if (cell->request_type == SYNC_MUTEX) { mutex = cell->wait_object; if (mutex_get_lock_word(mutex) == 0) { return(TRUE); } } else if (cell->request_type == RW_LOCK_EX) { lock = cell->wait_object; if (rw_lock_get_reader_count(lock) == 0 && rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED) { return(TRUE); } if (rw_lock_get_reader_count(lock) == 0 && rw_lock_get_writer(lock) == RW_LOCK_WAIT_EX && os_thread_eq(lock->writer_thread, cell->thread)) { return(TRUE); } } else if (cell->request_type == RW_LOCK_SHARED) { lock = cell->wait_object; if (rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED) { return(TRUE); } } return(FALSE);}/**********************************************************************Frees the cell. NOTE! sync_array_wait_event frees the cellautomatically! */voidsync_array_free_cell(/*=================*/ sync_array_t* arr, /* in: wait array */ ulint index) /* in: index of the cell in array */{ sync_cell_t* cell; sync_array_enter(arr); cell = sync_array_get_nth_cell(arr, index); ut_a(cell->wait_object != NULL); cell->wait_object = NULL; ut_a(arr->n_reserved > 0); arr->n_reserved--; sync_array_exit(arr);}/**************************************************************************Looks for the cells in the wait array which refer to the wait objectspecified, and sets their corresponding events to the signaled state. In thisway releases the threads waiting for the object to contend for the object.It is possible that no such cell is found, in which case does nothing. */voidsync_array_signal_object(/*=====================*/ sync_array_t* arr, /* in: wait array */ void* object) /* in: wait object */{ sync_cell_t* cell; ulint count; ulint i; sync_array_enter(arr); arr->sg_count++; i = 0; count = 0; while (count < arr->n_reserved) { cell = sync_array_get_nth_cell(arr, i); if (cell->wait_object != NULL) { count++; if (cell->wait_object == object) { sync_cell_event_set(cell); } } i++; } sync_array_exit(arr);}/**************************************************************************If the wakeup algorithm does not work perfectly at semaphore relases,this function will do the waking (see the comment in mutex_exit). Thisfunction should be called about every 1 second in the server. */voidsync_arr_wake_threads_if_sema_free(void)/*====================================*/{ sync_array_t* arr = sync_primary_wait_array; sync_cell_t* cell; ulint count; ulint i; sync_array_enter(arr); i = 0; count = 0; while (count < arr->n_reserved) { cell = sync_array_get_nth_cell(arr, i); if (cell->wait_object != NULL) { count++; if (sync_arr_cell_can_wake_up(cell)) { sync_cell_event_set(cell); } } i++; } sync_array_exit(arr);}/**************************************************************************Prints warnings of long semaphore waits to stderr. */iboolsync_array_print_long_waits(void)/*=============================*/ /* out: TRUE if fatal semaphore wait threshold was exceeded */{ sync_cell_t* cell; ibool old_val; ibool noticed = FALSE; ulint i; ulint fatal_timeout = srv_fatal_semaphore_wait_threshold; ibool fatal = FALSE; for (i = 0; i < sync_primary_wait_array->n_cells; i++) { cell = sync_array_get_nth_cell(sync_primary_wait_array, i); if (cell->wait_object != NULL && difftime(time(NULL), cell->reservation_time) > 240) { fputs("InnoDB: Warning: a long semaphore wait:\n", stderr); sync_array_cell_print(stderr, cell); noticed = TRUE; } if (cell->wait_object != NULL && difftime(time(NULL), cell->reservation_time) > fatal_timeout) { fatal = TRUE; } } if (noticed) { fprintf(stderr,"InnoDB: ###### Starts InnoDB Monitor for 30 secs to print diagnostic info:\n"); old_val = srv_print_innodb_monitor; /* If some crucial semaphore is reserved, then also the InnoDB Monitor can hang, and we do not get diagnostics. Since in many cases an InnoDB hang is caused by a pwrite() or a pread() call hanging inside the operating system, let us print right now the values of pending calls of these. */ fprintf(stderr,"InnoDB: Pending preads %lu, pwrites %lu\n", (ulong)os_file_n_pending_preads, (ulong)os_file_n_pending_pwrites); srv_print_innodb_monitor = TRUE; os_event_set(srv_lock_timeout_thread_event); os_thread_sleep(30000000); srv_print_innodb_monitor = old_val; fprintf(stderr,"InnoDB: ###### Diagnostic info printed to the standard error stream\n"); } return(fatal);}/**************************************************************************Prints info of the wait array. */staticvoidsync_array_output_info(/*===================*/ FILE* file, /* in: file where to print */ sync_array_t* arr) /* in: wait array; NOTE! caller must own the mutex */{ sync_cell_t* cell; ulint count; ulint i; fprintf(file, "OS WAIT ARRAY INFO: reservation count %ld, signal count %ld\n", (long) arr->res_count, (long) arr->sg_count); i = 0; count = 0; while (count < arr->n_reserved) { cell = sync_array_get_nth_cell(arr, i); if (cell->wait_object != NULL) { count++; sync_array_cell_print(file, cell); } i++; }}/**************************************************************************Prints info of the wait array. */voidsync_array_print_info(/*==================*/ FILE* file, /* in: file where to print */ sync_array_t* arr) /* in: wait array */{ sync_array_enter(arr); sync_array_output_info(file, arr); sync_array_exit(arr);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -