Esempio n. 1
0
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;
}
Esempio n. 2
0
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);
}
Esempio n. 3
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);
}
Esempio n. 4
0
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);
}
Esempio n. 5
0
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);
}
Esempio n. 6
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;
}
Esempio n. 7
0
/*
  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;
}