/*************************************************************//** Report a failed assertion. */ UNIV_INTERN void ut_dbg_assertion_failed( /*====================*/ const char* expr, /*!< in: the failed assertion (optional) */ const char* file, /*!< in: source file containing the assertion */ ulint line) /*!< in: line number of the assertion */ { ut_print_timestamp(stderr); #ifdef UNIV_HOTBACKUP fprintf(stderr, " InnoDB: Assertion failure in file %s line %lu\n", file, line); #else /* UNIV_HOTBACKUP */ fprintf(stderr, " InnoDB: Assertion failure in thread %lu" " in file %s line %lu\n", os_thread_pf(os_thread_get_curr_id()), innobase_basename(file), line); #endif /* UNIV_HOTBACKUP */ if (expr) { fprintf(stderr, "InnoDB: Failing assertion: %s\n", expr); } fputs("InnoDB: We intentionally generate a memory trap.\n" "InnoDB: Submit a detailed bug report" " to http://bugs.mysql.com.\n" "InnoDB: If you get repeated assertion failures" " or crashes, even\n" "InnoDB: immediately after the mysqld startup, there may be\n" "InnoDB: corruption in the InnoDB tablespace. Please refer to\n" "InnoDB: " REFMAN "forcing-innodb-recovery.html\n" "InnoDB: about forcing recovery.\n", stderr); }
/******************************************************************//** Reports info of a wait array cell. */ static void sync_array_cell_print( /*==================*/ FILE* file, /*!< in: file where to print */ sync_cell_t* cell) /*!< in: sync cell */ { mutex_t* mutex; rw_lock_t* rwlock; ulint type; ulint writer; type = cell->request_type; fprintf(file, "--Thread %lu has waited at %s line %lu" " for %.2f seconds the semaphore:\n", (ulong) os_thread_pf(cell->thread), innobase_basename(cell->file), (ulong) cell->line, difftime(time(NULL), cell->reservation_time)); if (type == SYNC_MUTEX) { /* We use old_wait_mutex in case the cell has already been freed meanwhile */ mutex = cell->old_wait_mutex; fprintf(file, "Mutex at %p created file %s line %lu, lock var %lu\n" #ifdef UNIV_SYNC_DEBUG "Last time reserved in file %s line %lu, " #endif /* UNIV_SYNC_DEBUG */ "waiters flag %lu\n", (void*) mutex, innobase_basename(mutex->cfile_name), (ulong) mutex->cline, (ulong) mutex->lock_word, #ifdef UNIV_SYNC_DEBUG mutex->file_name, (ulong) mutex->line, #endif /* UNIV_SYNC_DEBUG */ (ulong) mutex->waiters); } else if (type == RW_LOCK_EX || type == RW_LOCK_WAIT_EX || type == RW_LOCK_SHARED) { fputs(type == RW_LOCK_EX ? "X-lock on" : type == RW_LOCK_WAIT_EX ? "X-lock (wait_ex) on" : "S-lock on", file); rwlock = cell->old_wait_rw_lock; fprintf(file, " RW-latch at %p created in file %s line %lu\n", (void*) rwlock, innobase_basename(rwlock->cfile_name), (ulong) rwlock->cline); writer = rw_lock_get_writer(rwlock); if (writer != RW_LOCK_NOT_LOCKED) { fprintf(file, "a writer (thread id %lu) has" " reserved it in mode %s", (ulong) os_thread_pf(rwlock->writer_thread), writer == RW_LOCK_EX ? " exclusive\n" : " wait exclusive\n"); } fprintf(file, "number of readers %lu, waiters flag %lu, " "lock_word: %lx\n" "Last time read locked in file %s line %lu\n" "Last time write locked in file %s line %lu\n", (ulong) rw_lock_get_reader_count(rwlock), (ulong) rwlock->waiters, rwlock->lock_word, innobase_basename(rwlock->last_s_file_name), (ulong) rwlock->last_s_line, rwlock->last_x_file_name, (ulong) rwlock->last_x_line); } else { ut_error; } if (!cell->waiting) { fputs("wait has ended\n", file); } }
/***************************************************************//** Removes a memory heap (which is going to be freed by the caller) from the list of live memory heaps. Returns the size of the heap in terms of how much memory in bytes was allocated for the user of the heap (not the total space occupied by the heap). Also validates the heap. NOTE: This function does not free the storage occupied by the heap itself, only the node in the list of heaps. */ UNIV_INTERN void mem_hash_remove( /*============*/ mem_heap_t* heap, /*!< in: the heap to be freed */ const char* file_name, /*!< in: file name of freeing */ ulint line) /*!< in: line where freed */ { mem_hash_node_t* node; ulint cell_no; ibool error; ulint size; ut_ad(mem_heap_check(heap)); mutex_enter(&mem_hash_mutex); cell_no = ut_hash_ulint((ulint)heap, MEM_HASH_SIZE); /* Look for the heap in the hash table list */ node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(cell_no)); while (node != NULL) { if (node->heap == heap) { break; } node = UT_LIST_GET_NEXT(list, node); } if (node == NULL) { fprintf(stderr, "Memory heap or buffer freed in %s line %lu" " did not exist.\n", innobase_basename(file_name), (ulong) line); ut_error; } /* Remove from lists */ UT_LIST_REMOVE(list, *mem_hash_get_nth_cell(cell_no), node); UT_LIST_REMOVE(all_list, mem_all_list_base, node); /* Validate the heap which will be freed */ mem_heap_validate_or_print(node->heap, NULL, FALSE, &error, &size, NULL, NULL); if (error) { fprintf(stderr, "Inconsistency in memory heap or" " buffer n:o %lu created\n" "in %s line %lu and tried to free in %s line %lu.\n" "Hex dump of 400 bytes around memory heap" " first block start:\n", node->nth_heap, innobase_basename(node->file_name), (ulong) node->line, innobase_basename(file_name), (ulong) line); ut_print_buf(stderr, (byte*)node->heap - 200, 400); fputs("\nDump of the mem heap:\n", stderr); mem_heap_validate_or_print(node->heap, NULL, TRUE, &error, &size, NULL, NULL); ut_error; } /* Free the memory occupied by the node struct */ ut_free(node); mem_current_allocated_memory -= size; mutex_exit(&mem_hash_mutex); }
/******************************************************************//** 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; } }