summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDana Robinson <derobins@hdfgroup.org>2014-04-11 19:04:54 (GMT)
committerDana Robinson <derobins@hdfgroup.org>2014-04-11 19:04:54 (GMT)
commitf466a5d298885c4d3dd813c0e6c8db9319cade50 (patch)
tree770e2cec48a2a6497ad1e0ce6175b5ec6d4424e4 /src
parent17a1f1a5976b98db1788200f0b015694f85cb008 (diff)
downloadhdf5-f466a5d298885c4d3dd813c0e6c8db9319cade50.zip
hdf5-f466a5d298885c4d3dd813c0e6c8db9319cade50.tar.gz
hdf5-f466a5d298885c4d3dd813c0e6c8db9319cade50.tar.bz2
[svn-r25018] Purpose:
Merged r24893, r24961, r24965 from trunk. Fix for thread-local storage resource leaks on Windows with Win32 threads. Prohibits thread-safe + C++/Fortran/static library in CMake. Tested on: 64-bit Windows 7 w/ Visual Studio 2012
Diffstat (limited to 'src')
-rw-r--r--src/H5.c73
-rw-r--r--src/H5CS.c10
-rw-r--r--src/H5E.c121
-rw-r--r--src/H5TS.c225
-rw-r--r--src/H5TSprivate.h13
-rw-r--r--src/H5private.h2
6 files changed, 330 insertions, 114 deletions
diff --git a/src/H5.c b/src/H5.c
index 6354ad0..1515f96 100644
--- a/src/H5.c
+++ b/src/H5.c
@@ -147,13 +147,23 @@ H5_init_library(void)
#endif
/*
- * Install atexit() library cleanup routine unless the H5dont_atexit()
+ * Install atexit() library cleanup routines unless the H5dont_atexit()
* has been called. Once we add something to the atexit() list it stays
* there permanently, so we set H5_dont_atexit_g after we add it to prevent
* adding it again later if the library is cosed and reopened.
*/
if (!H5_dont_atexit_g) {
- (void)HDatexit(H5_term_library);
+
+#if defined(H5_HAVE_THREADSAFE) && defined(H5_HAVE_WIN_THREADS)
+ /* Clean up Win32 thread resources. Pthreads automatically cleans up.
+ * This must be entered before the library cleanup code so it's
+ * executed in LIFO order (i.e., last).
+ */
+ (void)HDatexit(H5TS_win32_process_exit);
+#endif /* H5_HAVE_THREADSAFE && H5_HAVE_WIN_THREADS */
+
+ /* Normal library termination code */
+ (void)HDatexit(H5_term_library);
H5_dont_atexit_g = TRUE;
} /* end if */
@@ -328,7 +338,7 @@ H5_term_library(void)
done:
#ifdef H5_HAVE_THREADSAFE
H5_API_UNLOCK
-#endif
+#endif /* H5_HAVE_THREADSAFE */
return;
} /* end H5_term_library() */
@@ -829,3 +839,60 @@ H5free_memory(void *mem)
FUNC_LEAVE_API(SUCCEED)
} /* end H5free_memory() */
+
+#ifdef H5_HAVE_WIN32_API
+/*-------------------------------------------------------------------------
+ * Function: DllMain
+ *
+ * Purpose: Handles various conditions in the library on Windows.
+ *
+ * NOTE: The main purpose of this is for handling Win32 thread cleanup
+ * on thread/process detach.
+ *
+ * Return: TRUE on success, FALSE on failure
+ *
+ *-------------------------------------------------------------------------
+ */
+BOOL WINAPI
+DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved)
+{
+ /* Don't add our function enter/leave macros since this function will be
+ * called before the library is initialized.
+ *
+ * NOTE: Do NOT call any CRT functions in DllMain!
+ * This includes any functions that are called by from here!
+ */
+
+ BOOL fOkay = TRUE;
+
+ switch(fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ break;
+
+ case DLL_PROCESS_DETACH:
+ break;
+
+ case DLL_THREAD_ATTACH:
+#ifdef H5_HAVE_WIN_THREADS
+ if(H5TS_win32_thread_enter() < 0)
+ fOkay = FALSE;
+#endif /* H5_HAVE_WIN_THREADS */
+ break;
+
+ case DLL_THREAD_DETACH:
+#ifdef H5_HAVE_WIN_THREADS
+ if(H5TS_win32_thread_exit() < 0)
+ fOkay = FALSE;
+#endif /* H5_HAVE_WIN_THREADS */
+ break;
+
+ default:
+ /* Shouldn't get here */
+ fOkay = FALSE;
+ break;
+ }
+
+ return fOkay;
+}
+#endif /* H5_HAVE_WIN32_API */
diff --git a/src/H5CS.c b/src/H5CS.c
index 4ccd0f8..29182ce 100644
--- a/src/H5CS.c
+++ b/src/H5CS.c
@@ -83,12 +83,16 @@ H5CS_get_stack(void)
fstack = H5TS_get_thread_local_value(H5TS_funcstk_key_g);
if (!fstack) {
- /* no associated value with current thread - create one */
- fstack = (H5CS_t *)HDmalloc(sizeof(H5CS_t)); /* Don't use H5MM_malloc() here, it causes infinite recursion */
+ /* No associated value with current thread - create one */
+#ifdef H5_HAVE_WIN_THREADS
+ fstack = (H5CS_t *)LocalAlloc(LPTR, sizeof(H5CS_t)); /* Win32 has to use LocalAlloc to match the LocalFree in DllMain */
+#else
+ fstack = (H5CS_t *)HDmalloc(sizeof(H5CS_t)); /* Don't use H5MM_malloc() here, it causes infinite recursion */
+#endif /* H5_HAVE_WIN_THREADS */
HDassert(fstack);
/* Set the thread-specific info */
- fstack->nused=0;
+ fstack->nused=0;
/* (It's not necessary to release this in this API, it is
* released by the "key destructor" set up in the H5TS
diff --git a/src/H5E.c b/src/H5E.c
index 5974205..671d3de 100644
--- a/src/H5E.c
+++ b/src/H5E.c
@@ -122,7 +122,7 @@ H5FL_DEFINE_STATIC(H5E_msg_t);
/* Error class ID class */
static const H5I_class_t H5I_ERRCLS_CLS[1] = {{
H5I_ERROR_CLASS, /* ID class value */
- H5I_CLASS_REUSE_IDS, /* Class flags */
+ 0, /* Class flags */
0, /* # of reserved IDs for class */
(H5I_free_t)H5E_unregister_class /* Callback routine for closing objects of this class */
}};
@@ -130,7 +130,7 @@ static const H5I_class_t H5I_ERRCLS_CLS[1] = {{
/* Error message ID class */
static const H5I_class_t H5I_ERRMSG_CLS[1] = {{
H5I_ERROR_MSG, /* ID class value */
- H5I_CLASS_REUSE_IDS, /* Class flags */
+ 0, /* Class flags */
0, /* # of reserved IDs for class */
(H5I_free_t)H5E_close_msg /* Callback routine for closing objects of this class */
}};
@@ -138,13 +138,14 @@ static const H5I_class_t H5I_ERRMSG_CLS[1] = {{
/* Error stack ID class */
static const H5I_class_t H5I_ERRSTK_CLS[1] = {{
H5I_ERROR_STACK, /* ID class value */
- H5I_CLASS_REUSE_IDS, /* Class flags */
+ 0, /* Class flags */
0, /* # of reserved IDs for class */
(H5I_free_t)H5E_close_stack /* Callback routine for closing objects of this class */
}};
-
+
+
/*-------------------------------------------------------------------------
* Function: H5E_init
*
@@ -171,7 +172,8 @@ done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5E_init() */
-
+
+
/*--------------------------------------------------------------------------
* Function: H5E_set_default_auto
*
@@ -209,7 +211,8 @@ H5E_set_default_auto(H5E_t *stk)
FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5E_set_default_auto() */
-
+
+
/*--------------------------------------------------------------------------
* Function: H5E_init_interface
*
@@ -264,7 +267,8 @@ done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5E_init_interface() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5E_term_interface
*
@@ -336,7 +340,8 @@ H5E_term_interface(void)
FUNC_LEAVE_NOAPI(n)
} /* end H5E_term_interface() */
-
+
+
#ifdef H5_HAVE_THREADSAFE
/*-------------------------------------------------------------------------
* Function: H5E_get_stack
@@ -363,8 +368,12 @@ H5E_get_stack(void)
estack = (H5E_t *)H5TS_get_thread_local_value(H5TS_errstk_key_g);
if(!estack) {
- /* no associated value with current thread - create one */
- estack = (H5E_t *)H5MM_calloc(sizeof(H5E_t));
+ /* No associated value with current thread - create one */
+#ifdef H5_HAVE_WIN_THREADS
+ estack = (H5E_t *)LocalAlloc(LPTR, sizeof(H5E_t)); /* Win32 has to use LocalAlloc to match the LocalFree in DllMain */
+#else
+ estack = (H5E_t *)H5FL_MALLOC(H5E_t);
+#endif /* H5_HAVE_WIN_THREADS */
HDassert(estack);
/* Set the thread-specific info */
@@ -383,7 +392,8 @@ H5E_get_stack(void)
} /* end H5E_get_stack() */
#endif /* H5_HAVE_THREADSAFE */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5E_free_class
*
@@ -413,7 +423,8 @@ H5E_free_class(H5E_cls_t *cls)
FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5E_free_class() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5Eregister_class
*
@@ -451,7 +462,8 @@ done:
FUNC_LEAVE_API(ret_value)
} /* end H5Eregister_class() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5E_register_class
*
@@ -500,7 +512,8 @@ done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5E_register_class() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5Eunregister_class
*
@@ -536,7 +549,8 @@ done:
FUNC_LEAVE_API(ret_value)
} /* end H5Eunregister_class() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5E_unregister_class
*
@@ -571,7 +585,8 @@ done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5E_unregister_class() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5Eget_class_name
*
@@ -606,7 +621,8 @@ done:
FUNC_LEAVE_API(ret_value)
} /* end H5Eget_class_name() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5E_get_class_name
*
@@ -644,7 +660,8 @@ H5E_get_class_name(const H5E_cls_t *cls, char *name, size_t size)
FUNC_LEAVE_NOAPI(len)
} /* end H5E_get_class_name() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5E_close_msg_cb
*
@@ -682,7 +699,8 @@ done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5E_close_msg_cb() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5Eclose_msg
*
@@ -715,7 +733,8 @@ done:
FUNC_LEAVE_API(ret_value)
} /* end H5Eclose_msg() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5E_close_msg
*
@@ -744,7 +763,8 @@ H5E_close_msg(H5E_msg_t *err)
FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5E_close_msg() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5Ecreate_msg
*
@@ -835,7 +855,8 @@ done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5E_create_msg() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5Eget_msg
*
@@ -870,7 +891,8 @@ done:
FUNC_LEAVE_API(ret_value)
} /* end H5Eget_msg() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5Ecreate_stack
*
@@ -907,7 +929,8 @@ done:
FUNC_LEAVE_API(ret_value)
} /* end H5Ecreate_stack() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5Eget_current_stack
*
@@ -943,7 +966,8 @@ done:
FUNC_LEAVE_API(ret_value)
} /* end H5Eget_current_stack() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5E_get_current_stack
*
@@ -1020,7 +1044,8 @@ done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5E_get_current_stack() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5Eset_current_stack
*
@@ -1068,7 +1093,8 @@ done:
FUNC_LEAVE_API(ret_value)
} /* end H5Eset_current_stack() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5E_set_current_stack
*
@@ -1132,7 +1158,8 @@ done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5E_set_current_stack() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5Eclose_stack
*
@@ -1170,7 +1197,8 @@ done:
FUNC_LEAVE_API(ret_value)
} /* end H5Eclose_stack() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5E_close_stack
*
@@ -1200,7 +1228,8 @@ H5E_close_stack(H5E_t *estack)
FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5E_close_stack() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5Eget_num
*
@@ -1245,7 +1274,8 @@ done:
FUNC_LEAVE_API(ret_value)
} /* end H5Eget_num() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5E_get_num
*
@@ -1268,7 +1298,8 @@ H5E_get_num(const H5E_t *estack)
FUNC_LEAVE_NOAPI((ssize_t)estack->nused)
} /* end H5E_get_num() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5Epop
*
@@ -1317,7 +1348,8 @@ done:
FUNC_LEAVE_API(ret_value)
} /* end H5Epop() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5Epush2
*
@@ -1369,6 +1401,11 @@ H5Epush2(hid_t err_stack, const char *file, const char *func, unsigned line,
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a error stack ID")
} /* end else */
+/* Note that the variable-argument parsing for the format is identical in
+ * the H5E_printf_stack() routine - correct errors and make changes in both
+ * places. -QAK
+ */
+
/* Format the description */
va_start(ap, fmt);
va_started = TRUE;
@@ -1426,7 +1463,8 @@ done:
FUNC_LEAVE_API(ret_value)
} /* end H5Epush2() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5Eclear2
*
@@ -1468,7 +1506,8 @@ done:
FUNC_LEAVE_API(ret_value)
} /* end H5Eclear2() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5Eprint2
*
@@ -1515,7 +1554,8 @@ done:
FUNC_LEAVE_API(ret_value)
} /* end H5Eprint2() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5Ewalk2
*
@@ -1563,7 +1603,8 @@ done:
FUNC_LEAVE_API(ret_value)
} /* end H5Ewalk2() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5Eget_auto2
*
@@ -1619,7 +1660,8 @@ done:
FUNC_LEAVE_API(ret_value)
} /* end H5Eget_auto2() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5Eset_auto2
*
@@ -1688,7 +1730,8 @@ done:
FUNC_LEAVE_API(ret_value)
} /* end H5Eset_auto2() */
-
+
+
/*-------------------------------------------------------------------------
* Function: H5Eauto_is_v2
*
diff --git a/src/H5TS.c b/src/H5TS.c
index 8b75ab2..3c7e4f4 100644
--- a/src/H5TS.c
+++ b/src/H5TS.c
@@ -56,8 +56,6 @@ H5TS_key_t H5TS_cancel_key_g;
* PROGRAMMER: Quincey Koziol
* February 7, 2003
*
- * MODIFICATIONS:
- *
*--------------------------------------------------------------------------
*/
static void
@@ -68,39 +66,9 @@ H5TS_key_destructor(void *key_val)
HDfree(key_val);
}
-#ifdef H5_HAVE_WIN_THREADS
-/*--------------------------------------------------------------------------
- * NAME
- * H5TS_win32_first_thread_init
- *
- * USAGE
- * H5TS_win32_first_thread_init()
- *
- * RETURNS
- *
- * DESCRIPTION
- * Special function on windows needed to call the H5TS_first_thread_init
- * function.
- *
- * PROGRAMMER: Mike McGreevy
- * September 1, 2010
- *
- * MODIFICATIONS:
- *
- *--------------------------------------------------------------------------
- */
-BOOL CALLBACK
-H5TS_win32_first_thread_init(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContex)
-{
- InitializeCriticalSection ( &H5_g.init_lock.CriticalSection );
- H5TS_errstk_key_g = TlsAlloc();
- H5TS_funcstk_key_g = TlsAlloc();
- H5TS_cancel_key_g = TlsAlloc();
+#ifndef H5_HAVE_WIN_THREADS
- return TRUE;
-} /* H5TS_win32_first_thread_init() */
-#else /* H5_HAVE_WIN_THREADS */
/*--------------------------------------------------------------------------
* NAME
* H5TS_pthread_first_thread_init
@@ -118,8 +86,6 @@ H5TS_win32_first_thread_init(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpCont
* PROGRAMMER: Chee Wai LEE
* May 2, 2000
*
- * MODIFICATIONS:
- *
*--------------------------------------------------------------------------
*/
void
@@ -149,6 +115,7 @@ H5TS_pthread_first_thread_init(void)
}
#endif /* H5_HAVE_WIN_THREADS */
+
/*--------------------------------------------------------------------------
* NAME
* H5TS_mutex_lock
@@ -167,11 +134,6 @@ H5TS_pthread_first_thread_init(void)
* PROGRAMMER: Chee Wai LEE
* May 2, 2000
*
- * MODIFICATIONS:
- *
- * 19 May 2000, Bill Wendling
- * Changed (*foo). form of accessing structure members to the -> form.
- *
*--------------------------------------------------------------------------
*/
herr_t
@@ -203,6 +165,7 @@ H5TS_mutex_lock(H5TS_mutex_t *mutex)
#endif /* H5_HAVE_WIN_THREADS */
}
+
/*--------------------------------------------------------------------------
* NAME
* H5TS_mutex_unlock
@@ -221,12 +184,6 @@ H5TS_mutex_lock(H5TS_mutex_t *mutex)
* PROGRAMMER: Chee Wai LEE
* May 2, 2000
*
- * MODIFICATIONS:
- *
- * 19 May 2000, Bill Wendling
- * Changed (*foo). form of accessing structure members to the -> form.
- * Also gave the function a return value.
- *
*--------------------------------------------------------------------------
*/
herr_t
@@ -258,6 +215,7 @@ H5TS_mutex_unlock(H5TS_mutex_t *mutex)
#endif /* H5_HAVE_WIN_THREADS */
} /* H5TS_mutex_unlock */
+
/*--------------------------------------------------------------------------
* NAME
* H5TS_cancel_count_inc
@@ -280,12 +238,6 @@ H5TS_mutex_unlock(H5TS_mutex_t *mutex)
* PROGRAMMER: Chee Wai LEE
* May 2, 2000
*
- * MODIFICATIONS:
- *
- * 19 May 2000, Bill Wendling
- * Changed function to return a value. Also changed the malloc() call to
- * the H5MM_malloc() call and checked the returned pointer.
- *
*--------------------------------------------------------------------------
*/
herr_t
@@ -328,6 +280,7 @@ H5TS_cancel_count_inc(void)
#endif /* H5_HAVE_WIN_THREADS */
}
+
/*--------------------------------------------------------------------------
* NAME
* H5TS_cancel_count_dec
@@ -348,11 +301,6 @@ H5TS_cancel_count_inc(void)
* PROGRAMMER: Chee Wai LEE
* May 2, 2000
*
- * MODIFICATIONS:
- *
- * 19 May 2000, Bill Wendling
- * Changed so that function returns a value. May be of limited usefulness.
- *
*--------------------------------------------------------------------------
*/
herr_t
@@ -377,6 +325,154 @@ H5TS_cancel_count_dec(void)
}
+#ifdef H5_HAVE_WIN_THREADS
+/*--------------------------------------------------------------------------
+ * NAME
+ * H5TS_win32_process_enter
+ *
+ * RETURNS
+ * SUCCEED/FAIL
+ *
+ * DESCRIPTION
+ * Per-process setup on Windows when using Win32 threads.
+ *
+ *--------------------------------------------------------------------------
+ */
+H5_DLL BOOL CALLBACK
+H5TS_win32_process_enter(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContex)
+{
+ BOOL ret_value = TRUE;
+
+ /* Initialize the critical section (can't fail) */
+ InitializeCriticalSection(&H5_g.init_lock.CriticalSection);
+
+ /* Set up thread local storage */
+ if(TLS_OUT_OF_INDEXES == (H5TS_errstk_key_g = TlsAlloc()))
+ ret_value = FALSE;
+
+#ifdef H5_HAVE_CODESTACK
+ if(TLS_OUT_OF_INDEXES == (H5TS_funcstk_key_g = TlsAlloc()))
+ ret_value = FALSE;
+#endif /* H5_HAVE_CODESTACK */
+
+ return ret_value;
+} /* H5TS_win32_process_enter() */
+#endif /* H5_HAVE_WIN_THREADS */
+
+
+#ifdef H5_HAVE_WIN_THREADS
+/*--------------------------------------------------------------------------
+ * NAME
+ * H5TS_win32_thread_enter
+ *
+ * RETURNS
+ * SUCCEED/FAIL
+ *
+ * DESCRIPTION
+ * Per-thread setup on Windows when using Win32 threads.
+ *
+ *--------------------------------------------------------------------------
+ */
+herr_t
+H5TS_win32_thread_enter(void)
+{
+ herr_t ret_value = SUCCEED;
+
+ /* Currently a placeholder function. TLS setup is performed
+ * elsewhere in the library.
+ *
+ * WARNING: Do NOT use C standard library functions here.
+ * CRT functions are not allowed in DllMain, which is where this code
+ * is used.
+ */
+
+ return ret_value;
+} /* H5TS_win32_thread_enter() */
+#endif /* H5_HAVE_WIN_THREADS */
+
+
+#ifdef H5_HAVE_WIN_THREADS
+/*--------------------------------------------------------------------------
+ * NAME
+ * H5TS_win32_process_exit
+ *
+ * RETURNS
+ * SUCCEED/FAIL
+ *
+ * DESCRIPTION
+ * Per-process cleanup on Windows when using Win32 threads.
+ *
+ *--------------------------------------------------------------------------
+ */
+void
+H5TS_win32_process_exit(void)
+{
+
+ /* Windows uses a different thread local storage mechanism which does
+ * not support auto-freeing like pthreads' keys.
+ *
+ * This function is currently registered via atexit() and is called
+ * AFTER H5_term_library().
+ */
+
+ /* Clean up critical section resources (can't fail) */
+ DeleteCriticalSection(&H5_g.init_lock.CriticalSection);
+
+ /* Clean up per-process thread local storage */
+ TlsFree(H5TS_errstk_key_g);
+
+#ifdef H5_HAVE_CODESTACK
+ TlsFree(H5TS_funcstk_key_g);
+#endif /* H5_HAVE_CODESTACK */
+
+ return;
+} /* H5TS_win32_process_exit() */
+#endif /* H5_HAVE_WIN_THREADS */
+
+
+#ifdef H5_HAVE_WIN_THREADS
+/*--------------------------------------------------------------------------
+ * NAME
+ * H5TS_win32_thread_exit
+ *
+ * RETURNS
+ * SUCCEED/FAIL
+ *
+ * DESCRIPTION
+ * Per-thread cleanup on Windows when using Win32 threads.
+ *
+ *--------------------------------------------------------------------------
+ */
+herr_t
+H5TS_win32_thread_exit(void)
+{
+ LPVOID lpvData;
+ herr_t ret_value = SUCCEED;
+
+ /* Windows uses a different thread local storage mechanism which does
+ * not support auto-freeing like pthreads' keys.
+ *
+ * WARNING: Do NOT use C standard library functions here.
+ * CRT functions are not allowed in DllMain, which is where this code
+ * is used.
+ */
+
+ /* Clean up per-thread thread local storage */
+ lpvData = TlsGetValue(H5TS_errstk_key_g);
+ if(lpvData)
+ LocalFree((HLOCAL)lpvData);
+
+#ifdef H5_HAVE_CODESTACK
+ lpvData = TlsGetValue(H5TS_funcstk_key_g);
+ if(lpvData)
+ LocalFree((HLOCAL)lpvData);
+#endif /* H5_HAVE_CODESTACK */
+
+ return ret_value;
+} /* H5TS_win32_thread_exit() */
+#endif /* H5_HAVE_WIN_THREADS */
+
+
/*--------------------------------------------------------------------------
* NAME
* H5TS_create_thread
@@ -399,16 +495,17 @@ H5TS_create_thread(void *func, H5TS_attr_t *attr, void *udata)
#ifdef H5_HAVE_WIN_THREADS
- /* When calling C runtime functions, you have to use _beginthread or
+ /* When calling C runtime functions, you should use _beginthread or
* _beginthreadex instead of CreateThread. Threads created with
- * CreateThread risk being killed in low-memory situations.
- * We use _beginthread instead of _begintheadex because the latter
- * requires a stdcall function (and we don't need the more advanced
- * features it exposes).
+ * CreateThread risk being killed in low-memory situations. Since we
+ * only create threads in our test code, this is unlikely to be an issue
+ * and we'll use the easier-to-deal-with CreateThread for now.
*
- * NOTE: No error checks here! ret_value will be -1L on errors.
+ * NOTE: _beginthread() auto-recycles its handle when execution completes
+ * so you can't wait on it, making it unsuitable for the existing
+ * test code.
*/
- ret_value = _beginthread(func, 0 /* stack size */, udata);
+ ret_value = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, udata, 0, NULL);
#else /* H5_HAVE_WIN_THREADS */
diff --git a/src/H5TSprivate.h b/src/H5TSprivate.h
index 7f55f4f..cc22f96 100644
--- a/src/H5TSprivate.h
+++ b/src/H5TSprivate.h
@@ -51,6 +51,7 @@ typedef INIT_ONCE H5TS_once_t;
/* not used on windows side, but need to be defined to something */
#define H5TS_SCOPE_SYSTEM 0
#define H5TS_SCOPE_PROCESS 0
+#define H5TS_CALL_CONV WINAPI
/* Functions */
#define H5TS_get_thread_local_value(key) TlsGetValue( key )
@@ -63,8 +64,13 @@ typedef INIT_ONCE H5TS_once_t;
#define H5TS_mutex_lock_simple(mutex) EnterCriticalSection(mutex)
#define H5TS_mutex_unlock_simple(mutex) LeaveCriticalSection(mutex)
-H5_DLL BOOL CALLBACK
-H5TS_win32_first_thread_init(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContex);
+/* Functions called from DllMain */
+H5_DLL BOOL CALLBACK H5TS_win32_process_enter(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContex);
+H5_DLL void H5TS_win32_process_exit(void);
+H5_DLL herr_t H5TS_win32_thread_enter(void);
+H5_DLL herr_t H5TS_win32_thread_exit(void);
+
+
#else /* H5_HAVE_WIN_THREADS */
@@ -86,6 +92,7 @@ typedef pthread_once_t H5TS_once_t;
/* Scope Definitions */
#define H5TS_SCOPE_SYSTEM PTHREAD_SCOPE_SYSTEM
#define H5TS_SCOPE_PROCESS PTHREAD_SCOPE_PROCESS
+#define H5TS_CALL_CONV /* unused - Windows only */
/* Functions */
#define H5TS_get_thread_local_value(key) pthread_getspecific( key )
@@ -117,8 +124,6 @@ H5_DLL herr_t H5TS_cancel_count_inc(void);
H5_DLL herr_t H5TS_cancel_count_dec(void);
H5_DLL H5TS_thread_t H5TS_create_thread(void * func, H5TS_attr_t * attr, void *udata);
-
-
#if defined c_plusplus || defined __cplusplus
}
#endif /* c_plusplus || __cplusplus */
diff --git a/src/H5private.h b/src/H5private.h
index f8ede63..18a0fc0 100644
--- a/src/H5private.h
+++ b/src/H5private.h
@@ -1730,7 +1730,7 @@ typedef struct H5_api_struct {
/* Macro for first thread initialization */
#ifdef H5_HAVE_WIN_THREADS
-#define H5_FIRST_THREAD_INIT InitOnceExecuteOnce(&H5TS_first_init_g, H5TS_win32_first_thread_init, NULL, NULL);
+#define H5_FIRST_THREAD_INIT InitOnceExecuteOnce(&H5TS_first_init_g, H5TS_win32_process_enter, NULL, NULL);
#else
#define H5_FIRST_THREAD_INIT pthread_once(&H5TS_first_init_g, H5TS_pthread_first_thread_init);
#endif