1
/*****************************************************************************
3
Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
5
This program is free software; you can redistribute it and/or modify it under
6
the terms of the GNU General Public License as published by the Free Software
7
Foundation; version 2 of the License.
9
This program is distributed in the hope that it will be useful, but WITHOUT
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License along with
14
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15
St, Fifth Floor, Boston, MA 02110-1301 USA
17
*****************************************************************************/
19
/**************************************************//**
21
The interface to the operating system
22
synchronization primitives.
24
Created 9/6/1995 Heikki Tuuri
25
*******************************************************/
37
#include "srv0start.h"
39
#include "ha_prototypes.h"
41
/* Type definition for an operating system mutex struct */
42
struct os_mutex_struct{
43
os_event_t event; /*!< Used by sync0arr.c for queing threads */
44
void* handle; /*!< OS handle to mutex */
45
ulint count; /*!< we use this counter to check
46
that the same thread does not
47
recursively lock the mutex: we
48
do not assume that the OS mutex
49
supports recursive locking, though
50
NT seems to do that */
51
UT_LIST_NODE_T(os_mutex_str_t) os_mutex_list;
52
/* list of all 'slow' OS mutexes created */
55
/** Mutex protecting counts and the lists of OS mutexes and events */
56
UNIV_INTERN os_mutex_t os_sync_mutex;
57
/** TRUE if os_sync_mutex has been initialized */
58
static ibool os_sync_mutex_inited = FALSE;
59
/** TRUE when os_sync_free() is being executed */
60
static ibool os_sync_free_called = FALSE;
62
/** This is incremented by 1 in os_thread_create and decremented by 1 in
64
UNIV_INTERN ulint os_thread_count = 0;
66
/** The list of all events created */
67
static UT_LIST_BASE_NODE_T(os_event_struct_t) os_event_list;
69
/** The list of all OS 'slow' mutexes */
70
static UT_LIST_BASE_NODE_T(os_mutex_str_t) os_mutex_list;
72
UNIV_INTERN ulint os_event_count = 0;
73
UNIV_INTERN ulint os_mutex_count = 0;
74
UNIV_INTERN ulint os_fast_mutex_count = 0;
76
/* Because a mutex is embedded inside an event and there is an
77
event embedded inside a mutex, on free, this generates a recursive call.
78
This version of the free event function doesn't acquire the global lock */
79
static void os_event_free_internal(os_event_t event);
81
/* On Windows (Vista and later), load function pointers for condition
82
variable handling. Those functions are not available in prior versions,
83
so we have to use them via runtime loading, as long as we support XP. */
84
static void os_cond_module_init(void);
87
/* Prototypes and function pointers for condition variable functions */
88
typedef VOID (WINAPI* InitializeConditionVariableProc)
89
(PCONDITION_VARIABLE ConditionVariable);
90
static InitializeConditionVariableProc initialize_condition_variable;
92
typedef BOOL (WINAPI* SleepConditionVariableCSProc)
93
(PCONDITION_VARIABLE ConditionVariable,
94
PCRITICAL_SECTION CriticalSection,
95
DWORD dwMilliseconds);
96
static SleepConditionVariableCSProc sleep_condition_variable;
98
typedef VOID (WINAPI* WakeAllConditionVariableProc)
99
(PCONDITION_VARIABLE ConditionVariable);
100
static WakeAllConditionVariableProc wake_all_condition_variable;
102
typedef VOID (WINAPI* WakeConditionVariableProc)
103
(PCONDITION_VARIABLE ConditionVariable);
104
static WakeConditionVariableProc wake_condition_variable;
107
/*********************************************************//**
108
Initialitze condition variable */
113
os_cond_t* cond) /*!< in: condition variable. */
118
ut_a(initialize_condition_variable != NULL);
119
initialize_condition_variable(cond);
121
ut_a(pthread_cond_init(cond, NULL) == 0);
125
/*********************************************************//**
126
Wait on condition variable */
131
os_cond_t* cond, /*!< in: condition variable. */
132
os_fast_mutex_t* mutex) /*!< in: fast mutex */
138
ut_a(sleep_condition_variable != NULL);
139
ut_a(sleep_condition_variable(cond, mutex, INFINITE));
141
ut_a(pthread_cond_wait(cond, mutex) == 0);
145
/*********************************************************//**
146
Wakes all threads waiting for condition variable */
151
os_cond_t* cond) /*!< in: condition variable. */
156
ut_a(wake_all_condition_variable != NULL);
157
wake_all_condition_variable(cond);
159
ut_a(pthread_cond_broadcast(cond) == 0);
163
/*********************************************************//**
164
Wakes one thread waiting for condition variable */
169
os_cond_t* cond) /*!< in: condition variable. */
174
ut_a(wake_condition_variable != NULL);
175
wake_condition_variable(cond);
177
ut_a(pthread_cond_signal(cond) == 0);
181
/*********************************************************//**
182
Destroys condition variable */
187
os_cond_t* cond) /*!< in: condition variable. */
192
ut_a(pthread_cond_destroy(cond) == 0);
196
/*********************************************************//**
197
On Windows (Vista and later), load function pointers for condition variable
198
handling. Those functions are not available in prior versions, so we have to
199
use them via runtime loading, as long as we support XP. */
202
os_cond_module_init(void)
203
/*=====================*/
208
if (!srv_use_native_conditions)
211
h_dll = GetModuleHandle("kernel32");
213
initialize_condition_variable = (InitializeConditionVariableProc)
214
GetProcAddress(h_dll, "InitializeConditionVariable");
215
sleep_condition_variable = (SleepConditionVariableCSProc)
216
GetProcAddress(h_dll, "SleepConditionVariableCS");
217
wake_all_condition_variable = (WakeAllConditionVariableProc)
218
GetProcAddress(h_dll, "WakeAllConditionVariable");
219
wake_condition_variable = (WakeConditionVariableProc)
220
GetProcAddress(h_dll, "WakeConditionVariable");
222
/* When using native condition variables, check function pointers */
223
ut_a(initialize_condition_variable);
224
ut_a(sleep_condition_variable);
225
ut_a(wake_all_condition_variable);
226
ut_a(wake_condition_variable);
230
/*********************************************************//**
231
Initializes global event and OS 'slow' mutex lists. */
237
UT_LIST_INIT(os_event_list);
238
UT_LIST_INIT(os_mutex_list);
240
os_sync_mutex = NULL;
241
os_sync_mutex_inited = FALSE;
243
/* Now for Windows only */
244
os_cond_module_init();
246
os_sync_mutex = os_mutex_create();
248
os_sync_mutex_inited = TRUE;
251
/*********************************************************//**
252
Frees created events and OS 'slow' mutexes. */
261
os_sync_free_called = TRUE;
262
event = UT_LIST_GET_FIRST(os_event_list);
266
os_event_free(event);
268
event = UT_LIST_GET_FIRST(os_event_list);
271
mutex = UT_LIST_GET_FIRST(os_mutex_list);
274
if (mutex == os_sync_mutex) {
275
/* Set the flag to FALSE so that we do not try to
276
reserve os_sync_mutex any more in remaining freeing
277
operations in shutdown */
278
os_sync_mutex_inited = FALSE;
281
os_mutex_free(mutex);
283
mutex = UT_LIST_GET_FIRST(os_mutex_list);
285
os_sync_free_called = FALSE;
288
/*********************************************************//**
289
Creates an event semaphore, i.e., a semaphore which may just have two
290
states: signaled and nonsignaled. The created event is manual reset: it
291
must be reset explicitly by calling sync_os_reset_event.
292
@return the event handle */
297
const char* name) /*!< in: the name of the event, if NULL
298
the event is created without a name */
303
if(!srv_use_native_conditions) {
305
event = ut_malloc(sizeof(struct os_event_struct));
307
event->handle = CreateEvent(NULL,
311
if (!event->handle) {
313
"InnoDB: Could not create a Windows event"
314
" semaphore; Windows error %lu\n",
315
(ulong) GetLastError());
317
} else /* Windows with condition variables */
323
event = ut_malloc(sizeof(struct os_event_struct));
325
os_fast_mutex_init(&(event->os_mutex));
327
os_cond_init(&(event->cond_var));
329
event->is_set = FALSE;
331
/* We return this value in os_event_reset(), which can then be
332
be used to pass to the os_event_wait_low(). The value of zero
333
is reserved in os_event_wait_low() for the case when the
334
caller does not want to pass any signal_count value. To
335
distinguish between the two cases we initialize signal_count
337
event->signal_count = 1;
340
/* The os_sync_mutex can be NULL because during startup an event
341
can be created [ because it's embedded in the mutex/rwlock ] before
342
this module has been initialized */
343
if (os_sync_mutex != NULL) {
344
os_mutex_enter(os_sync_mutex);
347
/* Put to the list of events */
348
UT_LIST_ADD_FIRST(os_event_list, os_event_list, event);
352
if (os_sync_mutex != NULL) {
353
os_mutex_exit(os_sync_mutex);
359
/**********************************************************//**
360
Sets an event semaphore to the signaled state: lets waiting threads
366
os_event_t event) /*!< in: event to set */
371
if (!srv_use_native_conditions) {
372
ut_a(SetEvent(event->handle));
379
os_fast_mutex_lock(&(event->os_mutex));
384
event->is_set = TRUE;
385
event->signal_count += 1;
386
os_cond_broadcast(&(event->cond_var));
389
os_fast_mutex_unlock(&(event->os_mutex));
392
/**********************************************************//**
393
Resets an event semaphore to the nonsignaled state. Waiting threads will
394
stop to wait for the event.
395
The return value should be passed to os_even_wait_low() if it is desired
396
that this thread should not wait in case of an intervening call to
397
os_event_set() between this os_event_reset() and the
398
os_event_wait_low() call. See comments for os_event_wait_low().
399
@return current signal_count. */
404
os_event_t event) /*!< in: event to reset */
411
if(!srv_use_native_conditions) {
412
ut_a(ResetEvent(event->handle));
417
os_fast_mutex_lock(&(event->os_mutex));
419
if (!event->is_set) {
422
event->is_set = FALSE;
424
ret = event->signal_count;
426
os_fast_mutex_unlock(&(event->os_mutex));
430
/**********************************************************//**
431
Frees an event object, without acquiring the global lock. */
434
os_event_free_internal(
435
/*===================*/
436
os_event_t event) /*!< in: event to free */
439
if(!srv_use_native_conditions) {
441
ut_a(CloseHandle(event->handle));
447
/* This is to avoid freeing the mutex twice */
448
os_fast_mutex_free(&(event->os_mutex));
450
os_cond_destroy(&(event->cond_var));
453
/* Remove from the list of events */
454
UT_LIST_REMOVE(os_event_list, os_event_list, event);
461
/**********************************************************//**
462
Frees an event object. */
467
os_event_t event) /*!< in: event to free */
472
if(!srv_use_native_conditions){
473
ut_a(CloseHandle(event->handle));
474
} else /*Windows with condition variables */
477
os_fast_mutex_free(&(event->os_mutex));
479
os_cond_destroy(&(event->cond_var));
482
/* Remove from the list of events */
483
os_mutex_enter(os_sync_mutex);
485
UT_LIST_REMOVE(os_event_list, os_event_list, event);
489
os_mutex_exit(os_sync_mutex);
494
/**********************************************************//**
495
Waits for an event object until it is in the signaled state. If
496
srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS this also exits the
497
waiting thread when the event becomes signaled (or immediately if the
498
event is already in the signaled state).
500
Typically, if the event has been signalled after the os_event_reset()
501
we'll return immediately because event->is_set == TRUE.
502
There are, however, situations (e.g.: sync_array code) where we may
503
lose this information. For example:
505
thread A calls os_event_reset()
506
thread B calls os_event_set() [event->is_set == TRUE]
507
thread C calls os_event_reset() [event->is_set == FALSE]
508
thread A calls os_event_wait() [infinite wait!]
509
thread C calls os_event_wait() [infinite wait!]
511
Where such a scenario is possible, to avoid infinite wait, the
512
value returned by os_event_reset() should be passed in as
518
os_event_t event, /*!< in: event to wait */
519
ib_int64_t reset_sig_count)/*!< in: zero or the value
520
returned by previous call of
523
ib_int64_t old_signal_count;
526
if(!srv_use_native_conditions) {
531
UT_NOT_USED(reset_sig_count);
533
/* Specify an infinite wait */
534
err = WaitForSingleObject(event->handle, INFINITE);
536
ut_a(err == WAIT_OBJECT_0);
538
if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
539
os_thread_exit(NULL);
545
os_fast_mutex_lock(&(event->os_mutex));
547
if (reset_sig_count) {
548
old_signal_count = reset_sig_count;
550
old_signal_count = event->signal_count;
554
if (event->is_set == TRUE
555
|| event->signal_count != old_signal_count) {
557
os_fast_mutex_unlock(&(event->os_mutex));
559
if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
561
os_thread_exit(NULL);
563
/* Ok, we may return */
568
os_cond_wait(&(event->cond_var), &(event->os_mutex));
570
/* Solaris manual said that spurious wakeups may occur: we
571
have to check if the event really has been signaled after
572
we came here to wait */
576
/*********************************************************//**
577
Creates an operating system mutex semaphore. Because these are slow, the
578
mutex semaphore of InnoDB itself (mutex_t) should be used where possible.
579
@return the mutex handle */
582
os_mutex_create(void)
583
/*=================*/
585
os_fast_mutex_t* mutex;
586
os_mutex_t mutex_str;
588
mutex = ut_malloc(sizeof(os_fast_mutex_t));
590
os_fast_mutex_init(mutex);
591
mutex_str = ut_malloc(sizeof(os_mutex_str_t));
593
mutex_str->handle = mutex;
594
mutex_str->count = 0;
595
mutex_str->event = os_event_create(NULL);
597
if (UNIV_LIKELY(os_sync_mutex_inited)) {
598
/* When creating os_sync_mutex itself we cannot reserve it */
599
os_mutex_enter(os_sync_mutex);
602
UT_LIST_ADD_FIRST(os_mutex_list, os_mutex_list, mutex_str);
606
if (UNIV_LIKELY(os_sync_mutex_inited)) {
607
os_mutex_exit(os_sync_mutex);
613
/**********************************************************//**
614
Acquires ownership of a mutex semaphore. */
619
os_mutex_t mutex) /*!< in: mutex to acquire */
621
os_fast_mutex_lock(mutex->handle);
625
ut_a(mutex->count == 1);
628
/**********************************************************//**
629
Releases ownership of a mutex. */
634
os_mutex_t mutex) /*!< in: mutex to release */
638
ut_a(mutex->count == 1);
641
os_fast_mutex_unlock(mutex->handle);
644
/**********************************************************//**
645
Frees a mutex object. */
650
os_mutex_t mutex) /*!< in: mutex to free */
654
if (UNIV_LIKELY(!os_sync_free_called)) {
655
os_event_free_internal(mutex->event);
658
if (UNIV_LIKELY(os_sync_mutex_inited)) {
659
os_mutex_enter(os_sync_mutex);
662
UT_LIST_REMOVE(os_mutex_list, os_mutex_list, mutex);
666
if (UNIV_LIKELY(os_sync_mutex_inited)) {
667
os_mutex_exit(os_sync_mutex);
670
os_fast_mutex_free(mutex->handle);
671
ut_free(mutex->handle);
675
/*********************************************************//**
676
Initializes an operating system fast mutex semaphore. */
681
os_fast_mutex_t* fast_mutex) /*!< in: fast mutex */
686
InitializeCriticalSection((LPCRITICAL_SECTION) fast_mutex);
688
ut_a(0 == innobase_fast_mutex_init(fast_mutex));
690
if (UNIV_LIKELY(os_sync_mutex_inited)) {
691
/* When creating os_sync_mutex itself (in Unix) we cannot
694
os_mutex_enter(os_sync_mutex);
697
os_fast_mutex_count++;
699
if (UNIV_LIKELY(os_sync_mutex_inited)) {
700
os_mutex_exit(os_sync_mutex);
704
/**********************************************************//**
705
Acquires ownership of a fast mutex. */
710
os_fast_mutex_t* fast_mutex) /*!< in: mutex to acquire */
713
EnterCriticalSection((LPCRITICAL_SECTION) fast_mutex);
715
pthread_mutex_lock(fast_mutex);
719
/**********************************************************//**
720
Releases ownership of a fast mutex. */
723
os_fast_mutex_unlock(
724
/*=================*/
725
os_fast_mutex_t* fast_mutex) /*!< in: mutex to release */
728
LeaveCriticalSection(fast_mutex);
730
pthread_mutex_unlock(fast_mutex);
734
/**********************************************************//**
735
Frees a mutex object. */
740
os_fast_mutex_t* fast_mutex) /*!< in: mutex to free */
745
DeleteCriticalSection((LPCRITICAL_SECTION) fast_mutex);
749
ret = pthread_mutex_destroy(fast_mutex);
751
if (UNIV_UNLIKELY(ret != 0)) {
752
ut_print_timestamp(stderr);
754
" InnoDB: error: return value %lu when calling\n"
755
"InnoDB: pthread_mutex_destroy().\n", (ulint)ret);
757
"InnoDB: Byte contents of the pthread mutex at %p:\n",
759
ut_print_buf(stderr, fast_mutex, sizeof(os_fast_mutex_t));
763
if (UNIV_LIKELY(os_sync_mutex_inited)) {
764
/* When freeing the last mutexes, we have
765
already freed os_sync_mutex */
767
os_mutex_enter(os_sync_mutex);
770
ut_ad(os_fast_mutex_count > 0);
771
os_fast_mutex_count--;
773
if (UNIV_LIKELY(os_sync_mutex_inited)) {
774
os_mutex_exit(os_sync_mutex);