mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 02:46:29 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			242 lines
		
	
	
	
		
			6.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			242 lines
		
	
	
	
		
			6.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|    Copyright (c) 2007, 2008, Sun Microsystems, Inc,
 | |
|    Copyright (c) 2011, 2012, Monty Program Ab
 | |
| 
 | |
|    This program is free software; you can redistribute it and/or modify
 | |
|    it under the terms of the GNU General Public License as published by
 | |
|    the Free Software Foundation; version 2 of the License.
 | |
| 
 | |
|    This program is distributed in the hope that it will be useful,
 | |
|    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|    GNU General Public License for more details.
 | |
| 
 | |
|    You should have received a copy of the GNU General Public License
 | |
|    along with this program; if not, write to the Free Software
 | |
|    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
 | |
| 
 | |
| #include <my_global.h>
 | |
| #include <wqueue.h>
 | |
| 
 | |
| #define STRUCT_PTR(TYPE, MEMBER, a)                                           \
 | |
|           (TYPE *) ((char *) (a) - offsetof(TYPE, MEMBER))
 | |
| /*
 | |
|   Link a thread into double-linked queue of waiting threads.
 | |
| 
 | |
|   SYNOPSIS
 | |
|     wqueue_link_into_queue()
 | |
|       wqueue              pointer to the queue structure
 | |
|       thread              pointer to the thread to be added to the queue
 | |
| 
 | |
|   RETURN VALUE
 | |
|     none
 | |
| 
 | |
|   NOTES.
 | |
|     Queue is represented by a circular list of the thread structures
 | |
|     The list is double-linked of the type (**prev,*next), accessed by
 | |
|     a pointer to the last element.
 | |
| */
 | |
| 
 | |
| void wqueue_link_into_queue(WQUEUE *wqueue, struct st_my_thread_var *thread)
 | |
| {
 | |
|   struct st_my_thread_var *last;
 | |
|   if (!(last= wqueue->last_thread))
 | |
|   {
 | |
|     /* Queue is empty */
 | |
|     thread->next= thread;
 | |
|     thread->prev= &thread->next;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     thread->prev= last->next->prev;
 | |
|     last->next->prev= &thread->next;
 | |
|     thread->next= last->next;
 | |
|     last->next= thread;
 | |
|   }
 | |
|   wqueue->last_thread= thread;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|   Add a thread to single-linked queue of waiting threads
 | |
| 
 | |
|   SYNOPSIS
 | |
|     wqueue_add_to_queue()
 | |
|       wqueue              pointer to the queue structure
 | |
|       thread              pointer to the thread to be added to the queue
 | |
| 
 | |
|   RETURN VALUE
 | |
|     none
 | |
| 
 | |
|   NOTES.
 | |
|     Queue is represented by a circular list of the thread structures
 | |
|     The list is single-linked of the type (*next), accessed by a pointer
 | |
|     to the last element.
 | |
| */
 | |
| 
 | |
| void wqueue_add_to_queue(WQUEUE *wqueue, struct st_my_thread_var *thread)
 | |
| {
 | |
|   struct st_my_thread_var *last;
 | |
|   if (!(last= wqueue->last_thread))
 | |
|     thread->next= thread;
 | |
|   else
 | |
|   {
 | |
|     thread->next= last->next;
 | |
|     last->next= thread;
 | |
|   }
 | |
| #ifndef DBUG_OFF
 | |
|   thread->prev= NULL; /* force segfault if used */
 | |
| #endif
 | |
|   wqueue->last_thread= thread;
 | |
| }
 | |
| 
 | |
| /*
 | |
|   Unlink a thread from double-linked queue of waiting threads
 | |
| 
 | |
|   SYNOPSIS
 | |
|     wqueue_unlink_from_queue()
 | |
|       wqueue              pointer to the queue structure
 | |
|       thread              pointer to the thread to be removed from the queue
 | |
| 
 | |
|   RETURN VALUE
 | |
|     none
 | |
| 
 | |
|   NOTES.
 | |
|     See NOTES for link_into_queue
 | |
| */
 | |
| 
 | |
| void wqueue_unlink_from_queue(WQUEUE *wqueue, struct st_my_thread_var *thread)
 | |
| {
 | |
|   if (thread->next == thread)
 | |
|     /* The queue contains only one member */
 | |
|     wqueue->last_thread= NULL;
 | |
|   else
 | |
|   {
 | |
|     thread->next->prev= thread->prev;
 | |
|     *thread->prev= thread->next;
 | |
|     if (wqueue->last_thread == thread)
 | |
|       wqueue->last_thread= STRUCT_PTR(struct st_my_thread_var, next,
 | |
|                                       thread->prev);
 | |
|   }
 | |
|   thread->next= NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|   Remove all threads from queue signaling them to proceed
 | |
| 
 | |
|   SYNOPSIS
 | |
|     wqueue_realease_queue()
 | |
|       wqueue              pointer to the queue structure
 | |
|       thread              pointer to the thread to be added to the queue
 | |
| 
 | |
|   RETURN VALUE
 | |
|     none
 | |
| 
 | |
|   NOTES.
 | |
|     See notes for add_to_queue
 | |
|     When removed from the queue each thread is signaled via condition
 | |
|     variable thread->suspend.
 | |
| */
 | |
| 
 | |
| void wqueue_release_queue(WQUEUE *wqueue)
 | |
| {
 | |
|   struct st_my_thread_var *last= wqueue->last_thread;
 | |
|   struct st_my_thread_var *next= last->next;
 | |
|   struct st_my_thread_var *thread;
 | |
|   do
 | |
|   {
 | |
|     thread= next;
 | |
|     mysql_cond_signal(&thread->suspend);
 | |
|     next= thread->next;
 | |
|     thread->next= NULL;
 | |
|   }
 | |
|   while (thread != last);
 | |
|   wqueue->last_thread= NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   @brief Removes all threads waiting for read or first one waiting for write.
 | |
| 
 | |
|   @param wqueue          pointer to the queue structure
 | |
|   @param thread          pointer to the thread to be added to the queue
 | |
| 
 | |
|   @note This function is applicable only to single linked lists.
 | |
| */
 | |
| 
 | |
| void wqueue_release_one_locktype_from_queue(WQUEUE *wqueue)
 | |
| {
 | |
|   struct st_my_thread_var *last= wqueue->last_thread;
 | |
|   struct st_my_thread_var *next= last->next;
 | |
|   struct st_my_thread_var *thread;
 | |
|   struct st_my_thread_var *new_list= NULL;
 | |
|   uint first_type= next->lock_type;
 | |
|   if (first_type == MY_PTHREAD_LOCK_WRITE)
 | |
|   {
 | |
|     /* release first waiting for write lock */
 | |
|     mysql_cond_signal(&next->suspend);
 | |
|     if (next == last)
 | |
|       wqueue->last_thread= NULL;
 | |
|     else
 | |
|       last->next= next->next;
 | |
|     next->next= NULL;
 | |
|     return;
 | |
|   }
 | |
|   do
 | |
|   {
 | |
|     thread= next;
 | |
|     next= thread->next;
 | |
|     if (thread->lock_type == MY_PTHREAD_LOCK_WRITE)
 | |
|     {
 | |
|       /* skip waiting for write lock */
 | |
|       if (new_list)
 | |
|       {
 | |
|         thread->next= new_list->next;
 | |
|         new_list= new_list->next= thread;
 | |
|       }
 | |
|       else
 | |
|         new_list= thread->next= thread;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       /* release waiting for read lock */
 | |
|       mysql_cond_signal(&thread->suspend);
 | |
|       thread->next= NULL;
 | |
|     }
 | |
|   } while (thread != last);
 | |
|   wqueue->last_thread= new_list;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|   Add thread and wait
 | |
| 
 | |
|   SYNOPSIS
 | |
|     wqueue_add_and_wait()
 | |
|     wqueue               queue to add to
 | |
|     thread               thread which is waiting
 | |
|     lock                 mutex need for the operation
 | |
| */
 | |
| 
 | |
| void wqueue_add_and_wait(WQUEUE *wqueue,
 | |
|                          struct st_my_thread_var *thread,
 | |
|                          mysql_mutex_t *lock)
 | |
| {
 | |
|   DBUG_ENTER("wqueue_add_and_wait");
 | |
|   DBUG_PRINT("enter",
 | |
|              ("thread: %p cond: %p mutex: %p",
 | |
|               thread, &thread->suspend, lock));
 | |
|   wqueue_add_to_queue(wqueue, thread);
 | |
|   do
 | |
|   {
 | |
|     DBUG_PRINT("info", ("wait... cond:  %p  mutex:  %p",
 | |
|                         &thread->suspend, lock));
 | |
|     mysql_cond_wait(&thread->suspend, lock);
 | |
|     DBUG_PRINT("info", ("wait done cond: %p mutex: %p next: %p",
 | |
|                         &thread->suspend, lock,
 | |
|                         thread->next));
 | |
|   }
 | |
|   while (thread->next);
 | |
|   DBUG_VOID_RETURN;
 | |
| }
 | 
