diff options
Diffstat (limited to 'storage/innobase/os/os0sync.c')
-rw-r--r-- | storage/innobase/os/os0sync.c | 648 |
1 files changed, 648 insertions, 0 deletions
diff --git a/storage/innobase/os/os0sync.c b/storage/innobase/os/os0sync.c new file mode 100644 index 00000000000..18d92af5054 --- /dev/null +++ b/storage/innobase/os/os0sync.c @@ -0,0 +1,648 @@ +/****************************************************** +The interface to the operating system +synchronization primitives. + +(c) 1995 Innobase Oy + +Created 9/6/1995 Heikki Tuuri +*******************************************************/ + +#include "os0sync.h" +#ifdef UNIV_NONINL +#include "os0sync.ic" +#endif + +#ifdef __WIN__ +#include <windows.h> +#endif + +#include "ut0mem.h" +#include "srv0start.h" + +/* Type definition for an operating system mutex struct */ +struct os_mutex_struct{ + void* handle; /* OS handle to mutex */ + ulint count; /* we use this counter to check + that the same thread does not + recursively lock the mutex: we + do not assume that the OS mutex + supports recursive locking, though + NT seems to do that */ + UT_LIST_NODE_T(os_mutex_str_t) os_mutex_list; + /* list of all 'slow' OS mutexes created */ +}; + +/* Mutex protecting counts and the lists of OS mutexes and events */ +os_mutex_t os_sync_mutex; +ibool os_sync_mutex_inited = FALSE; + +/* This is incremented by 1 in os_thread_create and decremented by 1 in +os_thread_exit */ +ulint os_thread_count = 0; + +/* The list of all events created */ +UT_LIST_BASE_NODE_T(os_event_struct_t) os_event_list; + +/* The list of all OS 'slow' mutexes */ +UT_LIST_BASE_NODE_T(os_mutex_str_t) os_mutex_list; + +ulint os_event_count = 0; +ulint os_mutex_count = 0; +ulint os_fast_mutex_count = 0; + + +/************************************************************* +Initializes global event and OS 'slow' mutex lists. */ + +void +os_sync_init(void) +/*==============*/ +{ + UT_LIST_INIT(os_event_list); + UT_LIST_INIT(os_mutex_list); + + os_sync_mutex = os_mutex_create(NULL); + + os_sync_mutex_inited = TRUE; +} + +/************************************************************* +Frees created events and OS 'slow' mutexes. */ + +void +os_sync_free(void) +/*==============*/ +{ + os_event_t event; + os_mutex_t mutex; + + event = UT_LIST_GET_FIRST(os_event_list); + + while (event) { + + os_event_free(event); + + event = UT_LIST_GET_FIRST(os_event_list); + } + + mutex = UT_LIST_GET_FIRST(os_mutex_list); + + while (mutex) { + if (mutex == os_sync_mutex) { + /* Set the flag to FALSE so that we do not try to + reserve os_sync_mutex any more in remaining freeing + operations in shutdown */ + os_sync_mutex_inited = FALSE; + } + + os_mutex_free(mutex); + + mutex = UT_LIST_GET_FIRST(os_mutex_list); + } +} + +/************************************************************* +Creates an event semaphore, i.e., a semaphore which may just have two +states: signaled and nonsignaled. The created event is manual reset: it +must be reset explicitly by calling sync_os_reset_event. */ + +os_event_t +os_event_create( +/*============*/ + /* out: the event handle */ + const char* name) /* in: the name of the event, if NULL + the event is created without a name */ +{ +#ifdef __WIN__ + os_event_t event; + + event = ut_malloc(sizeof(struct os_event_struct)); + + event->handle = CreateEvent(NULL,/* No security attributes */ + TRUE, /* Manual reset */ + FALSE, /* Initial state nonsignaled */ + name); + if (!event->handle) { + fprintf(stderr, +"InnoDB: Could not create a Windows event semaphore; Windows error %lu\n", + (ulong) GetLastError()); + } +#else /* Unix */ + os_event_t event; + + UT_NOT_USED(name); + + event = ut_malloc(sizeof(struct os_event_struct)); + + os_fast_mutex_init(&(event->os_mutex)); + +#if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10) + ut_a(0 == pthread_cond_init(&(event->cond_var), + pthread_condattr_default)); +#else + ut_a(0 == pthread_cond_init(&(event->cond_var), NULL)); +#endif + event->is_set = FALSE; + event->signal_count = 0; +#endif /* __WIN__ */ + + /* Put to the list of events */ + os_mutex_enter(os_sync_mutex); + + UT_LIST_ADD_FIRST(os_event_list, os_event_list, event); + + os_event_count++; + + os_mutex_exit(os_sync_mutex); + + return(event); +} + +#ifdef __WIN__ +/************************************************************* +Creates an auto-reset event semaphore, i.e., an event which is automatically +reset when a single thread is released. Works only in Windows. */ + +os_event_t +os_event_create_auto( +/*=================*/ + /* out: the event handle */ + const char* name) /* in: the name of the event, if NULL + the event is created without a name */ +{ + os_event_t event; + + event = ut_malloc(sizeof(struct os_event_struct)); + + event->handle = CreateEvent(NULL,/* No security attributes */ + FALSE, /* Auto-reset */ + FALSE, /* Initial state nonsignaled */ + name); + + if (!event->handle) { + fprintf(stderr, +"InnoDB: Could not create a Windows auto event semaphore; Windows error %lu\n", + (ulong) GetLastError()); + } + + /* Put to the list of events */ + os_mutex_enter(os_sync_mutex); + + UT_LIST_ADD_FIRST(os_event_list, os_event_list, event); + + os_event_count++; + + os_mutex_exit(os_sync_mutex); + + return(event); +} +#endif + +/************************************************************** +Sets an event semaphore to the signaled state: lets waiting threads +proceed. */ + +void +os_event_set( +/*=========*/ + os_event_t event) /* in: event to set */ +{ +#ifdef __WIN__ + ut_a(event); + ut_a(SetEvent(event->handle)); +#else + ut_a(event); + + os_fast_mutex_lock(&(event->os_mutex)); + + if (event->is_set) { + /* Do nothing */ + } else { + event->is_set = TRUE; + event->signal_count += 1; + ut_a(0 == pthread_cond_broadcast(&(event->cond_var))); + } + + os_fast_mutex_unlock(&(event->os_mutex)); +#endif +} + +/************************************************************** +Resets an event semaphore to the nonsignaled state. Waiting threads will +stop to wait for the event. */ + +void +os_event_reset( +/*===========*/ + os_event_t event) /* in: event to reset */ +{ +#ifdef __WIN__ + ut_a(event); + + ut_a(ResetEvent(event->handle)); +#else + ut_a(event); + + os_fast_mutex_lock(&(event->os_mutex)); + + if (!event->is_set) { + /* Do nothing */ + } else { + event->is_set = FALSE; + } + + os_fast_mutex_unlock(&(event->os_mutex)); +#endif +} + +/************************************************************** +Frees an event object. */ + +void +os_event_free( +/*==========*/ + os_event_t event) /* in: event to free */ + +{ +#ifdef __WIN__ + ut_a(event); + + ut_a(CloseHandle(event->handle)); +#else + ut_a(event); + + os_fast_mutex_free(&(event->os_mutex)); + ut_a(0 == pthread_cond_destroy(&(event->cond_var))); +#endif + /* Remove from the list of events */ + + os_mutex_enter(os_sync_mutex); + + UT_LIST_REMOVE(os_event_list, os_event_list, event); + + os_event_count--; + + os_mutex_exit(os_sync_mutex); + + ut_free(event); +} + +/************************************************************** +Waits for an event object until it is in the signaled state. If +srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS this also exits the +waiting thread when the event becomes signaled (or immediately if the +event is already in the signaled state). */ + +void +os_event_wait( +/*==========*/ + os_event_t event) /* in: event to wait */ +{ +#ifdef __WIN__ + DWORD err; + + ut_a(event); + + /* Specify an infinite time limit for waiting */ + err = WaitForSingleObject(event->handle, INFINITE); + + ut_a(err == WAIT_OBJECT_0); + + if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { + os_thread_exit(NULL); + } +#else + ib_longlong old_signal_count; + + os_fast_mutex_lock(&(event->os_mutex)); + + old_signal_count = event->signal_count; +loop: + if (event->is_set == TRUE + || event->signal_count != old_signal_count) { + + os_fast_mutex_unlock(&(event->os_mutex)); + + if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { + + os_thread_exit(NULL); + } + /* Ok, we may return */ + + return; + } + + pthread_cond_wait(&(event->cond_var), &(event->os_mutex)); + + /* Solaris manual said that spurious wakeups may occur: we have to + check if the event really has been signaled after we came here to + wait */ + + goto loop; +#endif +} + +/************************************************************** +Waits for an event object until it is in the signaled state or +a timeout is exceeded. In Unix the timeout is always infinite. */ + +ulint +os_event_wait_time( +/*===============*/ + /* out: 0 if success, OS_SYNC_TIME_EXCEEDED if + timeout was exceeded */ + os_event_t event, /* in: event to wait */ + ulint time) /* in: timeout in microseconds, or + OS_SYNC_INFINITE_TIME */ +{ +#ifdef __WIN__ + DWORD err; + + ut_a(event); + + if (time != OS_SYNC_INFINITE_TIME) { + err = WaitForSingleObject(event->handle, (DWORD) time / 1000); + } else { + err = WaitForSingleObject(event->handle, INFINITE); + } + + if (err == WAIT_OBJECT_0) { + + return(0); + } else if (err == WAIT_TIMEOUT) { + + return(OS_SYNC_TIME_EXCEEDED); + } else { + ut_error; + return(1000000); /* dummy value to eliminate compiler warn. */ + } +#else + UT_NOT_USED(time); + + /* In Posix this is just an ordinary, infinite wait */ + + os_event_wait(event); + + return(0); +#endif +} + +#ifdef __WIN__ +/************************************************************** +Waits for any event in an OS native event array. Returns if even a single +one is signaled or becomes signaled. */ + +ulint +os_event_wait_multiple( +/*===================*/ + /* out: index of the event + which was signaled */ + ulint n, /* in: number of events in the + array */ + os_native_event_t* native_event_array) + /* in: pointer to an array of event + handles */ +{ + DWORD index; + + ut_a(native_event_array); + ut_a(n > 0); + + index = WaitForMultipleObjects((DWORD) n, native_event_array, + FALSE, /* Wait for any 1 event */ + INFINITE); /* Infinite wait time + limit */ + ut_a(index >= WAIT_OBJECT_0); /* NOTE: Pointless comparision */ + ut_a(index < WAIT_OBJECT_0 + n); + + if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { + os_thread_exit(NULL); + } + + return(index - WAIT_OBJECT_0); +} +#endif + +/************************************************************* +Creates an operating system mutex semaphore. Because these are slow, the +mutex semaphore of InnoDB itself (mutex_t) should be used where possible. */ + +os_mutex_t +os_mutex_create( +/*============*/ + /* out: the mutex handle */ + const char* name) /* in: the name of the mutex, if NULL + the mutex is created without a name */ +{ +#ifdef __WIN__ + HANDLE mutex; + os_mutex_t mutex_str; + + mutex = CreateMutex(NULL, /* No security attributes */ + FALSE, /* Initial state: no owner */ + name); + ut_a(mutex); +#else + os_fast_mutex_t* mutex; + os_mutex_t mutex_str; + + UT_NOT_USED(name); + + mutex = ut_malloc(sizeof(os_fast_mutex_t)); + + os_fast_mutex_init(mutex); +#endif + mutex_str = ut_malloc(sizeof(os_mutex_str_t)); + + mutex_str->handle = mutex; + mutex_str->count = 0; + + if (os_sync_mutex_inited) { + /* When creating os_sync_mutex itself we cannot reserve it */ + os_mutex_enter(os_sync_mutex); + } + + UT_LIST_ADD_FIRST(os_mutex_list, os_mutex_list, mutex_str); + + os_mutex_count++; + + if (os_sync_mutex_inited) { + os_mutex_exit(os_sync_mutex); + } + + return(mutex_str); +} + +/************************************************************** +Acquires ownership of a mutex semaphore. */ + +void +os_mutex_enter( +/*===========*/ + os_mutex_t mutex) /* in: mutex to acquire */ +{ +#ifdef __WIN__ + DWORD err; + + ut_a(mutex); + + /* Specify infinite time limit for waiting */ + err = WaitForSingleObject(mutex->handle, INFINITE); + + ut_a(err == WAIT_OBJECT_0); + + (mutex->count)++; + ut_a(mutex->count == 1); +#else + os_fast_mutex_lock(mutex->handle); + + (mutex->count)++; + + ut_a(mutex->count == 1); +#endif +} + +/************************************************************** +Releases ownership of a mutex. */ + +void +os_mutex_exit( +/*==========*/ + os_mutex_t mutex) /* in: mutex to release */ +{ + ut_a(mutex); + + ut_a(mutex->count == 1); + + (mutex->count)--; +#ifdef __WIN__ + ut_a(ReleaseMutex(mutex->handle)); +#else + os_fast_mutex_unlock(mutex->handle); +#endif +} + +/************************************************************** +Frees a mutex object. */ + +void +os_mutex_free( +/*==========*/ + os_mutex_t mutex) /* in: mutex to free */ +{ + ut_a(mutex); + + if (os_sync_mutex_inited) { + os_mutex_enter(os_sync_mutex); + } + + UT_LIST_REMOVE(os_mutex_list, os_mutex_list, mutex); + + os_mutex_count--; + + if (os_sync_mutex_inited) { + os_mutex_exit(os_sync_mutex); + } + +#ifdef __WIN__ + ut_a(CloseHandle(mutex->handle)); + + ut_free(mutex); +#else + os_fast_mutex_free(mutex->handle); + ut_free(mutex->handle); + ut_free(mutex); +#endif +} + +/************************************************************* +Initializes an operating system fast mutex semaphore. */ + +void +os_fast_mutex_init( +/*===============*/ + os_fast_mutex_t* fast_mutex) /* in: fast mutex */ +{ +#ifdef __WIN__ + ut_a(fast_mutex); + + InitializeCriticalSection((LPCRITICAL_SECTION) fast_mutex); +#else +#if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10) + ut_a(0 == pthread_mutex_init(fast_mutex, pthread_mutexattr_default)); +#else + ut_a(0 == pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST)); +#endif +#endif + if (os_sync_mutex_inited) { + /* When creating os_sync_mutex itself (in Unix) we cannot + reserve it */ + + os_mutex_enter(os_sync_mutex); + } + + os_fast_mutex_count++; + + if (os_sync_mutex_inited) { + os_mutex_exit(os_sync_mutex); + } +} + +/************************************************************** +Acquires ownership of a fast mutex. */ + +void +os_fast_mutex_lock( +/*===============*/ + os_fast_mutex_t* fast_mutex) /* in: mutex to acquire */ +{ +#ifdef __WIN__ + EnterCriticalSection((LPCRITICAL_SECTION) fast_mutex); +#else + pthread_mutex_lock(fast_mutex); +#endif +} + +/************************************************************** +Releases ownership of a fast mutex. */ + +void +os_fast_mutex_unlock( +/*=================*/ + os_fast_mutex_t* fast_mutex) /* in: mutex to release */ +{ +#ifdef __WIN__ + LeaveCriticalSection(fast_mutex); +#else + pthread_mutex_unlock(fast_mutex); +#endif +} + +/************************************************************** +Frees a mutex object. */ + +void +os_fast_mutex_free( +/*===============*/ + os_fast_mutex_t* fast_mutex) /* in: mutex to free */ +{ +#ifdef __WIN__ + ut_a(fast_mutex); + + DeleteCriticalSection((LPCRITICAL_SECTION) fast_mutex); +#else + ut_a(0 == pthread_mutex_destroy(fast_mutex)); +#endif + if (os_sync_mutex_inited) { + /* When freeing the last mutexes, we have + already freed os_sync_mutex */ + + os_mutex_enter(os_sync_mutex); + } + + os_fast_mutex_count--; + + if (os_sync_mutex_inited) { + os_mutex_exit(os_sync_mutex); + } +} |