ibool rw_lock_own( /*========*/ /* out: TRUE if locked */ 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)); mutex_enter(&(lock->mutex)); 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)) { mutex_exit(&(lock->mutex)); /* Found! */ return(TRUE); } info = UT_LIST_GET_NEXT(list, info); } mutex_exit(&(lock->mutex)); return(FALSE); }
ibool rw_lock_is_locked( /*==============*/ /* out: TRUE if locked */ rw_lock_t* lock, /* in: rw-lock */ ulint lock_type) /* in: lock type: RW_LOCK_SHARED, RW_LOCK_EX */ { ibool ret = FALSE; ut_ad(lock); ut_ad(rw_lock_validate(lock)); mutex_enter(&(lock->mutex)); if (lock_type == RW_LOCK_SHARED) { if (lock->reader_count > 0) { ret = TRUE; } } else if (lock_type == RW_LOCK_EX) { if (lock->writer == RW_LOCK_EX) { ret = TRUE; } } else { ut_error; } mutex_exit(&(lock->mutex)); return(ret); }
/******************************************************************//** Checks if somebody has locked the rw-lock in the specified mode. @return TRUE if locked */ UNIV_INTERN ibool rw_lock_is_locked( /*==============*/ rw_lock_t* lock, /*!< in: rw-lock */ ulint lock_type) /*!< in: lock type: RW_LOCK_SHARED, RW_LOCK_EX */ { ibool ret = FALSE; ut_ad(lock); ut_ad(rw_lock_validate(lock)); if (lock_type == RW_LOCK_SHARED) { if (rw_lock_get_reader_count(lock) > 0) { ret = TRUE; } } else if (lock_type == RW_LOCK_EX) { if (rw_lock_get_writer(lock) == RW_LOCK_EX) { ret = TRUE; } } else { ut_error; } return(ret); }
void rw_lock_free( /*=========*/ rw_lock_t* lock) /* in: rw-lock */ { ut_ad(rw_lock_validate(lock)); ut_a(rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED); ut_a(rw_lock_get_waiters(lock) == 0); ut_a(rw_lock_get_reader_count(lock) == 0); lock->magic_n = 0; mutex_free(rw_lock_get_mutex(lock)); mutex_enter(&rw_lock_list_mutex); os_event_free(lock->event); #ifdef __WIN__ os_event_free(lock->wait_ex_event); #endif if (UT_LIST_GET_PREV(list, lock)) { ut_a(UT_LIST_GET_PREV(list, lock)->magic_n == RW_LOCK_MAGIC_N); } if (UT_LIST_GET_NEXT(list, lock)) { ut_a(UT_LIST_GET_NEXT(list, lock)->magic_n == RW_LOCK_MAGIC_N); } UT_LIST_REMOVE(list, rw_lock_list, lock); mutex_exit(&rw_lock_list_mutex); }
/******************************************************************//** Calling this function is obligatory only if the memory buffer containing the rw-lock is freed. Removes an rw-lock object from the global list. The rw-lock is checked to be in the non-locked state. */ UNIV_INTERN void rw_lock_free_func( /*==============*/ rw_lock_t* lock) /*!< in: rw-lock */ { ut_ad(rw_lock_validate(lock)); ut_a(lock->lock_word == X_LOCK_DECR); #ifndef INNODB_RW_LOCKS_USE_ATOMICS mutex_free(rw_lock_get_mutex(lock)); #endif /* INNODB_RW_LOCKS_USE_ATOMICS */ mutex_enter(&rw_lock_list_mutex); os_event_free(lock->event); os_event_free(lock->wait_ex_event); ut_ad(UT_LIST_GET_PREV(list, lock) == NULL || UT_LIST_GET_PREV(list, lock)->magic_n == RW_LOCK_MAGIC_N); ut_ad(UT_LIST_GET_NEXT(list, lock) == NULL || UT_LIST_GET_NEXT(list, lock)->magic_n == RW_LOCK_MAGIC_N); UT_LIST_REMOVE(list, rw_lock_list, lock); mutex_exit(&rw_lock_list_mutex); ut_d(lock->magic_n = 0); }
void rw_lock_free( /*=========*/ rw_lock_t* lock) /* in: rw-lock */ { ut_ad(rw_lock_validate(lock)); ut_a(rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED); ut_a(rw_lock_get_waiters(lock) == 0); ut_a(rw_lock_get_reader_count(lock) == 0); lock->magic_n = 0; mutex_free(rw_lock_get_mutex(lock)); mutex_enter(&rw_lock_list_mutex); UT_LIST_REMOVE(list, rw_lock_list, lock); mutex_exit(&rw_lock_list_mutex); }
ibool rw_lock_own( /*========*/ /* out: TRUE if locked */ rw_lock_t* lock, /* in: rw-lock */ ulint lock_type) /* in: lock type */ { rw_lock_debug_t* info; ut_ad(lock); ut_ad(rw_lock_validate(lock)); #ifndef UNIV_SYNC_DEBUG ut_error; #endif mutex_enter(&(lock->mutex)); info = UT_LIST_GET_FIRST(lock->debug_list); while (info != NULL) { if ((info->thread_id == os_thread_get_curr_id()) && (info->pass == 0) && (info->lock_type == lock_type)) { mutex_exit(&(lock->mutex)); /* Found! */ return(TRUE); } info = UT_LIST_GET_NEXT(list, info); } mutex_exit(&(lock->mutex)); return(FALSE); }
void rw_lock_x_lock_func( /*================*/ rw_lock_t* lock, /* in: pointer to rw-lock */ ulint pass, /* in: pass value; != 0, if the lock will be passed to another thread to unlock */ const char* file_name,/* in: file name where lock requested */ ulint line) /* in: line where requested */ { ulint index; /* index of the reserved wait cell */ ulint state; /* lock state acquired */ ulint i; /* spin round count */ ut_ad(rw_lock_validate(lock)); lock_loop: /* Acquire the mutex protecting the rw-lock fields */ mutex_enter_fast(&(lock->mutex)); state = rw_lock_x_lock_low(lock, pass, file_name, line); mutex_exit(&(lock->mutex)); if (state == RW_LOCK_EX) { return; /* Locking succeeded */ } else if (state == RW_LOCK_NOT_LOCKED) { /* Spin waiting for the writer field to become free */ i = 0; while (rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED && i < SYNC_SPIN_ROUNDS) { if (srv_spin_wait_delay) { ut_delay(ut_rnd_interval(0, srv_spin_wait_delay)); } i++; } if (i == SYNC_SPIN_ROUNDS) { os_thread_yield(); } } else if (state == RW_LOCK_WAIT_EX) { /* Spin waiting for the reader count field to become zero */ i = 0; while (rw_lock_get_reader_count(lock) != 0 && i < SYNC_SPIN_ROUNDS) { if (srv_spin_wait_delay) { ut_delay(ut_rnd_interval(0, srv_spin_wait_delay)); } i++; } if (i == SYNC_SPIN_ROUNDS) { os_thread_yield(); } } else { i = 0; /* Eliminate a compiler warning */ ut_error; } if (srv_print_latch_waits) { fprintf(stderr, "Thread %lu spin wait rw-x-lock at %p" " cfile %s cline %lu rnds %lu\n", os_thread_pf(os_thread_get_curr_id()), (void*) lock, lock->cfile_name, (ulong) lock->cline, (ulong) i); } rw_x_spin_wait_count++; /* We try once again to obtain the lock. Acquire the mutex protecting the rw-lock fields */ mutex_enter(rw_lock_get_mutex(lock)); state = rw_lock_x_lock_low(lock, pass, file_name, line); if (state == RW_LOCK_EX) { mutex_exit(rw_lock_get_mutex(lock)); return; /* Locking succeeded */ } rw_x_system_call_count++; sync_array_reserve_cell(sync_primary_wait_array, lock, #ifdef __WIN__ /* On windows RW_LOCK_WAIT_EX signifies that this thread should wait on the special wait_ex_event. */ (state == RW_LOCK_WAIT_EX) ? RW_LOCK_WAIT_EX : #endif RW_LOCK_EX, file_name, line, &index); rw_lock_set_waiters(lock, 1); mutex_exit(rw_lock_get_mutex(lock)); if (srv_print_latch_waits) { fprintf(stderr, "Thread %lu OS wait for rw-x-lock at %p" " cfile %s cline %lu\n", os_thread_pf(os_thread_get_curr_id()), (void*) lock, lock->cfile_name, (ulong) lock->cline); } rw_x_system_call_count++; rw_x_os_wait_count++; sync_array_wait_event(sync_primary_wait_array, index); goto lock_loop; }
void rw_lock_s_lock_spin( /*================*/ rw_lock_t* lock, /* in: pointer to rw-lock */ ulint pass, /* in: pass value; != 0, if the lock will be passed to another thread to unlock */ const char* file_name, /* in: file name where lock requested */ ulint line) /* in: line where requested */ { ulint index; /* index of the reserved wait cell */ ulint i; /* spin round count */ ut_ad(rw_lock_validate(lock)); lock_loop: rw_s_spin_wait_count++; /* Spin waiting for the writer field to become free */ i = 0; while (rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED && i < SYNC_SPIN_ROUNDS) { if (srv_spin_wait_delay) { ut_delay(ut_rnd_interval(0, srv_spin_wait_delay)); } i++; } if (i == SYNC_SPIN_ROUNDS) { os_thread_yield(); } if (srv_print_latch_waits) { fprintf(stderr, "Thread %lu spin wait rw-s-lock at %p" " cfile %s cline %lu rnds %lu\n", (ulong) os_thread_pf(os_thread_get_curr_id()), (void*) lock, lock->cfile_name, (ulong) lock->cline, (ulong) i); } mutex_enter(rw_lock_get_mutex(lock)); /* We try once again to obtain the lock */ if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) { mutex_exit(rw_lock_get_mutex(lock)); return; /* Success */ } else { /* If we get here, locking did not succeed, we may suspend the thread to wait in the wait array */ rw_s_system_call_count++; sync_array_reserve_cell(sync_primary_wait_array, lock, RW_LOCK_SHARED, file_name, line, &index); rw_lock_set_waiters(lock, 1); mutex_exit(rw_lock_get_mutex(lock)); if (srv_print_latch_waits) { fprintf(stderr, "Thread %lu OS wait rw-s-lock at %p" " cfile %s cline %lu\n", os_thread_pf(os_thread_get_curr_id()), (void*) lock, lock->cfile_name, (ulong) lock->cline); } rw_s_system_call_count++; rw_s_os_wait_count++; sync_array_wait_event(sync_primary_wait_array, index); goto lock_loop; } }
/******************************************************************//** NOTE! Use the corresponding macro, not directly this function! Lock an rw-lock in exclusive mode for the current thread. If the rw-lock is locked in shared or exclusive mode, or there is an exclusive lock request waiting, the function spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting for the lock before suspending the thread. If the same thread has an x-lock on the rw-lock, locking succeed, with the following exception: if pass != 0, only a single x-lock may be taken on the lock. NOTE: If the same thread has an s-lock, locking does not succeed! */ UNIV_INTERN void rw_lock_x_lock_func( /*================*/ rw_lock_t* lock, /*!< in: pointer to rw-lock */ ulint pass, /*!< in: pass value; != 0, if the lock will be passed to another thread to unlock */ const char* file_name,/*!< in: file name where lock requested */ ulint line) /*!< in: line where requested */ { ulint index; /*!< index of the reserved wait cell */ ulint i; /*!< spin round count */ ibool spinning = FALSE; ut_ad(rw_lock_validate(lock)); #ifdef UNIV_SYNC_DEBUG ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); #endif /* UNIV_SYNC_DEBUG */ i = 0; lock_loop: if (rw_lock_x_lock_low(lock, pass, file_name, line)) { rw_x_spin_round_count += i; return; /* Locking succeeded */ } else { if (!spinning) { spinning = TRUE; rw_x_spin_wait_count++; } /* Spin waiting for the lock_word to become free */ while (i < SYNC_SPIN_ROUNDS && lock->lock_word <= 0) { if (srv_spin_wait_delay) { ut_delay(ut_rnd_interval(0, srv_spin_wait_delay)); } i++; } if (i == SYNC_SPIN_ROUNDS) { os_thread_yield(); } else { goto lock_loop; } } rw_x_spin_round_count += i; if (srv_print_latch_waits) { fprintf(stderr, "Thread %lu spin wait rw-x-lock at %p" " cfile %s cline %lu rnds %lu\n", os_thread_pf(os_thread_get_curr_id()), (void*) lock, innobase_basename(lock->cfile_name), (ulong) lock->cline, (ulong) i); } sync_array_reserve_cell(sync_primary_wait_array, lock, RW_LOCK_EX, file_name, line, &index); /* Waiters must be set before checking lock_word, to ensure signal is sent. This could lead to a few unnecessary wake-up signals. */ rw_lock_set_waiter_flag(lock); if (rw_lock_x_lock_low(lock, pass, file_name, line)) { sync_array_free_cell(sync_primary_wait_array, index); return; /* Locking succeeded */ } if (srv_print_latch_waits) { fprintf(stderr, "Thread %lu OS wait for rw-x-lock at %p" " cfile %s cline %lu\n", os_thread_pf(os_thread_get_curr_id()), (void*) lock, innobase_basename(lock->cfile_name), (ulong) lock->cline); } /* these stats may not be accurate */ lock->count_os_wait++; rw_x_os_wait_count++; sync_array_wait_event(sync_primary_wait_array, index); i = 0; goto lock_loop; }
/******************************************************************//** Lock an rw-lock in shared mode for the current thread. If the rw-lock is locked in exclusive mode, or there is an exclusive lock request waiting, the function spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting for the lock, before suspending the thread. */ UNIV_INTERN void rw_lock_s_lock_spin( /*================*/ rw_lock_t* lock, /*!< in: pointer to rw-lock */ ulint pass, /*!< in: pass value; != 0, if the lock will be passed to another thread to unlock */ const char* file_name, /*!< in: file name where lock requested */ ulint line) /*!< in: line where requested */ { ulint index; /* index of the reserved wait cell */ ulint i = 0; /* spin round count */ ut_ad(rw_lock_validate(lock)); rw_s_spin_wait_count++; /*!< Count calls to this function */ lock_loop: /* Spin waiting for the writer field to become free */ while (i < SYNC_SPIN_ROUNDS && lock->lock_word <= 0) { if (srv_spin_wait_delay) { ut_delay(ut_rnd_interval(0, srv_spin_wait_delay)); } i++; } if (i == SYNC_SPIN_ROUNDS) { os_thread_yield(); } if (srv_print_latch_waits) { fprintf(stderr, "Thread %lu spin wait rw-s-lock at %p" " cfile %s cline %lu rnds %lu\n", (ulong) os_thread_pf(os_thread_get_curr_id()), (void*) lock, innobase_basename(lock->cfile_name), (ulong) lock->cline, (ulong) i); } /* We try once again to obtain the lock */ if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) { rw_s_spin_round_count += i; return; /* Success */ } else { if (i < SYNC_SPIN_ROUNDS) { goto lock_loop; } rw_s_spin_round_count += i; sync_array_reserve_cell(sync_primary_wait_array, lock, RW_LOCK_SHARED, file_name, line, &index); /* Set waiters before checking lock_word to ensure wake-up signal is sent. This may lead to some unnecessary signals. */ rw_lock_set_waiter_flag(lock); if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) { sync_array_free_cell(sync_primary_wait_array, index); return; /* Success */ } if (srv_print_latch_waits) { fprintf(stderr, "Thread %lu OS wait rw-s-lock at %p" " cfile %s cline %lu\n", os_thread_pf(os_thread_get_curr_id()), (void*) lock, innobase_basename(lock->cfile_name), (ulong) lock->cline); } /* these stats may not be accurate */ lock->count_os_wait++; rw_s_os_wait_count++; sync_array_wait_event(sync_primary_wait_array, index); i = 0; goto lock_loop; } }