ulint rw_lock_n_locked(void) /*==================*/ { rw_lock_t* lock; ulint count = 0; mutex_enter(&rw_lock_list_mutex); lock = UT_LIST_GET_FIRST(rw_lock_list); while (lock != NULL) { mutex_enter(rw_lock_get_mutex(lock)); if ((rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED) || (rw_lock_get_reader_count(lock) != 0)) { count++; } mutex_exit(rw_lock_get_mutex(lock)); lock = UT_LIST_GET_NEXT(list, lock); } mutex_exit(&rw_lock_list_mutex); return(count); }
ulint rw_lock_n_locked(void) /*==================*/ { #ifndef UNIV_SYNC_DEBUG printf( "Sorry, cannot give rw-lock info in non-debug version!\n"); ut_error; return(0); #else rw_lock_t* lock; ulint count = 0; mutex_enter(&rw_lock_list_mutex); lock = UT_LIST_GET_FIRST(rw_lock_list); while (lock != NULL) { mutex_enter(rw_lock_get_mutex(lock)); if ((rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED) || (rw_lock_get_reader_count(lock) != 0)) { count++; } mutex_exit(rw_lock_get_mutex(lock)); lock = UT_LIST_GET_NEXT(list, lock); } mutex_exit(&rw_lock_list_mutex); return(count); #endif }
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_create_func( /*================*/ rw_lock_t* lock, /* in: pointer to memory */ char* cfile_name, /* in: file name where created */ ulint cline) /* in: file line where created */ { /* If this is the very first time a synchronization object is created, then the following call initializes the sync system. */ mutex_create(rw_lock_get_mutex(lock)); mutex_set_level(rw_lock_get_mutex(lock), SYNC_NO_ORDER_CHECK); lock->mutex.cfile_name = cfile_name; lock->mutex.cline = cline; rw_lock_set_waiters(lock, 0); rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED); lock->writer_count = 0; rw_lock_set_reader_count(lock, 0); lock->writer_is_wait_ex = FALSE; UT_LIST_INIT(lock->debug_list); lock->magic_n = RW_LOCK_MAGIC_N; lock->level = SYNC_LEVEL_NONE; lock->cfile_name = cfile_name; lock->cline = cline; lock->last_s_file_name = "not yet reserved"; lock->last_x_file_name = "not yet reserved"; lock->last_s_line = 0; lock->last_x_line = 0; mutex_enter(&rw_lock_list_mutex); UT_LIST_ADD_FIRST(list, rw_lock_list, lock); mutex_exit(&rw_lock_list_mutex); }
ibool rw_lock_validate( /*=============*/ rw_lock_t* lock) { ut_a(lock); mutex_enter(rw_lock_get_mutex(lock)); ut_a(lock->magic_n == RW_LOCK_MAGIC_N); ut_a((rw_lock_get_reader_count(lock) == 0) || (rw_lock_get_writer(lock) != RW_LOCK_EX)); ut_a((rw_lock_get_writer(lock) == RW_LOCK_EX) || (rw_lock_get_writer(lock) == RW_LOCK_WAIT_EX) || (rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED)); ut_a((rw_lock_get_waiters(lock) == 0) || (rw_lock_get_waiters(lock) == 1)); ut_a((lock->writer != RW_LOCK_EX) || (lock->writer_count > 0)); mutex_exit(rw_lock_get_mutex(lock)); return(TRUE); }
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); }
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; }
/********************************************************************** Low-level function for acquiring an exclusive lock. */ UNIV_INLINE ulint rw_lock_x_lock_low( /*===============*/ /* out: RW_LOCK_NOT_LOCKED if did not succeed, RW_LOCK_EX if success, RW_LOCK_WAIT_EX, if got wait reservation */ 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 */ { ut_ad(mutex_own(rw_lock_get_mutex(lock))); if (rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED) { if (rw_lock_get_reader_count(lock) == 0) { rw_lock_set_writer(lock, RW_LOCK_EX); lock->writer_thread = os_thread_get_curr_id(); lock->writer_count++; lock->pass = pass; #ifdef UNIV_SYNC_DEBUG rw_lock_add_debug_info(lock, pass, RW_LOCK_EX, file_name, line); #endif lock->last_x_file_name = file_name; lock->last_x_line = (unsigned int) line; /* Locking succeeded, we may return */ return(RW_LOCK_EX); } else { /* There are readers, we have to wait */ rw_lock_set_writer(lock, RW_LOCK_WAIT_EX); lock->writer_thread = os_thread_get_curr_id(); lock->pass = pass; lock->writer_is_wait_ex = TRUE; #ifdef UNIV_SYNC_DEBUG rw_lock_add_debug_info(lock, pass, RW_LOCK_WAIT_EX, file_name, line); #endif return(RW_LOCK_WAIT_EX); } } else if ((rw_lock_get_writer(lock) == RW_LOCK_WAIT_EX) && os_thread_eq(lock->writer_thread, os_thread_get_curr_id())) { if (rw_lock_get_reader_count(lock) == 0) { rw_lock_set_writer(lock, RW_LOCK_EX); lock->writer_count++; lock->pass = pass; lock->writer_is_wait_ex = FALSE; #ifdef UNIV_SYNC_DEBUG rw_lock_remove_debug_info(lock, pass, RW_LOCK_WAIT_EX); rw_lock_add_debug_info(lock, pass, RW_LOCK_EX, file_name, line); #endif lock->last_x_file_name = file_name; lock->last_x_line = (unsigned int) line; /* Locking succeeded, we may return */ return(RW_LOCK_EX); } return(RW_LOCK_WAIT_EX); } else if ((rw_lock_get_writer(lock) == RW_LOCK_EX) && os_thread_eq(lock->writer_thread, os_thread_get_curr_id()) && (lock->pass == 0) && (pass == 0)) { lock->writer_count++; #ifdef UNIV_SYNC_DEBUG rw_lock_add_debug_info(lock, pass, RW_LOCK_EX, file_name, line); #endif lock->last_x_file_name = file_name; lock->last_x_line = (unsigned int) line; /* Locking succeeded, we may return */ return(RW_LOCK_EX); } /* Locking did not succeed */ return(RW_LOCK_NOT_LOCKED); }
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; } }
void rw_lock_create_func( /*================*/ rw_lock_t* lock, /* in: pointer to memory */ #ifdef UNIV_DEBUG # ifdef UNIV_SYNC_DEBUG ulint level, /* in: level */ # endif /* UNIV_SYNC_DEBUG */ const char* cmutex_name, /* in: mutex name */ #endif /* UNIV_DEBUG */ const char* cfile_name, /* in: file name where created */ ulint cline) /* in: file line where created */ { /* If this is the very first time a synchronization object is created, then the following call initializes the sync system. */ mutex_create(rw_lock_get_mutex(lock), SYNC_NO_ORDER_CHECK); lock->mutex.cfile_name = cfile_name; lock->mutex.cline = cline; #if defined UNIV_DEBUG && !defined UNIV_HOTBACKUP lock->mutex.cmutex_name = cmutex_name; lock->mutex.mutex_type = 1; #endif /* UNIV_DEBUG && !UNIV_HOTBACKUP */ rw_lock_set_waiters(lock, 0); rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED); lock->writer_count = 0; rw_lock_set_reader_count(lock, 0); lock->writer_is_wait_ex = FALSE; #ifdef UNIV_SYNC_DEBUG UT_LIST_INIT(lock->debug_list); lock->level = level; #endif /* UNIV_SYNC_DEBUG */ lock->magic_n = RW_LOCK_MAGIC_N; lock->cfile_name = cfile_name; lock->cline = (unsigned int) cline; lock->last_s_file_name = "not yet reserved"; lock->last_x_file_name = "not yet reserved"; lock->last_s_line = 0; lock->last_x_line = 0; lock->event = os_event_create(NULL); #ifdef __WIN__ lock->wait_ex_event = os_event_create(NULL); #endif mutex_enter(&rw_lock_list_mutex); if (UT_LIST_GET_LEN(rw_lock_list) > 0) { ut_a(UT_LIST_GET_FIRST(rw_lock_list)->magic_n == RW_LOCK_MAGIC_N); } UT_LIST_ADD_FIRST(list, rw_lock_list, lock); mutex_exit(&rw_lock_list_mutex); }
/******************************************************************//** Creates, or rather, initializes an rw-lock object in a specified memory location (which must be appropriately aligned). The rw-lock is initialized to the non-locked state. Explicit freeing of the rw-lock with rw_lock_free is necessary only if the memory block containing it is freed. */ UNIV_INTERN void rw_lock_create_func( /*================*/ rw_lock_t* lock, /*!< in: pointer to memory */ #ifdef UNIV_DEBUG # ifdef UNIV_SYNC_DEBUG ulint level, /*!< in: level */ # endif /* UNIV_SYNC_DEBUG */ const char* cmutex_name, /*!< in: mutex name */ #endif /* UNIV_DEBUG */ const char* cfile_name, /*!< in: file name where created */ ulint cline) /*!< in: file line where created */ { /* If this is the very first time a synchronization object is created, then the following call initializes the sync system. */ #ifndef INNODB_RW_LOCKS_USE_ATOMICS mutex_create(rw_lock_mutex_key, rw_lock_get_mutex(lock), SYNC_NO_ORDER_CHECK); lock->mutex.cfile_name = cfile_name; lock->mutex.cline = cline; ut_d(lock->mutex.cmutex_name = cmutex_name); ut_d(lock->mutex.mutex_type = 1); #else /* INNODB_RW_LOCKS_USE_ATOMICS */ # ifdef UNIV_DEBUG UT_NOT_USED(cmutex_name); # endif #endif /* INNODB_RW_LOCKS_USE_ATOMICS */ lock->lock_word = X_LOCK_DECR; lock->waiters = 0; /* We set this value to signify that lock->writer_thread contains garbage at initialization and cannot be used for recursive x-locking. */ lock->recursive = FALSE; /* Silence Valgrind when UNIV_DEBUG_VALGRIND is not enabled. */ memset((void*) &lock->writer_thread, 0, sizeof lock->writer_thread); UNIV_MEM_INVALID(&lock->writer_thread, sizeof lock->writer_thread); #ifdef UNIV_SYNC_DEBUG UT_LIST_INIT(lock->debug_list); lock->level = level; #endif /* UNIV_SYNC_DEBUG */ ut_d(lock->magic_n = RW_LOCK_MAGIC_N); lock->cfile_name = cfile_name; lock->cline = (unsigned int) cline; lock->count_os_wait = 0; lock->last_s_file_name = "not yet reserved"; lock->last_x_file_name = "not yet reserved"; lock->last_s_line = 0; lock->last_x_line = 0; lock->event = os_event_create(NULL); lock->wait_ex_event = os_event_create(NULL); mutex_enter(&rw_lock_list_mutex); ut_ad(UT_LIST_GET_FIRST(rw_lock_list) == NULL || UT_LIST_GET_FIRST(rw_lock_list)->magic_n == RW_LOCK_MAGIC_N); UT_LIST_ADD_FIRST(list, rw_lock_list, lock); mutex_exit(&rw_lock_list_mutex); }