1 /**
2 * WinPR: Windows Portable Runtime
3 * Process Thread Functions
4 *
5 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6 * Copyright 2015 Hewlett-Packard Development Company, L.P.
7 * Copyright 2021 David Fort <contact@hardening-consulting.com>
8 *
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <assert.h>
28
29 #include <winpr/handle.h>
30
31 #include <winpr/thread.h>
32
33 /**
34 * api-ms-win-core-processthreads-l1-1-1.dll
35 *
36 * CreateRemoteThread
37 * CreateRemoteThreadEx
38 * CreateThread
39 * DeleteProcThreadAttributeList
40 * ExitThread
41 * FlushInstructionCache
42 * FlushProcessWriteBuffers
43 * GetCurrentThread
44 * GetCurrentThreadId
45 * GetCurrentThreadStackLimits
46 * GetExitCodeThread
47 * GetPriorityClass
48 * GetStartupInfoW
49 * GetThreadContext
50 * GetThreadId
51 * GetThreadIdealProcessorEx
52 * GetThreadPriority
53 * GetThreadPriorityBoost
54 * GetThreadTimes
55 * InitializeProcThreadAttributeList
56 * OpenThread
57 * OpenThreadToken
58 * QueryProcessAffinityUpdateMode
59 * QueueUserAPC
60 * ResumeThread
61 * SetPriorityClass
62 * SetThreadContext
63 * SetThreadPriority
64 * SetThreadPriorityBoost
65 * SetThreadStackGuarantee
66 * SetThreadToken
67 * SuspendThread
68 * SwitchToThread
69 * TerminateThread
70 * UpdateProcThreadAttribute
71 */
72
73 #ifndef _WIN32
74
75 #include <winpr/crt.h>
76 #include <winpr/platform.h>
77
78 #ifdef HAVE_UNISTD_H
79 #include <unistd.h>
80 #endif
81
82 #ifdef HAVE_SYS_EVENTFD_H
83 #include <sys/eventfd.h>
84 #endif
85
86 #include <winpr/debug.h>
87
88 #include <errno.h>
89 #include <fcntl.h>
90
91 #include <winpr/collections.h>
92
93 #include "thread.h"
94 #include "apc.h"
95
96 #include "../handle/handle.h"
97 #include "../log.h"
98 #define TAG WINPR_TAG("thread")
99
100 static WINPR_THREAD mainThread;
101 static wListDictionary* thread_list = NULL;
102
103 static BOOL ThreadCloseHandle(HANDLE handle);
104 static void cleanup_handle(void* obj);
105
ThreadIsHandled(HANDLE handle)106 static BOOL ThreadIsHandled(HANDLE handle)
107 {
108 WINPR_THREAD* pThread = (WINPR_THREAD*)handle;
109
110 if (!pThread || (pThread->Type != HANDLE_TYPE_THREAD))
111 {
112 SetLastError(ERROR_INVALID_HANDLE);
113 return FALSE;
114 }
115
116 return TRUE;
117 }
118
ThreadGetFd(HANDLE handle)119 static int ThreadGetFd(HANDLE handle)
120 {
121 WINPR_THREAD* pThread = (WINPR_THREAD*)handle;
122
123 if (!ThreadIsHandled(handle))
124 return -1;
125
126 return pThread->event.fds[0];
127 }
128
ThreadCleanupHandle(HANDLE handle)129 static DWORD ThreadCleanupHandle(HANDLE handle)
130 {
131 WINPR_THREAD* thread = (WINPR_THREAD*)handle;
132
133 if (!ThreadIsHandled(handle))
134 return WAIT_FAILED;
135
136 if (pthread_mutex_lock(&thread->mutex))
137 return WAIT_FAILED;
138
139 if (!thread->joined)
140 {
141 int status;
142 status = pthread_join(thread->thread, NULL);
143
144 if (status != 0)
145 {
146 WLog_ERR(TAG, "pthread_join failure: [%d] %s", status, strerror(status));
147 pthread_mutex_unlock(&thread->mutex);
148 return WAIT_FAILED;
149 }
150 else
151 thread->joined = TRUE;
152 }
153
154 if (pthread_mutex_unlock(&thread->mutex))
155 return WAIT_FAILED;
156
157 return WAIT_OBJECT_0;
158 }
159
160 static HANDLE_OPS ops = { ThreadIsHandled,
161 ThreadCloseHandle,
162 ThreadGetFd,
163 ThreadCleanupHandle,
164 NULL,
165 NULL,
166 NULL,
167 NULL,
168 NULL,
169 NULL,
170 NULL,
171 NULL,
172 NULL,
173 NULL,
174 NULL,
175 NULL,
176 NULL,
177 NULL,
178 NULL,
179 NULL };
180
dump_thread(WINPR_THREAD * thread)181 static void dump_thread(WINPR_THREAD* thread)
182 {
183 #if defined(WITH_DEBUG_THREADS)
184 void* stack = winpr_backtrace(20);
185 char** msg;
186 size_t used, i;
187 WLog_DBG(TAG, "Called from:");
188 msg = winpr_backtrace_symbols(stack, &used);
189
190 for (i = 0; i < used; i++)
191 WLog_DBG(TAG, "[%" PRIdz "]: %s", i, msg[i]);
192
193 free(msg);
194 winpr_backtrace_free(stack);
195 WLog_DBG(TAG, "Thread handle created still not closed!");
196 msg = winpr_backtrace_symbols(thread->create_stack, &used);
197
198 for (i = 0; i < used; i++)
199 WLog_DBG(TAG, "[%" PRIdz "]: %s", i, msg[i]);
200
201 free(msg);
202
203 if (thread->started)
204 {
205 WLog_DBG(TAG, "Thread still running!");
206 }
207 else if (!thread->exit_stack)
208 {
209 WLog_DBG(TAG, "Thread suspended.");
210 }
211 else
212 {
213 WLog_DBG(TAG, "Thread exited at:");
214 msg = winpr_backtrace_symbols(thread->exit_stack, &used);
215
216 for (i = 0; i < used; i++)
217 WLog_DBG(TAG, "[%" PRIdz "]: %s", i, msg[i]);
218
219 free(msg);
220 }
221
222 #endif
223 }
224
225 /**
226 * TODO: implement thread suspend/resume using pthreads
227 * http://stackoverflow.com/questions/3140867/suspend-pthreads-without-using-condition
228 */
set_event(WINPR_THREAD * thread)229 static BOOL set_event(WINPR_THREAD* thread)
230 {
231 return winpr_event_set(&thread->event);
232 }
233
reset_event(WINPR_THREAD * thread)234 static BOOL reset_event(WINPR_THREAD* thread)
235 {
236 return winpr_event_reset(&thread->event);
237 }
238
thread_compare(const void * a,const void * b)239 static BOOL thread_compare(const void* a, const void* b)
240 {
241 const pthread_t* p1 = a;
242 const pthread_t* p2 = b;
243 BOOL rc = pthread_equal(*p1, *p2);
244 return rc;
245 }
246
247 static INIT_ONCE threads_InitOnce = INIT_ONCE_STATIC_INIT;
248 static pthread_t mainThreadId;
249 static DWORD currentThreadTlsIndex = TLS_OUT_OF_INDEXES;
250
initializeThreads(PINIT_ONCE InitOnce,PVOID Parameter,PVOID * Context)251 BOOL initializeThreads(PINIT_ONCE InitOnce, PVOID Parameter, PVOID* Context)
252 {
253 if (!apc_init(&mainThread.apc))
254 {
255 WLog_ERR(TAG, "failed to initialize APC");
256 goto out;
257 }
258
259 mainThread.Type = HANDLE_TYPE_THREAD;
260 mainThreadId = pthread_self();
261
262 currentThreadTlsIndex = TlsAlloc();
263 if (currentThreadTlsIndex == TLS_OUT_OF_INDEXES)
264 {
265 WLog_ERR(TAG, "Major bug, unable to allocate a TLS value for currentThread");
266 }
267
268 out:
269 return TRUE;
270 }
271
272 /* Thread launcher function responsible for registering
273 * cleanup handlers and calling pthread_exit, if not done
274 * in thread function. */
thread_launcher(void * arg)275 static void* thread_launcher(void* arg)
276 {
277 DWORD rc = 0;
278 WINPR_THREAD* thread = (WINPR_THREAD*)arg;
279 LPTHREAD_START_ROUTINE fkt;
280
281 if (!thread)
282 {
283 WLog_ERR(TAG, "Called with invalid argument %p", arg);
284 goto exit;
285 }
286
287 if (!TlsSetValue(currentThreadTlsIndex, thread))
288 {
289 WLog_ERR(TAG, "thread %d, unable to set current thread value", pthread_self());
290 goto exit;
291 }
292
293 if (!(fkt = thread->lpStartAddress))
294 {
295 WLog_ERR(TAG, "Thread function argument is %p", (void*)fkt);
296 goto exit;
297 }
298
299 if (pthread_mutex_lock(&thread->threadIsReadyMutex))
300 goto exit;
301
302 if (!ListDictionary_Contains(thread_list, &thread->thread))
303 {
304 if (pthread_cond_wait(&thread->threadIsReady, &thread->threadIsReadyMutex) != 0)
305 {
306 WLog_ERR(TAG, "The thread could not be made ready");
307 pthread_mutex_unlock(&thread->threadIsReadyMutex);
308 goto exit;
309 }
310 }
311
312 if (pthread_mutex_unlock(&thread->threadIsReadyMutex))
313 goto exit;
314
315 assert(ListDictionary_Contains(thread_list, &thread->thread));
316 rc = fkt(thread->lpParameter);
317 exit:
318
319 if (thread)
320 {
321 apc_cleanupThread(thread);
322
323 if (!thread->exited)
324 thread->dwExitCode = rc;
325
326 set_event(thread);
327
328 if (thread->detached || !thread->started)
329 cleanup_handle(thread);
330 }
331
332 return NULL;
333 }
334
winpr_StartThread(WINPR_THREAD * thread)335 static BOOL winpr_StartThread(WINPR_THREAD* thread)
336 {
337 pthread_attr_t attr;
338 pthread_attr_init(&attr);
339 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
340
341 if (thread->dwStackSize > 0)
342 pthread_attr_setstacksize(&attr, (size_t)thread->dwStackSize);
343
344 thread->started = TRUE;
345 reset_event(thread);
346
347 if (pthread_create(&thread->thread, &attr, thread_launcher, thread))
348 goto error;
349
350 if (pthread_mutex_lock(&thread->threadIsReadyMutex))
351 goto error;
352
353 if (!ListDictionary_Add(thread_list, &thread->thread, thread))
354 {
355 WLog_ERR(TAG, "failed to add the thread to the thread list");
356 pthread_mutex_unlock(&thread->threadIsReadyMutex);
357 goto error;
358 }
359
360 if (pthread_cond_signal(&thread->threadIsReady) != 0)
361 {
362 WLog_ERR(TAG, "failed to signal the thread was ready");
363 pthread_mutex_unlock(&thread->threadIsReadyMutex);
364 goto error;
365 }
366
367 if (pthread_mutex_unlock(&thread->threadIsReadyMutex))
368 goto error;
369
370 pthread_attr_destroy(&attr);
371 dump_thread(thread);
372 return TRUE;
373 error:
374 pthread_attr_destroy(&attr);
375 return FALSE;
376 }
377
CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId)378 HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize,
379 LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter,
380 DWORD dwCreationFlags, LPDWORD lpThreadId)
381 {
382 HANDLE handle;
383 WINPR_THREAD* thread;
384 thread = (WINPR_THREAD*)calloc(1, sizeof(WINPR_THREAD));
385
386 if (!thread)
387 return NULL;
388
389 thread->dwStackSize = dwStackSize;
390 thread->lpParameter = lpParameter;
391 thread->lpStartAddress = lpStartAddress;
392 thread->lpThreadAttributes = lpThreadAttributes;
393 thread->ops = &ops;
394 #if defined(WITH_DEBUG_THREADS)
395 thread->create_stack = winpr_backtrace(20);
396 dump_thread(thread);
397 #endif
398
399 if (!winpr_event_init(&thread->event))
400 {
401 WLog_ERR(TAG, "failed to create event");
402 goto error_event;
403 }
404
405 if (pthread_mutex_init(&thread->mutex, NULL) != 0)
406 {
407 WLog_ERR(TAG, "failed to initialize thread mutex");
408 goto error_mutex;
409 }
410
411 if (!apc_init(&thread->apc))
412 {
413 WLog_ERR(TAG, "failed to initialize APC");
414 goto error_APC;
415 }
416
417 if (pthread_mutex_init(&thread->threadIsReadyMutex, NULL) != 0)
418 {
419 WLog_ERR(TAG, "failed to initialize a mutex for a condition variable");
420 goto error_thread_ready_mutex;
421 }
422
423 if (pthread_cond_init(&thread->threadIsReady, NULL) != 0)
424 {
425 WLog_ERR(TAG, "failed to initialize a condition variable");
426 goto error_thread_ready;
427 }
428
429 WINPR_HANDLE_SET_TYPE_AND_MODE(thread, HANDLE_TYPE_THREAD, WINPR_FD_READ);
430 handle = (HANDLE)thread;
431
432 if (!thread_list)
433 {
434 InitOnceExecuteOnce(&threads_InitOnce, initializeThreads, NULL, NULL);
435 thread_list = ListDictionary_New(TRUE);
436
437 if (!thread_list)
438 {
439 WLog_ERR(TAG, "Couldn't create global thread list");
440 goto error_thread_list;
441 }
442
443 thread_list->objectKey.fnObjectEquals = thread_compare;
444 }
445
446 if (!(dwCreationFlags & CREATE_SUSPENDED))
447 {
448 if (!winpr_StartThread(thread))
449 goto error_thread_list;
450 }
451 else
452 {
453 if (!set_event(thread))
454 goto error_thread_list;
455 }
456
457 return handle;
458 error_thread_list:
459 pthread_cond_destroy(&thread->threadIsReady);
460 error_thread_ready:
461 pthread_mutex_destroy(&thread->threadIsReadyMutex);
462 error_thread_ready_mutex:
463 apc_uninit(&thread->apc);
464 error_APC:
465 pthread_mutex_destroy(&thread->mutex);
466 error_mutex:
467 winpr_event_uninit(&thread->event);
468 error_event:
469 free(thread);
470 return NULL;
471 }
472
cleanup_handle(void * obj)473 void cleanup_handle(void* obj)
474 {
475 int rc;
476 WINPR_THREAD* thread = (WINPR_THREAD*)obj;
477
478 if (!apc_uninit(&thread->apc))
479 WLog_ERR(TAG, "failed to destroy APC");
480
481 rc = pthread_cond_destroy(&thread->threadIsReady);
482 if (rc)
483 WLog_ERR(TAG, "failed to destroy thread->threadIsReady [%d] %s (%d)", rc, strerror(errno),
484 errno);
485
486 rc = pthread_mutex_destroy(&thread->threadIsReadyMutex);
487 if (rc)
488 WLog_ERR(TAG, "failed to destroy thread->threadIsReadyMutex [%d] %s (%d)", rc,
489 strerror(errno), errno);
490
491 rc = pthread_mutex_destroy(&thread->mutex);
492 if (rc)
493 WLog_ERR(TAG, "failed to destroy thread->mutex [%d] %s (%d)", rc, strerror(errno), errno);
494
495 winpr_event_uninit(&thread->event);
496
497 if (thread_list && ListDictionary_Contains(thread_list, &thread->thread))
498 ListDictionary_Remove(thread_list, &thread->thread);
499
500 #if defined(WITH_DEBUG_THREADS)
501
502 if (thread->create_stack)
503 winpr_backtrace_free(thread->create_stack);
504
505 if (thread->exit_stack)
506 winpr_backtrace_free(thread->exit_stack);
507
508 #endif
509 free(thread);
510 }
511
ThreadCloseHandle(HANDLE handle)512 BOOL ThreadCloseHandle(HANDLE handle)
513 {
514 WINPR_THREAD* thread = (WINPR_THREAD*)handle;
515
516 if (!thread_list)
517 {
518 WLog_ERR(TAG, "Thread list does not exist, check call!");
519 dump_thread(thread);
520 }
521 else if (!ListDictionary_Contains(thread_list, &thread->thread))
522 {
523 WLog_ERR(TAG, "Thread list does not contain this thread! check call!");
524 dump_thread(thread);
525 }
526 else
527 {
528 ListDictionary_Lock(thread_list);
529 dump_thread(thread);
530
531 if ((thread->started) && (WaitForSingleObject(thread, 0) != WAIT_OBJECT_0))
532 {
533 WLog_DBG(TAG, "Thread running, setting to detached state!");
534 thread->detached = TRUE;
535 pthread_detach(thread->thread);
536 }
537 else
538 {
539 cleanup_handle(thread);
540 }
541
542 ListDictionary_Unlock(thread_list);
543
544 if (ListDictionary_Count(thread_list) < 1)
545 {
546 ListDictionary_Free(thread_list);
547 thread_list = NULL;
548 }
549 }
550
551 return TRUE;
552 }
553
CreateRemoteThread(HANDLE hProcess,LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId)554 HANDLE CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes,
555 SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
556 LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId)
557 {
558 WLog_ERR(TAG, "%s: not implemented", __FUNCTION__);
559 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
560 return NULL;
561 }
562
ExitThread(DWORD dwExitCode)563 VOID ExitThread(DWORD dwExitCode)
564 {
565 DWORD rc;
566 pthread_t tid = pthread_self();
567
568 if (!thread_list)
569 {
570 WLog_ERR(TAG, "function called without existing thread list!");
571 #if defined(WITH_DEBUG_THREADS)
572 DumpThreadHandles();
573 #endif
574 pthread_exit(0);
575 }
576 else if (!ListDictionary_Contains(thread_list, &tid))
577 {
578 WLog_ERR(TAG, "function called, but no matching entry in thread list!");
579 #if defined(WITH_DEBUG_THREADS)
580 DumpThreadHandles();
581 #endif
582 pthread_exit(0);
583 }
584 else
585 {
586 WINPR_THREAD* thread;
587 ListDictionary_Lock(thread_list);
588 thread = ListDictionary_GetItemValue(thread_list, &tid);
589 assert(thread);
590 thread->exited = TRUE;
591 thread->dwExitCode = dwExitCode;
592 #if defined(WITH_DEBUG_THREADS)
593 thread->exit_stack = winpr_backtrace(20);
594 #endif
595 ListDictionary_Unlock(thread_list);
596 set_event(thread);
597 rc = thread->dwExitCode;
598
599 if (thread->detached || !thread->started)
600 cleanup_handle(thread);
601
602 pthread_exit((void*)(size_t)rc);
603 }
604 }
605
GetExitCodeThread(HANDLE hThread,LPDWORD lpExitCode)606 BOOL GetExitCodeThread(HANDLE hThread, LPDWORD lpExitCode)
607 {
608 ULONG Type;
609 WINPR_HANDLE* Object;
610 WINPR_THREAD* thread;
611
612 if (!winpr_Handle_GetInfo(hThread, &Type, &Object))
613 return FALSE;
614
615 thread = (WINPR_THREAD*)Object;
616 *lpExitCode = thread->dwExitCode;
617 return TRUE;
618 }
619
winpr_GetCurrentThread(VOID)620 WINPR_THREAD* winpr_GetCurrentThread(VOID)
621 {
622 WINPR_THREAD* ret;
623
624 InitOnceExecuteOnce(&threads_InitOnce, initializeThreads, NULL, NULL);
625 if (mainThreadId == pthread_self())
626 return (HANDLE)&mainThread;
627
628 ret = TlsGetValue(currentThreadTlsIndex);
629 if (!ret)
630 {
631 WLog_ERR(TAG, "function called, but no matching entry in thread list!");
632 #if defined(WITH_DEBUG_THREADS)
633 DumpThreadHandles();
634 #endif
635 }
636 return ret;
637 }
638
_GetCurrentThread(VOID)639 HANDLE _GetCurrentThread(VOID)
640 {
641 return (HANDLE)winpr_GetCurrentThread();
642 }
643
GetCurrentThreadId(VOID)644 DWORD GetCurrentThreadId(VOID)
645 {
646 pthread_t tid;
647 tid = pthread_self();
648 /* Since pthread_t can be 64-bits on some systems, take just the */
649 /* lower 32-bits of it for the thread ID returned by this function. */
650 return (DWORD)tid & 0xffffffffUL;
651 }
652
653 typedef struct
654 {
655 WINPR_APC_ITEM apc;
656 PAPCFUNC completion;
657 ULONG_PTR completionArg;
658 } UserApcItem;
659
userAPC(LPVOID arg)660 void userAPC(LPVOID arg)
661 {
662 UserApcItem* userApc = (UserApcItem*)arg;
663
664 userApc->completion(userApc->completionArg);
665
666 userApc->apc.markedForRemove = TRUE;
667 }
668
QueueUserAPC(PAPCFUNC pfnAPC,HANDLE hThread,ULONG_PTR dwData)669 DWORD QueueUserAPC(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData)
670 {
671 ULONG Type;
672 WINPR_HANDLE* Object;
673 WINPR_THREAD* thread;
674 WINPR_APC_ITEM* apc;
675 UserApcItem* apcItem;
676
677 if (!pfnAPC)
678 return 1;
679
680 if (!winpr_Handle_GetInfo(hThread, &Type, &Object) || Object->Type != HANDLE_TYPE_THREAD)
681 {
682 WLog_ERR(TAG, "hThread is not a thread");
683 SetLastError(ERROR_INVALID_PARAMETER);
684 return (DWORD)0;
685 }
686 thread = (WINPR_THREAD*)Object;
687
688 apcItem = calloc(1, sizeof(*apcItem));
689 if (!apcItem)
690 {
691 SetLastError(ERROR_INVALID_PARAMETER);
692 return (DWORD)0;
693 }
694
695 apc = &apcItem->apc;
696 apc->type = APC_TYPE_USER;
697 apc->markedForFree = TRUE;
698 apc->alwaysSignaled = TRUE;
699 apc->completion = userAPC;
700 apc->completionArgs = apc;
701 apcItem->completion = pfnAPC;
702 apcItem->completionArg = dwData;
703 apc_register(hThread, apc);
704 return 1;
705 }
706
ResumeThread(HANDLE hThread)707 DWORD ResumeThread(HANDLE hThread)
708 {
709 ULONG Type;
710 WINPR_HANDLE* Object;
711 WINPR_THREAD* thread;
712
713 if (!winpr_Handle_GetInfo(hThread, &Type, &Object))
714 return (DWORD)-1;
715
716 thread = (WINPR_THREAD*)Object;
717
718 if (pthread_mutex_lock(&thread->mutex))
719 return (DWORD)-1;
720
721 if (!thread->started)
722 {
723 if (!winpr_StartThread(thread))
724 {
725 pthread_mutex_unlock(&thread->mutex);
726 return (DWORD)-1;
727 }
728 }
729 else
730 WLog_WARN(TAG, "Thread already started!");
731
732 if (pthread_mutex_unlock(&thread->mutex))
733 return (DWORD)-1;
734
735 return 0;
736 }
737
SuspendThread(HANDLE hThread)738 DWORD SuspendThread(HANDLE hThread)
739 {
740 WLog_ERR(TAG, "%s: not implemented", __FUNCTION__);
741 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
742 return (DWORD)-1;
743 }
744
SwitchToThread(VOID)745 BOOL SwitchToThread(VOID)
746 {
747 /**
748 * Note: on some operating systems sched_yield is a stub returning -1.
749 * usleep should at least trigger a context switch if any thread is waiting.
750 */
751 if (sched_yield() != 0)
752 usleep(1);
753
754 return TRUE;
755 }
756
TerminateThread(HANDLE hThread,DWORD dwExitCode)757 BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode)
758 {
759 ULONG Type;
760 WINPR_HANDLE* Object;
761 WINPR_THREAD* thread;
762
763 if (!winpr_Handle_GetInfo(hThread, &Type, &Object))
764 return FALSE;
765
766 thread = (WINPR_THREAD*)Object;
767 thread->exited = TRUE;
768 thread->dwExitCode = dwExitCode;
769
770 if (pthread_mutex_lock(&thread->mutex))
771 return FALSE;
772
773 #ifndef ANDROID
774 pthread_cancel(thread->thread);
775 #else
776 WLog_ERR(TAG, "Function not supported on this platform!");
777 #endif
778
779 if (pthread_mutex_unlock(&thread->mutex))
780 return FALSE;
781
782 set_event(thread);
783 return TRUE;
784 }
785
786 #if defined(WITH_DEBUG_THREADS)
DumpThreadHandles(void)787 VOID DumpThreadHandles(void)
788 {
789 char** msg;
790 size_t used, i;
791 void* stack = winpr_backtrace(20);
792 WLog_DBG(TAG, "---------------- Called from ----------------------------");
793 msg = winpr_backtrace_symbols(stack, &used);
794
795 for (i = 0; i < used; i++)
796 {
797 WLog_DBG(TAG, "[%" PRIdz "]: %s", i, msg[i]);
798 }
799
800 free(msg);
801 winpr_backtrace_free(stack);
802 WLog_DBG(TAG, "---------------- Start Dumping thread handles -----------");
803
804 if (!thread_list)
805 {
806 WLog_DBG(TAG, "All threads properly shut down and disposed of.");
807 }
808 else
809 {
810 ULONG_PTR* keys = NULL;
811 ListDictionary_Lock(thread_list);
812 int x, count = ListDictionary_GetKeys(thread_list, &keys);
813 WLog_DBG(TAG, "Dumping %d elements", count);
814
815 for (x = 0; x < count; x++)
816 {
817 WINPR_THREAD* thread = ListDictionary_GetItemValue(thread_list, (void*)keys[x]);
818 WLog_DBG(TAG, "Thread [%d] handle created still not closed!", x);
819 msg = winpr_backtrace_symbols(thread->create_stack, &used);
820
821 for (i = 0; i < used; i++)
822 {
823 WLog_DBG(TAG, "[%" PRIdz "]: %s", i, msg[i]);
824 }
825
826 free(msg);
827
828 if (thread->started)
829 {
830 WLog_DBG(TAG, "Thread [%d] still running!", x);
831 }
832 else
833 {
834 WLog_DBG(TAG, "Thread [%d] exited at:", x);
835 msg = winpr_backtrace_symbols(thread->exit_stack, &used);
836
837 for (i = 0; i < used; i++)
838 WLog_DBG(TAG, "[%" PRIdz "]: %s", i, msg[i]);
839
840 free(msg);
841 }
842 }
843
844 free(keys);
845 ListDictionary_Unlock(thread_list);
846 }
847
848 WLog_DBG(TAG, "---------------- End Dumping thread handles -------------");
849 }
850 #endif
851 #endif
852