/****************************************************** 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" /* 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 */ }; /************************************************************* 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 */ char* name) /* in: the name of the event, if NULL the event is created without a name */ { #ifdef __WIN__ HANDLE event; event = CreateEvent(NULL, /* No security attributes */ TRUE, /* Manual reset */ FALSE, /* Initial state nonsignaled */ name); ut_a(event); return(event); #else os_event_t event; UT_NOT_USED(name); event = ut_malloc(sizeof(struct os_event_struct)); os_fast_mutex_init(&(event->os_mutex)); pthread_cond_init(&(event->cond_var), NULL); event->is_set = FALSE; return(event); #endif } /************************************************************* Creates an auto-reset event semaphore, i.e., an event which is automatically reset when a single thread is released. */ os_event_t os_event_create_auto( /*=================*/ /* out: the event handle */ char* name) /* in: the name of the event, if NULL the event is created without a name */ { #ifdef __WIN__ HANDLE event; event = CreateEvent(NULL, /* No security attributes */ FALSE, /* Auto-reset */ FALSE, /* Initial state nonsignaled */ name); ut_a(event); return(event); #else /* Does nothing in Posix because we do not need this with MySQL */ UT_NOT_USED(name); return(NULL); #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)); #else ut_a(event); os_fast_mutex_lock(&(event->os_mutex)); if (event->is_set) { /* Do nothing */ } else { event->is_set = TRUE; 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)); #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)); #else ut_a(event); os_fast_mutex_free(&(event->os_mutex)); pthread_cond_destroy(&(event->cond_var)); ut_free(event); #endif } /************************************************************** Waits for an event object until it is 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, INFINITE); ut_a(err == WAIT_OBJECT_0); #else os_fast_mutex_lock(&(event->os_mutex)); loop: if (event->is_set == TRUE) { os_fast_mutex_unlock(&(event->os_mutex)); /* 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 the 'is_set' variable again */ goto loop; #endif } /************************************************************** Waits for an event object until it is in the signaled state or a timeout is exceeded. */ 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, time / 1000); } else { err = WaitForSingleObject(event, INFINITE); } if (err == WAIT_OBJECT_0) { return(0); } else if (err == WAIT_TIMEOUT) { return(OS_SYNC_TIME_EXCEEDED); } else { ut_error; } #else UT_NOT_USED(time); /* In Posix this is just an ordinary, infinite wait */ os_event_wait(event); return(0); #endif } /************************************************************** Waits for any event in an 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_event_t* event_array) /* in: pointer to an array of event handles */ { #ifdef __WIN__ DWORD index; ut_a(event_array); ut_a(n > 0); index = WaitForMultipleObjects(n, event_array, FALSE, /* Wait for any 1 event */ INFINITE); /* Infinite wait time limit */ ut_a(index >= WAIT_OBJECT_0); ut_a(index < WAIT_OBJECT_0 + n); return(index - WAIT_OBJECT_0); #else ut_a(n == 0); /* In Posix we can only wait for a single event */ os_event_wait(*event_array); return(0); #endif } /************************************************************* Creates an operating system mutex semaphore. Because these are slow, the mutex semaphore of the database itself (sync_mutex_t) should be used where possible. */ os_mutex_t os_mutex_create( /*============*/ /* out: the mutex handle */ 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); mutex_str = ut_malloc(sizeof(os_mutex_str_t)); mutex_str->handle = mutex; mutex_str->count = 0; return(mutex_str); #else os_fast_mutex_t* os_mutex; os_mutex_t mutex_str; UT_NOT_USED(name); os_mutex = ut_malloc(sizeof(os_fast_mutex_t)); os_fast_mutex_init(os_mutex); mutex_str = ut_malloc(sizeof(os_mutex_str_t)); mutex_str->handle = os_mutex; mutex_str->count = 0; return(mutex_str); #endif } /************************************************************** 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 */ { #ifdef __WIN__ ut_a(mutex); ut_a(mutex->count == 1); (mutex->count)--; ut_a(ReleaseMutex(mutex->handle)); #else ut_a(mutex); ut_a(mutex->count == 1); (mutex->count)--; os_fast_mutex_unlock(mutex->handle); #endif } /************************************************************** Frees a mutex object. */ void os_mutex_free( /*==========*/ os_mutex_t mutex) /* in: mutex to free */ { #ifdef __WIN__ ut_a(mutex); ut_a(CloseHandle(mutex->handle)); ut_free(mutex); #else os_fast_mutex_free(mutex->handle); ut_free(mutex->handle); ut_free(mutex); #endif } #ifndef _WIN32 /************************************************************* 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 pthread_mutex_init(fast_mutex, NULL); #endif } /************************************************************** 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 } /************************************************************** 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_NOT_USED(fast_mutex); #endif } #endif