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