📄 os0sync.c
字号:
/******************************************************The interface to the operating systemsynchronization primitives.(c) 1995 Innobase OyCreated 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 inos_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. */voidos_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. */voidos_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 twostates: signaled and nonsignaled. The created event is manual reset: itmust be reset explicitly by calling sync_os_reset_event. */os_event_tos_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 */ (LPCTSTR) 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 automaticallyreset when a single thread is released. Works only in Windows. */os_event_tos_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 */ (LPCTSTR) 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 threadsproceed. */voidos_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 willstop to wait for the event. */voidos_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. */voidos_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. Ifsrv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS this also exits thewaiting thread when the event becomes signaled (or immediately if theevent is already in the signaled state). */voidos_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; for (;;) { 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 */ }#endif}/**************************************************************Waits for an event object until it is in the signaled state ora timeout is exceeded. In Unix the timeout is always infinite. */ulintos_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 singleone is signaled or becomes signaled. */ulintos_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, themutex semaphore of InnoDB itself (mutex_t) should be used where possible. */os_mutex_tos_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 */ (LPCTSTR) 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. */voidos_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. */voidos_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. */voidos_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. */voidos_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. */voidos_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. */voidos_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. */voidos_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 int ret; ret = pthread_mutex_destroy(fast_mutex); if (ret != 0) { ut_print_timestamp(stderr); fprintf(stderr," InnoDB: error: return value %lu when calling\n""InnoDB: pthread_mutex_destroy().\n", (ulint)ret); fprintf(stderr,"InnoDB: Byte contents of the pthread mutex at %p:\n", fast_mutex); ut_print_buf(stderr, (const byte*)fast_mutex, sizeof(os_fast_mutex_t)); fprintf(stderr, "\n"); }#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); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -