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., 59 Temple
15
Place, Suite 330, Boston, MA 02111-1307 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
/* Type definition for an operating system mutex struct */
40
struct os_mutex_struct{
41
os_event_t event; /*!< Used by sync0arr.c for queing threads */
42
void* handle; /*!< OS handle to mutex */
43
ulint count; /*!< we use this counter to check
44
that the same thread does not
45
recursively lock the mutex: we
46
do not assume that the OS mutex
47
supports recursive locking, though
48
NT seems to do that */
49
UT_LIST_NODE_T(os_mutex_str_t) os_mutex_list;
50
/* list of all 'slow' OS mutexes created */
53
/** Mutex protecting counts and the lists of OS mutexes and events */
54
UNIV_INTERN os_mutex_t os_sync_mutex;
55
/** TRUE if os_sync_mutex has been initialized */
56
static ibool os_sync_mutex_inited = FALSE;
57
/** TRUE when os_sync_free() is being executed */
58
static ibool os_sync_free_called = FALSE;
60
/** This is incremented by 1 in os_thread_create and decremented by 1 in
62
UNIV_INTERN ulint os_thread_count = 0;
64
/** The list of all events created */
65
static UT_LIST_BASE_NODE_T(os_event_struct_t) os_event_list;
67
/** The list of all OS 'slow' mutexes */
68
static UT_LIST_BASE_NODE_T(os_mutex_str_t) os_mutex_list;
70
UNIV_INTERN ulint os_event_count = 0;
71
UNIV_INTERN ulint os_mutex_count = 0;
72
UNIV_INTERN ulint os_fast_mutex_count = 0;
74
/* Because a mutex is embedded inside an event and there is an
75
event embedded inside a mutex, on free, this generates a recursive call.
76
This version of the free event function doesn't acquire the global lock */
77
static void os_event_free_internal(os_event_t event);
79
/*********************************************************//**
80
Initializes global event and OS 'slow' mutex lists. */
86
UT_LIST_INIT(os_event_list);
87
UT_LIST_INIT(os_mutex_list);
90
os_sync_mutex_inited = FALSE;
92
os_sync_mutex = os_mutex_create(NULL);
94
os_sync_mutex_inited = TRUE;
97
/*********************************************************//**
98
Frees created events and OS 'slow' mutexes. */
107
os_sync_free_called = TRUE;
108
event = UT_LIST_GET_FIRST(os_event_list);
112
os_event_free(event);
114
event = UT_LIST_GET_FIRST(os_event_list);
117
mutex = UT_LIST_GET_FIRST(os_mutex_list);
120
if (mutex == os_sync_mutex) {
121
/* Set the flag to FALSE so that we do not try to
122
reserve os_sync_mutex any more in remaining freeing
123
operations in shutdown */
124
os_sync_mutex_inited = FALSE;
127
os_mutex_free(mutex);
129
mutex = UT_LIST_GET_FIRST(os_mutex_list);
131
os_sync_free_called = FALSE;
134
/*********************************************************//**
135
Creates an event semaphore, i.e., a semaphore which may just have two
136
states: signaled and nonsignaled. The created event is manual reset: it
137
must be reset explicitly by calling sync_os_reset_event.
138
@return the event handle */
143
const char* name) /*!< in: the name of the event, if NULL
144
the event is created without a name */
149
event = ut_malloc(sizeof(struct os_event_struct));
151
event->handle = CreateEvent(NULL, /* No security attributes */
152
TRUE, /* Manual reset */
153
FALSE, /* Initial state nonsignaled */
155
if (!event->handle) {
157
"InnoDB: Could not create a Windows event semaphore;"
158
" Windows error %lu\n",
159
(ulong) GetLastError());
166
event = ut_malloc(sizeof(struct os_event_struct));
168
os_fast_mutex_init(&(event->os_mutex));
170
ut_a(0 == pthread_cond_init(&(event->cond_var), NULL));
172
event->is_set = FALSE;
174
/* We return this value in os_event_reset(), which can then be
175
be used to pass to the os_event_wait_low(). The value of zero
176
is reserved in os_event_wait_low() for the case when the
177
caller does not want to pass any signal_count value. To
178
distinguish between the two cases we initialize signal_count
180
event->signal_count = 1;
183
/* The os_sync_mutex can be NULL because during startup an event
184
can be created [ because it's embedded in the mutex/rwlock ] before
185
this module has been initialized */
186
if (os_sync_mutex != NULL) {
187
os_mutex_enter(os_sync_mutex);
190
/* Put to the list of events */
191
UT_LIST_ADD_FIRST(os_event_list, os_event_list, event);
195
if (os_sync_mutex != NULL) {
196
os_mutex_exit(os_sync_mutex);
202
/**********************************************************//**
203
Sets an event semaphore to the signaled state: lets waiting threads
209
os_event_t event) /*!< in: event to set */
213
ut_a(SetEvent(event->handle));
217
os_fast_mutex_lock(&(event->os_mutex));
222
event->is_set = TRUE;
223
event->signal_count += 1;
224
ut_a(0 == pthread_cond_broadcast(&(event->cond_var)));
227
os_fast_mutex_unlock(&(event->os_mutex));
231
/**********************************************************//**
232
Resets an event semaphore to the nonsignaled state. Waiting threads will
233
stop to wait for the event.
234
The return value should be passed to os_even_wait_low() if it is desired
235
that this thread should not wait in case of an intervening call to
236
os_event_set() between this os_event_reset() and the
237
os_event_wait_low() call. See comments for os_event_wait_low().
238
@return current signal_count. */
243
os_event_t event) /*!< in: event to reset */
250
ut_a(ResetEvent(event->handle));
254
os_fast_mutex_lock(&(event->os_mutex));
256
if (!event->is_set) {
259
event->is_set = FALSE;
261
ret = event->signal_count;
263
os_fast_mutex_unlock(&(event->os_mutex));
268
/**********************************************************//**
269
Frees an event object, without acquiring the global lock. */
272
os_event_free_internal(
273
/*===================*/
274
os_event_t event) /*!< in: event to free */
279
ut_a(CloseHandle(event->handle));
283
/* This is to avoid freeing the mutex twice */
284
os_fast_mutex_free(&(event->os_mutex));
286
ut_a(0 == pthread_cond_destroy(&(event->cond_var)));
288
/* Remove from the list of events */
290
UT_LIST_REMOVE(os_event_list, os_event_list, event);
297
/**********************************************************//**
298
Frees an event object. */
303
os_event_t event) /*!< in: event to free */
309
ut_a(CloseHandle(event->handle));
313
os_fast_mutex_free(&(event->os_mutex));
314
ut_a(0 == pthread_cond_destroy(&(event->cond_var)));
316
/* Remove from the list of events */
318
os_mutex_enter(os_sync_mutex);
320
UT_LIST_REMOVE(os_event_list, os_event_list, event);
324
os_mutex_exit(os_sync_mutex);
329
/**********************************************************//**
330
Waits for an event object until it is in the signaled state. If
331
srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS this also exits the
332
waiting thread when the event becomes signaled (or immediately if the
333
event is already in the signaled state).
335
Typically, if the event has been signalled after the os_event_reset()
336
we'll return immediately because event->is_set == TRUE.
337
There are, however, situations (e.g.: sync_array code) where we may
338
lose this information. For example:
340
thread A calls os_event_reset()
341
thread B calls os_event_set() [event->is_set == TRUE]
342
thread C calls os_event_reset() [event->is_set == FALSE]
343
thread A calls os_event_wait() [infinite wait!]
344
thread C calls os_event_wait() [infinite wait!]
346
Where such a scenario is possible, to avoid infinite wait, the
347
value returned by os_event_reset() should be passed in as
353
os_event_t event, /*!< in: event to wait */
354
ib_int64_t reset_sig_count)/*!< in: zero or the value
355
returned by previous call of
363
UT_NOT_USED(reset_sig_count);
365
/* Specify an infinite time limit for waiting */
366
err = WaitForSingleObject(event->handle, INFINITE);
368
ut_a(err == WAIT_OBJECT_0);
370
if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
371
os_thread_exit(NULL);
374
ib_int64_t old_signal_count;
376
os_fast_mutex_lock(&(event->os_mutex));
378
if (reset_sig_count) {
379
old_signal_count = reset_sig_count;
381
old_signal_count = event->signal_count;
385
if (event->is_set == TRUE
386
|| event->signal_count != old_signal_count) {
388
os_fast_mutex_unlock(&(event->os_mutex));
390
if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
392
os_thread_exit(NULL);
394
/* Ok, we may return */
399
pthread_cond_wait(&(event->cond_var), &(event->os_mutex));
401
/* Solaris manual said that spurious wakeups may occur: we
402
have to check if the event really has been signaled after
403
we came here to wait */
408
/**********************************************************//**
409
Waits for an event object until it is in the signaled state or
410
a timeout is exceeded. In Unix the timeout is always infinite.
411
@return 0 if success, OS_SYNC_TIME_EXCEEDED if timeout was exceeded */
416
os_event_t event, /*!< in: event to wait */
417
ulint time) /*!< in: timeout in microseconds, or
418
OS_SYNC_INFINITE_TIME */
425
if (time != OS_SYNC_INFINITE_TIME) {
426
err = WaitForSingleObject(event->handle, (DWORD) time / 1000);
428
err = WaitForSingleObject(event->handle, INFINITE);
431
if (err == WAIT_OBJECT_0) {
434
} else if (err == WAIT_TIMEOUT) {
436
return(OS_SYNC_TIME_EXCEEDED);
439
return(1000000); /* dummy value to eliminate compiler warn. */
444
/* In Posix this is just an ordinary, infinite wait */
446
os_event_wait(event);
453
/**********************************************************//**
454
Waits for any event in an OS native event array. Returns if even a single
455
one is signaled or becomes signaled.
456
@return index of the event which was signaled */
459
os_event_wait_multiple(
460
/*===================*/
461
ulint n, /*!< in: number of events in the
463
os_native_event_t* native_event_array)
464
/*!< in: pointer to an array of event
469
ut_a(native_event_array);
472
index = WaitForMultipleObjects((DWORD) n, native_event_array,
473
FALSE, /* Wait for any 1 event */
474
INFINITE); /* Infinite wait time
476
ut_a(index >= WAIT_OBJECT_0); /* NOTE: Pointless comparison */
477
ut_a(index < WAIT_OBJECT_0 + n);
479
if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
480
os_thread_exit(NULL);
483
return(index - WAIT_OBJECT_0);
487
/*********************************************************//**
488
Creates an operating system mutex semaphore. Because these are slow, the
489
mutex semaphore of InnoDB itself (mutex_t) should be used where possible.
490
@return the mutex handle */
495
const char* name) /*!< in: the name of the mutex, if NULL
496
the mutex is created without a name */
500
os_mutex_t mutex_str;
502
mutex = CreateMutex(NULL, /* No security attributes */
503
FALSE, /* Initial state: no owner */
507
os_fast_mutex_t* mutex;
508
os_mutex_t mutex_str;
512
mutex = ut_malloc(sizeof(os_fast_mutex_t));
514
os_fast_mutex_init(mutex);
516
mutex_str = ut_malloc(sizeof(os_mutex_str_t));
518
mutex_str->handle = mutex;
519
mutex_str->count = 0;
520
mutex_str->event = os_event_create(NULL);
522
if (UNIV_LIKELY(os_sync_mutex_inited)) {
523
/* When creating os_sync_mutex itself we cannot reserve it */
524
os_mutex_enter(os_sync_mutex);
527
UT_LIST_ADD_FIRST(os_mutex_list, os_mutex_list, mutex_str);
531
if (UNIV_LIKELY(os_sync_mutex_inited)) {
532
os_mutex_exit(os_sync_mutex);
538
/**********************************************************//**
539
Acquires ownership of a mutex semaphore. */
544
os_mutex_t mutex) /*!< in: mutex to acquire */
551
/* Specify infinite time limit for waiting */
552
err = WaitForSingleObject(mutex->handle, INFINITE);
554
ut_a(err == WAIT_OBJECT_0);
557
ut_a(mutex->count == 1);
559
os_fast_mutex_lock(mutex->handle);
563
ut_a(mutex->count == 1);
567
/**********************************************************//**
568
Releases ownership of a mutex. */
573
os_mutex_t mutex) /*!< in: mutex to release */
577
ut_a(mutex->count == 1);
581
ut_a(ReleaseMutex(mutex->handle));
583
os_fast_mutex_unlock(mutex->handle);
587
/**********************************************************//**
588
Frees a mutex object. */
593
os_mutex_t mutex) /*!< in: mutex to free */
597
if (UNIV_LIKELY(!os_sync_free_called)) {
598
os_event_free_internal(mutex->event);
601
if (UNIV_LIKELY(os_sync_mutex_inited)) {
602
os_mutex_enter(os_sync_mutex);
605
UT_LIST_REMOVE(os_mutex_list, os_mutex_list, mutex);
609
if (UNIV_LIKELY(os_sync_mutex_inited)) {
610
os_mutex_exit(os_sync_mutex);
614
ut_a(CloseHandle(mutex->handle));
618
os_fast_mutex_free(mutex->handle);
619
ut_free(mutex->handle);
624
/*********************************************************//**
625
Initializes an operating system fast mutex semaphore. */
630
os_fast_mutex_t* fast_mutex) /*!< in: fast mutex */
635
InitializeCriticalSection((LPCRITICAL_SECTION) fast_mutex);
637
ut_a(0 == pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST));
639
if (UNIV_LIKELY(os_sync_mutex_inited)) {
640
/* When creating os_sync_mutex itself (in Unix) we cannot
643
os_mutex_enter(os_sync_mutex);
646
os_fast_mutex_count++;
648
if (UNIV_LIKELY(os_sync_mutex_inited)) {
649
os_mutex_exit(os_sync_mutex);
653
/**********************************************************//**
654
Acquires ownership of a fast mutex. */
659
os_fast_mutex_t* fast_mutex) /*!< in: mutex to acquire */
662
EnterCriticalSection((LPCRITICAL_SECTION) fast_mutex);
664
pthread_mutex_lock(fast_mutex);
668
/**********************************************************//**
669
Releases ownership of a fast mutex. */
672
os_fast_mutex_unlock(
673
/*=================*/
674
os_fast_mutex_t* fast_mutex) /*!< in: mutex to release */
677
LeaveCriticalSection(fast_mutex);
679
pthread_mutex_unlock(fast_mutex);
683
/**********************************************************//**
684
Frees a mutex object. */
689
os_fast_mutex_t* fast_mutex) /*!< in: mutex to free */
694
DeleteCriticalSection((LPCRITICAL_SECTION) fast_mutex);
698
ret = pthread_mutex_destroy(fast_mutex);
700
if (UNIV_UNLIKELY(ret != 0)) {
701
ut_print_timestamp(stderr);
703
" InnoDB: error: return value %lu when calling\n"
704
"InnoDB: pthread_mutex_destroy().\n", (ulint)ret);
706
"InnoDB: Byte contents of the pthread mutex at %p:\n",
708
ut_print_buf(stderr, fast_mutex, sizeof(os_fast_mutex_t));
712
if (UNIV_LIKELY(os_sync_mutex_inited)) {
713
/* When freeing the last mutexes, we have
714
already freed os_sync_mutex */
716
os_mutex_enter(os_sync_mutex);
719
ut_ad(os_fast_mutex_count > 0);
720
os_fast_mutex_count--;
722
if (UNIV_LIKELY(os_sync_mutex_inited)) {
723
os_mutex_exit(os_sync_mutex);