mirror of
https://github.com/MariaDB/server.git
synced 2025-01-15 19:42:28 +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;
|
|
}
|