void rw_lock_add_debug_info( /*===================*/ rw_lock_t* lock, /* in: rw-lock */ ulint pass, /* in: pass value */ ulint lock_type, /* in: lock type */ const char* file_name, /* in: file where requested */ ulint line) /* in: line where requested */ { rw_lock_debug_t* info; ut_ad(lock); ut_ad(file_name); info = rw_lock_debug_create(); rw_lock_debug_mutex_enter(); info->file_name = file_name; info->line = line; info->lock_type = lock_type; info->thread_id = os_thread_get_curr_id(); info->pass = pass; UT_LIST_ADD_FIRST(list, lock->debug_list, info); rw_lock_debug_mutex_exit(); if ((pass == 0) && (lock_type != RW_LOCK_WAIT_EX)) { sync_thread_add_level(lock, lock->level); } }
/******************************************************************//** Checks if the thread has locked the rw-lock in the specified mode, with the pass value == 0. @return TRUE if locked */ UNIV_INTERN ibool rw_lock_own( /*========*/ rw_lock_t* lock, /*!< in: rw-lock */ ulint lock_type) /*!< in: lock type: RW_LOCK_SHARED, RW_LOCK_EX */ { rw_lock_debug_t* info; ut_ad(lock); ut_ad(rw_lock_validate(lock)); rw_lock_debug_mutex_enter(); info = UT_LIST_GET_FIRST(lock->debug_list); while (info != NULL) { if (os_thread_eq(info->thread_id, os_thread_get_curr_id()) && (info->pass == 0) && (info->lock_type == lock_type)) { rw_lock_debug_mutex_exit(); /* Found! */ return(TRUE); } info = UT_LIST_GET_NEXT(list, info); } rw_lock_debug_mutex_exit(); return(FALSE); }
void sync_array_wait_event( /*==================*/ sync_array_t* arr, /* in: wait array */ ulint index) /* in: index of the reserved cell */ { sync_cell_t* cell; os_event_t event; ut_a(arr); sync_array_enter(arr); cell = sync_array_get_nth_cell(arr, index); ut_a(cell->wait_object); ut_a(!cell->waiting); ut_ad(os_thread_get_curr_id() == cell->thread); if (cell->request_type == SYNC_MUTEX) { event = ((mutex_t*) cell->wait_object)->event; #ifdef __WIN__ /* On windows if the thread about to wait is the one which has set the state of the rw_lock to RW_LOCK_WAIT_EX, then it waits on a special event i.e.: wait_ex_event. */ } else if (cell->request_type == RW_LOCK_WAIT_EX) { event = ((rw_lock_t*) cell->wait_object)->wait_ex_event; #endif } else { event = ((rw_lock_t*) cell->wait_object)->event; } cell->waiting = TRUE; #ifdef UNIV_SYNC_DEBUG /* We use simple enter to the mutex below, because if we cannot acquire it at once, mutex_enter would call recursively sync_array routines, leading to trouble. rw_lock_debug_mutex freezes the debug lists. */ rw_lock_debug_mutex_enter(); if (TRUE == sync_array_detect_deadlock(arr, cell, cell, 0)) { fputs("########################################\n", stderr); ut_error; } rw_lock_debug_mutex_exit(); #endif sync_array_exit(arr); os_event_wait_low(event, cell->signal_count); sync_array_free_cell(arr, index); }
/***************************************************************//** Prints debug info of currently locked rw-locks. */ UNIV_INTERN void rw_lock_list_print_info( /*====================*/ FILE* file) /*!< in: file where to print */ { rw_lock_t* lock; ulint count = 0; rw_lock_debug_t* info; mutex_enter(&rw_lock_list_mutex); fputs("-------------\n" "RW-LATCH INFO\n" "-------------\n", file); lock = UT_LIST_GET_FIRST(rw_lock_list); while (lock != NULL) { count++; #ifndef INNODB_RW_LOCKS_USE_ATOMICS mutex_enter(&(lock->mutex)); #endif if (lock->lock_word != X_LOCK_DECR) { fprintf(file, "RW-LOCK: %p ", (void*) lock); if (rw_lock_get_waiters(lock)) { fputs(" Waiters for the lock exist\n", file); } else { putc('\n', file); } rw_lock_debug_mutex_enter(); info = UT_LIST_GET_FIRST(lock->debug_list); while (info != NULL) { rw_lock_debug_print(file, info); info = UT_LIST_GET_NEXT(list, info); } rw_lock_debug_mutex_exit(); } #ifndef INNODB_RW_LOCKS_USE_ATOMICS mutex_exit(&(lock->mutex)); #endif lock = UT_LIST_GET_NEXT(list, lock); } fprintf(file, "Total number of rw-locks %ld\n", count); mutex_exit(&rw_lock_list_mutex); }
/******************************************************************//** This function should be called when a thread starts to wait on a wait array cell. In the debug version this function checks if the wait for a semaphore will result in a deadlock, in which case prints info and asserts. */ UNIV_INTERN void sync_array_wait_event( /*==================*/ sync_array_t* arr, /*!< in: wait array */ ulint index) /*!< in: index of the reserved cell */ { sync_cell_t* cell; os_event_t event; ut_a(arr); sync_array_enter(arr); cell = sync_array_get_nth_cell(arr, index); ut_a(cell->wait_object); ut_a(!cell->waiting); ut_ad(os_thread_get_curr_id() == cell->thread); event = sync_cell_get_event(cell); cell->waiting = TRUE; #ifdef UNIV_SYNC_DEBUG /* We use simple enter to the mutex below, because if we cannot acquire it at once, mutex_enter would call recursively sync_array routines, leading to trouble. rw_lock_debug_mutex freezes the debug lists. */ rw_lock_debug_mutex_enter(); if (TRUE == sync_array_detect_deadlock(arr, cell, cell, 0)) { fputs("########################################\n", stderr); ut_error; } rw_lock_debug_mutex_exit(); #endif sync_array_exit(arr); os_event_wait_low(event, cell->signal_count); sync_array_free_cell(arr, index); }
/******************************************************************//** Removes a debug information struct for an rw-lock. */ UNIV_INTERN void rw_lock_remove_debug_info( /*======================*/ rw_lock_t* lock, /*!< in: rw-lock */ ulint pass, /*!< in: pass value */ ulint lock_type) /*!< in: lock type */ { rw_lock_debug_t* info; ut_ad(lock); if ((pass == 0) && (lock_type != RW_LOCK_WAIT_EX)) { sync_thread_reset_level(lock); } rw_lock_debug_mutex_enter(); info = UT_LIST_GET_FIRST(lock->debug_list); while (info != NULL) { if ((pass == info->pass) && ((pass != 0) || os_thread_eq(info->thread_id, os_thread_get_curr_id())) && (info->lock_type == lock_type)) { /* Found! */ UT_LIST_REMOVE(list, lock->debug_list, info); rw_lock_debug_mutex_exit(); rw_lock_debug_free(info); return; } info = UT_LIST_GET_NEXT(list, info); } ut_error; }
/***************************************************************//** Prints debug info of an rw-lock. */ UNIV_INTERN void rw_lock_print( /*==========*/ rw_lock_t* lock) /*!< in: rw-lock */ { rw_lock_debug_t* info; fprintf(stderr, "-------------\n" "RW-LATCH INFO\n" "RW-LATCH: %p ", (void*) lock); #ifndef INNODB_RW_LOCKS_USE_ATOMICS /* We used to acquire lock->mutex here, but it would cause a recursive call to sync_thread_add_level() if UNIV_SYNC_DEBUG is defined. Since this function is only invoked from sync_thread_levels_g(), let us choose the smaller evil: performing dirty reads instead of causing bogus deadlocks or assertion failures. */ #endif if (lock->lock_word != X_LOCK_DECR) { if (rw_lock_get_waiters(lock)) { fputs(" Waiters for the lock exist\n", stderr); } else { putc('\n', stderr); } rw_lock_debug_mutex_enter(); info = UT_LIST_GET_FIRST(lock->debug_list); while (info != NULL) { rw_lock_debug_print(stderr, info); info = UT_LIST_GET_NEXT(list, info); } rw_lock_debug_mutex_exit(); } }