diff options
Diffstat (limited to 'storage/innobase/os/os0thread.cc')
-rw-r--r-- | storage/innobase/os/os0thread.cc | 245 |
1 files changed, 150 insertions, 95 deletions
diff --git a/storage/innobase/os/os0thread.cc b/storage/innobase/os/os0thread.cc index a5b0f7de6ae..da2a2f59616 100644 --- a/storage/innobase/os/os0thread.cc +++ b/storage/innobase/os/os0thread.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -23,30 +23,49 @@ The interface to the operating system thread control primitives Created 9/8/1995 Heikki Tuuri *******************************************************/ +#include "ha_prototypes.h" + #include "os0thread.h" +#include "ut0new.h" + #ifdef UNIV_NONINL #include "os0thread.ic" #endif -#ifdef __WIN__ -#include <windows.h> -#endif - #ifndef UNIV_HOTBACKUP #include "srv0srv.h" -#include "os0sync.h" +#include "os0event.h" + +#include <map> + +/** Mutex that tracks the thread count. Used by innorwlocktest.cc +FIXME: the unit tests should use APIs */ +SysMutex thread_mutex; + +/** Number of threads active. */ +ulint os_thread_count; + +#ifdef _WIN32 +typedef std::map< + DWORD, + HANDLE, + std::less<DWORD>, + ut_allocator<std::pair<const DWORD, HANDLE> > > WinThreadMap; +/** This STL map remembers the initial handle returned by CreateThread +so that it can be closed when the thread exits. */ +static WinThreadMap win_thread_map; +#endif /* _WIN32 */ /***************************************************************//** Compares two thread ids for equality. -@return TRUE if equal */ -UNIV_INTERN +@return TRUE if equal */ ibool os_thread_eq( /*=========*/ os_thread_id_t a, /*!< in: OS thread or thread id */ os_thread_id_t b) /*!< in: OS thread or thread id */ { -#ifdef __WIN__ +#ifdef _WIN32 if (a == b) { return(TRUE); } @@ -64,34 +83,25 @@ os_thread_eq( /****************************************************************//** Converts an OS thread id to a ulint. It is NOT guaranteed that the ulint is unique for the thread though! -@return thread identifier as a number */ -UNIV_INTERN +@return thread identifier as a number */ ulint os_thread_pf( /*=========*/ os_thread_id_t a) /*!< in: OS thread identifier */ { -#ifdef UNIV_HPUX10 - /* In HP-UX-10.20 a pthread_t is a struct of 3 fields: field1, field2, - field3. We do not know if field1 determines the thread uniquely. */ - - return((ulint)(a.field1)); -#else return((ulint) a); -#endif } /*****************************************************************//** Returns the thread identifier of current thread. Currently the thread identifier in Unix is the thread handle itself. Note that in HP-UX pthread_t is a struct of 3 fields. -@return current thread identifier */ -UNIV_INTERN +@return current thread identifier */ os_thread_id_t os_thread_get_curr_id(void) /*=======================*/ { -#ifdef __WIN__ +#ifdef _WIN32 return(GetCurrentThreadId()); #else return(pthread_self()); @@ -100,10 +110,11 @@ os_thread_get_curr_id(void) /****************************************************************//** 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 +the function given. +NOTE: We count the number of threads in os_thread_exit(). A created +thread should always use that to exit so thatthe thread count will be +decremented. +We do not return an error code because if there is one, we crash here. */ os_thread_t os_thread_create_func( /*==================*/ @@ -114,86 +125,74 @@ os_thread_create_func( os_thread_id_t* thread_id) /*!< out: id of the created thread, or NULL */ { + os_thread_id_t new_thread_id; + /* the new thread should look recent changes up here so far. */ os_wmb; -#ifdef __WIN__ - os_thread_t thread; - DWORD win_thread_id; +#ifdef _WIN32 + HANDLE handle; - os_mutex_enter(os_sync_mutex); - os_thread_count++; - os_mutex_exit(os_sync_mutex); - - thread = CreateThread(NULL, /* no security attributes */ + handle = CreateThread(NULL, /* no security attributes */ 0, /* default size stack */ func, arg, 0, /* thread runs immediately */ - &win_thread_id); + &new_thread_id); - if (thread_id) { - *thread_id = win_thread_id; + if (!handle) { + /* If we cannot start a new thread, life has no meaning. */ + ib::fatal() << "CreateThread returned " << GetLastError(); } - return((os_thread_t)thread); -#else - int ret; - os_thread_t pthread; + mutex_enter(&thread_mutex); + + std::pair<WinThreadMap::iterator, bool> ret; + + ret = win_thread_map.insert( + std::pair<DWORD, HANDLE>(new_thread_id, handle)); + + ut_ad((*ret.first).first == new_thread_id); + ut_ad((*ret.first).second == handle); + ut_a(ret.second == true); /* true means thread_id was new */ + + os_thread_count++; + + mutex_exit(&thread_mutex); + + return((os_thread_t)handle); +#else /* _WIN32 else */ + 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); + mutex_enter(&thread_mutex); + ++os_thread_count; + mutex_exit(&thread_mutex); -#ifdef UNIV_HPUX10 - ret = pthread_create(&pthread, pthread_attr_default, func, arg); -#else - ret = pthread_create(&pthread, &attr, func, arg); -#endif - if (ret) { - fprintf(stderr, - "InnoDB: Error: pthread_create returned %d\n", ret); - exit(1); + int ret = pthread_create(&new_thread_id, &attr, func, arg); + + if (ret != 0) { + ib::fatal() << "pthread_create returned " << ret; } -#ifndef UNIV_HPUX10 pthread_attr_destroy(&attr); -#endif + +#endif /* not _WIN32 */ ut_a(os_thread_count <= OS_THREAD_MAX_N); - if (thread_id) { - *thread_id = pthread; + /* Return the thread_id if the caller requests it. */ + if (thread_id != NULL) { + *thread_id = new_thread_id; } - return(pthread); -#endif + return((os_thread_t)new_thread_id); } /*****************************************************************//** Exits the current thread. */ -UNIV_INTERN void os_thread_exit( /*===========*/ @@ -201,21 +200,30 @@ os_thread_exit( 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())); + ib::info() << "Thread exits, id " + << os_thread_pf(os_thread_get_curr_id()); #endif #ifdef UNIV_PFS_THREAD pfs_delete_thread(); #endif - os_mutex_enter(os_sync_mutex); + mutex_enter(&thread_mutex); + os_thread_count--; - os_mutex_exit(os_sync_mutex); -#ifdef __WIN__ +#ifdef _WIN32 + DWORD win_thread_id = GetCurrentThreadId(); + HANDLE handle = win_thread_map[win_thread_id]; + CloseHandle(handle); + size_t ret = win_thread_map.erase(win_thread_id); + ut_a(ret == 1); + + mutex_exit(&thread_mutex); + ExitThread((DWORD) exit_value); #else + mutex_exit(&thread_mutex); pthread_detach(pthread_self()); pthread_exit(exit_value); #endif @@ -223,41 +231,88 @@ os_thread_exit( /*****************************************************************//** Advises the os to give up remainder of the thread's time slice. */ -UNIV_INTERN void os_thread_yield(void) /*=================*/ { -#if defined(__WIN__) +#if defined(_WIN32) SwitchToThread(); -#elif (defined(HAVE_SCHED_YIELD) && defined(HAVE_SCHED_H)) - sched_yield(); -#elif defined(HAVE_PTHREAD_YIELD_ZERO_ARG) - pthread_yield(); -#elif defined(HAVE_PTHREAD_YIELD_ONE_ARG) - pthread_yield(0); #else - os_thread_sleep(0); + sched_yield(); #endif } #endif /* !UNIV_HOTBACKUP */ /*****************************************************************//** The thread sleeps at least the time given in microseconds. */ -UNIV_INTERN void os_thread_sleep( /*============*/ ulint tm) /*!< in: time in microseconds */ { -#ifdef __WIN__ +#ifdef _WIN32 Sleep((DWORD) tm / 1000); +#elif defined(HAVE_NANOSLEEP) + struct timespec t; + + t.tv_sec = tm / 1000000; + t.tv_nsec = (tm % 1000000) * 1000; + + ::nanosleep(&t, NULL); #else - struct timeval t; + struct timeval t; t.tv_sec = tm / 1000000; t.tv_usec = tm % 1000000; select(0, NULL, NULL, NULL, &t); -#endif +#endif /* _WIN32 */ } + +/*****************************************************************//** +Check if there are threads active. +@return true if the thread count > 0. */ +bool +os_thread_active() +/*==============*/ +{ + mutex_enter(&thread_mutex); + + bool active = (os_thread_count > 0); + + /* All the threads have exited or are just exiting; + NOTE that the threads may not have completed their + exit yet. Should we use pthread_join() to make sure + they have exited? If we did, we would have to + remove the pthread_detach() from + os_thread_exit(). Now we just sleep 0.1 + seconds and hope that is enough! */ + + mutex_exit(&thread_mutex); + + return(active); +} + +/** +Initializes OS thread management data structures. */ +void +os_thread_init() +/*============*/ +{ + mutex_create(LATCH_ID_THREAD_MUTEX, &thread_mutex); +} + +/** +Frees OS thread management data structures. */ +void +os_thread_free() +/*============*/ +{ + if (os_thread_count != 0) { + ib::warn() << "Some (" << os_thread_count << ") threads are" + " still active"; + } + + mutex_destroy(&thread_mutex); +} + |