From c304f457cfef721068cce108e1413c939dd4053b Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 14 Jul 2014 19:36:31 +0200 Subject: [PATCH 01/18] Implemented thread handling for WaitForMultipleObjects. Implemented thread specific functions. --- cmake/ConfigOptions.cmake | 1 + config.h.in | 1 + winpr/include/winpr/thread.h | 6 +- winpr/libwinpr/handle/handle.c | 15 +- winpr/libwinpr/pool/pool.c | 11 +- winpr/libwinpr/synch/wait.c | 122 ++++++----- winpr/libwinpr/thread/thread.c | 365 +++++++++++++++++++++++++++++++-- winpr/libwinpr/thread/thread.h | 6 + 8 files changed, 426 insertions(+), 101 deletions(-) diff --git a/cmake/ConfigOptions.cmake b/cmake/ConfigOptions.cmake index 17af6d9cd..87ffefe6e 100644 --- a/cmake/ConfigOptions.cmake +++ b/cmake/ConfigOptions.cmake @@ -109,6 +109,7 @@ option(WITH_DEBUG_SCARD "Print smartcard debug messages" ${DEFAULT_DEBUG_OPTION} option(WITH_DEBUG_SND "Print rdpsnd debug messages" ${DEFAULT_DEBUG_OPTION}) option(WITH_DEBUG_SVC "Print static virtual channel debug messages." ${DEFAULT_DEBUG_OPTION}) option(WITH_DEBUG_TRANSPORT "Print transport debug messages." ${DEFAULT_DEBUG_OPTION}) +option(WITH_DEBUG_THREADS "Print thread debug messages, enables handle dump" ${DEFAULT_DEBUG_OPTION}) option(WITH_DEBUG_TIMEZONE "Print timezone debug messages." ${DEFAULT_DEBUG_OPTION}) option(WITH_DEBUG_WND "Print window order debug messages" ${DEFAULT_DEBUG_OPTION}) option(WITH_DEBUG_X11_CLIPRDR "Print X11 clipboard redirection debug messages" ${DEFAULT_DEBUG_OPTION}) diff --git a/config.h.in b/config.h.in index b196cc5ae..09eebf370 100644 --- a/config.h.in +++ b/config.h.in @@ -80,6 +80,7 @@ #cmakedefine WITH_DEBUG_SVC #cmakedefine WITH_DEBUG_RDPEI #cmakedefine WITH_DEBUG_TIMEZONE +#cmakedefine WITH_DEBUG_THREADS #cmakedefine WITH_DEBUG_TRANSPORT #cmakedefine WITH_DEBUG_WND #cmakedefine WITH_DEBUG_X11 diff --git a/winpr/include/winpr/thread.h b/winpr/include/winpr/thread.h index 71beed8ef..c7bb43b37 100644 --- a/winpr/include/winpr/thread.h +++ b/winpr/include/winpr/thread.h @@ -200,7 +200,11 @@ WINPR_API BOOL TlsFree(DWORD dwTlsIndex); /* CommandLineToArgvA is not present in the original Windows API, WinPR always exports it */ -WINPR_API LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs); +WINPR_API LPSTR *CommandLineToArgvA(LPCSTR lpCmdLine, int *pNumArgs); + +#if defined(WITH_DEBUG_THREADS) +WINPR_API VOID DumpThreadHandles(void); +#endif #ifdef __cplusplus } diff --git a/winpr/libwinpr/handle/handle.c b/winpr/libwinpr/handle/handle.c index a634eb7ab..ff02aea9b 100644 --- a/winpr/libwinpr/handle/handle.c +++ b/winpr/libwinpr/handle/handle.c @@ -127,20 +127,7 @@ BOOL CloseHandle(HANDLE hObject) LeaveCriticalSection(&_HandleCloseCbsLock); - if (Type == HANDLE_TYPE_THREAD) - { - WINPR_THREAD* thread; - thread = (WINPR_THREAD*) Object; - - if (thread->started) - { - pthread_detach(thread->thread); - } - - free(thread); - return TRUE; - } - else if (Type == HANDLE_TYPE_PROCESS) + if (Type == HANDLE_TYPE_PROCESS) { WINPR_PROCESS* process; process = (WINPR_PROCESS*) Object; diff --git a/winpr/libwinpr/pool/pool.c b/winpr/libwinpr/pool/pool.c index e7c099e39..df5c17087 100644 --- a/winpr/libwinpr/pool/pool.c +++ b/winpr/libwinpr/pool/pool.c @@ -100,11 +100,13 @@ static void* thread_pool_work_func(void* arg) } } + ExitThread(0); return NULL; } static void threads_close(void *thread) { + WaitForSingleObject(thread, INFINITE); CloseHandle(thread); } @@ -184,15 +186,6 @@ VOID CloseThreadpool(PTP_POOL ptpp) SetEvent(ptpp->TerminateEvent); - index = ArrayList_Count(ptpp->Threads) - 1; - - while (index >= 0) - { - thread = (HANDLE) ArrayList_GetItem(ptpp->Threads, index); - WaitForSingleObject(thread, INFINITE); - index--; - } - ArrayList_Free(ptpp->Threads); Queue_Free(ptpp->PendingQueue); CountdownEvent_Free(ptpp->WorkComplete); diff --git a/winpr/libwinpr/synch/wait.c b/winpr/libwinpr/synch/wait.c index ea6e0921b..2f41dc685 100644 --- a/winpr/libwinpr/synch/wait.c +++ b/winpr/libwinpr/synch/wait.c @@ -107,33 +107,6 @@ static long long ts_difftime(const struct timespec* o, return newValue - oldValue; } -static int pthread_timedjoin_np(pthread_t td, void** res, - struct timespec* timeout) -{ - struct timespec timenow; - struct timespec sleepytime; - /* This is just to avoid a completely busy wait */ - sleepytime.tv_sec = 0; - sleepytime.tv_nsec = 10000000; /* 10ms */ - - do - { - if (pthread_kill(td, 0)) - return pthread_join(td, res); - - nanosleep(&sleepytime, NULL); - clock_gettime(CLOCK_MONOTONIC, &timenow); - - if (ts_difftime(timeout, &timenow) >= 0) - { - return ETIMEDOUT; - } - } - while (TRUE); - - return ETIMEDOUT; -} - #if defined(__FreeBSD__) /*the only way to get it work is to remove the static*/ int pthread_mutex_timedlock(pthread_mutex_t* mutex, const struct timespec* timeout) @@ -143,10 +116,13 @@ static int pthread_mutex_timedlock(pthread_mutex_t* mutex, const struct timespec { struct timespec timenow; struct timespec sleepytime; + unsigned long long diff; int retcode; /* This is just to avoid a completely busy wait */ - sleepytime.tv_sec = 0; - sleepytime.tv_nsec = 10000000; /* 10ms */ + clock_gettime(CLOCK_MONOTONIC, &timenow); + diff = ts_difftime(&timenow, timeout); + sleepytime.tv_sec = diff / 1000000000LL; + sleepytime.tv_nsec = diff % 1000000000LL; while ((retcode = pthread_mutex_trylock(mutex)) == EBUSY) { @@ -223,43 +199,30 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) if (Type == HANDLE_TYPE_THREAD) { - int status = 0; - WINPR_THREAD* thread; - void* thread_status = NULL; - thread = (WINPR_THREAD*) Object; + void *thread_status; + int status; + WINPR_THREAD *thread = (WINPR_THREAD *)Object; + status = waitOnFd(thread->pipe_fd[0], dwMilliseconds); - if (thread->started) + if (status < 0) { - if (dwMilliseconds != INFINITE) - { - struct timespec timeout; - - /* pthread_timedjoin_np returns ETIMEDOUT in case the timeout is 0, - * so set it to the smallest value to get a proper return value. */ - if (dwMilliseconds == 0) - dwMilliseconds ++; - - clock_gettime(CLOCK_MONOTONIC, &timeout); - ts_add_ms(&timeout, dwMilliseconds); - status = pthread_timedjoin_np(thread->thread, &thread_status, &timeout); - - if (ETIMEDOUT == status) - return WAIT_TIMEOUT; - } - else - status = pthread_join(thread->thread, &thread_status); - - thread->started = FALSE; - - if (status != 0) - { - WLog_ERR(TAG, "pthread_join failure: [%d] %s", - status, strerror(status)); - } - - if (thread_status) - thread->dwExitCode = ((DWORD)(size_t) thread_status); + WLog_ERR(TAG, "waitOnFd() failure [%d] %s", errno, strerror(errno)); + return WAIT_FAILED; } +> + if (status != 1) + return WAIT_TIMEOUT; + + status = pthread_join(thread->thread, &thread_status); + + if (status != 0) + { + WLog_ERR(TAG, "pthread_join failure: [%d] %s", + status, strerror(status)); + } + + if (thread_status) + thread->dwExitCode = ((DWORD)(size_t) thread_status); } else if (Type == HANDLE_TYPE_PROCESS) { @@ -517,6 +480,17 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl return WAIT_FAILED; } } + else if (Type == HANDLE_TYPE_THREAD) + { + WINPR_THREAD *thread = (WINPR_THREAD *) Object; + fd = thread->pipe_fd[0]; + + if (fd == -1) + { + WLog_ERR(TAG, "invalid thread file descriptor"); + return WAIT_FAILED; + } + } else if (Type == HANDLE_TYPE_NAMED_PIPE) { WINPR_NAMED_PIPE* pipe = (WINPR_NAMED_PIPE*) Object; @@ -604,6 +578,11 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl WINPR_TIMER* timer = (WINPR_TIMER*) Object; fd = timer->fd; } + else if (Type == HANDLE_TYPE_THREAD) + { + WINPR_THREAD *thread = (WINPR_THREAD *) Object; + fd = thread->pipe_fd[0]; + } else if (Type == HANDLE_TYPE_NAMED_PIPE) { WINPR_NAMED_PIPE* pipe = (WINPR_NAMED_PIPE*) Object; @@ -651,6 +630,23 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl return WAIT_FAILED; } } + else if (Type == HANDLE_TYPE_THREAD) + { + void *thread_status; + int status; + WINPR_THREAD *thread = (WINPR_THREAD *)Object; + status = pthread_join(thread->thread, &thread_status); + + if (status != 0) + { + WLog_ERR(TAG, " pthread_join failure: [%d] %s", + status, strerror(status)); + return WAIT_FAILED; + } + + if (thread_status) + thread->dwExitCode = ((DWORD)(size_t) thread_status); + } return (WAIT_OBJECT_0 + index); } diff --git a/winpr/libwinpr/thread/thread.c b/winpr/libwinpr/thread/thread.c index 51b775b7d..2e280311e 100644 --- a/winpr/libwinpr/thread/thread.c +++ b/winpr/libwinpr/thread/thread.c @@ -21,6 +21,8 @@ #include "config.h" #endif +#include + #include #include @@ -70,22 +72,154 @@ #include #include -#if defined(__linux__) && !defined(__ANDROID__) +#ifdef HAVE_UNISTD_H #include -#include -#include #endif +#ifdef HAVE_EVENTFD_H +#include +#endif + +#ifdef HAVE_EXECINFO_H +#include +#endif + +#include + +#include + #include "thread.h" #include "../handle/handle.h" +static pthread_once_t thread_initialized = PTHREAD_ONCE_INIT; +static HANDLE_CLOSE_CB _ThreadHandleCloseCb; +static wListDictionary *thread_list = NULL; + +static BOOL ThreadCloseHandle(HANDLE handle); +static void cleanup_handle(WINPR_THREAD *thread); + +static BOOL ThreadIsHandled(HANDLE handle) +{ + WINPR_THREAD *pThread = (WINPR_THREAD *)handle; + + if (!pThread || pThread->Type != HANDLE_TYPE_THREAD) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + return TRUE; +} + + +static void ThreadInitialize(void) +{ + _ThreadHandleCloseCb.IsHandled = ThreadIsHandled; + _ThreadHandleCloseCb.CloseHandle = ThreadCloseHandle; + RegisterHandleCloseCb(&_ThreadHandleCloseCb); +} + +static void dump_thread(WINPR_THREAD *thread) +{ +#if defined(WITH_DEBUG_THREADS) && defined(HAVE_EXECINFO_H) + void *stack[20]; + fprintf(stderr, "Called from:\n"); + backtrace_symbols_fd(stack, 20, STDERR_FILENO); + fprintf(stderr, "Thread handle created still not closed!\n"); + backtrace_symbols_fd(thread->create_stack, 20, STDERR_FILENO); + + if (thread->started) + fprintf(stderr, "Thread still running!\n"); + else if (!thread->exit_stack) + fprintf(stderr, "Thread suspended.\n"); + else + { + fprintf(stderr, "Thread exited at:\n"); + backtrace_symbols_fd(thread->exit_stack, 20, STDERR_FILENO); + } + +#endif +} + /** * TODO: implement thread suspend/resume using pthreads * http://stackoverflow.com/questions/3140867/suspend-pthreads-without-using-condition */ +static BOOL set_event(WINPR_THREAD *thread) +{ + int length; + BOOL status = FALSE; +#ifdef HAVE_EVENTFD_H + eventfd_t val = 1; -void winpr_StartThread(WINPR_THREAD* thread) + do + { + length = eventfd_write(thread->pipe_fd[0], val); + } + while ((length < 0) && (errno == EINTR)); + + status = (length == 0) ? TRUE : FALSE; +#else + + if (WaitForSingleObject(thread, 0) != WAIT_OBJECT_0) + { + length = write(thread->pipe_fd[1], "-", 1); + + if (length == 1) + status = TRUE; + } + else + { + status = TRUE; + } + +#endif + thread->started = FALSE; + return status; +} + +static BOOL reset_event(WINPR_THREAD *thread) +{ + int length; + BOOL status = FALSE; + + while (WaitForSingleObject(thread, 0) == WAIT_OBJECT_0) + { +#ifdef HAVE_EVENTFD_H + eventfd_t value; + + do + { + length = eventfd_read(thread->pipe_fd[0], &value); + } + while ((length < 0) && (errno == EINTR)); + + if ((length > 0) && (!status)) + status = TRUE; + +#else + length = read(thread->pipe_fd[0], &length, 1); + + if ((length == 1) && (!status)) + status = TRUE; + +#endif + } + + thread->started = TRUE; + return status; +} + +static int thread_compare(void *a, void *b) +{ + pthread_t *p1 = a; + pthread_t *p2 = b; + int rc = pthread_equal(*p1, *p2); + return rc; +} + +void winpr_StartThread(WINPR_THREAD *thread) { pthread_attr_t attr; @@ -95,10 +229,12 @@ void winpr_StartThread(WINPR_THREAD* thread) if (thread->dwStackSize > 0) pthread_attr_setstacksize(&attr, (size_t) thread->dwStackSize); - thread->started = TRUE; pthread_create(&thread->thread, &attr, (pthread_start_routine) thread->lpStartAddress, thread->lpParameter); pthread_attr_destroy(&attr); + reset_event(thread); + ListDictionary_Add(thread_list, &thread->thread, thread); + dump_thread(thread); } HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, @@ -112,32 +248,162 @@ HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize if (!thread) return NULL; - thread->started = FALSE; + pthread_once(&thread_initialized, ThreadInitialize); thread->dwStackSize = dwStackSize; thread->lpParameter = lpParameter; thread->lpStartAddress = lpStartAddress; thread->lpThreadAttributes = lpThreadAttributes; +#if defined(WITH_DEBUG_THREADS) && defined(HAVE_EXECINFO_H) + backtrace(thread->create_stack, 20); + dump_thread(thread); +#endif +#ifdef HAVE_EVENTFD_H + thread->pipe_fd[0] = eventfd(0, EFD_NONBLOCK); + if (thread->pipe_fd[0] < 0) + { + fprintf(stderr, "[%s]: failed to create thread\n", __FUNCTION__); + free(thread); + return NULL; + } + +#else + + if (pipe(thread->pipe_fd) < 0) + { + fprintf(stderr, "[%s]: failed to create thread\n", __FUNCTION__); + free(thread); + return NULL; + } + +#endif pthread_mutex_init(&thread->mutex, 0); WINPR_HANDLE_SET_TYPE(thread, HANDLE_TYPE_THREAD); handle = (HANDLE) thread; + if (NULL == thread_list) + { + thread_list = ListDictionary_New(TRUE); + thread_list->objectKey.fnObjectEquals = thread_compare; + } + if (!(dwCreationFlags & CREATE_SUSPENDED)) winpr_StartThread(thread); + else + set_event(thread); return handle; } +void cleanup_handle(WINPR_THREAD *thread) +{ + ListDictionary_Remove(thread_list, &thread->thread); + int rc = pthread_mutex_destroy(&thread->mutex); + + if (rc) + { + fprintf(stderr, "[%s]: failed to destroy mutex [%d] %s (%d)\n", __FUNCTION__, rc, strerror(errno), errno); + } + + if (thread->pipe_fd[0]) + close(thread->pipe_fd[0]); + + if (thread->pipe_fd[1]) + close(thread->pipe_fd[1]); + + free(thread); +} + +BOOL ThreadCloseHandle(HANDLE handle) +{ + WINPR_THREAD *thread = (WINPR_THREAD *)handle; + + if (!thread_list) + { + fprintf(stderr, "[%s]: Thread list does not exist, check call!\n", __FUNCTION__); + dump_thread(thread); + } + else if (!ListDictionary_Contains(thread_list, &thread->thread)) + { + fprintf(stderr, "[%s]: Thread list does not contain this thread! check call!\n", __FUNCTION__); + dump_thread(thread); + } + else + { + ListDictionary_Lock(thread_list); + dump_thread(thread); + + if (!thread->started) + cleanup_handle(thread); + else if (WaitForSingleObject(thread, 0) == WAIT_OBJECT_0) + cleanup_handle(thread); + else + { + fprintf(stderr, "[%s]: Thread running, setting to detached state!\n", __FUNCTION__); + thread->detached = TRUE; + pthread_detach(thread->thread); + } + + ListDictionary_Unlock(thread_list); + + if (ListDictionary_Count(thread_list) < 1) + { + ListDictionary_Free(thread_list); + thread_list = NULL; + } + } + + return TRUE; +} + HANDLE CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId) { + fprintf(stderr, "[%s]: not implemented\n", __FUNCTION__); return NULL; } VOID ExitThread(DWORD dwExitCode) { - pthread_exit((void*) (size_t) dwExitCode); + pthread_t tid = pthread_self(); + + if (NULL == thread_list) + { + fprintf(stderr, "[%s]: function called without existing thread list!\n", __FUNCTION__); +#if defined(WITH_DEBUG_THREADS) + DumpThreadHandles(); +#endif + } + else if (!ListDictionary_Contains(thread_list, &tid)) + { + fprintf(stderr, "[%s]: function called, but no matching entry in thread list!\n", __FUNCTION__); +#if defined(WITH_DEBUG_THREADS) + DumpThreadHandles(); +#endif + } + else + { + WINPR_THREAD *thread; + ListDictionary_Lock(thread_list); + thread = ListDictionary_GetItemValue(thread_list, &tid); + assert(thread); +#if defined(WITH_DEBUG_THREADS) && defined(HAVE_EXECINFO_H) + backtrace(thread->exit_stack, 20); +#endif + + if (!thread->detached) + { + set_event(thread); + thread->dwExitCode = dwExitCode; + } + else + cleanup_handle(thread); + + ListDictionary_Unlock(thread_list); + } + + pthread_exit((void *)(size_t) dwExitCode); } BOOL GetExitCodeThread(HANDLE hThread, LPDWORD lpExitCode) @@ -158,20 +424,36 @@ BOOL GetExitCodeThread(HANDLE hThread, LPDWORD lpExitCode) HANDLE _GetCurrentThread(VOID) { - return NULL; + HANDLE hdl = NULL; + pthread_t tid = pthread_self(); + + if (NULL == thread_list) + { + fprintf(stderr, "[%s]: function called without existing thread list!\n", __FUNCTION__); +#if defined(WITH_DEBUG_THREADS) + DumpThreadHandles(); +#endif + } + else if (!ListDictionary_Contains(thread_list, &tid)) + { + fprintf(stderr, "[%s]: function called, but no matching entry in thread list!\n", __FUNCTION__); +#if defined(WITH_DEBUG_THREADS) + DumpThreadHandles(); +#endif + } + else + { + hdl = ListDictionary_GetItemValue(thread_list, &tid); + } + + return hdl; } DWORD GetCurrentThreadId(VOID) { -#if defined(__linux__) && !defined(__ANDROID__) - pid_t tid; - tid = syscall(SYS_gettid); - return (DWORD) tid; -#else pthread_t tid; tid = pthread_self(); return (DWORD) tid; -#endif } DWORD ResumeThread(HANDLE hThread) @@ -189,6 +471,8 @@ DWORD ResumeThread(HANDLE hThread) if (!thread->started) winpr_StartThread(thread); + else + fprintf(stderr, "[%s]: Thread already started!\n", __FUNCTION__); pthread_mutex_unlock(&thread->mutex); @@ -197,6 +481,7 @@ DWORD ResumeThread(HANDLE hThread) DWORD SuspendThread(HANDLE hThread) { + fprintf(stderr, "[%s]: Function not implemented!\n", __FUNCTION__); return 0; } @@ -220,6 +505,8 @@ BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode) #ifndef ANDROID pthread_cancel(thread->thread); +#else + fprintf(stderr, "[%s]: Function not supported on this platform!\n", __FUNCTION__); #endif pthread_mutex_unlock(&thread->mutex); @@ -227,5 +514,55 @@ BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode) return TRUE; } +#if defined(WITH_DEBUG_THREADS) +VOID DumpThreadHandles(void) +{ + void *stack[20]; +#if defined(HAVE_EXECINFO_H) + backtrace(stack, 20); +#endif + fprintf(stderr, "---------------- Called from ----------------------------\n"); +#if defined(HAVE_EXECINFO_H) + backtrace_symbols_fd(stack, 20, STDERR_FILENO); +#endif + fprintf(stderr, "---------------- Start Dumping thread handles -----------\n"); + + if (!thread_list) + fprintf(stderr, "All threads properly shut down and disposed of.\n"); + else + { + ULONG_PTR *keys = NULL; + ListDictionary_Lock(thread_list); + int x, count = ListDictionary_GetKeys(thread_list, &keys); + fprintf(stderr, "Dumping %d elements\n", count); + + for (x=0; xcreate_stack, 20, STDERR_FILENO); +#endif + + if (thread->started) + fprintf(stderr, "Thread [%d] still running!\n", x); + else + { + fprintf(stderr, "Thread [%d] exited at:\n", x); +#if defined(HAVE_EXECINFO_H) + backtrace_symbols_fd(thread->exit_stack, 20, STDERR_FILENO); +#endif + } + } + + if (keys) + free(keys); + + ListDictionary_Unlock(thread_list); + } + + fprintf(stderr, "---------------- End Dumping thread handles -------------\n"); +} +#endif #endif diff --git a/winpr/libwinpr/thread/thread.h b/winpr/libwinpr/thread/thread.h index 67fc3d831..ea7c5334b 100644 --- a/winpr/libwinpr/thread/thread.h +++ b/winpr/libwinpr/thread/thread.h @@ -35,7 +35,9 @@ struct winpr_thread WINPR_HANDLE_DEF(); BOOL started; + int pipe_fd[2]; BOOL mainProcess; + BOOL detached; DWORD dwExitCode; pthread_t thread; SIZE_T dwStackSize; @@ -43,6 +45,10 @@ struct winpr_thread pthread_mutex_t mutex; LPTHREAD_START_ROUTINE lpStartAddress; LPSECURITY_ATTRIBUTES lpThreadAttributes; +#if defined(WITH_DEBUG_THREADS) + void *create_stack[20]; + void *exit_stack[20]; +#endif }; typedef struct winpr_thread WINPR_THREAD; From 3d7b65a430f7aab86228d312de7b8575511b48c5 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 15 Jul 2014 11:11:59 +0200 Subject: [PATCH 02/18] Now using thread_launcher function to properly clean up thread resources at exit. --- winpr/libwinpr/thread/thread.c | 115 +++++++++++++++++++-------------- 1 file changed, 65 insertions(+), 50 deletions(-) diff --git a/winpr/libwinpr/thread/thread.c b/winpr/libwinpr/thread/thread.c index 2e280311e..1a09af1c9 100644 --- a/winpr/libwinpr/thread/thread.c +++ b/winpr/libwinpr/thread/thread.c @@ -29,7 +29,7 @@ /** * api-ms-win-core-processthreads-l1-1-1.dll - * + * * CreateRemoteThread * CreateRemoteThreadEx * CreateThread @@ -93,11 +93,12 @@ #include "../handle/handle.h" static pthread_once_t thread_initialized = PTHREAD_ONCE_INIT; + static HANDLE_CLOSE_CB _ThreadHandleCloseCb; static wListDictionary *thread_list = NULL; static BOOL ThreadCloseHandle(HANDLE handle); -static void cleanup_handle(WINPR_THREAD *thread); +static void cleanup_handle(void *obj); static BOOL ThreadIsHandled(HANDLE handle) { @@ -219,18 +220,53 @@ static int thread_compare(void *a, void *b) return rc; } -void winpr_StartThread(WINPR_THREAD *thread) +/* Thread launcher function responsible for registering + * cleanup handlers and calling pthread_exit, if not done + * in thread function. */ +static void *thread_launcher(void *arg) +{ + void *rc = NULL; + WINPR_THREAD *thread = (WINPR_THREAD *)arg; + + if (!thread) + { + fprintf(stderr, "[%s]: Called with invalid argument %p\n", __FUNCTION__, arg); + goto exit; + } + else + { + void *(*fkt)(void *) = (void *)thread->lpStartAddress; + + if (!fkt) + { + fprintf(stderr, "[%s]: Thread function argument is %p\n", fkt); + goto exit; + } + + rc = fkt(thread->lpParameter); + } + +exit: + set_event(thread); + thread->dwExitCode = (DWORD)(size_t)rc; + + if (thread->detached || !thread->started) + cleanup_handle(thread); + + pthread_exit(rc); + return rc; +} + +static void winpr_StartThread(WINPR_THREAD *thread) { pthread_attr_t attr; - pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); if (thread->dwStackSize > 0) pthread_attr_setstacksize(&attr, (size_t) thread->dwStackSize); - pthread_create(&thread->thread, &attr, (pthread_start_routine) thread->lpStartAddress, thread->lpParameter); - + pthread_create(&thread->thread, &attr, thread_launcher, thread); pthread_attr_destroy(&attr); reset_event(thread); ListDictionary_Add(thread_list, &thread->thread, thread); @@ -238,12 +274,11 @@ void winpr_StartThread(WINPR_THREAD *thread) } HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, - LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId) + LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId) { HANDLE handle; - WINPR_THREAD* thread; - - thread = (WINPR_THREAD*) calloc(1, sizeof(WINPR_THREAD)); + WINPR_THREAD *thread; + thread = (WINPR_THREAD *) calloc(1, sizeof(WINPR_THREAD)); if (!thread) return NULL; @@ -278,7 +313,6 @@ HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize #endif pthread_mutex_init(&thread->mutex, 0); - WINPR_HANDLE_SET_TYPE(thread, HANDLE_TYPE_THREAD); handle = (HANDLE) thread; @@ -296,15 +330,14 @@ HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize return handle; } -void cleanup_handle(WINPR_THREAD *thread) +void cleanup_handle(void *obj) { - ListDictionary_Remove(thread_list, &thread->thread); + WINPR_THREAD *thread = (WINPR_THREAD *)obj; int rc = pthread_mutex_destroy(&thread->mutex); if (rc) - { - fprintf(stderr, "[%s]: failed to destroy mutex [%d] %s (%d)\n", __FUNCTION__, rc, strerror(errno), errno); - } + fprintf(stderr, "[%s]: failed to destroy mutex [%d] %s (%d)\n", + __FUNCTION__, rc, strerror(errno), errno); if (thread->pipe_fd[0]) close(thread->pipe_fd[0]); @@ -312,6 +345,9 @@ void cleanup_handle(WINPR_THREAD *thread) if (thread->pipe_fd[1]) close(thread->pipe_fd[1]); + if (thread_list && ListDictionary_Contains(thread_list, &thread->thread)) + ListDictionary_Remove(thread_list, &thread->thread); + free(thread); } @@ -334,17 +370,14 @@ BOOL ThreadCloseHandle(HANDLE handle) ListDictionary_Lock(thread_list); dump_thread(thread); - if (!thread->started) - cleanup_handle(thread); - else if (WaitForSingleObject(thread, 0) == WAIT_OBJECT_0) - cleanup_handle(thread); - else + if ((thread->started) && (WaitForSingleObject(thread, 0) != WAIT_OBJECT_0)) { fprintf(stderr, "[%s]: Thread running, setting to detached state!\n", __FUNCTION__); thread->detached = TRUE; pthread_detach(thread->thread); } - + else + cleanup_handle(thread); ListDictionary_Unlock(thread_list); if (ListDictionary_Count(thread_list) < 1) @@ -358,7 +391,7 @@ BOOL ThreadCloseHandle(HANDLE handle) } HANDLE CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, - LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId) + LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId) { fprintf(stderr, "[%s]: not implemented\n", __FUNCTION__); return NULL; @@ -366,6 +399,7 @@ HANDLE CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttribu VOID ExitThread(DWORD dwExitCode) { +#if defined(WITH_DEBUG_THREADS) && defined(HAVE_EXECINFO_H) pthread_t tid = pthread_self(); if (NULL == thread_list) @@ -388,37 +422,25 @@ VOID ExitThread(DWORD dwExitCode) ListDictionary_Lock(thread_list); thread = ListDictionary_GetItemValue(thread_list, &tid); assert(thread); -#if defined(WITH_DEBUG_THREADS) && defined(HAVE_EXECINFO_H) backtrace(thread->exit_stack, 20); -#endif - - if (!thread->detached) - { - set_event(thread); - thread->dwExitCode = dwExitCode; - } - else - cleanup_handle(thread); - ListDictionary_Unlock(thread_list); } - pthread_exit((void *)(size_t) dwExitCode); +#endif + fprintf(stderr, "[%s] terminated...\n", __FUNCTION__); } BOOL GetExitCodeThread(HANDLE hThread, LPDWORD lpExitCode) { ULONG Type; PVOID Object; - WINPR_THREAD* thread; + WINPR_THREAD *thread; if (!winpr_Handle_GetInfo(hThread, &Type, &Object)) return FALSE; - thread = (WINPR_THREAD*) Object; - + thread = (WINPR_THREAD *) Object; *lpExitCode = thread->dwExitCode; - return TRUE; } @@ -460,13 +482,12 @@ DWORD ResumeThread(HANDLE hThread) { ULONG Type; PVOID Object; - WINPR_THREAD* thread; + WINPR_THREAD *thread; if (!winpr_Handle_GetInfo(hThread, &Type, &Object)) return 0; - thread = (WINPR_THREAD*) Object; - + thread = (WINPR_THREAD *) Object; pthread_mutex_lock(&thread->mutex); if (!thread->started) @@ -475,7 +496,6 @@ DWORD ResumeThread(HANDLE hThread) fprintf(stderr, "[%s]: Thread already started!\n", __FUNCTION__); pthread_mutex_unlock(&thread->mutex); - return 0; } @@ -494,23 +514,19 @@ BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode) { ULONG Type; PVOID Object; - WINPR_THREAD* thread; + WINPR_THREAD *thread; if (!winpr_Handle_GetInfo(hThread, &Type, &Object)) return 0; - thread = (WINPR_THREAD*) Object; - + thread = (WINPR_THREAD *) Object; pthread_mutex_lock(&thread->mutex); - #ifndef ANDROID pthread_cancel(thread->thread); #else fprintf(stderr, "[%s]: Function not supported on this platform!\n", __FUNCTION__); #endif - pthread_mutex_unlock(&thread->mutex); - return TRUE; } @@ -557,7 +573,6 @@ VOID DumpThreadHandles(void) if (keys) free(keys); - ListDictionary_Unlock(thread_list); } From c846379e6096407f575195177604d4b8bf893294 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 15 Jul 2014 12:18:25 +0200 Subject: [PATCH 03/18] Removed noreturn from ExitThread, does not conform to http://msdn.microsoft.com/en-us/library/windows/desktop/ms682659%28v=vs.85%29.aspx and crashes FreeRDP. --- winpr/include/winpr/thread.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winpr/include/winpr/thread.h b/winpr/include/winpr/thread.h index c7bb43b37..83a398c88 100644 --- a/winpr/include/winpr/thread.h +++ b/winpr/include/winpr/thread.h @@ -163,7 +163,7 @@ WINPR_API HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T d WINPR_API HANDLE CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId); -DECLSPEC_NORETURN WINPR_API VOID ExitThread(DWORD dwExitCode); +WINPR_API VOID ExitThread(DWORD dwExitCode); WINPR_API BOOL GetExitCodeThread(HANDLE hThread, LPDWORD lpExitCode); WINPR_API HANDLE _GetCurrentThread(void); From 8de2868281a9159c7ff48ab9a43c9e893324181e Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 15 Jul 2014 12:42:53 +0200 Subject: [PATCH 04/18] Preferring exit code from ExitThread now over thread function return. --- winpr/libwinpr/thread/thread.c | 14 +++++++++----- winpr/libwinpr/thread/thread.h | 3 ++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/winpr/libwinpr/thread/thread.c b/winpr/libwinpr/thread/thread.c index 1a09af1c9..79fca5114 100644 --- a/winpr/libwinpr/thread/thread.c +++ b/winpr/libwinpr/thread/thread.c @@ -248,7 +248,9 @@ static void *thread_launcher(void *arg) exit: set_event(thread); - thread->dwExitCode = (DWORD)(size_t)rc; + + if (!thread->exited) + thread->dwExitCode = (DWORD)(size_t)rc; if (thread->detached || !thread->started) cleanup_handle(thread); @@ -378,6 +380,7 @@ BOOL ThreadCloseHandle(HANDLE handle) } else cleanup_handle(thread); + ListDictionary_Unlock(thread_list); if (ListDictionary_Count(thread_list) < 1) @@ -399,7 +402,6 @@ HANDLE CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttribu VOID ExitThread(DWORD dwExitCode) { -#if defined(WITH_DEBUG_THREADS) && defined(HAVE_EXECINFO_H) pthread_t tid = pthread_self(); if (NULL == thread_list) @@ -422,12 +424,13 @@ VOID ExitThread(DWORD dwExitCode) ListDictionary_Lock(thread_list); thread = ListDictionary_GetItemValue(thread_list, &tid); assert(thread); + thread->exited = TRUE; + thread->dwExitCode = dwExitCode; +#if defined(WITH_DEBUG_THREADS) && defined(HAVE_EXECINFO_H) backtrace(thread->exit_stack, 20); +#endif ListDictionary_Unlock(thread_list); } - -#endif - fprintf(stderr, "[%s] terminated...\n", __FUNCTION__); } BOOL GetExitCodeThread(HANDLE hThread, LPDWORD lpExitCode) @@ -573,6 +576,7 @@ VOID DumpThreadHandles(void) if (keys) free(keys); + ListDictionary_Unlock(thread_list); } diff --git a/winpr/libwinpr/thread/thread.h b/winpr/libwinpr/thread/thread.h index ea7c5334b..a6f0c3c82 100644 --- a/winpr/libwinpr/thread/thread.h +++ b/winpr/libwinpr/thread/thread.h @@ -28,7 +28,7 @@ #include "../handle/handle.h" -typedef void *(*pthread_start_routine)(void*); +typedef void *(*pthread_start_routine)(void *); struct winpr_thread { @@ -38,6 +38,7 @@ struct winpr_thread int pipe_fd[2]; BOOL mainProcess; BOOL detached; + BOOL exited; DWORD dwExitCode; pthread_t thread; SIZE_T dwStackSize; From f80f5621ac30d8c7c9792e7c96c8860a2eed6db0 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 15 Jul 2014 14:39:34 +0200 Subject: [PATCH 05/18] Fixed thread handle cleanup, checking for resource cleanup now before resetting flags. --- winpr/libwinpr/thread/thread.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/winpr/libwinpr/thread/thread.c b/winpr/libwinpr/thread/thread.c index 79fca5114..a30bcc512 100644 --- a/winpr/libwinpr/thread/thread.c +++ b/winpr/libwinpr/thread/thread.c @@ -247,14 +247,13 @@ static void *thread_launcher(void *arg) } exit: - set_event(thread); - if (!thread->exited) thread->dwExitCode = (DWORD)(size_t)rc; if (thread->detached || !thread->started) cleanup_handle(thread); + set_event(thread); pthread_exit(rc); return rc; } From 8a352c6f636e2b925da06a82e26cad2b884cc73f Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 16 Jul 2014 09:40:59 +0200 Subject: [PATCH 06/18] Fixed thread cleanup, now saving state of started flag, setting event and then cleaning up the thread resources. --- winpr/libwinpr/thread/thread.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/winpr/libwinpr/thread/thread.c b/winpr/libwinpr/thread/thread.c index a30bcc512..47ccd47b0 100644 --- a/winpr/libwinpr/thread/thread.c +++ b/winpr/libwinpr/thread/thread.c @@ -225,6 +225,7 @@ static int thread_compare(void *a, void *b) * in thread function. */ static void *thread_launcher(void *arg) { + BOOL started; void *rc = NULL; WINPR_THREAD *thread = (WINPR_THREAD *)arg; @@ -247,13 +248,16 @@ static void *thread_launcher(void *arg) } exit: + if (!thread->exited) thread->dwExitCode = (DWORD)(size_t)rc; - if (thread->detached || !thread->started) + started = thread->started; + set_event(thread); + + if (thread->detached || !started) cleanup_handle(thread); - set_event(thread); pthread_exit(rc); return rc; } From 56ae60994380d4f56c573ab3803b9d584b65b0d6 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 16 Jul 2014 09:56:30 +0200 Subject: [PATCH 07/18] Removed WaitForSingleObject in reset_event, joining thread when not allowed. --- winpr/libwinpr/thread/thread.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/winpr/libwinpr/thread/thread.c b/winpr/libwinpr/thread/thread.c index 47ccd47b0..6fbd77d56 100644 --- a/winpr/libwinpr/thread/thread.c +++ b/winpr/libwinpr/thread/thread.c @@ -184,31 +184,26 @@ static BOOL reset_event(WINPR_THREAD *thread) { int length; BOOL status = FALSE; - - while (WaitForSingleObject(thread, 0) == WAIT_OBJECT_0) - { #ifdef HAVE_EVENTFD_H - eventfd_t value; + eventfd_t value; - do - { - length = eventfd_read(thread->pipe_fd[0], &value); - } - while ((length < 0) && (errno == EINTR)); + do + { + length = eventfd_read(thread->pipe_fd[0], &value); + } + while ((length < 0) && (errno == EINTR)); - if ((length > 0) && (!status)) - status = TRUE; + if ((length > 0) && (!status)) + status = TRUE; #else - length = read(thread->pipe_fd[0], &length, 1); + length = read(thread->pipe_fd[0], &length, 1); - if ((length == 1) && (!status)) - status = TRUE; + if ((length == 1) && (!status)) + status = TRUE; #endif - } - - thread->started = TRUE; + thread->started = status; return status; } From 5122ce939a305be713ee5e7bd392817dd0265a78 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 16 Jul 2014 11:56:25 +0200 Subject: [PATCH 08/18] Added funcion name to debug messages. Fixed setting of started flag for threads. pthred_exit now used correct return value argument. Return value now also set when terminating thread. --- winpr/libwinpr/thread/thread.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/winpr/libwinpr/thread/thread.c b/winpr/libwinpr/thread/thread.c index 6fbd77d56..3088dc837 100644 --- a/winpr/libwinpr/thread/thread.c +++ b/winpr/libwinpr/thread/thread.c @@ -125,18 +125,18 @@ static void dump_thread(WINPR_THREAD *thread) { #if defined(WITH_DEBUG_THREADS) && defined(HAVE_EXECINFO_H) void *stack[20]; - fprintf(stderr, "Called from:\n"); + fprintf(stderr, "[%s]: Called from:\n", __FUNCTION__); backtrace_symbols_fd(stack, 20, STDERR_FILENO); - fprintf(stderr, "Thread handle created still not closed!\n"); + fprintf(stderr, "[%s]: Thread handle created still not closed!\n", __FUNCTION__); backtrace_symbols_fd(thread->create_stack, 20, STDERR_FILENO); if (thread->started) - fprintf(stderr, "Thread still running!\n"); + fprintf(stderr, "[%s]: Thread still running!\n", __FUNCTION__); else if (!thread->exit_stack) - fprintf(stderr, "Thread suspended.\n"); + fprintf(stderr, "[%s]: Thread suspended.\n", __FUNCTION__); else { - fprintf(stderr, "Thread exited at:\n"); + fprintf(stderr, "[%s]: Thread exited at:\n", __FUNCTION__); backtrace_symbols_fd(thread->exit_stack, 20, STDERR_FILENO); } @@ -176,7 +176,6 @@ static BOOL set_event(WINPR_THREAD *thread) } #endif - thread->started = FALSE; return status; } @@ -203,7 +202,6 @@ static BOOL reset_event(WINPR_THREAD *thread) status = TRUE; #endif - thread->started = status; return status; } @@ -220,7 +218,6 @@ static int thread_compare(void *a, void *b) * in thread function. */ static void *thread_launcher(void *arg) { - BOOL started; void *rc = NULL; WINPR_THREAD *thread = (WINPR_THREAD *)arg; @@ -247,13 +244,12 @@ exit: if (!thread->exited) thread->dwExitCode = (DWORD)(size_t)rc; - started = thread->started; set_event(thread); - if (thread->detached || !started) + if (thread->detached || !thread->started) cleanup_handle(thread); - pthread_exit(rc); + pthread_exit(thread->dwExitCode); return rc; } @@ -271,6 +267,7 @@ static void winpr_StartThread(WINPR_THREAD *thread) reset_event(thread); ListDictionary_Add(thread_list, &thread->thread, thread); dump_thread(thread); + thread->started = TRUE; } HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, @@ -398,7 +395,7 @@ HANDLE CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttribu return NULL; } -VOID ExitThread(DWORD dwExitCode) +VOID _ExitThread(DWORD dwExitCode) { pthread_t tid = pthread_self(); @@ -521,6 +518,7 @@ BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode) return 0; thread = (WINPR_THREAD *) Object; + thread->dwExitCode = dwExitCode; pthread_mutex_lock(&thread->mutex); #ifndef ANDROID pthread_cancel(thread->thread); @@ -538,6 +536,7 @@ VOID DumpThreadHandles(void) #if defined(HAVE_EXECINFO_H) backtrace(stack, 20); #endif + fprintf(stderr, "---------------- %s ----------------------\n", __FUNCTION); fprintf(stderr, "---------------- Called from ----------------------------\n"); #if defined(HAVE_EXECINFO_H) backtrace_symbols_fd(stack, 20, STDERR_FILENO); From c5bb6125c1cc85c2eaebf6aedeaf232c7e1239c4 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 16 Jul 2014 11:58:45 +0200 Subject: [PATCH 09/18] Added additional tests for WaitForSingleObject and WaitForMultipleObjects. --- winpr/libwinpr/synch/test/CMakeLists.txt | 1 + .../synch/test/TestSynchMultipleThreads.c | 154 ++++++++++++++++++ winpr/libwinpr/synch/test/TestSynchThread.c | 74 ++++++++- 3 files changed, 224 insertions(+), 5 deletions(-) create mode 100644 winpr/libwinpr/synch/test/TestSynchMultipleThreads.c diff --git a/winpr/libwinpr/synch/test/CMakeLists.txt b/winpr/libwinpr/synch/test/CMakeLists.txt index 68b76faa0..df6a8ce12 100644 --- a/winpr/libwinpr/synch/test/CMakeLists.txt +++ b/winpr/libwinpr/synch/test/CMakeLists.txt @@ -12,6 +12,7 @@ set(${MODULE_PREFIX}_TESTS TestSynchCritical.c TestSynchSemaphore.c TestSynchThread.c + TestSynchMultipleThreads.c TestSynchTimerQueue.c TestSynchWaitableTimer.c TestSynchWaitableTimerAPC.c) diff --git a/winpr/libwinpr/synch/test/TestSynchMultipleThreads.c b/winpr/libwinpr/synch/test/TestSynchMultipleThreads.c new file mode 100644 index 000000000..3ced1fa48 --- /dev/null +++ b/winpr/libwinpr/synch/test/TestSynchMultipleThreads.c @@ -0,0 +1,154 @@ + +#include + +#include +#include +#include + +static void *test_thread(void *arg) +{ + long timeout = random(); + timeout %= 1000; + timeout += 100; + Sleep(timeout); + ExitThread(0); + return NULL; +} + +static int start_threads(DWORD count, HANDLE *threads) +{ + DWORD i; + + for (i=0; i (WAIT_OBJECT_0 + THREADS))) + { + printf("WaitForMultipleObjects INFINITE failed\n"); + rc = -1; + } + + if (WaitForMultipleObjects(THREADS, threads, TRUE, INFINITE) != WAIT_OBJECT_0) + { + printf("WaitForMultipleObjects bWaitAll, INFINITE failed\n"); + rc = -1; + } + + if (close_threads(THREADS, threads)) + return -1; + + if (rc) + return rc; + + /* WaitOne, timeout */ + if (start_threads(THREADS, threads)) + return -1; + + if (WaitForMultipleObjects(THREADS, threads, FALSE, 50) != WAIT_TIMEOUT) + { + printf("WaitForMultipleObjects timeout 50 failed\n"); + rc = -1; + } + + if (WaitForMultipleObjects(THREADS, threads, TRUE, INFINITE) != WAIT_OBJECT_0) + { + printf("WaitForMultipleObjects bWaitAll, INFINITE failed\n"); + rc = -1; + } + + if (close_threads(THREADS, threads)) + return -1; + + /* WaitOne, timeout, multiple joins */ + if (start_threads(THREADS, threads)) + return -1; + + for (i=0; i Date: Wed, 16 Jul 2014 11:59:26 +0200 Subject: [PATCH 10/18] Error messages now prefixed with function name. Implemented bWaitAll for WaitForMultipleObjects. pthread_join now only called on first wait event, later ones skip this to avoid undefined behavior. --- winpr/libwinpr/synch/wait.c | 512 ++++++++++++++++++++---------------- 1 file changed, 292 insertions(+), 220 deletions(-) diff --git a/winpr/libwinpr/synch/wait.c b/winpr/libwinpr/synch/wait.c index 2f41dc685..5acf99d80 100644 --- a/winpr/libwinpr/synch/wait.c +++ b/winpr/libwinpr/synch/wait.c @@ -93,25 +93,26 @@ int clock_gettime(int clk_id, struct timespec* t) #endif -/* Drop in replacement for the linux pthread_timedjoin_np and - * pthread_mutex_timedlock functions. - */ -#if !defined(HAVE_PTHREAD_GNU_EXT) -#include -static long long ts_difftime(const struct timespec* o, - const struct timespec* n) +static long long ts_difftime(const struct timespec *o, + const struct timespec *n) { long long oldValue = o->tv_sec * 1000000000LL + o->tv_nsec; long long newValue = n->tv_sec * 1000000000LL + n->tv_nsec; return newValue - oldValue; } +/* Drop in replacement for the linux pthread_timedjoin_np and + * pthread_mutex_timedlock functions. + */ +#if !defined(HAVE_PTHREAD_GNU_EXT) +#include + #if defined(__FreeBSD__) /*the only way to get it work is to remove the static*/ -int pthread_mutex_timedlock(pthread_mutex_t* mutex, const struct timespec* timeout) +int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *timeout) #else -static int pthread_mutex_timedlock(pthread_mutex_t* mutex, const struct timespec* timeout) +static int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *timeout) #endif { struct timespec timenow; @@ -199,7 +200,6 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) if (Type == HANDLE_TYPE_THREAD) { - void *thread_status; int status; WINPR_THREAD *thread = (WINPR_THREAD *)Object; status = waitOnFd(thread->pipe_fd[0], dwMilliseconds); @@ -213,21 +213,25 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) if (status != 1) return WAIT_TIMEOUT; - status = pthread_join(thread->thread, &thread_status); - - if (status != 0) + if (!thread->joined) { WLog_ERR(TAG, "pthread_join failure: [%d] %s", status, strerror(status)); } - if (thread_status) - thread->dwExitCode = ((DWORD)(size_t) thread_status); + if (status != 0) + { + fprintf(stderr, "%s: pthread_join failure: [%d] %s\n", __FUNCTION__, + status, strerror(status)); + } + else + thread->joined = TRUE; + } } else if (Type == HANDLE_TYPE_PROCESS) { - WINPR_PROCESS* process; - process = (WINPR_PROCESS*) Object; + WINPR_PROCESS *process; + process = (WINPR_PROCESS *) Object; if (waitpid(process->pid, &(process->status), 0) != -1) { @@ -239,8 +243,8 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) } else if (Type == HANDLE_TYPE_MUTEX) { - WINPR_MUTEX* mutex; - mutex = (WINPR_MUTEX*) Object; + WINPR_MUTEX *mutex; + mutex = (WINPR_MUTEX *) Object; if (dwMilliseconds != INFINITE) { @@ -261,9 +265,8 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) else if (Type == HANDLE_TYPE_EVENT) { int status; - WINPR_EVENT* event; - event = (WINPR_EVENT*) Object; - + WINPR_EVENT *event; + event = (WINPR_EVENT *) Object; status = waitOnFd(event->pipe_fd[0], dwMilliseconds); if (status < 0) @@ -277,8 +280,8 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) } else if (Type == HANDLE_TYPE_SEMAPHORE) { - WINPR_SEMAPHORE* semaphore; - semaphore = (WINPR_SEMAPHORE*) Object; + WINPR_SEMAPHORE *semaphore; + semaphore = (WINPR_SEMAPHORE *) Object; #ifdef WINPR_PIPE_SEMAPHORE if (semaphore->pipe_fd[0] != -1) @@ -307,16 +310,16 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) #else #if defined __APPLE__ - semaphore_wait(*((winpr_sem_t*) semaphore->sem)); + semaphore_wait(*((winpr_sem_t *) semaphore->sem)); #else - sem_wait((winpr_sem_t*) semaphore->sem); + sem_wait((winpr_sem_t *) semaphore->sem); #endif #endif } else if (Type == HANDLE_TYPE_TIMER) { - WINPR_TIMER* timer; - timer = (WINPR_TIMER*) Object; + WINPR_TIMER *timer; + timer = (WINPR_TIMER *) Object; #ifdef HAVE_EVENTFD_H if (timer->fd != -1) @@ -334,7 +337,7 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) if (status != 1) return WAIT_TIMEOUT; - status = read(timer->fd, (void*) &expirations, sizeof(UINT64)); + status = read(timer->fd, (void *) &expirations, sizeof(UINT64)); if (status != 8) { @@ -368,7 +371,7 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) { int fd; int status; - WINPR_NAMED_PIPE* pipe = (WINPR_NAMED_PIPE*) Object; + WINPR_NAMED_PIPE *pipe = (WINPR_NAMED_PIPE *) Object; fd = (pipe->ServerMode) ? pipe->serverfd : pipe->clientfd; if (fd == -1) @@ -407,8 +410,15 @@ DWORD WaitForSingleObjectEx(HANDLE hHandle, DWORD dwMilliseconds, BOOL bAlertabl #define MAXIMUM_WAIT_OBJECTS 64 -DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAll, DWORD dwMilliseconds) +DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAll, DWORD dwMilliseconds) { + struct timespec starttime; + struct timespec timenow; + unsigned long long diff; + DWORD signalled; + DWORD polled; + DWORD *poll_map; + BOOL *signalled_idx; int fd = -1; int index; int status; @@ -428,235 +438,297 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl return WAIT_FAILED; } -#ifdef HAVE_POLL_H - pollfds = alloca(nCount * sizeof(struct pollfd)); -#else - maxfd = 0; - FD_ZERO(&fds); - ZeroMemory(&timeout, sizeof(timeout)); -#endif - if (bWaitAll) { - WLog_ERR(TAG, "bWaitAll not yet implemented"); - assert(0); + signalled_idx = alloca(nCount * sizeof(BOOL)); + memset(signalled_idx, FALSE, nCount * sizeof(BOOL)); + poll_map = alloca(nCount * sizeof(DWORD)); + memset(poll_map, 0, nCount * sizeof(DWORD)); } - for (index = 0; index < nCount; index++) +#ifdef HAVE_POLL_H + pollfds = alloca(nCount * sizeof(struct pollfd)); +#endif + signalled = 0; + + do { - if (!winpr_Handle_GetInfo(lpHandles[index], &Type, &Object)) - { - WLog_ERR(TAG, "invalid handle"); - return WAIT_FAILED; - } + if (bWaitAll && (dwMilliseconds != INFINITE)) + clock_gettime(CLOCK_MONOTONIC, &starttime); - if (Type == HANDLE_TYPE_EVENT) - { - fd = ((WINPR_EVENT*) Object)->pipe_fd[0]; +#ifndef HAVE_POLL_H + maxfd = 0; + FD_ZERO(&fds); + ZeroMemory(&timeout, sizeof(timeout)); +#endif + polled = (bWaitAll) ? 0 : nCount; - if (fd == -1) + for (index = 0; index < nCount; index++) + { + if (bWaitAll) + { + if (signalled_idx[index]) + continue; + + poll_map[polled++] = index; + } + + if (!winpr_Handle_GetInfo(lpHandles[index], &Type, &Object)) { WLog_ERR(TAG, "invalid event file descriptor"); return WAIT_FAILED; } - } - else if (Type == HANDLE_TYPE_SEMAPHORE) - { + + if (Type == HANDLE_TYPE_EVENT) + { + fd = ((WINPR_EVENT *) Object)->pipe_fd[0]; + + if (fd == -1) + { + fprintf(stderr, "%s: invalid event file descriptor\n", __FUNCTION__); + return WAIT_FAILED; + } + } + else if (Type == HANDLE_TYPE_SEMAPHORE) + { #ifdef WINPR_PIPE_SEMAPHORE - fd = ((WINPR_SEMAPHORE*) Object)->pipe_fd[0]; + fd = ((WINPR_SEMAPHORE *) Object)->pipe_fd[0]; #else WLog_ERR(TAG, "semaphore not supported"); return WAIT_FAILED; #endif - } - else if (Type == HANDLE_TYPE_TIMER) - { - WINPR_TIMER* timer = (WINPR_TIMER*) Object; - fd = timer->fd; - - if (fd == -1) - { - WLog_ERR(TAG, "invalid timer file descriptor"); - return WAIT_FAILED; - } - } - else if (Type == HANDLE_TYPE_THREAD) - { - WINPR_THREAD *thread = (WINPR_THREAD *) Object; - fd = thread->pipe_fd[0]; - - if (fd == -1) - { - WLog_ERR(TAG, "invalid thread file descriptor"); - return WAIT_FAILED; - } - } - else if (Type == HANDLE_TYPE_NAMED_PIPE) - { - WINPR_NAMED_PIPE* pipe = (WINPR_NAMED_PIPE*) Object; - fd = (pipe->ServerMode) ? pipe->serverfd : pipe->clientfd; - - if (fd == -1) - { - WLog_ERR(TAG, "invalid timer file descriptor"); - return WAIT_FAILED; - } - } - else - { - WLog_ERR(TAG, "unknown handle type %d", (int) Type); - return WAIT_FAILED; - } - - if (fd == -1) - { - WLog_ERR(TAG, "invalid file descriptor"); - return WAIT_FAILED; - } - -#ifdef HAVE_POLL_H - pollfds[index].fd = fd; - pollfds[index].events = POLLIN; - pollfds[index].revents = 0; -#else - FD_SET(fd, &fds); - - if (fd > maxfd) - maxfd = fd; - -#endif - } - -#ifdef HAVE_POLL_H - - do - { - status = poll(pollfds, nCount, dwMilliseconds); - } - while (status < 0 && errno == EINTR); - -#else - - if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0)) - { - timeout.tv_sec = dwMilliseconds / 1000; - timeout.tv_usec = (dwMilliseconds % 1000) * 1000; - } - - do - { - status = select(maxfd + 1, &fds, 0, 0, - (dwMilliseconds == INFINITE) ? NULL : &timeout); - } - while (status < 0 && errno == EINTR); - -#endif - - if (status < 0) - { - WLog_ERR(TAG, "select() failure [%d] %s", errno, strerror(errno)); - return WAIT_FAILED; - } - - if (status == 0) - return WAIT_TIMEOUT; - - for (index = 0; index < nCount; index++) - { - winpr_Handle_GetInfo(lpHandles[index], &Type, &Object); - - if (Type == HANDLE_TYPE_EVENT) - { - fd = ((WINPR_EVENT*) Object)->pipe_fd[0]; - } - else if (Type == HANDLE_TYPE_SEMAPHORE) - { - fd = ((WINPR_SEMAPHORE*) Object)->pipe_fd[0]; - } - else if (Type == HANDLE_TYPE_TIMER) - { - WINPR_TIMER* timer = (WINPR_TIMER*) Object; - fd = timer->fd; - } - else if (Type == HANDLE_TYPE_THREAD) - { - WINPR_THREAD *thread = (WINPR_THREAD *) Object; - fd = thread->pipe_fd[0]; - } - else if (Type == HANDLE_TYPE_NAMED_PIPE) - { - WINPR_NAMED_PIPE* pipe = (WINPR_NAMED_PIPE*) Object; - fd = (pipe->ServerMode) ? pipe->serverfd : pipe->clientfd; - } - -#ifdef HAVE_POLL_H - - if (pollfds[index].revents & POLLIN) -#else - if (FD_ISSET(fd, &fds)) -#endif - { - if (Type == HANDLE_TYPE_SEMAPHORE) - { - int length; - length = read(fd, &length, 1); - - if (length != 1) - { - WLog_ERR(TAG, "semaphore read() failure [%d] %s", errno, strerror(errno)); - return WAIT_FAILED; - } } else if (Type == HANDLE_TYPE_TIMER) { - int length; - UINT64 expirations; - length = read(fd, (void*) &expirations, sizeof(UINT64)); + WINPR_TIMER *timer = (WINPR_TIMER *) Object; + fd = timer->fd; - if (length != 8) + if (fd == -1) { - if (length == -1) - { - if (errno == ETIMEDOUT) - return WAIT_TIMEOUT; - - WLog_ERR(TAG, "timer read() failure [%d] %s", errno, strerror(errno)); - } - else - { - WLog_ERR(TAG, "timer read() failure - incorrect number of bytes read"); - } - + fprintf(stderr, "%s: invalid timer file descriptor\n", __FUNCTION__); return WAIT_FAILED; } } else if (Type == HANDLE_TYPE_THREAD) { - void *thread_status; - int status; - WINPR_THREAD *thread = (WINPR_THREAD *)Object; - status = pthread_join(thread->thread, &thread_status); + WINPR_THREAD *thread = (WINPR_THREAD *) Object; + fd = thread->pipe_fd[0]; - if (status != 0) + if (fd == -1) { - WLog_ERR(TAG, " pthread_join failure: [%d] %s", - status, strerror(status)); + fprintf(stderr, "%s: invalid thread file descriptor\n", __FUNCTION__); return WAIT_FAILED; } + } + else if (Type == HANDLE_TYPE_NAMED_PIPE) + { + WINPR_NAMED_PIPE *pipe = (WINPR_NAMED_PIPE *) Object; + fd = (pipe->ServerMode) ? pipe->serverfd : pipe->clientfd; - if (thread_status) - thread->dwExitCode = ((DWORD)(size_t) thread_status); + if (fd == -1) + { + fprintf(stderr, "%s: invalid timer file descriptor\n", __FUNCTION__); + return WAIT_FAILED; + } + } + else + { + fprintf(stderr, "%s: unknown handle type %d\n", __FUNCTION__, (int) Type); + return WAIT_FAILED; } - return (WAIT_OBJECT_0 + index); + if (fd == -1) + { + fprintf(stderr, "%s: invalid file descriptor\n", __FUNCTION__); + return WAIT_FAILED; + } + +#ifdef HAVE_POLL_H + pollfds[index].fd = fd; + pollfds[index].events = POLLIN; + pollfds[index].revents = 0; +#else + FD_SET(fd, &fds); + + if (fd > maxfd) + maxfd = fd; + +#endif + } + +#ifdef HAVE_POLL_H + + do + { + status = poll(pollfds, nCount, dwMilliseconds); + } + while (status < 0 && errno == EINTR); + +#else + + if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0)) + { + timeout.tv_sec = dwMilliseconds / 1000; + timeout.tv_usec = (dwMilliseconds % 1000) * 1000; + } + + do + { + status = select(maxfd + 1, &fds, 0, 0, + (dwMilliseconds == INFINITE) ? NULL : &timeout); + } + while (status < 0 && errno == EINTR); + +#endif + + if (status < 0) + { +#ifdef HAVE_POLL_H + fprintf(stderr, "%s: poll() failure [%d] %s\n", __FUNCTION__, errno, + strerror(errno)); +#else + fprintf(stderr, "%s: select() failure [%d] %s\n", __FUNCTION__, errno, + strerror(errno)); +#endif + return WAIT_FAILED; + } + + if (status == 0) + return WAIT_TIMEOUT; + + if (bWaitAll && (dwMilliseconds != INFINITE)) + { + clock_gettime(CLOCK_MONOTONIC, &timenow); + diff = ts_difftime(&timenow, &starttime); + + if (diff / 1000 > dwMilliseconds) + return WAIT_TIMEOUT; + else + dwMilliseconds -= (diff / 1000); + } + + for (index = 0; index < polled; index++) + { + DWORD idx; + + if (bWaitAll) + idx = poll_map[index]; + else + idx = index; + + winpr_Handle_GetInfo(lpHandles[idx], &Type, &Object); + + if (Type == HANDLE_TYPE_EVENT) + { + fd = ((WINPR_EVENT *) Object)->pipe_fd[0]; + } + else if (Type == HANDLE_TYPE_SEMAPHORE) + { + fd = ((WINPR_SEMAPHORE *) Object)->pipe_fd[0]; + } + else if (Type == HANDLE_TYPE_TIMER) + { + WINPR_TIMER *timer = (WINPR_TIMER *) Object; + fd = timer->fd; + } + else if (Type == HANDLE_TYPE_THREAD) + { + WINPR_THREAD *thread = (WINPR_THREAD *) Object; + fd = thread->pipe_fd[0]; + } + else if (Type == HANDLE_TYPE_NAMED_PIPE) + { + WINPR_NAMED_PIPE *pipe = (WINPR_NAMED_PIPE *) Object; + fd = (pipe->ServerMode) ? pipe->serverfd : pipe->clientfd; + } + +#ifdef HAVE_POLL_H + + if (pollfds[index].revents & POLLIN) +#else + if (FD_ISSET(fd, &fds)) +#endif + { + if (Type == HANDLE_TYPE_SEMAPHORE) + { + int length; + length = read(fd, &length, 1); + + if (length != 1) + { + fprintf(stderr, "%s: semaphore read() failure [%d] %s\n", __FUNCTION__, errno, strerror(errno)); + return WAIT_FAILED; + } + } + else if (Type == HANDLE_TYPE_TIMER) + { + int length; + UINT64 expirations; + length = read(fd, (void *) &expirations, sizeof(UINT64)); + + if (length != 8) + { + if (length == -1) + { + if (errno == ETIMEDOUT) + return WAIT_TIMEOUT; + + fprintf(stderr, "%s: timer read() failure [%d] %s\n", __FUNCTION__, errno, strerror(errno)); + } + else + { + fprintf(stderr, "%s: timer read() failure - incorrect number of bytes read", __FUNCTION__); + } + + return WAIT_FAILED; + } + } + else if (Type == HANDLE_TYPE_THREAD) + { + WINPR_THREAD *thread = (WINPR_THREAD *)Object; + + if (!thread->joined) + { + int status; + status = pthread_join(thread->thread, NULL); + if (status != 0) + { + fprintf(stderr, "%s: pthread_join failure: [%d] %s\n", + __FUNCTION__, status, strerror(status)); + return WAIT_FAILED; + } + else + thread->joined = TRUE; + } + } + + if (bWaitAll) + { + signalled_idx[idx] = TRUE; + + /* Continue checks from last position. */ + for (; signalled < nCount; signalled++) + { + if (!signalled_idx[signalled]) + break; + } + } + + if (!bWaitAll) + return (WAIT_OBJECT_0 + index); + + if (bWaitAll && (signalled >= nCount)) + return (WAIT_OBJECT_0); + } } } + while (bWaitAll); WLog_ERR(TAG, "failed (unknown error)"); return WAIT_FAILED; } -DWORD WaitForMultipleObjectsEx(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAll, DWORD dwMilliseconds, BOOL bAlertable) +DWORD WaitForMultipleObjectsEx(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAll, DWORD dwMilliseconds, BOOL bAlertable) { WLog_ERR(TAG, "[ERROR] %s: Function not implemented."); assert(0); From 7ef2bd3ca089ba3730cc77b6d4cc9a67fab1bed3 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 16 Jul 2014 12:01:18 +0200 Subject: [PATCH 11/18] Added joined flag. --- winpr/libwinpr/thread/thread.h | 1 + 1 file changed, 1 insertion(+) diff --git a/winpr/libwinpr/thread/thread.h b/winpr/libwinpr/thread/thread.h index a6f0c3c82..cd16c7af7 100644 --- a/winpr/libwinpr/thread/thread.h +++ b/winpr/libwinpr/thread/thread.h @@ -38,6 +38,7 @@ struct winpr_thread int pipe_fd[2]; BOOL mainProcess; BOOL detached; + BOOL joined; BOOL exited; DWORD dwExitCode; pthread_t thread; From 02a4d77da110568fe6dc2b8bcad8d86b588dacda Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 16 Jul 2014 12:01:58 +0200 Subject: [PATCH 12/18] Setting exited flag in TerminateThread now to allow setting return code. --- winpr/libwinpr/thread/thread.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/winpr/libwinpr/thread/thread.c b/winpr/libwinpr/thread/thread.c index 3088dc837..e3ed52470 100644 --- a/winpr/libwinpr/thread/thread.c +++ b/winpr/libwinpr/thread/thread.c @@ -395,7 +395,7 @@ HANDLE CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttribu return NULL; } -VOID _ExitThread(DWORD dwExitCode) +VOID ExitThread(DWORD dwExitCode) { pthread_t tid = pthread_self(); @@ -518,7 +518,8 @@ BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode) return 0; thread = (WINPR_THREAD *) Object; - thread->dwExitCode = dwExitCode; + thread->exited = TRUE; + thread->dwExitCode = dwExitCode; pthread_mutex_lock(&thread->mutex); #ifndef ANDROID pthread_cancel(thread->thread); From c6ed95d1bfbb4895528f6972c15bde0e03305e86 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 16 Jul 2014 12:03:46 +0200 Subject: [PATCH 13/18] Fixed typo --- winpr/libwinpr/synch/test/TestSynchThread.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winpr/libwinpr/synch/test/TestSynchThread.c b/winpr/libwinpr/synch/test/TestSynchThread.c index 9fde1de48..74a412ef7 100644 --- a/winpr/libwinpr/synch/test/TestSynchThread.c +++ b/winpr/libwinpr/synch/test/TestSynchThread.c @@ -98,7 +98,7 @@ int TestSynchThread(int argc, char *argv[]) return -1; } - /* Thread detach test */i + /* Thread detach test */ thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)test_thread, NULL, 0, NULL); From a6eff65259f6e1b7554bc88079019ad0fdac461b Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 16 Jul 2014 12:08:34 +0200 Subject: [PATCH 14/18] Fixed ExitThread, now running pthread_exit and setting event. --- winpr/include/winpr/thread.h | 2 +- winpr/libwinpr/thread/thread.c | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/winpr/include/winpr/thread.h b/winpr/include/winpr/thread.h index 83a398c88..54e9e192e 100644 --- a/winpr/include/winpr/thread.h +++ b/winpr/include/winpr/thread.h @@ -163,7 +163,7 @@ WINPR_API HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T d WINPR_API HANDLE CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId); -WINPR_API VOID ExitThread(DWORD dwExitCode); +WINPR_API DECLSPEC_NORETURN VOID ExitThread(DWORD dwExitCode); WINPR_API BOOL GetExitCodeThread(HANDLE hThread, LPDWORD lpExitCode); WINPR_API HANDLE _GetCurrentThread(void); diff --git a/winpr/libwinpr/thread/thread.c b/winpr/libwinpr/thread/thread.c index e3ed52470..5c287dc1f 100644 --- a/winpr/libwinpr/thread/thread.c +++ b/winpr/libwinpr/thread/thread.c @@ -425,6 +425,12 @@ VOID ExitThread(DWORD dwExitCode) backtrace(thread->exit_stack, 20); #endif ListDictionary_Unlock(thread_list); + set_event(thread); + + if (thread->detached || !thread->started) + cleanup_handle(thread); + + pthread_exit(thread->dwExitCode); } } @@ -537,7 +543,7 @@ VOID DumpThreadHandles(void) #if defined(HAVE_EXECINFO_H) backtrace(stack, 20); #endif - fprintf(stderr, "---------------- %s ----------------------\n", __FUNCTION); + fprintf(stderr, "---------------- %s ----------------------\n", __FUNCTION); fprintf(stderr, "---------------- Called from ----------------------------\n"); #if defined(HAVE_EXECINFO_H) backtrace_symbols_fd(stack, 20, STDERR_FILENO); From 8f98f28ce8d9f905937ede54a280ddad79a8aa13 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 27 Oct 2014 11:39:02 +0100 Subject: [PATCH 15/18] Fixed merge errors. --- winpr/libwinpr/synch/wait.c | 46 +++++----- winpr/libwinpr/thread/thread.c | 149 ++++++++++++++++++++------------- 2 files changed, 114 insertions(+), 81 deletions(-) diff --git a/winpr/libwinpr/synch/wait.c b/winpr/libwinpr/synch/wait.c index 5acf99d80..ac53ac38b 100644 --- a/winpr/libwinpr/synch/wait.c +++ b/winpr/libwinpr/synch/wait.c @@ -215,13 +215,11 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) if (!thread->joined) { - WLog_ERR(TAG, "pthread_join failure: [%d] %s", - status, strerror(status)); - } + status = pthread_join(thread->thread, NULL); if (status != 0) { - fprintf(stderr, "%s: pthread_join failure: [%d] %s\n", __FUNCTION__, + WLog_ERR(TAG, "pthread_join failure: [%d] %s", status, strerror(status)); } else @@ -461,7 +459,7 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl FD_ZERO(&fds); ZeroMemory(&timeout, sizeof(timeout)); #endif - polled = (bWaitAll) ? 0 : nCount; + polled = 0; for (index = 0; index < nCount; index++) { @@ -470,7 +468,7 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl if (signalled_idx[index]) continue; - poll_map[polled++] = index; + poll_map[polled] = index; } if (!winpr_Handle_GetInfo(lpHandles[index], &Type, &Object)) @@ -485,7 +483,7 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl if (fd == -1) { - fprintf(stderr, "%s: invalid event file descriptor\n", __FUNCTION__); + WLog_ERR(TAG, "invalid event file descriptor"); return WAIT_FAILED; } } @@ -505,7 +503,7 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl if (fd == -1) { - fprintf(stderr, "%s: invalid timer file descriptor\n", __FUNCTION__); + WLog_ERR(TAG, "invalid timer file descriptor"); return WAIT_FAILED; } } @@ -516,7 +514,7 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl if (fd == -1) { - fprintf(stderr, "%s: invalid thread file descriptor\n", __FUNCTION__); + WLog_ERR(TAG, "invalid thread file descriptor"); return WAIT_FAILED; } } @@ -527,26 +525,26 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl if (fd == -1) { - fprintf(stderr, "%s: invalid timer file descriptor\n", __FUNCTION__); + WLog_ERR(TAG, "invalid timer file descriptor"); return WAIT_FAILED; } } else { - fprintf(stderr, "%s: unknown handle type %d\n", __FUNCTION__, (int) Type); + WLog_ERR(TAG, "unknown handle type %d", (int) Type); return WAIT_FAILED; } if (fd == -1) { - fprintf(stderr, "%s: invalid file descriptor\n", __FUNCTION__); + WLog_ERR(TAG, "invalid file descriptor"); return WAIT_FAILED; } #ifdef HAVE_POLL_H - pollfds[index].fd = fd; - pollfds[index].events = POLLIN; - pollfds[index].revents = 0; + pollfds[polled].fd = fd; + pollfds[polled].events = POLLIN; + pollfds[polled].revents = 0; #else FD_SET(fd, &fds); @@ -554,13 +552,14 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl maxfd = fd; #endif + polled++; } #ifdef HAVE_POLL_H do { - status = poll(pollfds, nCount, dwMilliseconds); + status = poll(pollfds, polled, dwMilliseconds); } while (status < 0 && errno == EINTR); @@ -584,10 +583,10 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl if (status < 0) { #ifdef HAVE_POLL_H - fprintf(stderr, "%s: poll() failure [%d] %s\n", __FUNCTION__, errno, + WLog_ERR(TAG, "poll() failure [%d] %s", errno, strerror(errno)); #else - fprintf(stderr, "%s: select() failure [%d] %s\n", __FUNCTION__, errno, + WLog_ERR(TAG, "select() failure [%d] %s", errno, strerror(errno)); #endif return WAIT_FAILED; @@ -656,7 +655,7 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl if (length != 1) { - fprintf(stderr, "%s: semaphore read() failure [%d] %s\n", __FUNCTION__, errno, strerror(errno)); + WLog_ERR(TAG, "semaphore read() failure [%d] %s", errno, strerror(errno)); return WAIT_FAILED; } } @@ -673,11 +672,11 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl if (errno == ETIMEDOUT) return WAIT_TIMEOUT; - fprintf(stderr, "%s: timer read() failure [%d] %s\n", __FUNCTION__, errno, strerror(errno)); + WLog_ERR(TAG, "timer read() failure [%d] %s", errno, strerror(errno)); } else { - fprintf(stderr, "%s: timer read() failure - incorrect number of bytes read", __FUNCTION__); + WLog_ERR(TAG, "timer read() failure - incorrect number of bytes read"); } return WAIT_FAILED; @@ -691,10 +690,11 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl { int status; status = pthread_join(thread->thread, NULL); + if (status != 0) { - fprintf(stderr, "%s: pthread_join failure: [%d] %s\n", - __FUNCTION__, status, strerror(status)); + WLog_ERR(TAG, "pthread_join failure: [%d] %s", + status, strerror(status)); return WAIT_FAILED; } else diff --git a/winpr/libwinpr/thread/thread.c b/winpr/libwinpr/thread/thread.c index 5c287dc1f..a85e272d0 100644 --- a/winpr/libwinpr/thread/thread.c +++ b/winpr/libwinpr/thread/thread.c @@ -80,9 +80,7 @@ #include #endif -#ifdef HAVE_EXECINFO_H -#include -#endif +#include #include @@ -121,23 +119,41 @@ static void ThreadInitialize(void) RegisterHandleCloseCb(&_ThreadHandleCloseCb); } -static void dump_thread(WINPR_THREAD *thread) +static void dump_thread(WINPR_THREAD* thread) { -#if defined(WITH_DEBUG_THREADS) && defined(HAVE_EXECINFO_H) - void *stack[20]; - fprintf(stderr, "[%s]: Called from:\n", __FUNCTION__); - backtrace_symbols_fd(stack, 20, STDERR_FILENO); - fprintf(stderr, "[%s]: Thread handle created still not closed!\n", __FUNCTION__); - backtrace_symbols_fd(thread->create_stack, 20, STDERR_FILENO); +#if defined(WITH_DEBUG_THREADS) + void* stack = winpr_backtrace(20); + char** msg; + size_t used, i; + WLog_DBG(TAG, "Called from:"); + msg = winpr_backtrace_symbols(stack, &used); + + for (i=0; icreate_stack, &used); + + for (i=0; istarted) - fprintf(stderr, "[%s]: Thread still running!\n", __FUNCTION__); + WLog_DBG(TAG, "Thread still running!"); else if (!thread->exit_stack) - fprintf(stderr, "[%s]: Thread suspended.\n", __FUNCTION__); + WLog_DBG(TAG, "Thread suspended."); else { - fprintf(stderr, "[%s]: Thread exited at:\n", __FUNCTION__); - backtrace_symbols_fd(thread->exit_stack, 20, STDERR_FILENO); + WLog_DBG(TAG, "Thread exited at:"); + msg = winpr_backtrace_symbols(thread->exit_stack, &used); + + for (i=0; ilpParameter = lpParameter; thread->lpStartAddress = lpStartAddress; thread->lpThreadAttributes = lpThreadAttributes; -#if defined(WITH_DEBUG_THREADS) && defined(HAVE_EXECINFO_H) - backtrace(thread->create_stack, 20); +#if defined(WITH_DEBUG_THREADS) + thread->create_stack = winpr_backtrace(20); dump_thread(thread); #endif #ifdef HAVE_EVENTFD_H @@ -294,7 +310,7 @@ HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize if (thread->pipe_fd[0] < 0) { - fprintf(stderr, "[%s]: failed to create thread\n", __FUNCTION__); + WLog_ERR(TAG, "failed to create thread"); free(thread); return NULL; } @@ -303,7 +319,7 @@ HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize if (pipe(thread->pipe_fd) < 0) { - fprintf(stderr, "[%s]: failed to create thread\n", __FUNCTION__); + WLog_ERR(TAG, "failed to create thread"); free(thread); return NULL; } @@ -333,8 +349,8 @@ void cleanup_handle(void *obj) int rc = pthread_mutex_destroy(&thread->mutex); if (rc) - fprintf(stderr, "[%s]: failed to destroy mutex [%d] %s (%d)\n", - __FUNCTION__, rc, strerror(errno), errno); + WLog_ERR(TAG, "failed to destroy mutex [%d] %s (%d)", + rc, strerror(errno), errno); if (thread->pipe_fd[0]) close(thread->pipe_fd[0]); @@ -345,6 +361,15 @@ void cleanup_handle(void *obj) if (thread_list && ListDictionary_Contains(thread_list, &thread->thread)) ListDictionary_Remove(thread_list, &thread->thread); +#if defined(WITH_DEBUG_THREADS) + + if (thread->create_stack) + winpr_backtrace_free(thread->create_stack); + + if (thread->exit_stack) + winpr_backtrace_free(thread->exit_stack); + +#endif free(thread); } @@ -354,12 +379,12 @@ BOOL ThreadCloseHandle(HANDLE handle) if (!thread_list) { - fprintf(stderr, "[%s]: Thread list does not exist, check call!\n", __FUNCTION__); + WLog_ERR(TAG, "Thread list does not exist, check call!"); dump_thread(thread); } else if (!ListDictionary_Contains(thread_list, &thread->thread)) { - fprintf(stderr, "[%s]: Thread list does not contain this thread! check call!\n", __FUNCTION__); + WLog_ERR(TAG, "Thread list does not contain this thread! check call!"); dump_thread(thread); } else @@ -369,7 +394,7 @@ BOOL ThreadCloseHandle(HANDLE handle) if ((thread->started) && (WaitForSingleObject(thread, 0) != WAIT_OBJECT_0)) { - fprintf(stderr, "[%s]: Thread running, setting to detached state!\n", __FUNCTION__); + WLog_ERR(TAG, "Thread running, setting to detached state!"); thread->detached = TRUE; pthread_detach(thread->thread); } @@ -391,7 +416,7 @@ BOOL ThreadCloseHandle(HANDLE handle) HANDLE CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId) { - fprintf(stderr, "[%s]: not implemented\n", __FUNCTION__); + WLog_ERR(TAG, "not implemented"); return NULL; } @@ -401,14 +426,14 @@ VOID ExitThread(DWORD dwExitCode) if (NULL == thread_list) { - fprintf(stderr, "[%s]: function called without existing thread list!\n", __FUNCTION__); + WLog_ERR(TAG, "function called without existing thread list!"); #if defined(WITH_DEBUG_THREADS) DumpThreadHandles(); #endif } else if (!ListDictionary_Contains(thread_list, &tid)) { - fprintf(stderr, "[%s]: function called, but no matching entry in thread list!\n", __FUNCTION__); + WLog_ERR(TAG, "function called, but no matching entry in thread list!"); #if defined(WITH_DEBUG_THREADS) DumpThreadHandles(); #endif @@ -421,8 +446,8 @@ VOID ExitThread(DWORD dwExitCode) assert(thread); thread->exited = TRUE; thread->dwExitCode = dwExitCode; -#if defined(WITH_DEBUG_THREADS) && defined(HAVE_EXECINFO_H) - backtrace(thread->exit_stack, 20); +#if defined(WITH_DEBUG_THREADS) + thread->exit_stack = winpr_backtrace(20); #endif ListDictionary_Unlock(thread_list); set_event(thread); @@ -455,14 +480,14 @@ HANDLE _GetCurrentThread(VOID) if (NULL == thread_list) { - fprintf(stderr, "[%s]: function called without existing thread list!\n", __FUNCTION__); + WLog_ERR(TAG, "function called without existing thread list!"); #if defined(WITH_DEBUG_THREADS) DumpThreadHandles(); #endif } else if (!ListDictionary_Contains(thread_list, &tid)) { - fprintf(stderr, "[%s]: function called, but no matching entry in thread list!\n", __FUNCTION__); + WLog_ERR(TAG, "function called, but no matching entry in thread list!"); #if defined(WITH_DEBUG_THREADS) DumpThreadHandles(); #endif @@ -497,7 +522,7 @@ DWORD ResumeThread(HANDLE hThread) if (!thread->started) winpr_StartThread(thread); else - fprintf(stderr, "[%s]: Thread already started!\n", __FUNCTION__); + WLog_WARN(TAG, "Thread already started!"); pthread_mutex_unlock(&thread->mutex); return 0; @@ -505,7 +530,7 @@ DWORD ResumeThread(HANDLE hThread) DWORD SuspendThread(HANDLE hThread) { - fprintf(stderr, "[%s]: Function not implemented!\n", __FUNCTION__); + WLog_ERR(TAG, "Function not implemented!"); return 0; } @@ -530,7 +555,7 @@ BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode) #ifndef ANDROID pthread_cancel(thread->thread); #else - fprintf(stderr, "[%s]: Function not supported on this platform!\n", __FUNCTION__); + WLog_ERR(TAG, "Function not supported on this platform!"); #endif pthread_mutex_unlock(&thread->mutex); return TRUE; @@ -539,42 +564,50 @@ BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode) #if defined(WITH_DEBUG_THREADS) VOID DumpThreadHandles(void) { - void *stack[20]; -#if defined(HAVE_EXECINFO_H) - backtrace(stack, 20); -#endif - fprintf(stderr, "---------------- %s ----------------------\n", __FUNCTION); - fprintf(stderr, "---------------- Called from ----------------------------\n"); -#if defined(HAVE_EXECINFO_H) - backtrace_symbols_fd(stack, 20, STDERR_FILENO); -#endif - fprintf(stderr, "---------------- Start Dumping thread handles -----------\n"); + char** msg; + size_t used, i; + void* stack = winpr_backtrace(20); + WLog_DBG(TAG, "---------------- Called from ----------------------------"); + msg = winpr_backtrace_symbols(stack, &used); + + for (i=0; icreate_stack, 20, STDERR_FILENO); -#endif + WINPR_THREAD* thread = ListDictionary_GetItemValue(thread_list, (void*)keys[x]); + WLog_DBG(TAG, "Thread [%d] handle created still not closed!", x); + msg = winpr_backtrace_symbols(thread->create_stack, &used); + + for (i=0; istarted) - fprintf(stderr, "Thread [%d] still running!\n", x); + WLog_DBG(TAG, "Thread [%d] still running!", x); else { - fprintf(stderr, "Thread [%d] exited at:\n", x); -#if defined(HAVE_EXECINFO_H) - backtrace_symbols_fd(thread->exit_stack, 20, STDERR_FILENO); -#endif + WLog_DBG(TAG, "Thread [%d] exited at:", x); + msg = winpr_backtrace_symbols(thread->exit_stack, &used); + + for (i=0; i Date: Mon, 27 Oct 2014 11:45:39 +0100 Subject: [PATCH 16/18] Fixed missing includes and typo. --- winpr/libwinpr/synch/wait.c | 2 +- winpr/libwinpr/thread/thread.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/winpr/libwinpr/synch/wait.c b/winpr/libwinpr/synch/wait.c index ac53ac38b..d53535f26 100644 --- a/winpr/libwinpr/synch/wait.c +++ b/winpr/libwinpr/synch/wait.c @@ -209,7 +209,7 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) WLog_ERR(TAG, "waitOnFd() failure [%d] %s", errno, strerror(errno)); return WAIT_FAILED; } -> + if (status != 1) return WAIT_TIMEOUT; diff --git a/winpr/libwinpr/thread/thread.c b/winpr/libwinpr/thread/thread.c index a85e272d0..b9107f7bd 100644 --- a/winpr/libwinpr/thread/thread.c +++ b/winpr/libwinpr/thread/thread.c @@ -89,6 +89,8 @@ #include "thread.h" #include "../handle/handle.h" +#include "../log.h" +#define TAG WINPR_TAG("thread") static pthread_once_t thread_initialized = PTHREAD_ONCE_INIT; From 017e4a323e5113348b408468844e50b150c23cd9 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 3 Nov 2014 09:29:35 +0100 Subject: [PATCH 17/18] Locking thread until joined now, preventing multiple joins and race conditions. --- winpr/libwinpr/synch/wait.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/winpr/libwinpr/synch/wait.c b/winpr/libwinpr/synch/wait.c index d53535f26..630fc4cbc 100644 --- a/winpr/libwinpr/synch/wait.c +++ b/winpr/libwinpr/synch/wait.c @@ -76,7 +76,7 @@ #define CLOCK_REALTIME 0 #define CLOCK_MONOTONIC 0 -int clock_gettime(int clk_id, struct timespec* t) +int clock_gettime(int clk_id, struct timespec *t) { UINT64 time; double seconds; @@ -141,7 +141,7 @@ static int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec } #endif -static void ts_add_ms(struct timespec* ts, DWORD dwMilliseconds) +static void ts_add_ms(struct timespec *ts, DWORD dwMilliseconds) { ts->tv_sec += dwMilliseconds / 1000L; ts->tv_nsec += (dwMilliseconds % 1000L) * 1000000L; @@ -213,6 +213,8 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) if (status != 1) return WAIT_TIMEOUT; + pthread_mutex_lock(&thread->mutex); + if (!thread->joined) { status = pthread_join(thread->thread, NULL); @@ -220,11 +222,13 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) if (status != 0) { WLog_ERR(TAG, "pthread_join failure: [%d] %s", - status, strerror(status)); + status, strerror(status)); } else thread->joined = TRUE; } + + pthread_mutex_unlock(&thread->mutex); } else if (Type == HANDLE_TYPE_PROCESS) { @@ -423,7 +427,7 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl ULONG Type; PVOID Object; #ifdef HAVE_POLL_H - struct pollfd* pollfds; + struct pollfd *pollfds; #else int maxfd; fd_set fds; @@ -449,7 +453,7 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl #endif signalled = 0; - do + do { if (bWaitAll && (dwMilliseconds != INFINITE)) clock_gettime(CLOCK_MONOTONIC, &starttime); @@ -492,8 +496,8 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl #ifdef WINPR_PIPE_SEMAPHORE fd = ((WINPR_SEMAPHORE *) Object)->pipe_fd[0]; #else - WLog_ERR(TAG, "semaphore not supported"); - return WAIT_FAILED; + WLog_ERR(TAG, "semaphore not supported"); + return WAIT_FAILED; #endif } else if (Type == HANDLE_TYPE_TIMER) @@ -584,10 +588,10 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl { #ifdef HAVE_POLL_H WLog_ERR(TAG, "poll() failure [%d] %s", errno, - strerror(errno)); + strerror(errno)); #else WLog_ERR(TAG, "select() failure [%d] %s", errno, - strerror(errno)); + strerror(errno)); #endif return WAIT_FAILED; } @@ -685,6 +689,7 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl else if (Type == HANDLE_TYPE_THREAD) { WINPR_THREAD *thread = (WINPR_THREAD *)Object; + pthread_mutex_lock(&thread->mutex); if (!thread->joined) { @@ -694,12 +699,14 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl if (status != 0) { WLog_ERR(TAG, "pthread_join failure: [%d] %s", - status, strerror(status)); + status, strerror(status)); return WAIT_FAILED; } else thread->joined = TRUE; } + + pthread_mutex_unlock(&thread->mutex); } if (bWaitAll) From ff3fcc24c125d6db86bae9e661ab738f4b2cf887 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 10 Nov 2014 10:24:32 +0100 Subject: [PATCH 18/18] Fixed unlocking if pthread_join fails. --- winpr/libwinpr/synch/wait.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/winpr/libwinpr/synch/wait.c b/winpr/libwinpr/synch/wait.c index 630fc4cbc..eeb900106 100644 --- a/winpr/libwinpr/synch/wait.c +++ b/winpr/libwinpr/synch/wait.c @@ -223,6 +223,8 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) { WLog_ERR(TAG, "pthread_join failure: [%d] %s", status, strerror(status)); + pthread_mutex_unlock(&thread->mutex); + return WAIT_FAILED; } else thread->joined = TRUE; @@ -700,6 +702,7 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl { WLog_ERR(TAG, "pthread_join failure: [%d] %s", status, strerror(status)); + pthread_mutex_unlock(&thread->mutex); return WAIT_FAILED; } else