void thr_abort_locks(THR_LOCK *lock, my_bool upgrade_lock) { THR_LOCK_DATA *data; DBUG_ENTER("thr_abort_locks"); mysql_mutex_lock(&lock->mutex); for (data=lock->read_wait.data; data ; data=data->next) { data->type=TL_UNLOCK; /* Mark killed */ /* It's safe to signal the cond first: we're still holding the mutex. */ mysql_cond_signal(data->cond); data->cond=0; /* Removed from list */ } for (data=lock->write_wait.data; data ; data=data->next) { data->type=TL_UNLOCK; mysql_cond_signal(data->cond); data->cond=0; } lock->read_wait.last= &lock->read_wait.data; lock->write_wait.last= &lock->write_wait.data; lock->read_wait.data=lock->write_wait.data=0; if (upgrade_lock && lock->write.data) lock->write.data->type=TL_WRITE_ONLY; mysql_mutex_unlock(&lock->mutex); DBUG_VOID_RETURN; }
int audit_log_buffer_write(audit_log_buffer_t *log, const char *buf, size_t len) { if (len > log->size) return(1); mysql_mutex_lock(&log->mutex); loop: if (log->write_pos + len < log->flush_pos + log->size) { size_t wrlen= min(len, log->size - (log->write_pos % log->size)); memcpy(log->buf + (log->write_pos % log->size), buf, wrlen); if (wrlen < len) memcpy(log->buf, buf + wrlen, len - wrlen); log->write_pos= log->write_pos + len; DBUG_ASSERT(log->write_pos >= log->flush_pos); } else { if (!log->drop_if_full) { mysql_cond_wait(&log->flushed_cond, &log->mutex); goto loop; } } if (log->write_pos > log->flush_pos + log->size / 2) { mysql_cond_signal(&log->written_cond); } mysql_mutex_unlock(&log->mutex); return(0); }
my_bool thr_abort_locks_for_thread(THR_LOCK *lock, my_thread_id thread_id) { THR_LOCK_DATA *data; my_bool found= FALSE; DBUG_ENTER("thr_abort_locks_for_thread"); mysql_mutex_lock(&lock->mutex); for (data= lock->read_wait.data; data ; data= data->next) { if (data->owner->thread_id == thread_id) /* purecov: tested */ { DBUG_PRINT("info",("Aborting read-wait lock")); data->type= TL_UNLOCK; /* Mark killed */ /* It's safe to signal the cond first: we're still holding the mutex. */ found= TRUE; mysql_cond_signal(data->cond); data->cond= 0; /* Removed from list */ if (((*data->prev)= data->next)) data->next->prev= data->prev; else lock->read_wait.last= data->prev; } } for (data= lock->write_wait.data; data ; data= data->next) { if (data->owner->thread_id == thread_id) /* purecov: tested */ { DBUG_PRINT("info",("Aborting write-wait lock")); data->type= TL_UNLOCK; found= TRUE; mysql_cond_signal(data->cond); data->cond= 0; if (((*data->prev)= data->next)) data->next->prev= data->prev; else lock->write_wait.last= data->prev; } } wake_up_waiters(lock); mysql_mutex_unlock(&lock->mutex); DBUG_RETURN(found); }
void my_thread_end(void) { struct st_my_thread_var *tmp; tmp= _my_thread_var(); #ifdef EXTRA_DEBUG_THREADS my_message_local(INFORMATION_LEVEL, "my_thread_end(): tmp: 0x%lx " "pthread_self: 0x%lx thread_id: %ld", (long) tmp, (long) pthread_self(), tmp ? (long) tmp->id : 0L); #endif #ifdef HAVE_PSI_INTERFACE /* Remove the instrumentation for this thread. This must be done before trashing st_my_thread_var, because the LF_HASH depends on it. */ PSI_THREAD_CALL(delete_current_thread)(); #endif if (tmp && tmp->init) { #if !defined(DBUG_OFF) /* tmp->dbug is allocated inside DBUG library */ if (tmp->dbug) { DBUG_POP(); free(tmp->dbug); tmp->dbug=0; } #endif mysql_cond_destroy(&tmp->suspend); mysql_mutex_destroy(&tmp->mutex); free(tmp); /* Decrement counter for number of running threads. We are using this in my_thread_global_end() to wait until all threads have called my_thread_end and thus freed all memory they have allocated in my_thread_init() and DBUG_xxxx */ mysql_mutex_lock(&THR_LOCK_threads); DBUG_ASSERT(THR_thread_count != 0); if (--THR_thread_count == 0) mysql_cond_signal(&THR_COND_threads); mysql_mutex_unlock(&THR_LOCK_threads); } set_mysys_var(NULL); }
static inline void free_all_read_locks(THR_LOCK *lock, my_bool using_concurrent_insert) { THR_LOCK_DATA *data=lock->read_wait.data; check_locks(lock,"before freeing read locks",1); /* move all locks from read_wait list to read list */ (*lock->read.last)=data; data->prev=lock->read.last; lock->read.last=lock->read_wait.last; /* Clear read_wait list */ lock->read_wait.last= &lock->read_wait.data; do { mysql_cond_t *cond= data->cond; if ((int) data->type == (int) TL_READ_NO_INSERT) { if (using_concurrent_insert) { /* We can't free this lock; Link lock away from read chain back into read_wait chain */ if (((*data->prev)=data->next)) data->next->prev=data->prev; else lock->read.last=data->prev; *lock->read_wait.last= data; data->prev= lock->read_wait.last; lock->read_wait.last= &data->next; continue; } lock->read_no_write_count++; } /* purecov: begin inspected */ DBUG_PRINT("lock",("giving read lock to thread: 0x%x", data->owner->thread_id)); /* purecov: end */ data->cond=0; /* Mark thread free */ mysql_cond_signal(cond); } while ((data=data->next)); *lock->read_wait.last=0; if (!lock->read_wait.data) lock->write_lock_count=0; check_locks(lock,"after giving read locks",0); }
static void wake_up_waiters(THR_LOCK *lock) { THR_LOCK_DATA *data; enum thr_lock_type lock_type; DBUG_ENTER("wake_up_waiters"); if (!lock->write.data) /* If no active write locks */ { data=lock->write_wait.data; if (!lock->read.data) /* If no more locks in use */ { /* Release write-locks with TL_WRITE or TL_WRITE_ONLY priority first */ if (data && (data->type != TL_WRITE_LOW_PRIORITY || !lock->read_wait.data || lock->read_wait.data->type < TL_READ_HIGH_PRIORITY)) { if (lock->write_lock_count++ > max_write_lock_count) { /* Too many write locks in a row; Release all waiting read locks */ lock->write_lock_count=0; if (lock->read_wait.data) { DBUG_PRINT("info",("Freeing all read_locks because of max_write_lock_count")); free_all_read_locks(lock,0); goto end; } } for (;;) { if (((*data->prev)=data->next)) /* remove from wait-list */ data->next->prev= data->prev; else lock->write_wait.last=data->prev; (*lock->write.last)=data; /* Put in execute list */ data->prev=lock->write.last; data->next=0; lock->write.last= &data->next; if (data->type == TL_WRITE_CONCURRENT_INSERT && (*lock->check_status)(data->status_param)) data->type=TL_WRITE; /* Upgrade lock */ /* purecov: begin inspected */ DBUG_PRINT("lock",("giving write lock of type %d to thread: 0x%x", data->type, data->owner->thread_id)); /* purecov: end */ { mysql_cond_t *cond= data->cond; data->cond=0; /* Mark thread free */ mysql_cond_signal(cond); /* Start waiting thread */ } if (data->type != TL_WRITE_ALLOW_WRITE || !lock->write_wait.data || lock->write_wait.data->type != TL_WRITE_ALLOW_WRITE) break; data=lock->write_wait.data; /* Free this too */ } if (data->type >= TL_WRITE_LOW_PRIORITY) goto end; /* Release possible read locks together with the write lock */ } if (lock->read_wait.data) free_all_read_locks(lock, data && (data->type == TL_WRITE_CONCURRENT_INSERT || data->type == TL_WRITE_ALLOW_WRITE)); else { DBUG_PRINT("lock",("No waiting read locks to free")); } } else if (data && (lock_type= data->type) <= TL_WRITE_CONCURRENT_INSERT && ((lock_type != TL_WRITE_CONCURRENT_INSERT && lock_type != TL_WRITE_ALLOW_WRITE) || !lock->read_no_write_count)) { /* For ALLOW_READ, WRITE_ALLOW_WRITE or CONCURRENT_INSERT locks start WRITE locks together with the READ locks */ if (lock_type == TL_WRITE_CONCURRENT_INSERT && (*lock->check_status)(data->status_param)) { data->type=TL_WRITE; /* Upgrade lock */ if (lock->read_wait.data) free_all_read_locks(lock,0); goto end; } do { mysql_cond_t *cond= data->cond; if (((*data->prev)=data->next)) /* remove from wait-list */ data->next->prev= data->prev; else lock->write_wait.last=data->prev; (*lock->write.last)=data; /* Put in execute list */ data->prev=lock->write.last; lock->write.last= &data->next; data->next=0; /* Only one write lock */ data->cond=0; /* Mark thread free */ mysql_cond_signal(cond); /* Start waiting thread */ } while (lock_type == TL_WRITE_ALLOW_WRITE && (data=lock->write_wait.data) && data->type == TL_WRITE_ALLOW_WRITE); if (lock->read_wait.data) free_all_read_locks(lock, (lock_type == TL_WRITE_CONCURRENT_INSERT || lock_type == TL_WRITE_ALLOW_WRITE)); } else if (!data && lock->read_wait.data) free_all_read_locks(lock,0); } end: check_locks(lock, "after waking up waiters", 0); DBUG_VOID_RETURN; }
/* stress test: wait on a random number of random threads. it always succeeds (unless crashes or hangs). */ pthread_handler_t test_wt(void *arg) { int m, n, i, id, res; struct my_rnd_struct rand; my_thread_init(); mysql_mutex_lock(&mutex); id= cnt++; wt_thd_lazy_init(& thds[id].thd, & wt_deadlock_search_depth_short, & wt_timeout_short, & wt_deadlock_search_depth_long, & wt_timeout_long); /* now, wait for everybody to be ready to run */ if (cnt >= THREADS) mysql_cond_broadcast(&thread_sync); else while (cnt < THREADS) mysql_cond_wait(&thread_sync, &mutex); mysql_mutex_unlock(&mutex); my_rnd_init(&rand, (ulong)(intptr)&m, id); if (kill_strategy == YOUNGEST) thds[id].thd.weight= (ulong)~my_getsystime(); if (kill_strategy == LOCKS) thds[id].thd.weight= 0; for (m= *(int *)arg; m ; m--) { WT_RESOURCE_ID resid; int blockers[THREADS/10], j, k; resid.value= id; resid.type= &restype; res= 0; /* prepare for waiting for a random number of random threads */ for (j= n= (rnd() % THREADS)/10; !res && j >= 0; j--) { retry: i= rnd() % (THREADS-1); /* pick a random thread */ if (i >= id) i++; /* with a number from 0 to THREADS-1 excluding ours */ for (k=n; k >=j; k--) /* the one we didn't pick before */ if (blockers[k] == i) goto retry; blockers[j]= i; if (kill_strategy == RANDOM) thds[id].thd.weight= rnd(); mysql_mutex_lock(& thds[i].lock); res= wt_thd_will_wait_for(& thds[id].thd, & thds[i].thd, &resid); mysql_mutex_unlock(& thds[i].lock); } if (!res) { mysql_mutex_lock(&lock); res= wt_thd_cond_timedwait(& thds[id].thd, &lock); mysql_mutex_unlock(&lock); } if (res) { mysql_mutex_lock(& thds[id].lock); mysql_mutex_lock(&lock); wt_thd_release_all(& thds[id].thd); mysql_mutex_unlock(&lock); mysql_mutex_unlock(& thds[id].lock); if (kill_strategy == LOCKS) thds[id].thd.weight= 0; if (kill_strategy == YOUNGEST) thds[id].thd.weight= (ulong)~my_getsystime(); } else if (kill_strategy == LOCKS) thds[id].thd.weight++; } mysql_mutex_lock(&mutex); /* wait for everybody to finish */ if (!--cnt) mysql_cond_broadcast(&thread_sync); else while (cnt) mysql_cond_wait(&thread_sync, &mutex); mysql_mutex_lock(& thds[id].lock); mysql_mutex_lock(&lock); wt_thd_release_all(& thds[id].thd); mysql_mutex_unlock(&lock); mysql_mutex_unlock(& thds[id].lock); wt_thd_destroy(& thds[id].thd); if (!--running_threads) /* now, signal when everybody is done with deinit */ mysql_cond_signal(&cond); mysql_mutex_unlock(&mutex); DBUG_PRINT("wt", ("exiting")); my_thread_end(); return 0; }