1
/******************************************************
2
The interface to the operating system
3
synchronization primitives.
7
Created 9/6/1995 Heikki Tuuri
8
*******************************************************/
20
#include "srv0start.h"
22
/* Type definition for an operating system mutex struct */
23
struct os_mutex_struct{
24
os_event_t event; /* Used by sync0arr.c for queing threads */
25
void* handle; /* OS handle to mutex */
26
ulint count; /* we use this counter to check
27
that the same thread does not
28
recursively lock the mutex: we
29
do not assume that the OS mutex
30
supports recursive locking, though
31
NT seems to do that */
32
UT_LIST_NODE_T(os_mutex_str_t) os_mutex_list;
33
/* list of all 'slow' OS mutexes created */
36
/* Mutex protecting counts and the lists of OS mutexes and events */
37
UNIV_INTERN os_mutex_t os_sync_mutex;
38
static ibool os_sync_mutex_inited = FALSE;
39
static ibool os_sync_free_called = FALSE;
41
/* This is incremented by 1 in os_thread_create and decremented by 1 in
43
UNIV_INTERN ulint os_thread_count = 0;
45
/* The list of all events created */
46
static UT_LIST_BASE_NODE_T(os_event_struct_t) os_event_list;
48
/* The list of all OS 'slow' mutexes */
49
static UT_LIST_BASE_NODE_T(os_mutex_str_t) os_mutex_list;
51
UNIV_INTERN ulint os_event_count = 0;
52
UNIV_INTERN ulint os_mutex_count = 0;
53
UNIV_INTERN ulint os_fast_mutex_count = 0;
55
/* Because a mutex is embedded inside an event and there is an
56
event embedded inside a mutex, on free, this generates a recursive call.
57
This version of the free event function doesn't acquire the global lock */
58
static void os_event_free_internal(os_event_t event);
60
/*************************************************************
61
Initializes global event and OS 'slow' mutex lists. */
67
UT_LIST_INIT(os_event_list);
68
UT_LIST_INIT(os_mutex_list);
70
os_sync_mutex = os_mutex_create(NULL);
72
os_sync_mutex_inited = TRUE;
75
/*************************************************************
76
Frees created events and OS 'slow' mutexes. */
85
os_sync_free_called = TRUE;
86
event = UT_LIST_GET_FIRST(os_event_list);
92
event = UT_LIST_GET_FIRST(os_event_list);
95
mutex = UT_LIST_GET_FIRST(os_mutex_list);
98
if (mutex == os_sync_mutex) {
99
/* Set the flag to FALSE so that we do not try to
100
reserve os_sync_mutex any more in remaining freeing
101
operations in shutdown */
102
os_sync_mutex_inited = FALSE;
105
os_mutex_free(mutex);
107
mutex = UT_LIST_GET_FIRST(os_mutex_list);
109
os_sync_free_called = FALSE;
112
/*************************************************************
113
Creates an event semaphore, i.e., a semaphore which may just have two
114
states: signaled and nonsignaled. The created event is manual reset: it
115
must be reset explicitly by calling sync_os_reset_event. */
120
/* out: the event handle */
121
const char* name) /* in: the name of the event, if NULL
122
the event is created without a name */
127
event = ut_malloc(sizeof(struct os_event_struct));
129
event->handle = CreateEvent(NULL, /* No security attributes */
130
TRUE, /* Manual reset */
131
FALSE, /* Initial state nonsignaled */
133
if (!event->handle) {
135
"InnoDB: Could not create a Windows event semaphore;"
136
" Windows error %lu\n",
137
(ulong) GetLastError());
144
event = ut_malloc(sizeof(struct os_event_struct));
146
os_fast_mutex_init(&(event->os_mutex));
148
#if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10)
149
ut_a(0 == pthread_cond_init(&(event->cond_var),
150
pthread_condattr_default));
152
ut_a(0 == pthread_cond_init(&(event->cond_var), NULL));
154
event->is_set = FALSE;
156
/* We return this value in os_event_reset(), which can then be
157
be used to pass to the os_event_wait_low(). The value of zero
158
is reserved in os_event_wait_low() for the case when the
159
caller does not want to pass any signal_count value. To
160
distinguish between the two cases we initialize signal_count
162
event->signal_count = 1;
165
/* The os_sync_mutex can be NULL because during startup an event
166
can be created [ because it's embedded in the mutex/rwlock ] before
167
this module has been initialized */
168
if (os_sync_mutex != NULL) {
169
os_mutex_enter(os_sync_mutex);
172
/* Put to the list of events */
173
UT_LIST_ADD_FIRST(os_event_list, os_event_list, event);
177
if (os_sync_mutex != NULL) {
178
os_mutex_exit(os_sync_mutex);
185
/*************************************************************
186
Creates an auto-reset event semaphore, i.e., an event which is automatically
187
reset when a single thread is released. Works only in Windows. */
190
os_event_create_auto(
191
/*=================*/
192
/* out: the event handle */
193
const char* name) /* in: the name of the event, if NULL
194
the event is created without a name */
198
event = ut_malloc(sizeof(struct os_event_struct));
200
event->handle = CreateEvent(NULL, /* No security attributes */
201
FALSE, /* Auto-reset */
202
FALSE, /* Initial state nonsignaled */
205
if (!event->handle) {
207
"InnoDB: Could not create a Windows auto"
208
" event semaphore; Windows error %lu\n",
209
(ulong) GetLastError());
212
/* Put to the list of events */
213
os_mutex_enter(os_sync_mutex);
215
UT_LIST_ADD_FIRST(os_event_list, os_event_list, event);
219
os_mutex_exit(os_sync_mutex);
225
/**************************************************************
226
Sets an event semaphore to the signaled state: lets waiting threads
232
os_event_t event) /* in: event to set */
236
ut_a(SetEvent(event->handle));
240
os_fast_mutex_lock(&(event->os_mutex));
245
event->is_set = TRUE;
246
event->signal_count += 1;
247
ut_a(0 == pthread_cond_broadcast(&(event->cond_var)));
250
os_fast_mutex_unlock(&(event->os_mutex));
254
/**************************************************************
255
Resets an event semaphore to the nonsignaled state. Waiting threads will
256
stop to wait for the event.
257
The return value should be passed to os_even_wait_low() if it is desired
258
that this thread should not wait in case of an intervening call to
259
os_event_set() between this os_event_reset() and the
260
os_event_wait_low() call. See comments for os_event_wait_low(). */
265
/* out: current signal_count. */
266
os_event_t event) /* in: event to reset */
273
ut_a(ResetEvent(event->handle));
277
os_fast_mutex_lock(&(event->os_mutex));
279
if (!event->is_set) {
282
event->is_set = FALSE;
284
ret = event->signal_count;
286
os_fast_mutex_unlock(&(event->os_mutex));
291
/**************************************************************
292
Frees an event object, without acquiring the global lock. */
295
os_event_free_internal(
296
/*===================*/
297
os_event_t event) /* in: event to free */
302
ut_a(CloseHandle(event->handle));
306
/* This is to avoid freeing the mutex twice */
307
os_fast_mutex_free(&(event->os_mutex));
309
ut_a(0 == pthread_cond_destroy(&(event->cond_var)));
311
/* Remove from the list of events */
313
UT_LIST_REMOVE(os_event_list, os_event_list, event);
320
/**************************************************************
321
Frees an event object. */
326
os_event_t event) /* in: event to free */
332
ut_a(CloseHandle(event->handle));
336
os_fast_mutex_free(&(event->os_mutex));
337
ut_a(0 == pthread_cond_destroy(&(event->cond_var)));
339
/* Remove from the list of events */
341
os_mutex_enter(os_sync_mutex);
343
UT_LIST_REMOVE(os_event_list, os_event_list, event);
347
os_mutex_exit(os_sync_mutex);
352
/**************************************************************
353
Waits for an event object until it is in the signaled state. If
354
srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS this also exits the
355
waiting thread when the event becomes signaled (or immediately if the
356
event is already in the signaled state).
358
Typically, if the event has been signalled after the os_event_reset()
359
we'll return immediately because event->is_set == TRUE.
360
There are, however, situations (e.g.: sync_array code) where we may
361
lose this information. For example:
363
thread A calls os_event_reset()
364
thread B calls os_event_set() [event->is_set == TRUE]
365
thread C calls os_event_reset() [event->is_set == FALSE]
366
thread A calls os_event_wait() [infinite wait!]
367
thread C calls os_event_wait() [infinite wait!]
369
Where such a scenario is possible, to avoid infinite wait, the
370
value returned by os_event_reset() should be passed in as
376
os_event_t event, /* in: event to wait */
377
ib_int64_t reset_sig_count)/* in: zero or the value
378
returned by previous call of
386
UT_NOT_USED(reset_sig_count);
388
/* Specify an infinite time limit for waiting */
389
err = WaitForSingleObject(event->handle, INFINITE);
391
ut_a(err == WAIT_OBJECT_0);
393
if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
394
os_thread_exit(NULL);
397
ib_int64_t old_signal_count;
399
os_fast_mutex_lock(&(event->os_mutex));
401
if (reset_sig_count) {
402
old_signal_count = reset_sig_count;
404
old_signal_count = event->signal_count;
408
if (event->is_set == TRUE
409
|| event->signal_count != old_signal_count) {
411
os_fast_mutex_unlock(&(event->os_mutex));
413
if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
415
os_thread_exit(NULL);
417
/* Ok, we may return */
422
pthread_cond_wait(&(event->cond_var), &(event->os_mutex));
424
/* Solaris manual said that spurious wakeups may occur: we
425
have to check if the event really has been signaled after
426
we came here to wait */
431
/**************************************************************
432
Waits for an event object until it is in the signaled state or
433
a timeout is exceeded. In Unix the timeout is always infinite. */
438
/* out: 0 if success, OS_SYNC_TIME_EXCEEDED if
439
timeout was exceeded */
440
os_event_t event, /* in: event to wait */
441
ulint time) /* in: timeout in microseconds, or
442
OS_SYNC_INFINITE_TIME */
449
if (time != OS_SYNC_INFINITE_TIME) {
450
err = WaitForSingleObject(event->handle, (DWORD) time / 1000);
452
err = WaitForSingleObject(event->handle, INFINITE);
455
if (err == WAIT_OBJECT_0) {
458
} else if (err == WAIT_TIMEOUT) {
460
return(OS_SYNC_TIME_EXCEEDED);
463
return(1000000); /* dummy value to eliminate compiler warn. */
468
/* In Posix this is just an ordinary, infinite wait */
470
os_event_wait(event);
477
/**************************************************************
478
Waits for any event in an OS native event array. Returns if even a single
479
one is signaled or becomes signaled. */
482
os_event_wait_multiple(
483
/*===================*/
484
/* out: index of the event
485
which was signaled */
486
ulint n, /* in: number of events in the
488
os_native_event_t* native_event_array)
489
/* in: pointer to an array of event
494
ut_a(native_event_array);
497
index = WaitForMultipleObjects((DWORD) n, native_event_array,
498
FALSE, /* Wait for any 1 event */
499
INFINITE); /* Infinite wait time
501
ut_a(index >= WAIT_OBJECT_0); /* NOTE: Pointless comparision */
502
ut_a(index < WAIT_OBJECT_0 + n);
504
if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
505
os_thread_exit(NULL);
508
return(index - WAIT_OBJECT_0);
512
/*************************************************************
513
Creates an operating system mutex semaphore. Because these are slow, the
514
mutex semaphore of InnoDB itself (mutex_t) should be used where possible. */
519
/* out: the mutex handle */
520
const char* name) /* in: the name of the mutex, if NULL
521
the mutex is created without a name */
525
os_mutex_t mutex_str;
527
mutex = CreateMutex(NULL, /* No security attributes */
528
FALSE, /* Initial state: no owner */
532
os_fast_mutex_t* mutex;
533
os_mutex_t mutex_str;
537
mutex = ut_malloc(sizeof(os_fast_mutex_t));
539
os_fast_mutex_init(mutex);
541
mutex_str = ut_malloc(sizeof(os_mutex_str_t));
543
mutex_str->handle = mutex;
544
mutex_str->count = 0;
545
mutex_str->event = os_event_create(NULL);
547
if (UNIV_LIKELY(os_sync_mutex_inited)) {
548
/* When creating os_sync_mutex itself we cannot reserve it */
549
os_mutex_enter(os_sync_mutex);
552
UT_LIST_ADD_FIRST(os_mutex_list, os_mutex_list, mutex_str);
556
if (UNIV_LIKELY(os_sync_mutex_inited)) {
557
os_mutex_exit(os_sync_mutex);
563
/**************************************************************
564
Acquires ownership of a mutex semaphore. */
569
os_mutex_t mutex) /* in: mutex to acquire */
576
/* Specify infinite time limit for waiting */
577
err = WaitForSingleObject(mutex->handle, INFINITE);
579
ut_a(err == WAIT_OBJECT_0);
582
ut_a(mutex->count == 1);
584
os_fast_mutex_lock(mutex->handle);
588
ut_a(mutex->count == 1);
592
/**************************************************************
593
Releases ownership of a mutex. */
598
os_mutex_t mutex) /* in: mutex to release */
602
ut_a(mutex->count == 1);
606
ut_a(ReleaseMutex(mutex->handle));
608
os_fast_mutex_unlock(mutex->handle);
612
/**************************************************************
613
Frees a mutex object. */
618
os_mutex_t mutex) /* in: mutex to free */
622
if (UNIV_LIKELY(!os_sync_free_called)) {
623
os_event_free_internal(mutex->event);
626
if (UNIV_LIKELY(os_sync_mutex_inited)) {
627
os_mutex_enter(os_sync_mutex);
630
UT_LIST_REMOVE(os_mutex_list, os_mutex_list, mutex);
634
if (UNIV_LIKELY(os_sync_mutex_inited)) {
635
os_mutex_exit(os_sync_mutex);
639
ut_a(CloseHandle(mutex->handle));
643
os_fast_mutex_free(mutex->handle);
644
ut_free(mutex->handle);
649
/*************************************************************
650
Initializes an operating system fast mutex semaphore. */
655
os_fast_mutex_t* fast_mutex) /* in: fast mutex */
660
InitializeCriticalSection((LPCRITICAL_SECTION) fast_mutex);
662
#if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10)
663
ut_a(0 == pthread_mutex_init(fast_mutex, pthread_mutexattr_default));
665
ut_a(0 == pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST));
668
if (UNIV_LIKELY(os_sync_mutex_inited)) {
669
/* When creating os_sync_mutex itself (in Unix) we cannot
672
os_mutex_enter(os_sync_mutex);
675
os_fast_mutex_count++;
677
if (UNIV_LIKELY(os_sync_mutex_inited)) {
678
os_mutex_exit(os_sync_mutex);
682
/**************************************************************
683
Acquires ownership of a fast mutex. */
688
os_fast_mutex_t* fast_mutex) /* in: mutex to acquire */
691
EnterCriticalSection((LPCRITICAL_SECTION) fast_mutex);
693
pthread_mutex_lock(fast_mutex);
697
/**************************************************************
698
Releases ownership of a fast mutex. */
701
os_fast_mutex_unlock(
702
/*=================*/
703
os_fast_mutex_t* fast_mutex) /* in: mutex to release */
706
LeaveCriticalSection(fast_mutex);
708
pthread_mutex_unlock(fast_mutex);
712
/**************************************************************
713
Frees a mutex object. */
718
os_fast_mutex_t* fast_mutex) /* in: mutex to free */
723
DeleteCriticalSection((LPCRITICAL_SECTION) fast_mutex);
727
ret = pthread_mutex_destroy(fast_mutex);
730
ut_print_timestamp(stderr);
732
" InnoDB: error: return value %lu when calling\n"
733
"InnoDB: pthread_mutex_destroy().\n", (ulint)ret);
735
"InnoDB: Byte contents of the pthread mutex at %p:\n",
737
ut_print_buf(stderr, fast_mutex, sizeof(os_fast_mutex_t));
738
fprintf(stderr, "\n");
741
if (UNIV_LIKELY(os_sync_mutex_inited)) {
742
/* When freeing the last mutexes, we have
743
already freed os_sync_mutex */
745
os_mutex_enter(os_sync_mutex);
748
os_fast_mutex_count--;
750
if (UNIV_LIKELY(os_sync_mutex_inited)) {
751
os_mutex_exit(os_sync_mutex);