📄 sync0sync.c
字号:
calling pthread_mutex_trylock (in mutex_test_and_set implementation). Then we could end up spinning here indefinitely. The following 'i++' stops this infinite spin. */ i++; if (i < SYNC_SPIN_ROUNDS) { goto spin_loop; } sync_array_reserve_cell(sync_primary_wait_array, mutex, SYNC_MUTEX, file_name, line, &index); mutex_system_call_count++; /* The memory order of the array reservation and the change in the waiters field is important: when we suspend a thread, we first reserve the cell and then set waiters field to 1. When threads are released in mutex_exit, the waiters field is first set to zero and then the event is set to the signaled state. */ mutex_set_waiters(mutex, 1); /* Try to reserve still a few times */ for (i = 0; i < 4; i++) { if (mutex_test_and_set(mutex) == 0) { /* Succeeded! Free the reserved wait cell */ sync_array_free_cell(sync_primary_wait_array, index);#ifdef UNIV_SYNC_DEBUG mutex_set_debug_info(mutex, file_name, line);#endif#ifdef UNIV_SRV_PRINT_LATCH_WAITS fprintf(stderr, "Thread %lu spin wait succeeds at 2:" " mutex at %p\n", (ulong) os_thread_pf(os_thread_get_curr_id()), mutex);#endif goto finish_timing; /* Note that in this case we leave the waiters field set to 1. We cannot reset it to zero, as we do not know if there are other waiters. */ } } /* Now we know that there has been some thread holding the mutex after the change in the wait array and the waiters field was made.Now there is no risk of infinite wait on the event. */#ifdef UNIV_SRV_PRINT_LATCH_WAITS fprintf(stderr, "Thread %lu OS wait mutex at %p cfile %s cline %lu rnds %lu\n", (ulong) os_thread_pf(os_thread_get_curr_id()), mutex, mutex->cfile_name, (ulong) mutex->cline, (ulong) i);#endif mutex_system_call_count++; mutex_os_wait_count++;#ifndef UNIV_HOTBACKUP mutex->count_os_wait++; /* !!!!! Sometimes os_wait can be called without os_thread_yield */ if (timed_mutexes == 1 && timer_started==0) { ut_usectime(&sec, &ms); lstart_time= (ib_longlong)sec * 1000000 + ms; timer_started = 1; }#endif /* !UNIV_HOTBACKUP */ sync_array_wait_event(sync_primary_wait_array, index); goto mutex_loop; finish_timing:#ifndef UNIV_HOTBACKUP if (timed_mutexes == 1 && timer_started==1) { ut_usectime(&sec, &ms); lfinish_time= (ib_longlong)sec * 1000000 + ms; ltime_diff= (ulint) (lfinish_time - lstart_time); mutex->lspent_time += ltime_diff; if (mutex->lmax_spent_time < ltime_diff) { mutex->lmax_spent_time= ltime_diff; } }#endif /* !UNIV_HOTBACKUP */ return;}/**********************************************************************Releases the threads waiting in the primary wait array for this mutex. */voidmutex_signal_object(/*================*/ mutex_t* mutex) /* in: mutex */{ mutex_set_waiters(mutex, 0); /* The memory order of resetting the waiters field and signaling the object is important. See LEMMA 1 above. */ sync_array_signal_object(sync_primary_wait_array, mutex);}#ifdef UNIV_SYNC_DEBUG/**********************************************************************Sets the debug information for a reserved mutex. */voidmutex_set_debug_info(/*=================*/ mutex_t* mutex, /* in: mutex */ const char* file_name, /* in: file where requested */ ulint line) /* in: line where requested */{ ut_ad(mutex); ut_ad(file_name); sync_thread_add_level(mutex, mutex->level); mutex->file_name = file_name; mutex->line = line; mutex->thread_id = os_thread_get_curr_id();} /**********************************************************************Gets the debug information for a reserved mutex. */voidmutex_get_debug_info(/*=================*/ mutex_t* mutex, /* in: mutex */ const char** file_name, /* out: file where requested */ ulint* line, /* out: line where requested */ os_thread_id_t* thread_id) /* out: id of the thread which owns the mutex */{ ut_ad(mutex); *file_name = mutex->file_name; *line = mutex->line; *thread_id = mutex->thread_id;}#endif /* UNIV_SYNC_DEBUG *//**********************************************************************Sets the mutex latching level field. */voidmutex_set_level(/*============*/ mutex_t* mutex, /* in: mutex */ ulint level) /* in: level */{ mutex->level = level;}#ifdef UNIV_SYNC_DEBUG/**********************************************************************Checks that the current thread owns the mutex. Works only in the debugversion. */iboolmutex_own(/*======*/ /* out: TRUE if owns */ mutex_t* mutex) /* in: mutex */{ ut_a(mutex_validate(mutex)); if (mutex_get_lock_word(mutex) != 1) { return(FALSE); } if (!os_thread_eq(mutex->thread_id, os_thread_get_curr_id())) { return(FALSE); } return(TRUE);}/**********************************************************************Prints debug info of currently reserved mutexes. */voidmutex_list_print_info(void)/*=======================*/{ mutex_t* mutex; const char* file_name; ulint line; os_thread_id_t thread_id; ulint count = 0; fputs("----------\n" "MUTEX INFO\n" "----------\n", stderr); mutex_enter(&mutex_list_mutex); mutex = UT_LIST_GET_FIRST(mutex_list); while (mutex != NULL) { count++; if (mutex_get_lock_word(mutex) != 0) { mutex_get_debug_info(mutex, &file_name, &line, &thread_id); fprintf(stderr, "Locked mutex: addr %p thread %ld file %s line %ld\n", mutex, os_thread_pf(thread_id), file_name, line); } mutex = UT_LIST_GET_NEXT(list, mutex); } fprintf(stderr, "Total number of mutexes %ld\n", count); mutex_exit(&mutex_list_mutex);}/**********************************************************************Counts currently reserved mutexes. Works only in the debug version. */ulintmutex_n_reserved(void)/*==================*/{ mutex_t* mutex; ulint count = 0; mutex_enter(&mutex_list_mutex); mutex = UT_LIST_GET_FIRST(mutex_list); while (mutex != NULL) { if (mutex_get_lock_word(mutex) != 0) { count++; } mutex = UT_LIST_GET_NEXT(list, mutex); } mutex_exit(&mutex_list_mutex); ut_a(count >= 1); return(count - 1); /* Subtract one, because this function itself was holding one mutex (mutex_list_mutex) */}/**********************************************************************Returns TRUE if no mutex or rw-lock is currently locked. Works only inthe debug version. */iboolsync_all_freed(void)/*================*/{ return(mutex_n_reserved() + rw_lock_n_locked() == 0);}#endif /* UNIV_SYNC_DEBUG *//**********************************************************************Gets the value in the nth slot in the thread level arrays. */staticsync_thread_t*sync_thread_level_arrays_get_nth(/*=============================*/ /* out: pointer to thread slot */ ulint n) /* in: slot number */{ ut_ad(n < OS_THREAD_MAX_N); return(sync_thread_level_arrays + n);}/**********************************************************************Looks for the thread slot for the calling thread. */staticsync_thread_t*sync_thread_level_arrays_find_slot(void)/*====================================*/ /* out: pointer to thread slot, NULL if not found */ { sync_thread_t* slot; os_thread_id_t id; ulint i; id = os_thread_get_curr_id(); for (i = 0; i < OS_THREAD_MAX_N; i++) { slot = sync_thread_level_arrays_get_nth(i); if (slot->levels && os_thread_eq(slot->id, id)) { return(slot); } } return(NULL);}/**********************************************************************Looks for an unused thread slot. */staticsync_thread_t*sync_thread_level_arrays_find_free(void)/*====================================*/ /* out: pointer to thread slot */ { sync_thread_t* slot; ulint i; for (i = 0; i < OS_THREAD_MAX_N; i++) { slot = sync_thread_level_arrays_get_nth(i); if (slot->levels == NULL) { return(slot); } } return(NULL);}/**********************************************************************Gets the value in the nth slot in the thread level array. */staticsync_level_t*sync_thread_levels_get_nth(/*=======================*/ /* out: pointer to level slot */ sync_level_t* arr, /* in: pointer to level array for an OS thread */ ulint n) /* in: slot number */{ ut_ad(n < SYNC_THREAD_N_LEVELS); return(arr + n);}/**********************************************************************Checks if all the level values stored in the level array are greater thanthe given limit. */staticiboolsync_thread_levels_g(/*=================*/ /* out: TRUE if all greater */ sync_level_t* arr, /* in: pointer to level array for an OS thread */ ulint limit) /* in: level limit */{ sync_level_t* slot; rw_lock_t* lock; mutex_t* mutex; ulint i; for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) { slot = sync_thread_levels_get_nth(arr, i); if (slot->latch != NULL) { if (slot->level <= limit) { lock = slot->latch; mutex = slot->latch; fprintf(stderr, "InnoDB error: sync levels should be > %lu but a level is %lu\n", (ulong) limit, (ulong) slot->level); if (mutex->magic_n == MUTEX_MAGIC_N) { fprintf(stderr, "Mutex created at %s %lu\n", mutex->cfile_name, (ulong) mutex->cline); if (mutex_get_lock_word(mutex) != 0) {#ifdef UNIV_SYNC_DEBUG const char* file_name; ulint line; os_thread_id_t thread_id; mutex_get_debug_info(mutex, &file_name, &line, &thread_id); fprintf(stderr, "InnoDB: Locked mutex: addr %p thread %ld file %s line %ld\n", mutex, os_thread_pf(thread_id), file_name, (ulong) line);#else /* UNIV_SYNC_DEBUG */ fprintf(stderr, "InnoDB: Locked mutex: addr %p\n", mutex);#endif /* UNIV_SYNC_DEBUG */ } else { fputs("Not locked\n", stderr); } } else {#ifdef UNIV_SYNC_DEBUG rw_lock_print(lock);#endif /* UNIV_SYNC_DEBUG */ } return(FALSE); } } } return(TRUE);}/**********************************************************************Checks if the level value is stored in the level array. */staticiboolsync_thread_levels_contain(/*=======================*/ /* out: TRUE if stored */ sync_level_t* arr, /* in: pointer to level array for an OS thread */ ulint level) /* in: level */{ sync_level_t* slot; ulint i; for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) { slot = sync_thread_levels_get_nth(arr, i); if (slot->latch != NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -