/*****************************************************************//** Exits the current thread. */ UNIV_INTERN void os_thread_exit( /*===========*/ void* exit_value) /*!< in: exit value; in Windows this void* is cast as a DWORD */ { #ifdef UNIV_DEBUG_THREAD_CREATION fprintf(stderr, "Thread exits, id %lu\n", os_thread_pf(os_thread_get_curr_id())); #endif #ifdef UNIV_PFS_THREAD pfs_delete_thread(); #endif os_mutex_enter(os_sync_mutex); os_thread_count--; os_mutex_exit(os_sync_mutex); #ifdef __WIN__ ExitThread((DWORD)exit_value); #else pthread_detach(pthread_self()); pthread_exit(exit_value); #endif }
/**********************************************************//** Frees a mutex object. */ UNIV_INTERN void os_mutex_free( /*==========*/ os_mutex_t mutex) /*!< in: mutex to free */ { ut_a(mutex); if (UNIV_LIKELY(!os_sync_free_called)) { os_event_free_internal(mutex->event); } if (UNIV_LIKELY(os_sync_mutex_inited)) { os_mutex_enter(os_sync_mutex); } UT_LIST_REMOVE(os_mutex_list, os_mutex_list, mutex); os_mutex_count--; if (UNIV_LIKELY(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. */ UNIV_INTERN 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 ut_a(0 == pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST)); #endif if (UNIV_LIKELY(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 (UNIV_LIKELY(os_sync_mutex_inited)) { os_mutex_exit(os_sync_mutex); } }
/**********************************************************//** Frees an event object. */ UNIV_INTERN 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); }
/*****************************************************************//** Exits the current thread. */ UNIV_INTERN void os_thread_exit( /*===========*/ void* exit_value) /*!< in: exit value; in Windows this void* is cast as a DWORD */ { #ifndef __WIN__ int ret; #endif /* __WIN__ */ #ifdef UNIV_DEBUG_THREAD_CREATION ib_logger(ib_stream, "Thread exits, id %lu\n", os_thread_pf(os_thread_get_curr_id())); #endif /* UNIV_DEBUG_THREAD_CREATION */ os_mutex_enter(os_sync_mutex); os_thread_count--; os_mutex_exit(os_sync_mutex); #ifdef __WIN__ ExitThread((DWORD)exit_value); #else ret = pthread_detach(pthread_self()); ut_a(ret == 0); pthread_exit(exit_value); #endif /* __WIN__ */ }
/*********************************************************//** Creates an operating system mutex semaphore. Because these are slow, the mutex semaphore of InnoDB itself (mutex_t) should be used where possible. @return the mutex handle */ UNIV_INTERN os_mutex_t os_mutex_create( /*============*/ 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; mutex_str->event = os_event_create(NULL); if (UNIV_LIKELY(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 (UNIV_LIKELY(os_sync_mutex_inited)) { os_mutex_exit(os_sync_mutex); } return(mutex_str); }
/******************************************************************//** Releases the mutex semaphore protecting a sync array. */ static void sync_array_exit( /*============*/ sync_array_t* arr) /*!< in: sync wait array */ { ulint protection; protection = arr->protection; if (protection == SYNC_ARRAY_OS_MUTEX) { os_mutex_exit(arr->os_mutex); } else if (protection == SYNC_ARRAY_MUTEX) { mutex_exit(&(arr->mutex)); } else { ut_error; } }
/**********************************************************//** Frees a mutex object. */ UNIV_INTERN 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 int ret; ret = pthread_mutex_destroy(fast_mutex); if (UNIV_UNLIKELY(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", (void*) fast_mutex); ut_print_buf(stderr, fast_mutex, sizeof(os_fast_mutex_t)); putc('\n', stderr); } #endif if (UNIV_LIKELY(os_sync_mutex_inited)) { /* When freeing the last mutexes, we have already freed os_sync_mutex */ os_mutex_enter(os_sync_mutex); } ut_ad(os_fast_mutex_count > 0); os_fast_mutex_count--; if (UNIV_LIKELY(os_sync_mutex_inited)) { os_mutex_exit(os_sync_mutex); } }
/****************************************************************//** Creates a new thread of execution. The execution starts from the function given. The start function takes a void* parameter and returns an ulint. @return handle to the thread */ UNIV_INTERN os_thread_t os_thread_create( /*=============*/ #ifndef __WIN__ os_posix_f_t start_f, #else ulint (*start_f)(void*), /*!< in: pointer to function from which to start */ #endif void* arg, /*!< in: argument to start function */ os_thread_id_t* thread_id) /*!< out: id of the created thread, or NULL */ { #ifdef __WIN__ os_thread_t thread; DWORD win_thread_id; os_mutex_enter(os_sync_mutex); os_thread_count++; os_mutex_exit(os_sync_mutex); thread = CreateThread(NULL, /* no security attributes */ 0, /* default size stack */ (LPTHREAD_START_ROUTINE)start_f, arg, 0, /* thread runs immediately */ &win_thread_id); if (thread_id) { *thread_id = win_thread_id; } return(thread); #else int ret; os_thread_t pthread; pthread_attr_t attr; #ifndef UNIV_HPUX10 pthread_attr_init(&attr); #endif #ifdef UNIV_AIX /* We must make sure a thread stack is at least 32 kB, otherwise InnoDB might crash; we do not know if the default stack size on AIX is always big enough. An empirical test on AIX-4.3 suggested the size was 96 kB, though. */ ret = pthread_attr_setstacksize(&attr, (size_t)(PTHREAD_STACK_MIN + 32 * 1024)); if (ret) { fprintf(stderr, "InnoDB: Error: pthread_attr_setstacksize" " returned %d\n", ret); exit(1); } #endif os_mutex_enter(os_sync_mutex); os_thread_count++; os_mutex_exit(os_sync_mutex); #ifdef UNIV_HPUX10 ret = pthread_create(&pthread, pthread_attr_default, start_f, arg); #else ret = pthread_create(&pthread, &attr, start_f, arg); #endif if (ret) { fprintf(stderr, "InnoDB: Error: pthread_create returned %d\n", ret); exit(1); } #ifndef UNIV_HPUX10 pthread_attr_destroy(&attr); #endif if (thread_id) { *thread_id = pthread; } return(pthread); #endif }
/*********************************************************//** 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. @return the event handle */ UNIV_INTERN os_event_t os_event_create( /*============*/ 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)); ut_a(0 == pthread_cond_init(&(event->cond_var), NULL)); event->is_set = FALSE; /* We return this value in os_event_reset(), which can then be be used to pass to the os_event_wait_low(). The value of zero is reserved in os_event_wait_low() for the case when the caller does not want to pass any signal_count value. To distinguish between the two cases we initialize signal_count to 1 here. */ event->signal_count = 1; #endif /* __WIN__ */ /* The os_sync_mutex can be NULL because during startup an event can be created [ because it's embedded in the mutex/rwlock ] before this module has been initialized */ if (os_sync_mutex != NULL) { os_mutex_enter(os_sync_mutex); } /* Put to the list of events */ UT_LIST_ADD_FIRST(os_event_list, os_event_list, event); os_event_count++; if (os_sync_mutex != NULL) { os_mutex_exit(os_sync_mutex); } return(event); }
/****************************************************************//** Creates a new thread of execution. The execution starts from the function given. The start function takes a void* parameter and returns an ulint. @return handle to the thread */ UNIV_INTERN os_thread_t os_thread_create( /*=============*/ #ifndef __WIN__ os_posix_f_t start_f, #else ulint (*start_f)(void*), /*!< in: pointer to function from which to start */ #endif void* arg, /*!< in: argument to start function */ os_thread_id_t* thread_id) /*!< out: id of the created thread, or NULL */ { #ifdef __WIN__ os_thread_t thread; DWORD win_thread_id; os_mutex_enter(os_sync_mutex); os_thread_count++; os_mutex_exit(os_sync_mutex); thread = CreateThread(NULL, /* no security attributes */ 0, /* default size stack */ (LPTHREAD_START_ROUTINE)start_f, arg, 0, /* thread runs immediately */ &win_thread_id); if (srv_set_thread_priorities) { /* Set created thread priority the same as a normal query, we try to prevent starvation of threads by assigning same priority QUERY_PRIOR to all */ ut_a(SetThreadPriority(thread, srv_query_thread_priority)); } if (thread_id) { *thread_id = win_thread_id; } return(thread); #else int ret; os_thread_t pthread; pthread_attr_t attr; #ifndef UNIV_HPUX10 pthread_attr_init(&attr); #endif #ifdef UNIV_AIX /* We must make sure a thread stack is at least 32 kB, otherwise InnoDB might crash; we do not know if the default stack size on AIX is always big enough. An empirical test on AIX-4.3 suggested the size was 96 kB, though. */ ret = pthread_attr_setstacksize(&attr, (size_t)(PTHREAD_STACK_MIN + 32 * 1024)); if (ret) { srv_panic(ret, "InnoDB: Error: pthread_attr_setstacksize" " returned %d\n", ret); } #endif #ifdef __NETWARE__ ret = pthread_attr_setstacksize(&attr, (size_t) NW_THD_STACKSIZE); if (ret) { srv_panic(ret, "InnoDB: Error: pthread_attr_setstacksize" " returned %d\n", ret); } #endif os_mutex_enter(os_sync_mutex); os_thread_count++; os_mutex_exit(os_sync_mutex); #ifdef UNIV_HPUX10 ret = pthread_create(&pthread, pthread_attr_default, start_f, arg); #else ret = pthread_create(&pthread, &attr, start_f, arg); #endif if (ret) { srv_panic(ret, "InnoDB: Error: pthread_create returned %d\n", ret); } #ifndef UNIV_HPUX10 pthread_attr_destroy(&attr); #endif if (srv_set_thread_priorities) { #ifdef HAVE_PTHREAD_SETPRIO pthread_setprio(pthread, srv_query_thread_priority); #endif } if (thread_id) { *thread_id = pthread; } return(pthread); #endif }