summaryrefslogtreecommitdiff
path: root/storage/innobase/os/os0thread.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/os/os0thread.cc')
-rw-r--r--storage/innobase/os/os0thread.cc245
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);
+}
+