msvcrt: Handle of thread created by _beginthread should not be closed on thread detach.
Handle should be closed if _endthread is called or thread function exits. If thread is terminated by ExitThread or _endthreadex, thread handle remains valid. Signed-off-by: Paul Gofman <gofmanp@gmail.com> Signed-off-by: Piotr Caban <piotr@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
567f83a317
commit
faf59e5f06
|
@ -67,7 +67,6 @@ static inline void msvcrt_free_tls_mem(void)
|
||||||
|
|
||||||
if (tls)
|
if (tls)
|
||||||
{
|
{
|
||||||
CloseHandle(tls->handle);
|
|
||||||
MSVCRT_free(tls->efcvt_buffer);
|
MSVCRT_free(tls->efcvt_buffer);
|
||||||
MSVCRT_free(tls->asctime_buffer);
|
MSVCRT_free(tls->asctime_buffer);
|
||||||
MSVCRT_free(tls->wasctime_buffer);
|
MSVCRT_free(tls->wasctime_buffer);
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "msvcrt.h"
|
#include "msvcrt.h"
|
||||||
|
#include <process.h>
|
||||||
|
|
||||||
static inline float __port_infinity(void)
|
static inline float __port_infinity(void)
|
||||||
{
|
{
|
||||||
|
@ -540,6 +541,66 @@ static void test_math_functions(void)
|
||||||
ok(errno == 0xdeadbeef, "errno = %d\n", errno);
|
ok(errno == 0xdeadbeef, "errno = %d\n", errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __cdecl test_thread_func(void *end_thread_type)
|
||||||
|
{
|
||||||
|
if (end_thread_type == (void*)1)
|
||||||
|
_endthread();
|
||||||
|
else if (end_thread_type == (void*)2)
|
||||||
|
ExitThread(0);
|
||||||
|
else if (end_thread_type == (void*)3)
|
||||||
|
_endthreadex(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned __stdcall test_thread_func_ex(void *arg)
|
||||||
|
{
|
||||||
|
_endthread();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_thread_handle_close(void)
|
||||||
|
{
|
||||||
|
HANDLE hThread;
|
||||||
|
DWORD ret;
|
||||||
|
|
||||||
|
/* _beginthread: handle is not closed on ExitThread and _endthreadex */
|
||||||
|
hThread = (HANDLE)_beginthread(test_thread_func, 0, (void*)0);
|
||||||
|
ok(hThread != INVALID_HANDLE_VALUE, "_beginthread failed (%d)\n", errno);
|
||||||
|
WaitForSingleObject(hThread, INFINITE);
|
||||||
|
ret = CloseHandle(hThread);
|
||||||
|
ok(!ret, "ret = %d\n", ret);
|
||||||
|
|
||||||
|
hThread = (HANDLE)_beginthread(test_thread_func, 0, (void*)1);
|
||||||
|
ok(hThread != INVALID_HANDLE_VALUE, "_beginthread failed (%d)\n", errno);
|
||||||
|
WaitForSingleObject(hThread, INFINITE);
|
||||||
|
ret = CloseHandle(hThread);
|
||||||
|
ok(!ret, "ret = %d\n", ret);
|
||||||
|
|
||||||
|
hThread = (HANDLE)_beginthread(test_thread_func, 0, (void*)2);
|
||||||
|
ok(hThread != INVALID_HANDLE_VALUE, "_beginthread failed (%d)\n", errno);
|
||||||
|
Sleep(150);
|
||||||
|
ret = WaitForSingleObject(hThread, INFINITE);
|
||||||
|
ok(ret == WAIT_OBJECT_0, "ret = %d\n", ret);
|
||||||
|
ret = CloseHandle(hThread);
|
||||||
|
ok(ret, "ret = %d\n", ret);
|
||||||
|
|
||||||
|
hThread = (HANDLE)_beginthread(test_thread_func, 0, (void*)3);
|
||||||
|
ok(hThread != INVALID_HANDLE_VALUE, "_beginthread failed (%d)\n", errno);
|
||||||
|
Sleep(150);
|
||||||
|
ret = WaitForSingleObject(hThread, INFINITE);
|
||||||
|
ok(ret == WAIT_OBJECT_0, "ret = %d\n", ret);
|
||||||
|
ret = CloseHandle(hThread);
|
||||||
|
ok(ret, "ret = %d\n", ret);
|
||||||
|
|
||||||
|
/* _beginthreadex: handle is not closed on _endthread */
|
||||||
|
hThread = (HANDLE)_beginthreadex(NULL,0, test_thread_func_ex, NULL, 0, NULL);
|
||||||
|
ok(hThread != NULL, "_beginthreadex failed (%d)\n", errno);
|
||||||
|
Sleep(150);
|
||||||
|
ret = WaitForSingleObject(hThread, INFINITE);
|
||||||
|
ok(ret == WAIT_OBJECT_0, "ret = %d\n", ret);
|
||||||
|
ret = CloseHandle(hThread);
|
||||||
|
ok(ret, "ret = %d\n", ret);
|
||||||
|
}
|
||||||
|
|
||||||
START_TEST(misc)
|
START_TEST(misc)
|
||||||
{
|
{
|
||||||
int arg_c;
|
int arg_c;
|
||||||
|
@ -568,4 +629,5 @@ START_TEST(misc)
|
||||||
test__invalid_parameter();
|
test__invalid_parameter();
|
||||||
test_qsort_s();
|
test_qsort_s();
|
||||||
test_math_functions();
|
test_math_functions();
|
||||||
|
test_thread_handle_close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,38 @@ thread_data_t *msvcrt_get_thread_data(void)
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* _endthread (MSVCRT.@)
|
||||||
|
*/
|
||||||
|
void CDECL _endthread(void)
|
||||||
|
{
|
||||||
|
thread_data_t *tls;
|
||||||
|
|
||||||
|
TRACE("(void)\n");
|
||||||
|
|
||||||
|
tls = TlsGetValue(msvcrt_tls_index);
|
||||||
|
if (tls && tls->handle != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
CloseHandle(tls->handle);
|
||||||
|
tls->handle = INVALID_HANDLE_VALUE;
|
||||||
|
} else
|
||||||
|
WARN("tls=%p tls->handle=%p\n", tls, tls ? tls->handle : INVALID_HANDLE_VALUE);
|
||||||
|
|
||||||
|
/* FIXME */
|
||||||
|
ExitThread(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* _endthreadex (MSVCRT.@)
|
||||||
|
*/
|
||||||
|
void CDECL _endthreadex(
|
||||||
|
unsigned int retval) /* [in] Thread exit code */
|
||||||
|
{
|
||||||
|
TRACE("(%d)\n", retval);
|
||||||
|
|
||||||
|
/* FIXME */
|
||||||
|
ExitThread(retval);
|
||||||
|
}
|
||||||
|
|
||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
* _beginthread_trampoline
|
* _beginthread_trampoline
|
||||||
|
@ -69,6 +101,7 @@ static DWORD CALLBACK _beginthread_trampoline(LPVOID arg)
|
||||||
MSVCRT_free(arg);
|
MSVCRT_free(arg);
|
||||||
|
|
||||||
local_trampoline.start_address(local_trampoline.arglist);
|
local_trampoline.start_address(local_trampoline.arglist);
|
||||||
|
_endthread();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,29 +164,6 @@ MSVCRT_uintptr_t CDECL _beginthreadex(
|
||||||
initflag, thrdaddr);
|
initflag, thrdaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************************************
|
|
||||||
* _endthread (MSVCRT.@)
|
|
||||||
*/
|
|
||||||
void CDECL _endthread(void)
|
|
||||||
{
|
|
||||||
TRACE("(void)\n");
|
|
||||||
|
|
||||||
/* FIXME */
|
|
||||||
ExitThread(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************************************
|
|
||||||
* _endthreadex (MSVCRT.@)
|
|
||||||
*/
|
|
||||||
void CDECL _endthreadex(
|
|
||||||
unsigned int retval) /* [in] Thread exit code */
|
|
||||||
{
|
|
||||||
TRACE("(%d)\n", retval);
|
|
||||||
|
|
||||||
/* FIXME */
|
|
||||||
ExitThread(retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
* _getptd (MSVCR80.@)
|
* _getptd (MSVCR80.@)
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue