23#include <winpr/config.h>
25#include <winpr/winpr.h>
26#include <winpr/assert.h>
28#include <winpr/handle.h>
30#include <winpr/thread.h>
32#if defined(__FreeBSD__)
33#include <pthread_np.h>
34#elif defined(__linux__)
35#include <sys/syscall.h>
39#define MIN(x, y) (((x) < (y)) ? (x) : (y))
43#define MAX(x, y) (((x) > (y)) ? (x) : (y))
90#include <winpr/platform.h>
93#ifdef WINPR_HAVE_UNISTD_H
97#ifdef WINPR_HAVE_SYS_EVENTFD_H
98#include <sys/eventfd.h>
101#include <winpr/debug.h>
106#include <winpr/collections.h>
111#include "../handle/handle.h"
113#define TAG WINPR_TAG("thread")
115static WINPR_THREAD mainThread;
117#if defined(WITH_THREAD_LIST)
118static wListDictionary* thread_list =
nullptr;
121static BOOL ThreadCloseHandle(HANDLE handle);
122static void cleanup_handle(
void* obj);
124static BOOL ThreadIsHandled(HANDLE handle)
126 return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_THREAD, FALSE);
129static int ThreadGetFd(HANDLE handle)
131 WINPR_THREAD* pThread = (WINPR_THREAD*)handle;
133 if (!ThreadIsHandled(handle))
136 return pThread->event.fds[0];
139#define run_mutex_init(fkt, mux, arg) run_mutex_init_(fkt, #fkt, mux, arg)
140static BOOL run_mutex_init_(
int (*fkt)(pthread_mutex_t*,
const pthread_mutexattr_t*),
141 const char* name, pthread_mutex_t* mutex,
142 const pthread_mutexattr_t* mutexattr)
149 rc = fkt(mutex, mutexattr);
152 char ebuffer[256] = WINPR_C_ARRAY_INIT;
153 WLog_WARN(TAG,
"[%s] failed with [%s]", name, winpr_strerror(rc, ebuffer,
sizeof(ebuffer)));
158#define run_mutex_fkt(fkt, mux) run_mutex_fkt_(fkt, #fkt, mux)
159static BOOL run_mutex_fkt_(
int (*fkt)(pthread_mutex_t* mux),
const char* name,
160 pthread_mutex_t* mutex)
170 char ebuffer[256] = WINPR_C_ARRAY_INIT;
171 WLog_WARN(TAG,
"[%s] failed with [%s]", name, winpr_strerror(rc, ebuffer,
sizeof(ebuffer)));
176#define run_cond_init(fkt, cond, arg) run_cond_init_(fkt, #fkt, cond, arg)
177static BOOL run_cond_init_(
int (*fkt)(pthread_cond_t*,
const pthread_condattr_t*),
const char* name,
178 pthread_cond_t* condition,
const pthread_condattr_t* conditionattr)
183 WINPR_ASSERT(condition);
185 rc = fkt(condition, conditionattr);
188 char ebuffer[256] = WINPR_C_ARRAY_INIT;
189 WLog_WARN(TAG,
"[%s] failed with [%s]", name, winpr_strerror(rc, ebuffer,
sizeof(ebuffer)));
194#define run_cond_fkt(fkt, cond) run_cond_fkt_(fkt, #fkt, cond)
195static BOOL run_cond_fkt_(
int (*fkt)(pthread_cond_t* mux),
const char* name,
196 pthread_cond_t* condition)
201 WINPR_ASSERT(condition);
206 char ebuffer[256] = WINPR_C_ARRAY_INIT;
207 WLog_WARN(TAG,
"[%s] failed with [%s]", name, winpr_strerror(rc, ebuffer,
sizeof(ebuffer)));
212static int pthread_mutex_checked_unlock(pthread_mutex_t* mutex)
215 WINPR_ASSERT(pthread_mutex_trylock(mutex) == EBUSY);
216 return pthread_mutex_unlock(mutex);
221 WINPR_ASSERT(bundle);
224 if (!run_mutex_init(pthread_mutex_init, &bundle->mux,
nullptr))
227 if (!run_cond_init(pthread_cond_init, &bundle->cond,
nullptr))
236 WINPR_ASSERT(bundle);
238 run_cond_fkt(pthread_cond_destroy, &bundle->cond);
239 run_mutex_fkt(pthread_mutex_destroy, &bundle->mux);
246 WINPR_ASSERT(bundle);
248 if (!run_mutex_fkt(pthread_mutex_lock, &bundle->mux))
251 if (!run_cond_fkt(pthread_cond_signal, &bundle->cond))
253 if (!run_mutex_fkt(pthread_mutex_checked_unlock, &bundle->mux))
260 WINPR_ASSERT(bundle);
261 return run_mutex_fkt(pthread_mutex_lock, &bundle->mux);
266 WINPR_ASSERT(bundle);
267 return run_mutex_fkt(pthread_mutex_checked_unlock, &bundle->mux);
274 WINPR_ASSERT(bundle);
276 WINPR_ASSERT(pthread_mutex_trylock(&bundle->mux) == EBUSY);
280 int r = pthread_cond_wait(&bundle->cond, &bundle->mux);
283 char ebuffer[256] = WINPR_C_ARRAY_INIT;
284 WLog_ERR(TAG,
"failed to wait for %s [%s]", name,
285 winpr_strerror(r, ebuffer,
sizeof(ebuffer)));
288 case ENOTRECOVERABLE:
306static BOOL signal_thread_ready(WINPR_THREAD* thread)
308 WINPR_ASSERT(thread);
310 return mux_condition_bundle_signal(&thread->isCreated);
313static BOOL signal_thread_is_running(WINPR_THREAD* thread)
315 WINPR_ASSERT(thread);
317 return mux_condition_bundle_signal(&thread->isRunning);
320static DWORD ThreadCleanupHandle(HANDLE handle)
322 DWORD status = WAIT_FAILED;
323 WINPR_THREAD* thread = (WINPR_THREAD*)handle;
325 if (!ThreadIsHandled(handle))
328 if (!run_mutex_fkt(pthread_mutex_lock, &thread->mutex))
333 int rc = pthread_join(thread->thread,
nullptr);
337 char ebuffer[256] = WINPR_C_ARRAY_INIT;
338 WLog_ERR(TAG,
"pthread_join failure: [%d] %s", rc,
339 winpr_strerror(rc, ebuffer,
sizeof(ebuffer)));
343 thread->joined = TRUE;
346 status = WAIT_OBJECT_0;
349 if (!run_mutex_fkt(pthread_mutex_checked_unlock, &thread->mutex))
355static HANDLE_OPS ops = { ThreadIsHandled, ThreadCloseHandle, ThreadGetFd, ThreadCleanupHandle,
356 nullptr,
nullptr,
nullptr,
nullptr,
357 nullptr,
nullptr,
nullptr,
nullptr,
358 nullptr,
nullptr,
nullptr,
nullptr,
359 nullptr,
nullptr,
nullptr,
nullptr,
362static void dump_thread(WINPR_THREAD* thread)
364#if defined(WITH_DEBUG_THREADS)
365 void* stack = winpr_backtrace(20);
366 char** msg =
nullptr;
368 WLog_DBG(TAG,
"Called from:");
369 msg = winpr_backtrace_symbols(stack, &used);
371 for (
size_t i = 0; i < used; i++)
372 WLog_DBG(TAG,
"[%" PRIuz
"]: %s", i, msg[i]);
375 winpr_backtrace_free(stack);
376 WLog_DBG(TAG,
"Thread handle created still not closed!");
377 msg = winpr_backtrace_symbols(thread->create_stack, &used);
379 for (
size_t i = 0; i < used; i++)
380 WLog_DBG(TAG,
"[%" PRIuz
"]: %s", i, msg[i]);
386 WLog_DBG(TAG,
"Thread still running!");
388 else if (!thread->exit_stack)
390 WLog_DBG(TAG,
"Thread suspended.");
394 WLog_DBG(TAG,
"Thread exited at:");
395 msg = winpr_backtrace_symbols(thread->exit_stack, &used);
397 for (
size_t i = 0; i < used; i++)
398 WLog_DBG(TAG,
"[%" PRIuz
"]: %s", i, msg[i]);
403 WINPR_UNUSED(thread);
411static BOOL set_event(WINPR_THREAD* thread)
413 return winpr_event_set(&thread->event);
416static BOOL reset_event(WINPR_THREAD* thread)
418 return winpr_event_reset(&thread->event);
421#if defined(WITH_THREAD_LIST)
422static BOOL thread_compare(
const void* a,
const void* b)
424 const pthread_t* p1 = a;
425 const pthread_t* p2 = b;
426 BOOL rc = pthread_equal(*p1, *p2);
431static INIT_ONCE threads_InitOnce = INIT_ONCE_STATIC_INIT;
432static pthread_t mainThreadId;
433static pthread_key_t currentThreadTlsIndex = 0;
435static BOOL initializeThreads(WINPR_ATTR_UNUSED
PINIT_ONCE InitOnce,
436 WINPR_ATTR_UNUSED PVOID Parameter, WINPR_ATTR_UNUSED PVOID* Context)
438 if (!apc_init(&mainThread.apc))
440 WLog_ERR(TAG,
"failed to initialize APC");
444 mainThread.common.Type = HANDLE_TYPE_THREAD;
445 mainThreadId = pthread_self();
447 const int res = pthread_key_create(¤tThreadTlsIndex,
nullptr);
450 WLog_ERR(TAG,
"Major bug, unable to allocate a TLS value for currentThread");
454#if defined(WITH_THREAD_LIST)
455 thread_list = ListDictionary_New(TRUE);
459 WLog_ERR(TAG,
"Couldn't create global thread list");
460 goto error_thread_list;
463 thread_list->objectKey.fnObjectEquals = thread_compare;
470static BOOL signal_and_wait_for_ready(WINPR_THREAD* thread)
474 WINPR_ASSERT(thread);
476 if (!mux_condition_bundle_lock(&thread->isRunning))
479 if (!signal_thread_ready(thread))
482 if (!mux_condition_bundle_wait(&thread->isRunning,
"threadIsRunning"))
485#if defined(WITH_THREAD_LIST)
486 if (!ListDictionary_Contains(thread_list, &thread->thread))
488 WLog_ERR(TAG,
"Thread not in thread_list, startup failed!");
496 if (!mux_condition_bundle_unlock(&thread->isRunning))
505static void* thread_launcher(
void* arg)
508 WINPR_THREAD* thread = (WINPR_THREAD*)arg;
509 LPTHREAD_START_ROUTINE fkt =
nullptr;
513 WLog_ERR(TAG,
"Called with invalid argument %p", arg);
517 const int res = pthread_setspecific(currentThreadTlsIndex, thread);
520 WLog_ERR(TAG,
"thread %" PRIu64
", unable to set current thread value",
521 WINPR_CXX_COMPAT_CAST(uint64_t, pthread_self()));
525 if (!(fkt = thread->lpStartAddress))
529 LPTHREAD_START_ROUTINE fkt;
533 WLog_ERR(TAG,
"Thread function argument is %p", cnv.pv);
537 if (!signal_and_wait_for_ready(thread))
540 rc = fkt(thread->lpParameter);
545 apc_cleanupThread(thread);
548 thread->dwExitCode = rc;
552 (void)signal_thread_ready(thread);
554 if (thread->detached || !thread->started)
555 cleanup_handle(thread);
561static BOOL winpr_StartThread(WINPR_THREAD* thread)
565 pthread_attr_t attr = WINPR_C_ARRAY_INIT;
567 if (!mux_condition_bundle_lock(&thread->isCreated))
571 pthread_attr_init(&attr);
572 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
574 size_t stackSize = thread->dwStackSize;
577 size_t platformDefault = 0;
578 if ((pthread_attr_getstacksize(&attr, &platformDefault) == 0) &&
579 (platformDefault < WINPR_THREAD_DEFAULT_STACK_SIZE))
580 stackSize = WINPR_THREAD_DEFAULT_STACK_SIZE;
585 const int err = pthread_attr_setstacksize(&attr, stackSize);
588 char ebuffer[256] = WINPR_C_ARRAY_INIT;
589 WLog_WARN(TAG,
"pthread_attr_setstacksize(%" PRIuz
") failed: %s", stackSize,
590 winpr_strerror(err, ebuffer,
sizeof(ebuffer)));
594 thread->started = TRUE;
597#if defined(WITH_THREAD_LIST)
598 if (!ListDictionary_Add(thread_list, &thread->thread, thread))
600 WLog_ERR(TAG,
"failed to add the thread to the thread list");
605 if (pthread_create(&thread->thread, &attr, thread_launcher, thread))
608 if (!mux_condition_bundle_wait(&thread->isCreated,
"threadIsCreated"))
612 if (!mux_condition_bundle_unlock(&thread->isCreated))
615 if (!signal_thread_is_running(thread))
617 WLog_ERR(TAG,
"failed to signal the thread was ready");
625 if (!mux_condition_bundle_unlock(&thread->isCreated))
629 pthread_attr_destroy(&attr);
637BOOL SetThreadPriority(HANDLE hThread,
int nPriority)
642 if (!winpr_Handle_GetInfo(hThread, &Type, &Object) || Object->Type != HANDLE_TYPE_THREAD)
647 const int diff = (max - min);
648 const int normal = min + diff / 2;
649 const int off = MIN(1, diff / 4);
650 int sched_priority = -1;
652 switch (nPriority & ~(THREAD_MODE_BACKGROUND_BEGIN | THREAD_MODE_BACKGROUND_END))
654 case THREAD_PRIORITY_ABOVE_NORMAL:
655 sched_priority = MIN(normal + off, max);
657 case THREAD_PRIORITY_BELOW_NORMAL:
658 sched_priority = MAX(normal - off, min);
660 case THREAD_PRIORITY_HIGHEST:
661 sched_priority = max;
663 case THREAD_PRIORITY_IDLE:
664 sched_priority = min;
666 case THREAD_PRIORITY_LOWEST:
667 sched_priority = min;
669 case THREAD_PRIORITY_TIME_CRITICAL:
670 sched_priority = max;
673 case THREAD_PRIORITY_NORMAL:
674 sched_priority = normal;
677#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L) && defined(PTHREAD_SETSCHEDPRIO)
678 WINPR_THREAD* thread = (WINPR_THREAD*)Object;
679 const int rc = pthread_setschedprio(thread->thread, sched_priority);
682 char buffer[256] = WINPR_C_ARRAY_INIT;
683 WLog_ERR(TAG,
"pthread_setschedprio(%d) %s [%d]", sched_priority,
684 winpr_strerror(rc, buffer,
sizeof(buffer)), rc);
688 WLog_WARN(TAG,
"pthread_setschedprio(%d) not implemented, requires POSIX 2008 or later",
694HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,
size_t dwStackSize,
695 LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter,
696 DWORD dwCreationFlags, WINPR_ATTR_UNUSED LPDWORD lpThreadId)
698 HANDLE handle =
nullptr;
699 WINPR_THREAD* thread = (WINPR_THREAD*)calloc(1,
sizeof(WINPR_THREAD));
704 thread->dwStackSize = dwStackSize;
705 thread->lpParameter = lpParameter;
706 thread->lpStartAddress = lpStartAddress;
707 thread->lpThreadAttributes = lpThreadAttributes;
708 thread->common.ops = &ops;
709#if defined(WITH_DEBUG_THREADS)
710 thread->create_stack = winpr_backtrace(20);
714 if (!winpr_event_init(&thread->event))
716 WLog_ERR(TAG,
"failed to create event");
720 if (!run_mutex_init(pthread_mutex_init, &thread->mutex,
nullptr))
722 WLog_ERR(TAG,
"failed to initialize thread mutex");
726 if (!apc_init(&thread->apc))
728 WLog_ERR(TAG,
"failed to initialize APC");
732 if (!mux_condition_bundle_init(&thread->isCreated))
734 if (!mux_condition_bundle_init(&thread->isRunning))
737 WINPR_HANDLE_SET_TYPE_AND_MODE(thread, HANDLE_TYPE_THREAD, WINPR_FD_READ);
738 handle = (HANDLE)thread;
740 if (!InitOnceExecuteOnce(&threads_InitOnce, initializeThreads,
nullptr,
nullptr))
743 if (!(dwCreationFlags & CREATE_SUSPENDED))
745 if (!winpr_StartThread(thread))
750 if (!set_event(thread))
756 cleanup_handle(thread);
760void cleanup_handle(
void* obj)
762 WINPR_THREAD* thread = (WINPR_THREAD*)obj;
766 if (!apc_uninit(&thread->apc))
767 WLog_ERR(TAG,
"failed to destroy APC");
769 mux_condition_bundle_uninit(&thread->isCreated);
770 mux_condition_bundle_uninit(&thread->isRunning);
771 run_mutex_fkt(pthread_mutex_destroy, &thread->mutex);
773 winpr_event_uninit(&thread->event);
775#if defined(WITH_THREAD_LIST)
776 ListDictionary_Remove(thread_list, &thread->thread);
778#if defined(WITH_DEBUG_THREADS)
780 if (thread->create_stack)
781 winpr_backtrace_free(thread->create_stack);
783 if (thread->exit_stack)
784 winpr_backtrace_free(thread->exit_stack);
790BOOL ThreadCloseHandle(HANDLE handle)
792 WINPR_THREAD* thread = (WINPR_THREAD*)handle;
794#if defined(WITH_THREAD_LIST)
797 WLog_ERR(TAG,
"Thread list does not exist, check call!");
800 else if (!ListDictionary_Contains(thread_list, &thread->thread))
802 WLog_ERR(TAG,
"Thread list does not contain this thread! check call!");
807 ListDictionary_Lock(thread_list);
811 if ((thread->started) && (WaitForSingleObject(thread, 0) != WAIT_OBJECT_0))
813 WLog_DBG(TAG,
"Thread running, setting to detached state!");
814 thread->detached = TRUE;
815 pthread_detach(thread->thread);
819 cleanup_handle(thread);
822#if defined(WITH_THREAD_LIST)
823 ListDictionary_Unlock(thread_list);
830HANDLE CreateRemoteThread(WINPR_ATTR_UNUSED HANDLE hProcess,
831 WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpThreadAttributes,
832 WINPR_ATTR_UNUSED
size_t dwStackSize,
833 WINPR_ATTR_UNUSED LPTHREAD_START_ROUTINE lpStartAddress,
834 WINPR_ATTR_UNUSED LPVOID lpParameter,
835 WINPR_ATTR_UNUSED DWORD dwCreationFlags,
836 WINPR_ATTR_UNUSED LPDWORD lpThreadId)
838 WLog_ERR(TAG,
"not implemented");
839 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
843VOID ExitThread(DWORD dwExitCode)
845#if defined(WITH_THREAD_LIST)
847 pthread_t tid = pthread_self();
851 WLog_ERR(TAG,
"function called without existing thread list!");
852#if defined(WITH_DEBUG_THREADS)
857 else if (!ListDictionary_Contains(thread_list, &tid))
859 WLog_ERR(TAG,
"function called, but no matching entry in thread list!");
860#if defined(WITH_DEBUG_THREADS)
867 WINPR_THREAD* thread;
868 ListDictionary_Lock(thread_list);
869 thread = ListDictionary_GetItemValue(thread_list, &tid);
870 WINPR_ASSERT(thread);
871 thread->exited = TRUE;
872 thread->dwExitCode = dwExitCode;
873#if defined(WITH_DEBUG_THREADS)
874 thread->exit_stack = winpr_backtrace(20);
876 ListDictionary_Unlock(thread_list);
878 rc = thread->dwExitCode;
880 if (thread->detached || !thread->started)
881 cleanup_handle(thread);
883 pthread_exit((
void*)(
size_t)rc);
886 WINPR_UNUSED(dwExitCode);
890BOOL GetExitCodeThread(HANDLE hThread, LPDWORD lpExitCode)
894 WINPR_THREAD* thread =
nullptr;
896 if (!winpr_Handle_GetInfo(hThread, &Type, &Object) || Object->Type != HANDLE_TYPE_THREAD)
898 WLog_ERR(TAG,
"hThread is not a thread");
899 SetLastError(ERROR_INVALID_PARAMETER);
903 thread = (WINPR_THREAD*)Object;
904 *lpExitCode = thread->dwExitCode;
908WINPR_THREAD* winpr_GetCurrentThread(VOID)
910 WINPR_THREAD* ret =
nullptr;
912 if (!InitOnceExecuteOnce(&threads_InitOnce, initializeThreads,
nullptr,
nullptr))
914 if (mainThreadId == pthread_self())
915 return (HANDLE)&mainThread;
917 ret = pthread_getspecific(currentThreadTlsIndex);
921HANDLE _GetCurrentThread(VOID)
923 return (HANDLE)winpr_GetCurrentThread();
926DWORD GetCurrentThreadId(VOID)
928#if defined(__FreeBSD__)
929 return WINPR_CXX_COMPAT_CAST(DWORD, pthread_getthreadid_np());
930#elif defined(__OpenBSD__)
931 return WINPR_CXX_COMPAT_CAST(DWORD, getthrid());
932#elif defined(__linux__)
933 return WINPR_CXX_COMPAT_CAST(DWORD, syscall(SYS_gettid));
935 pthread_t tid = pthread_self();
938 uintptr_t ptid = WINPR_REINTERPRET_CAST(tid, pthread_t, uintptr_t);
939#if UINTPTR_MAX > UINT32_MAX
940 return (ptid & UINT32_MAX) ^ (ptid >> 32);
946 return WINPR_CXX_COMPAT_CAST(DWORD, ptid);
955 ULONG_PTR completionArg;
958static void userAPC(LPVOID arg)
960 UserApcItem* userApc = (UserApcItem*)arg;
962 userApc->completion(userApc->completionArg);
964 userApc->apc.markedForRemove = TRUE;
967DWORD QueueUserAPC(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData)
971 WINPR_APC_ITEM* apc =
nullptr;
972 UserApcItem* apcItem =
nullptr;
977 if (!winpr_Handle_GetInfo(hThread, &Type, &Object) || Object->Type != HANDLE_TYPE_THREAD)
979 WLog_ERR(TAG,
"hThread is not a thread");
980 SetLastError(ERROR_INVALID_PARAMETER);
984 apcItem = calloc(1,
sizeof(*apcItem));
987 SetLastError(ERROR_INVALID_PARAMETER);
992 apc->type = APC_TYPE_USER;
993 apc->markedForFree = TRUE;
994 apc->alwaysSignaled = TRUE;
995 apc->completion = userAPC;
996 apc->completionArgs = apc;
997 apcItem->completion = pfnAPC;
998 apcItem->completionArg = dwData;
999 apc_register(hThread, apc);
1003DWORD ResumeThread(HANDLE hThread)
1007 WINPR_THREAD* thread =
nullptr;
1009 if (!winpr_Handle_GetInfo(hThread, &Type, &Object) || Object->Type != HANDLE_TYPE_THREAD)
1011 WLog_ERR(TAG,
"hThread is not a thread");
1012 SetLastError(ERROR_INVALID_PARAMETER);
1016 thread = (WINPR_THREAD*)Object;
1018 if (!run_mutex_fkt(pthread_mutex_lock, &thread->mutex))
1021 if (!thread->started)
1023 if (!winpr_StartThread(thread))
1025 run_mutex_fkt(pthread_mutex_checked_unlock, &thread->mutex);
1030 WLog_WARN(TAG,
"Thread already started!");
1032 if (!run_mutex_fkt(pthread_mutex_checked_unlock, &thread->mutex))
1038DWORD SuspendThread(WINPR_ATTR_UNUSED HANDLE hThread)
1040 WLog_ERR(TAG,
"not implemented");
1041 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1045BOOL SwitchToThread(VOID)
1051 if (sched_yield() != 0)
1057BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode)
1061 WINPR_THREAD* thread =
nullptr;
1063 if (!winpr_Handle_GetInfo(hThread, &Type, &Object) || Object->Type != HANDLE_TYPE_THREAD)
1066 thread = (WINPR_THREAD*)Object;
1067 thread->exited = TRUE;
1068 thread->dwExitCode = dwExitCode;
1070 if (!run_mutex_fkt(pthread_mutex_lock, &thread->mutex))
1074 pthread_cancel(thread->thread);
1076 WLog_ERR(TAG,
"Function not supported on this platform!");
1079 if (!run_mutex_fkt(pthread_mutex_checked_unlock, &thread->mutex))
1086VOID DumpThreadHandles(
void)
1088#if defined(WITH_DEBUG_THREADS)
1089 char** msg =
nullptr;
1091 void* stack = winpr_backtrace(20);
1092 WLog_DBG(TAG,
"---------------- Called from ----------------------------");
1093 msg = winpr_backtrace_symbols(stack, &used);
1095 for (
size_t i = 0; i < used; i++)
1097 WLog_DBG(TAG,
"[%" PRIuz
"]: %s", i, msg[i]);
1101 winpr_backtrace_free(stack);
1102 WLog_DBG(TAG,
"---------------- Start Dumping thread handles -----------");
1104#if defined(WITH_THREAD_LIST)
1107 WLog_DBG(TAG,
"All threads properly shut down and disposed of.");
1111 ULONG_PTR* keys =
nullptr;
1112 ListDictionary_Lock(thread_list);
1113 int x, count = ListDictionary_GetKeys(thread_list, &keys);
1114 WLog_DBG(TAG,
"Dumping %d elements", count);
1116 for (
size_t x = 0; x < count; x++)
1118 WINPR_THREAD* thread = ListDictionary_GetItemValue(thread_list, (
void*)keys[x]);
1119 WLog_DBG(TAG,
"Thread [%d] handle created still not closed!", x);
1120 msg = winpr_backtrace_symbols(thread->create_stack, &used);
1122 for (
size_t i = 0; i < used; i++)
1124 WLog_DBG(TAG,
"[%" PRIdz
"]: %s", i, msg[i]);
1129 if (thread->started)
1131 WLog_DBG(TAG,
"Thread [%d] still running!", x);
1135 WLog_DBG(TAG,
"Thread [%d] exited at:", x);
1136 msg = winpr_backtrace_symbols(thread->exit_stack, &used);
1138 for (
size_t i = 0; i < used; i++)
1139 WLog_DBG(TAG,
"[%" PRIdz
"]: %s", i, msg[i]);
1146 ListDictionary_Unlock(thread_list);
1150 WLog_DBG(TAG,
"---------------- End Dumping thread handles -------------");