Refactor thread condition logic
* Add better return value checks
* Combine logic blocks in structs
* Add (easier to read) static functions for blocks
* Use condition variables only in combination with BOOL
(cherry picked from commit a77038a0c7
)
This commit is contained in:
parent
0cc152af3b
commit
4ca275d468
@ -24,7 +24,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include <winpr/handle.h>
|
||||
|
||||
@ -98,7 +98,10 @@
|
||||
#define TAG WINPR_TAG("thread")
|
||||
|
||||
static WINPR_THREAD mainThread;
|
||||
|
||||
#if defined(WITH_THREAD_LIST)
|
||||
static wListDictionary* thread_list = NULL;
|
||||
#endif
|
||||
|
||||
static BOOL ThreadCloseHandle(HANDLE handle);
|
||||
static void cleanup_handle(void* obj);
|
||||
@ -126,14 +129,190 @@ static int ThreadGetFd(HANDLE handle)
|
||||
return pThread->event.fds[0];
|
||||
}
|
||||
|
||||
#define run_mutex_init(fkt, mux, arg) run_mutex_init_(fkt, #fkt, mux, arg)
|
||||
static BOOL run_mutex_init_(int (*fkt)(pthread_mutex_t*, const pthread_mutexattr_t*),
|
||||
const char* name, pthread_mutex_t* mutex,
|
||||
const pthread_mutexattr_t* mutexattr)
|
||||
{
|
||||
int rc;
|
||||
|
||||
WINPR_ASSERT(fkt);
|
||||
WINPR_ASSERT(mutex);
|
||||
|
||||
rc = fkt(mutex, mutexattr);
|
||||
if (rc != 0)
|
||||
{
|
||||
WLog_WARN(TAG, "[%s] failed with [%s]", name, strerror(rc));
|
||||
}
|
||||
return rc == 0;
|
||||
}
|
||||
|
||||
#define run_mutex_fkt(fkt, mux) run_mutex_fkt_(fkt, #fkt, mux)
|
||||
static BOOL run_mutex_fkt_(int (*fkt)(pthread_mutex_t* mux), const char* name,
|
||||
pthread_mutex_t* mutex)
|
||||
{
|
||||
int rc;
|
||||
|
||||
WINPR_ASSERT(fkt);
|
||||
WINPR_ASSERT(mutex);
|
||||
|
||||
rc = fkt(mutex);
|
||||
if (rc != 0)
|
||||
{
|
||||
WLog_WARN(TAG, "[%s] failed with [%s]", name, strerror(rc));
|
||||
}
|
||||
return rc == 0;
|
||||
}
|
||||
|
||||
#define run_cond_init(fkt, cond, arg) run_cond_init_(fkt, #fkt, cond, arg)
|
||||
static BOOL run_cond_init_(int (*fkt)(pthread_cond_t*, const pthread_condattr_t*), const char* name,
|
||||
pthread_cond_t* condition, const pthread_condattr_t* conditionattr)
|
||||
{
|
||||
int rc;
|
||||
|
||||
WINPR_ASSERT(fkt);
|
||||
WINPR_ASSERT(condition);
|
||||
|
||||
rc = fkt(condition, conditionattr);
|
||||
if (rc != 0)
|
||||
{
|
||||
WLog_WARN(TAG, "[%s] failed with [%s]", name, strerror(rc));
|
||||
}
|
||||
return rc == 0;
|
||||
}
|
||||
|
||||
#define run_cond_fkt(fkt, cond) run_cond_fkt_(fkt, #fkt, cond)
|
||||
static BOOL run_cond_fkt_(int (*fkt)(pthread_cond_t* mux), const char* name,
|
||||
pthread_cond_t* condition)
|
||||
{
|
||||
int rc;
|
||||
|
||||
WINPR_ASSERT(fkt);
|
||||
WINPR_ASSERT(condition);
|
||||
|
||||
rc = fkt(condition);
|
||||
if (rc != 0)
|
||||
{
|
||||
WLog_WARN(TAG, "[%s] failed with [%s]", name, strerror(rc));
|
||||
}
|
||||
return rc == 0;
|
||||
}
|
||||
|
||||
static int pthread_mutex_checked_unlock(pthread_mutex_t* mutex)
|
||||
{
|
||||
WINPR_ASSERT(mutex);
|
||||
WINPR_ASSERT(pthread_mutex_trylock(mutex) == EBUSY);
|
||||
return pthread_mutex_unlock(mutex);
|
||||
}
|
||||
|
||||
static BOOL mux_condition_bundle_init(mux_condition_bundle* bundle)
|
||||
{
|
||||
WINPR_ASSERT(bundle);
|
||||
|
||||
bundle->val = FALSE;
|
||||
if (!run_mutex_init(pthread_mutex_init, &bundle->mux, NULL))
|
||||
return FALSE;
|
||||
|
||||
if (!run_cond_init(pthread_cond_init, &bundle->cond, NULL))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void mux_condition_bundle_uninit(mux_condition_bundle* bundle)
|
||||
{
|
||||
mux_condition_bundle empty = { 0 };
|
||||
|
||||
WINPR_ASSERT(bundle);
|
||||
|
||||
run_cond_fkt(pthread_cond_destroy, &bundle->cond);
|
||||
run_mutex_fkt(pthread_mutex_destroy, &bundle->mux);
|
||||
*bundle = empty;
|
||||
}
|
||||
|
||||
static BOOL mux_condition_bundle_signal(mux_condition_bundle* bundle)
|
||||
{
|
||||
BOOL rc = TRUE;
|
||||
WINPR_ASSERT(bundle);
|
||||
|
||||
if (!run_mutex_fkt(pthread_mutex_lock, &bundle->mux))
|
||||
return FALSE;
|
||||
bundle->val = TRUE;
|
||||
if (!run_cond_fkt(pthread_cond_signal, &bundle->cond))
|
||||
rc = FALSE;
|
||||
if (!run_mutex_fkt(pthread_mutex_checked_unlock, &bundle->mux))
|
||||
rc = FALSE;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL mux_condition_bundle_lock(mux_condition_bundle* bundle)
|
||||
{
|
||||
WINPR_ASSERT(bundle);
|
||||
return run_mutex_fkt(pthread_mutex_lock, &bundle->mux);
|
||||
}
|
||||
|
||||
static BOOL mux_condition_bundle_unlock(mux_condition_bundle* bundle)
|
||||
{
|
||||
WINPR_ASSERT(bundle);
|
||||
return run_mutex_fkt(pthread_mutex_checked_unlock, &bundle->mux);
|
||||
}
|
||||
|
||||
static BOOL mux_condition_bundle_wait(mux_condition_bundle* bundle, const char* name)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
|
||||
WINPR_ASSERT(bundle);
|
||||
WINPR_ASSERT(name);
|
||||
WINPR_ASSERT(pthread_mutex_trylock(&bundle->mux) == EBUSY);
|
||||
|
||||
while (!bundle->val)
|
||||
{
|
||||
int r = pthread_cond_wait(&bundle->cond, &bundle->mux);
|
||||
if (r != 0)
|
||||
{
|
||||
WLog_ERR(TAG, "failed to wait for %s [%s]", name, strerror(r));
|
||||
switch (r)
|
||||
{
|
||||
case ENOTRECOVERABLE:
|
||||
case EPERM:
|
||||
case ETIMEDOUT:
|
||||
case EINVAL:
|
||||
goto fail;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rc = bundle->val;
|
||||
|
||||
fail:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL signal_thread_ready(WINPR_THREAD* thread)
|
||||
{
|
||||
WINPR_ASSERT(thread);
|
||||
|
||||
return mux_condition_bundle_signal(&thread->isCreated);
|
||||
}
|
||||
|
||||
static BOOL signal_thread_is_running(WINPR_THREAD* thread)
|
||||
{
|
||||
WINPR_ASSERT(thread);
|
||||
|
||||
return mux_condition_bundle_signal(&thread->isRunning);
|
||||
}
|
||||
|
||||
static DWORD ThreadCleanupHandle(HANDLE handle)
|
||||
{
|
||||
DWORD status = WAIT_FAILED;
|
||||
WINPR_THREAD* thread = (WINPR_THREAD*)handle;
|
||||
|
||||
if (!ThreadIsHandled(handle))
|
||||
return WAIT_FAILED;
|
||||
|
||||
if (pthread_mutex_lock(&thread->mutex))
|
||||
if (!run_mutex_fkt(pthread_mutex_lock, &thread->mutex))
|
||||
return WAIT_FAILED;
|
||||
|
||||
if (!thread->joined)
|
||||
@ -144,17 +323,19 @@ static DWORD ThreadCleanupHandle(HANDLE handle)
|
||||
if (status != 0)
|
||||
{
|
||||
WLog_ERR(TAG, "pthread_join failure: [%d] %s", status, strerror(status));
|
||||
pthread_mutex_unlock(&thread->mutex);
|
||||
return WAIT_FAILED;
|
||||
goto fail;
|
||||
}
|
||||
else
|
||||
thread->joined = TRUE;
|
||||
}
|
||||
|
||||
if (pthread_mutex_unlock(&thread->mutex))
|
||||
status = WAIT_OBJECT_0;
|
||||
|
||||
fail:
|
||||
if (!run_mutex_fkt(pthread_mutex_checked_unlock, &thread->mutex))
|
||||
return WAIT_FAILED;
|
||||
|
||||
return WAIT_OBJECT_0;
|
||||
return status;
|
||||
}
|
||||
|
||||
static HANDLE_OPS ops = { ThreadIsHandled,
|
||||
@ -218,7 +399,8 @@ static void dump_thread(WINPR_THREAD* thread)
|
||||
|
||||
free(msg);
|
||||
}
|
||||
|
||||
#else
|
||||
WINPR_UNUSED(thread);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -236,6 +418,7 @@ static BOOL reset_event(WINPR_THREAD* thread)
|
||||
return winpr_event_reset(&thread->event);
|
||||
}
|
||||
|
||||
#if defined(WITH_THREAD_LIST)
|
||||
static BOOL thread_compare(const void* a, const void* b)
|
||||
{
|
||||
const pthread_t* p1 = a;
|
||||
@ -243,12 +426,13 @@ static BOOL thread_compare(const void* a, const void* b)
|
||||
BOOL rc = pthread_equal(*p1, *p2);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
static INIT_ONCE threads_InitOnce = INIT_ONCE_STATIC_INIT;
|
||||
static pthread_t mainThreadId;
|
||||
static DWORD currentThreadTlsIndex = TLS_OUT_OF_INDEXES;
|
||||
|
||||
BOOL initializeThreads(PINIT_ONCE InitOnce, PVOID Parameter, PVOID* Context)
|
||||
static BOOL initializeThreads(PINIT_ONCE InitOnce, PVOID Parameter, PVOID* Context)
|
||||
{
|
||||
if (!apc_init(&mainThread.apc))
|
||||
{
|
||||
@ -265,10 +449,54 @@ BOOL initializeThreads(PINIT_ONCE InitOnce, PVOID Parameter, PVOID* Context)
|
||||
WLog_ERR(TAG, "Major bug, unable to allocate a TLS value for currentThread");
|
||||
}
|
||||
|
||||
#if defined(WITH_THREAD_LIST)
|
||||
thread_list = ListDictionary_New(TRUE);
|
||||
|
||||
if (!thread_list)
|
||||
{
|
||||
WLog_ERR(TAG, "Couldn't create global thread list");
|
||||
goto error_thread_list;
|
||||
}
|
||||
|
||||
thread_list->objectKey.fnObjectEquals = thread_compare;
|
||||
#endif
|
||||
|
||||
out:
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL signal_and_wait_for_ready(WINPR_THREAD* thread)
|
||||
{
|
||||
BOOL res = FALSE;
|
||||
|
||||
WINPR_ASSERT(thread);
|
||||
|
||||
if (!mux_condition_bundle_lock(&thread->isRunning))
|
||||
return FALSE;
|
||||
|
||||
if (!signal_thread_ready(thread))
|
||||
goto fail;
|
||||
|
||||
if (!mux_condition_bundle_wait(&thread->isRunning, "threadIsRunning"))
|
||||
goto fail;
|
||||
|
||||
#if defined(WITH_THREAD_LIST)
|
||||
if (!ListDictionary_Contains(thread_list, &thread->thread))
|
||||
{
|
||||
WLog_ERR(TAG, "Thread not in thread_list, startup failed!");
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
|
||||
res = TRUE;
|
||||
|
||||
fail:
|
||||
if (!mux_condition_bundle_unlock(&thread->isRunning))
|
||||
return FALSE;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Thread launcher function responsible for registering
|
||||
* cleanup handlers and calling pthread_exit, if not done
|
||||
* in thread function. */
|
||||
@ -296,23 +524,9 @@ static void* thread_launcher(void* arg)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (pthread_mutex_lock(&thread->threadIsReadyMutex))
|
||||
if (!signal_and_wait_for_ready(thread))
|
||||
goto exit;
|
||||
|
||||
if (!ListDictionary_Contains(thread_list, &thread->thread))
|
||||
{
|
||||
if (pthread_cond_wait(&thread->threadIsReady, &thread->threadIsReadyMutex) != 0)
|
||||
{
|
||||
WLog_ERR(TAG, "The thread could not be made ready");
|
||||
pthread_mutex_unlock(&thread->threadIsReadyMutex);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (pthread_mutex_unlock(&thread->threadIsReadyMutex))
|
||||
goto exit;
|
||||
|
||||
assert(ListDictionary_Contains(thread_list, &thread->thread));
|
||||
rc = fkt(thread->lpParameter);
|
||||
exit:
|
||||
|
||||
@ -325,6 +539,8 @@ exit:
|
||||
|
||||
set_event(thread);
|
||||
|
||||
signal_thread_ready(thread);
|
||||
|
||||
if (thread->detached || !thread->started)
|
||||
cleanup_handle(thread);
|
||||
}
|
||||
@ -334,7 +550,14 @@ exit:
|
||||
|
||||
static BOOL winpr_StartThread(WINPR_THREAD* thread)
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
BOOL rc = FALSE;
|
||||
BOOL locked = FALSE;
|
||||
pthread_attr_t attr = { 0 };
|
||||
|
||||
if (!mux_condition_bundle_lock(&thread->isCreated))
|
||||
return FALSE;
|
||||
locked = TRUE;
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
||||
|
||||
@ -344,35 +567,44 @@ static BOOL winpr_StartThread(WINPR_THREAD* thread)
|
||||
thread->started = TRUE;
|
||||
reset_event(thread);
|
||||
|
||||
if (pthread_create(&thread->thread, &attr, thread_launcher, thread))
|
||||
goto error;
|
||||
|
||||
if (pthread_mutex_lock(&thread->threadIsReadyMutex))
|
||||
goto error;
|
||||
|
||||
#if defined(WITH_THREAD_LIST)
|
||||
if (!ListDictionary_Add(thread_list, &thread->thread, thread))
|
||||
{
|
||||
WLog_ERR(TAG, "failed to add the thread to the thread list");
|
||||
pthread_mutex_unlock(&thread->threadIsReadyMutex);
|
||||
goto error;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pthread_cond_signal(&thread->threadIsReady) != 0)
|
||||
if (pthread_create(&thread->thread, &attr, thread_launcher, thread))
|
||||
goto error;
|
||||
|
||||
if (!mux_condition_bundle_wait(&thread->isCreated, "threadIsCreated"))
|
||||
goto error;
|
||||
|
||||
locked = FALSE;
|
||||
if (!mux_condition_bundle_unlock(&thread->isCreated))
|
||||
goto error;
|
||||
|
||||
if (!signal_thread_is_running(thread))
|
||||
{
|
||||
WLog_ERR(TAG, "failed to signal the thread was ready");
|
||||
pthread_mutex_unlock(&thread->threadIsReadyMutex);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (pthread_mutex_unlock(&thread->threadIsReadyMutex))
|
||||
goto error;
|
||||
rc = TRUE;
|
||||
error:
|
||||
if (locked)
|
||||
{
|
||||
if (!mux_condition_bundle_unlock(&thread->isCreated))
|
||||
rc = FALSE;
|
||||
}
|
||||
|
||||
pthread_attr_destroy(&attr);
|
||||
dump_thread(thread);
|
||||
return TRUE;
|
||||
error:
|
||||
pthread_attr_destroy(&attr);
|
||||
return FALSE;
|
||||
|
||||
if (rc)
|
||||
dump_thread(thread);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize,
|
||||
@ -380,8 +612,7 @@ HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize
|
||||
DWORD dwCreationFlags, LPDWORD lpThreadId)
|
||||
{
|
||||
HANDLE handle;
|
||||
WINPR_THREAD* thread;
|
||||
thread = (WINPR_THREAD*)calloc(1, sizeof(WINPR_THREAD));
|
||||
WINPR_THREAD* thread = (WINPR_THREAD*)calloc(1, sizeof(WINPR_THREAD));
|
||||
|
||||
if (!thread)
|
||||
return NULL;
|
||||
@ -399,104 +630,66 @@ HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize
|
||||
if (!winpr_event_init(&thread->event))
|
||||
{
|
||||
WLog_ERR(TAG, "failed to create event");
|
||||
goto error_event;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (pthread_mutex_init(&thread->mutex, NULL) != 0)
|
||||
if (!run_mutex_init(pthread_mutex_init, &thread->mutex, NULL))
|
||||
{
|
||||
WLog_ERR(TAG, "failed to initialize thread mutex");
|
||||
goto error_mutex;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!apc_init(&thread->apc))
|
||||
{
|
||||
WLog_ERR(TAG, "failed to initialize APC");
|
||||
goto error_APC;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (pthread_mutex_init(&thread->threadIsReadyMutex, NULL) != 0)
|
||||
{
|
||||
WLog_ERR(TAG, "failed to initialize a mutex for a condition variable");
|
||||
goto error_thread_ready_mutex;
|
||||
}
|
||||
|
||||
if (pthread_cond_init(&thread->threadIsReady, NULL) != 0)
|
||||
{
|
||||
WLog_ERR(TAG, "failed to initialize a condition variable");
|
||||
goto error_thread_ready;
|
||||
}
|
||||
if (!mux_condition_bundle_init(&thread->isCreated))
|
||||
goto fail;
|
||||
if (!mux_condition_bundle_init(&thread->isRunning))
|
||||
goto fail;
|
||||
|
||||
WINPR_HANDLE_SET_TYPE_AND_MODE(thread, HANDLE_TYPE_THREAD, WINPR_FD_READ);
|
||||
handle = (HANDLE)thread;
|
||||
|
||||
if (!thread_list)
|
||||
{
|
||||
InitOnceExecuteOnce(&threads_InitOnce, initializeThreads, NULL, NULL);
|
||||
thread_list = ListDictionary_New(TRUE);
|
||||
|
||||
if (!thread_list)
|
||||
{
|
||||
WLog_ERR(TAG, "Couldn't create global thread list");
|
||||
goto error_thread_list;
|
||||
}
|
||||
|
||||
thread_list->objectKey.fnObjectEquals = thread_compare;
|
||||
}
|
||||
InitOnceExecuteOnce(&threads_InitOnce, initializeThreads, NULL, NULL);
|
||||
|
||||
if (!(dwCreationFlags & CREATE_SUSPENDED))
|
||||
{
|
||||
if (!winpr_StartThread(thread))
|
||||
goto error_thread_list;
|
||||
goto fail;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!set_event(thread))
|
||||
goto error_thread_list;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return handle;
|
||||
error_thread_list:
|
||||
pthread_cond_destroy(&thread->threadIsReady);
|
||||
error_thread_ready:
|
||||
pthread_mutex_destroy(&thread->threadIsReadyMutex);
|
||||
error_thread_ready_mutex:
|
||||
apc_uninit(&thread->apc);
|
||||
error_APC:
|
||||
pthread_mutex_destroy(&thread->mutex);
|
||||
error_mutex:
|
||||
winpr_event_uninit(&thread->event);
|
||||
error_event:
|
||||
free(thread);
|
||||
fail:
|
||||
cleanup_handle(thread);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void cleanup_handle(void* obj)
|
||||
{
|
||||
int rc;
|
||||
WINPR_THREAD* thread = (WINPR_THREAD*)obj;
|
||||
if (!thread)
|
||||
return;
|
||||
|
||||
if (!apc_uninit(&thread->apc))
|
||||
WLog_ERR(TAG, "failed to destroy APC");
|
||||
|
||||
rc = pthread_cond_destroy(&thread->threadIsReady);
|
||||
if (rc)
|
||||
WLog_ERR(TAG, "failed to destroy thread->threadIsReady [%d] %s (%d)", rc, strerror(errno),
|
||||
errno);
|
||||
|
||||
rc = pthread_mutex_destroy(&thread->threadIsReadyMutex);
|
||||
if (rc)
|
||||
WLog_ERR(TAG, "failed to destroy thread->threadIsReadyMutex [%d] %s (%d)", rc,
|
||||
strerror(errno), errno);
|
||||
|
||||
rc = pthread_mutex_destroy(&thread->mutex);
|
||||
if (rc)
|
||||
WLog_ERR(TAG, "failed to destroy thread->mutex [%d] %s (%d)", rc, strerror(errno), errno);
|
||||
mux_condition_bundle_uninit(&thread->isCreated);
|
||||
mux_condition_bundle_uninit(&thread->isRunning);
|
||||
run_mutex_fkt(pthread_mutex_destroy, &thread->mutex);
|
||||
|
||||
winpr_event_uninit(&thread->event);
|
||||
|
||||
if (thread_list && ListDictionary_Contains(thread_list, &thread->thread))
|
||||
ListDictionary_Remove(thread_list, &thread->thread);
|
||||
|
||||
#if defined(WITH_THREAD_LIST)
|
||||
ListDictionary_Remove(thread_list, &thread->thread);
|
||||
#endif
|
||||
#if defined(WITH_DEBUG_THREADS)
|
||||
|
||||
if (thread->create_stack)
|
||||
@ -513,6 +706,7 @@ BOOL ThreadCloseHandle(HANDLE handle)
|
||||
{
|
||||
WINPR_THREAD* thread = (WINPR_THREAD*)handle;
|
||||
|
||||
#if defined(WITH_THREAD_LIST)
|
||||
if (!thread_list)
|
||||
{
|
||||
WLog_ERR(TAG, "Thread list does not exist, check call!");
|
||||
@ -526,6 +720,7 @@ BOOL ThreadCloseHandle(HANDLE handle)
|
||||
else
|
||||
{
|
||||
ListDictionary_Lock(thread_list);
|
||||
#endif
|
||||
dump_thread(thread);
|
||||
|
||||
if ((thread->started) && (WaitForSingleObject(thread, 0) != WAIT_OBJECT_0))
|
||||
@ -539,14 +734,10 @@ BOOL ThreadCloseHandle(HANDLE handle)
|
||||
cleanup_handle(thread);
|
||||
}
|
||||
|
||||
#if defined(WITH_THREAD_LIST)
|
||||
ListDictionary_Unlock(thread_list);
|
||||
|
||||
if (ListDictionary_Count(thread_list) < 1)
|
||||
{
|
||||
ListDictionary_Free(thread_list);
|
||||
thread_list = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -562,6 +753,7 @@ HANDLE CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttribu
|
||||
|
||||
VOID ExitThread(DWORD dwExitCode)
|
||||
{
|
||||
#if defined(WITH_THREAD_LIST)
|
||||
DWORD rc;
|
||||
pthread_t tid = pthread_self();
|
||||
|
||||
@ -586,7 +778,7 @@ VOID ExitThread(DWORD dwExitCode)
|
||||
WINPR_THREAD* thread;
|
||||
ListDictionary_Lock(thread_list);
|
||||
thread = ListDictionary_GetItemValue(thread_list, &tid);
|
||||
assert(thread);
|
||||
WINPR_ASSERT(thread);
|
||||
thread->exited = TRUE;
|
||||
thread->dwExitCode = dwExitCode;
|
||||
#if defined(WITH_DEBUG_THREADS)
|
||||
@ -601,6 +793,9 @@ VOID ExitThread(DWORD dwExitCode)
|
||||
|
||||
pthread_exit((void*)(size_t)rc);
|
||||
}
|
||||
#else
|
||||
WINPR_UNUSED(dwExitCode);
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOL GetExitCodeThread(HANDLE hThread, LPDWORD lpExitCode)
|
||||
@ -657,7 +852,7 @@ typedef struct
|
||||
ULONG_PTR completionArg;
|
||||
} UserApcItem;
|
||||
|
||||
void userAPC(LPVOID arg)
|
||||
static void userAPC(LPVOID arg)
|
||||
{
|
||||
UserApcItem* userApc = (UserApcItem*)arg;
|
||||
|
||||
@ -670,7 +865,6 @@ DWORD QueueUserAPC(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData)
|
||||
{
|
||||
ULONG Type;
|
||||
WINPR_HANDLE* Object;
|
||||
WINPR_THREAD* thread;
|
||||
WINPR_APC_ITEM* apc;
|
||||
UserApcItem* apcItem;
|
||||
|
||||
@ -683,7 +877,6 @@ DWORD QueueUserAPC(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData)
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return (DWORD)0;
|
||||
}
|
||||
thread = (WINPR_THREAD*)Object;
|
||||
|
||||
apcItem = calloc(1, sizeof(*apcItem));
|
||||
if (!apcItem)
|
||||
@ -715,21 +908,21 @@ DWORD ResumeThread(HANDLE hThread)
|
||||
|
||||
thread = (WINPR_THREAD*)Object;
|
||||
|
||||
if (pthread_mutex_lock(&thread->mutex))
|
||||
if (!run_mutex_fkt(pthread_mutex_lock, &thread->mutex))
|
||||
return (DWORD)-1;
|
||||
|
||||
if (!thread->started)
|
||||
{
|
||||
if (!winpr_StartThread(thread))
|
||||
{
|
||||
pthread_mutex_unlock(&thread->mutex);
|
||||
run_mutex_fkt(pthread_mutex_checked_unlock, &thread->mutex);
|
||||
return (DWORD)-1;
|
||||
}
|
||||
}
|
||||
else
|
||||
WLog_WARN(TAG, "Thread already started!");
|
||||
|
||||
if (pthread_mutex_unlock(&thread->mutex))
|
||||
if (!run_mutex_fkt(pthread_mutex_checked_unlock, &thread->mutex))
|
||||
return (DWORD)-1;
|
||||
|
||||
return 0;
|
||||
@ -767,7 +960,7 @@ BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode)
|
||||
thread->exited = TRUE;
|
||||
thread->dwExitCode = dwExitCode;
|
||||
|
||||
if (pthread_mutex_lock(&thread->mutex))
|
||||
if (!run_mutex_fkt(pthread_mutex_lock, &thread->mutex))
|
||||
return FALSE;
|
||||
|
||||
#ifndef ANDROID
|
||||
@ -776,16 +969,16 @@ BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode)
|
||||
WLog_ERR(TAG, "Function not supported on this platform!");
|
||||
#endif
|
||||
|
||||
if (pthread_mutex_unlock(&thread->mutex))
|
||||
if (!run_mutex_fkt(pthread_mutex_checked_unlock, &thread->mutex))
|
||||
return FALSE;
|
||||
|
||||
set_event(thread);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if defined(WITH_DEBUG_THREADS)
|
||||
VOID DumpThreadHandles(void)
|
||||
{
|
||||
#if defined(WITH_DEBUG_THREADS)
|
||||
char** msg;
|
||||
size_t used, i;
|
||||
void* stack = winpr_backtrace(20);
|
||||
@ -801,6 +994,7 @@ VOID DumpThreadHandles(void)
|
||||
winpr_backtrace_free(stack);
|
||||
WLog_DBG(TAG, "---------------- Start Dumping thread handles -----------");
|
||||
|
||||
#if defined(WITH_THREAD_LIST)
|
||||
if (!thread_list)
|
||||
{
|
||||
WLog_DBG(TAG, "All threads properly shut down and disposed of.");
|
||||
@ -844,8 +1038,9 @@ VOID DumpThreadHandles(void)
|
||||
free(keys);
|
||||
ListDictionary_Unlock(thread_list);
|
||||
}
|
||||
#endif
|
||||
|
||||
WLog_DBG(TAG, "---------------- End Dumping thread handles -------------");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
@ -32,47 +32,63 @@
|
||||
#include "../synch/event.h"
|
||||
#include "apc.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define ALIGN64 __attribute__((aligned(8)))
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
#define ALIGN64 __declspec(align(8))
|
||||
#else
|
||||
#define ALIGN64
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef void* (*pthread_start_routine)(void*);
|
||||
typedef struct winpr_APC_item WINPR_APC_ITEM;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ALIGN64 pthread_mutex_t mux;
|
||||
ALIGN64 pthread_cond_t cond;
|
||||
ALIGN64 BOOL val;
|
||||
} mux_condition_bundle;
|
||||
|
||||
struct winpr_thread
|
||||
{
|
||||
WINPR_HANDLE_DEF();
|
||||
|
||||
BOOL started;
|
||||
WINPR_EVENT_IMPL event;
|
||||
BOOL mainProcess;
|
||||
BOOL detached;
|
||||
BOOL joined;
|
||||
BOOL exited;
|
||||
DWORD dwExitCode;
|
||||
pthread_t thread;
|
||||
SIZE_T dwStackSize;
|
||||
LPVOID lpParameter;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_mutex_t threadIsReadyMutex;
|
||||
pthread_cond_t threadIsReady;
|
||||
LPTHREAD_START_ROUTINE lpStartAddress;
|
||||
LPSECURITY_ATTRIBUTES lpThreadAttributes;
|
||||
APC_QUEUE apc;
|
||||
ALIGN64 BOOL started;
|
||||
ALIGN64 WINPR_EVENT_IMPL event;
|
||||
ALIGN64 BOOL mainProcess;
|
||||
ALIGN64 BOOL detached;
|
||||
ALIGN64 BOOL joined;
|
||||
ALIGN64 BOOL exited;
|
||||
ALIGN64 DWORD dwExitCode;
|
||||
ALIGN64 pthread_t thread;
|
||||
ALIGN64 SIZE_T dwStackSize;
|
||||
ALIGN64 LPVOID lpParameter;
|
||||
ALIGN64 pthread_mutex_t mutex;
|
||||
mux_condition_bundle isRunning;
|
||||
mux_condition_bundle isCreated;
|
||||
ALIGN64 LPTHREAD_START_ROUTINE lpStartAddress;
|
||||
ALIGN64 LPSECURITY_ATTRIBUTES lpThreadAttributes;
|
||||
ALIGN64 APC_QUEUE apc;
|
||||
#if defined(WITH_DEBUG_THREADS)
|
||||
void* create_stack;
|
||||
void* exit_stack;
|
||||
ALIGN64 void* create_stack;
|
||||
ALIGN64 void* exit_stack;
|
||||
#endif
|
||||
};
|
||||
typedef struct winpr_thread WINPR_THREAD;
|
||||
|
||||
WINPR_THREAD* winpr_GetCurrentThread(VOID);
|
||||
|
||||
struct winpr_process
|
||||
typedef struct
|
||||
{
|
||||
WINPR_HANDLE_DEF();
|
||||
|
||||
pid_t pid;
|
||||
int status;
|
||||
DWORD dwExitCode;
|
||||
};
|
||||
typedef struct winpr_process WINPR_PROCESS;
|
||||
} WINPR_PROCESS;
|
||||
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user