Coverage Report

Created: 2024-05-20 06:11

/src/FreeRDP/winpr/libwinpr/thread/thread.c
Line
Count
Source (jump to first uncovered line)
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
#include <winpr/config.h>
24
25
#include <winpr/assert.h>
26
27
#include <winpr/handle.h>
28
29
#include <winpr/thread.h>
30
31
/**
32
 * api-ms-win-core-processthreads-l1-1-1.dll
33
 *
34
 * CreateRemoteThread
35
 * CreateRemoteThreadEx
36
 * CreateThread
37
 * DeleteProcThreadAttributeList
38
 * ExitThread
39
 * FlushInstructionCache
40
 * FlushProcessWriteBuffers
41
 * GetCurrentThread
42
 * GetCurrentThreadId
43
 * GetCurrentThreadStackLimits
44
 * GetExitCodeThread
45
 * GetPriorityClass
46
 * GetStartupInfoW
47
 * GetThreadContext
48
 * GetThreadId
49
 * GetThreadIdealProcessorEx
50
 * GetThreadPriority
51
 * GetThreadPriorityBoost
52
 * GetThreadTimes
53
 * InitializeProcThreadAttributeList
54
 * OpenThread
55
 * OpenThreadToken
56
 * QueryProcessAffinityUpdateMode
57
 * QueueUserAPC
58
 * ResumeThread
59
 * SetPriorityClass
60
 * SetThreadContext
61
 * SetThreadPriority
62
 * SetThreadPriorityBoost
63
 * SetThreadStackGuarantee
64
 * SetThreadToken
65
 * SuspendThread
66
 * SwitchToThread
67
 * TerminateThread
68
 * UpdateProcThreadAttribute
69
 */
70
71
#ifndef _WIN32
72
73
#include <winpr/crt.h>
74
#include <winpr/platform.h>
75
76
#ifdef WINPR_HAVE_UNISTD_H
77
#include <unistd.h>
78
#endif
79
80
#ifdef WINPR_HAVE_SYS_EVENTFD_H
81
#include <sys/eventfd.h>
82
#endif
83
84
#include <winpr/debug.h>
85
86
#include <errno.h>
87
#include <fcntl.h>
88
89
#include <winpr/collections.h>
90
91
#include "thread.h"
92
#include "apc.h"
93
94
#include "../handle/handle.h"
95
#include "../log.h"
96
#define TAG WINPR_TAG("thread")
97
98
static WINPR_THREAD mainThread;
99
100
#if defined(WITH_THREAD_LIST)
101
static wListDictionary* thread_list = NULL;
102
#endif
103
104
static BOOL ThreadCloseHandle(HANDLE handle);
105
static void cleanup_handle(void* obj);
106
107
static BOOL ThreadIsHandled(HANDLE handle)
108
1.46M
{
109
1.46M
  return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_THREAD, FALSE);
110
1.46M
}
111
112
static int ThreadGetFd(HANDLE handle)
113
731k
{
114
731k
  WINPR_THREAD* pThread = (WINPR_THREAD*)handle;
115
116
731k
  if (!ThreadIsHandled(handle))
117
0
    return -1;
118
119
731k
  return pThread->event.fds[0];
120
731k
}
121
122
1.09M
#define run_mutex_init(fkt, mux, arg) run_mutex_init_(fkt, #fkt, mux, arg)
123
static BOOL run_mutex_init_(int (*fkt)(pthread_mutex_t*, const pthread_mutexattr_t*),
124
                            const char* name, pthread_mutex_t* mutex,
125
                            const pthread_mutexattr_t* mutexattr)
126
1.09M
{
127
1.09M
  int rc = 0;
128
129
1.09M
  WINPR_ASSERT(fkt);
130
1.09M
  WINPR_ASSERT(mutex);
131
132
1.09M
  rc = fkt(mutex, mutexattr);
133
1.09M
  if (rc != 0)
134
0
  {
135
0
    char ebuffer[256] = { 0 };
136
0
    WLog_WARN(TAG, "[%s] failed with [%s]", name, winpr_strerror(rc, ebuffer, sizeof(ebuffer)));
137
0
  }
138
1.09M
  return rc == 0;
139
1.09M
}
140
141
6.21M
#define run_mutex_fkt(fkt, mux) run_mutex_fkt_(fkt, #fkt, mux)
142
static BOOL run_mutex_fkt_(int (*fkt)(pthread_mutex_t* mux), const char* name,
143
                           pthread_mutex_t* mutex)
144
6.21M
{
145
6.21M
  int rc = 0;
146
147
6.21M
  WINPR_ASSERT(fkt);
148
6.21M
  WINPR_ASSERT(mutex);
149
150
6.21M
  rc = fkt(mutex);
151
6.21M
  if (rc != 0)
152
0
  {
153
0
    char ebuffer[256] = { 0 };
154
0
    WLog_WARN(TAG, "[%s] failed with [%s]", name, winpr_strerror(rc, ebuffer, sizeof(ebuffer)));
155
0
  }
156
6.21M
  return rc == 0;
157
6.21M
}
158
159
731k
#define run_cond_init(fkt, cond, arg) run_cond_init_(fkt, #fkt, cond, arg)
160
static BOOL run_cond_init_(int (*fkt)(pthread_cond_t*, const pthread_condattr_t*), const char* name,
161
                           pthread_cond_t* condition, const pthread_condattr_t* conditionattr)
162
731k
{
163
731k
  int rc = 0;
164
165
731k
  WINPR_ASSERT(fkt);
166
731k
  WINPR_ASSERT(condition);
167
168
731k
  rc = fkt(condition, conditionattr);
169
731k
  if (rc != 0)
170
0
  {
171
0
    char ebuffer[256] = { 0 };
172
0
    WLog_WARN(TAG, "[%s] failed with [%s]", name, winpr_strerror(rc, ebuffer, sizeof(ebuffer)));
173
0
  }
174
731k
  return rc == 0;
175
731k
}
176
177
1.82M
#define run_cond_fkt(fkt, cond) run_cond_fkt_(fkt, #fkt, cond)
178
static BOOL run_cond_fkt_(int (*fkt)(pthread_cond_t* mux), const char* name,
179
                          pthread_cond_t* condition)
180
1.82M
{
181
1.82M
  int rc = 0;
182
183
1.82M
  WINPR_ASSERT(fkt);
184
1.82M
  WINPR_ASSERT(condition);
185
186
1.82M
  rc = fkt(condition);
187
1.82M
  if (rc != 0)
188
0
  {
189
0
    char ebuffer[256] = { 0 };
190
0
    WLog_WARN(TAG, "[%s] failed with [%s]", name, winpr_strerror(rc, ebuffer, sizeof(ebuffer)));
191
0
  }
192
1.82M
  return rc == 0;
193
1.82M
}
194
195
static int pthread_mutex_checked_unlock(pthread_mutex_t* mutex)
196
2.55M
{
197
2.55M
  WINPR_ASSERT(mutex);
198
2.55M
  WINPR_ASSERT(pthread_mutex_trylock(mutex) == EBUSY);
199
2.55M
  return pthread_mutex_unlock(mutex);
200
2.55M
}
201
202
static BOOL mux_condition_bundle_init(mux_condition_bundle* bundle)
203
731k
{
204
731k
  WINPR_ASSERT(bundle);
205
206
731k
  bundle->val = FALSE;
207
731k
  if (!run_mutex_init(pthread_mutex_init, &bundle->mux, NULL))
208
0
    return FALSE;
209
210
731k
  if (!run_cond_init(pthread_cond_init, &bundle->cond, NULL))
211
0
    return FALSE;
212
731k
  return TRUE;
213
731k
}
214
215
static void mux_condition_bundle_uninit(mux_condition_bundle* bundle)
216
731k
{
217
731k
  mux_condition_bundle empty = { 0 };
218
219
731k
  WINPR_ASSERT(bundle);
220
221
731k
  run_cond_fkt(pthread_cond_destroy, &bundle->cond);
222
731k
  run_mutex_fkt(pthread_mutex_destroy, &bundle->mux);
223
731k
  *bundle = empty;
224
731k
}
225
226
static BOOL mux_condition_bundle_signal(mux_condition_bundle* bundle)
227
1.09M
{
228
1.09M
  BOOL rc = TRUE;
229
1.09M
  WINPR_ASSERT(bundle);
230
231
1.09M
  if (!run_mutex_fkt(pthread_mutex_lock, &bundle->mux))
232
0
    return FALSE;
233
1.09M
  bundle->val = TRUE;
234
1.09M
  if (!run_cond_fkt(pthread_cond_signal, &bundle->cond))
235
0
    rc = FALSE;
236
1.09M
  if (!run_mutex_fkt(pthread_mutex_checked_unlock, &bundle->mux))
237
0
    rc = FALSE;
238
1.09M
  return rc;
239
1.09M
}
240
241
static BOOL mux_condition_bundle_lock(mux_condition_bundle* bundle)
242
731k
{
243
731k
  WINPR_ASSERT(bundle);
244
731k
  return run_mutex_fkt(pthread_mutex_lock, &bundle->mux);
245
731k
}
246
247
static BOOL mux_condition_bundle_unlock(mux_condition_bundle* bundle)
248
731k
{
249
731k
  WINPR_ASSERT(bundle);
250
731k
  return run_mutex_fkt(pthread_mutex_checked_unlock, &bundle->mux);
251
731k
}
252
253
static BOOL mux_condition_bundle_wait(mux_condition_bundle* bundle, const char* name)
254
731k
{
255
731k
  BOOL rc = FALSE;
256
257
731k
  WINPR_ASSERT(bundle);
258
731k
  WINPR_ASSERT(name);
259
731k
  WINPR_ASSERT(pthread_mutex_trylock(&bundle->mux) == EBUSY);
260
261
1.46M
  while (!bundle->val)
262
731k
  {
263
731k
    int r = pthread_cond_wait(&bundle->cond, &bundle->mux);
264
731k
    if (r != 0)
265
0
    {
266
0
      char ebuffer[256] = { 0 };
267
0
      WLog_ERR(TAG, "failed to wait for %s [%s]", name,
268
0
               winpr_strerror(r, ebuffer, sizeof(ebuffer)));
269
0
      switch (r)
270
0
      {
271
0
        case ENOTRECOVERABLE:
272
0
        case EPERM:
273
0
        case ETIMEDOUT:
274
0
        case EINVAL:
275
0
          goto fail;
276
277
0
        default:
278
0
          break;
279
0
      }
280
0
    }
281
731k
  }
282
283
731k
  rc = bundle->val;
284
285
731k
fail:
286
731k
  return rc;
287
731k
}
288
289
static BOOL signal_thread_ready(WINPR_THREAD* thread)
290
730k
{
291
730k
  WINPR_ASSERT(thread);
292
293
730k
  return mux_condition_bundle_signal(&thread->isCreated);
294
730k
}
295
296
static BOOL signal_thread_is_running(WINPR_THREAD* thread)
297
365k
{
298
365k
  WINPR_ASSERT(thread);
299
300
365k
  return mux_condition_bundle_signal(&thread->isRunning);
301
365k
}
302
303
static DWORD ThreadCleanupHandle(HANDLE handle)
304
731k
{
305
731k
  DWORD status = WAIT_FAILED;
306
731k
  WINPR_THREAD* thread = (WINPR_THREAD*)handle;
307
308
731k
  if (!ThreadIsHandled(handle))
309
0
    return WAIT_FAILED;
310
311
731k
  if (!run_mutex_fkt(pthread_mutex_lock, &thread->mutex))
312
0
    return WAIT_FAILED;
313
314
731k
  if (!thread->joined)
315
365k
  {
316
365k
    int rc = pthread_join(thread->thread, NULL);
317
318
365k
    if (rc != 0)
319
0
    {
320
0
      char ebuffer[256] = { 0 };
321
0
      WLog_ERR(TAG, "pthread_join failure: [%d] %s", rc,
322
0
               winpr_strerror(rc, ebuffer, sizeof(ebuffer)));
323
0
      goto fail;
324
0
    }
325
365k
    else
326
365k
      thread->joined = TRUE;
327
365k
  }
328
329
731k
  status = WAIT_OBJECT_0;
330
331
731k
fail:
332
731k
  if (!run_mutex_fkt(pthread_mutex_checked_unlock, &thread->mutex))
333
0
    return WAIT_FAILED;
334
335
731k
  return status;
336
731k
}
337
338
static HANDLE_OPS ops = { ThreadIsHandled,
339
                        ThreadCloseHandle,
340
                        ThreadGetFd,
341
                        ThreadCleanupHandle,
342
                        NULL,
343
                        NULL,
344
                        NULL,
345
                        NULL,
346
                        NULL,
347
                        NULL,
348
                        NULL,
349
                        NULL,
350
                        NULL,
351
                        NULL,
352
                        NULL,
353
                        NULL,
354
                        NULL,
355
                        NULL,
356
                        NULL,
357
                        NULL,
358
                        NULL };
359
360
static void dump_thread(WINPR_THREAD* thread)
361
731k
{
362
#if defined(WITH_DEBUG_THREADS)
363
  void* stack = winpr_backtrace(20);
364
  char** msg = NULL;
365
  size_t used = 0;
366
  WLog_DBG(TAG, "Called from:");
367
  msg = winpr_backtrace_symbols(stack, &used);
368
369
  for (size_t i = 0; i < used; i++)
370
    WLog_DBG(TAG, "[%" PRIdz "]: %s", i, msg[i]);
371
372
  free(msg);
373
  winpr_backtrace_free(stack);
374
  WLog_DBG(TAG, "Thread handle created still not closed!");
375
  msg = winpr_backtrace_symbols(thread->create_stack, &used);
376
377
  for (size_t i = 0; i < used; i++)
378
    WLog_DBG(TAG, "[%" PRIdz "]: %s", i, msg[i]);
379
380
  free(msg);
381
382
  if (thread->started)
383
  {
384
    WLog_DBG(TAG, "Thread still running!");
385
  }
386
  else if (!thread->exit_stack)
387
  {
388
    WLog_DBG(TAG, "Thread suspended.");
389
  }
390
  else
391
  {
392
    WLog_DBG(TAG, "Thread exited at:");
393
    msg = winpr_backtrace_symbols(thread->exit_stack, &used);
394
395
    for (size_t i = 0; i < used; i++)
396
      WLog_DBG(TAG, "[%" PRIdz "]: %s", i, msg[i]);
397
398
    free(msg);
399
  }
400
#else
401
731k
  WINPR_UNUSED(thread);
402
731k
#endif
403
731k
}
404
405
/**
406
 * TODO: implement thread suspend/resume using pthreads
407
 * http://stackoverflow.com/questions/3140867/suspend-pthreads-without-using-condition
408
 */
409
static BOOL set_event(WINPR_THREAD* thread)
410
361k
{
411
361k
  return winpr_event_set(&thread->event);
412
361k
}
413
414
static BOOL reset_event(WINPR_THREAD* thread)
415
365k
{
416
365k
  return winpr_event_reset(&thread->event);
417
365k
}
418
419
#if defined(WITH_THREAD_LIST)
420
static BOOL thread_compare(const void* a, const void* b)
421
{
422
  const pthread_t* p1 = a;
423
  const pthread_t* p2 = b;
424
  BOOL rc = pthread_equal(*p1, *p2);
425
  return rc;
426
}
427
#endif
428
429
static INIT_ONCE threads_InitOnce = INIT_ONCE_STATIC_INIT;
430
static pthread_t mainThreadId;
431
static DWORD currentThreadTlsIndex = TLS_OUT_OF_INDEXES;
432
433
static BOOL initializeThreads(PINIT_ONCE InitOnce, PVOID Parameter, PVOID* Context)
434
1
{
435
1
  if (!apc_init(&mainThread.apc))
436
0
  {
437
0
    WLog_ERR(TAG, "failed to initialize APC");
438
0
    goto out;
439
0
  }
440
441
1
  mainThread.common.Type = HANDLE_TYPE_THREAD;
442
1
  mainThreadId = pthread_self();
443
444
1
  currentThreadTlsIndex = TlsAlloc();
445
1
  if (currentThreadTlsIndex == TLS_OUT_OF_INDEXES)
446
0
  {
447
0
    WLog_ERR(TAG, "Major bug, unable to allocate a TLS value for currentThread");
448
0
  }
449
450
#if defined(WITH_THREAD_LIST)
451
  thread_list = ListDictionary_New(TRUE);
452
453
  if (!thread_list)
454
  {
455
    WLog_ERR(TAG, "Couldn't create global thread list");
456
    goto error_thread_list;
457
  }
458
459
  thread_list->objectKey.fnObjectEquals = thread_compare;
460
#endif
461
462
1
out:
463
1
  return TRUE;
464
1
}
465
466
static BOOL signal_and_wait_for_ready(WINPR_THREAD* thread)
467
365k
{
468
365k
  BOOL res = FALSE;
469
470
365k
  WINPR_ASSERT(thread);
471
472
365k
  if (!mux_condition_bundle_lock(&thread->isRunning))
473
0
    return FALSE;
474
475
365k
  if (!signal_thread_ready(thread))
476
0
    goto fail;
477
478
365k
  if (!mux_condition_bundle_wait(&thread->isRunning, "threadIsRunning"))
479
0
    goto fail;
480
481
#if defined(WITH_THREAD_LIST)
482
  if (!ListDictionary_Contains(thread_list, &thread->thread))
483
  {
484
    WLog_ERR(TAG, "Thread not in thread_list, startup failed!");
485
    goto fail;
486
  }
487
#endif
488
489
365k
  res = TRUE;
490
491
365k
fail:
492
365k
  if (!mux_condition_bundle_unlock(&thread->isRunning))
493
0
    return FALSE;
494
495
365k
  return res;
496
365k
}
497
498
/* Thread launcher function responsible for registering
499
 * cleanup handlers and calling pthread_exit, if not done
500
 * in thread function. */
501
static void* thread_launcher(void* arg)
502
365k
{
503
365k
  DWORD rc = 0;
504
365k
  WINPR_THREAD* thread = (WINPR_THREAD*)arg;
505
365k
  LPTHREAD_START_ROUTINE fkt = NULL;
506
507
365k
  if (!thread)
508
0
  {
509
0
    WLog_ERR(TAG, "Called with invalid argument %p", arg);
510
0
    goto exit;
511
0
  }
512
513
365k
  if (!TlsSetValue(currentThreadTlsIndex, thread))
514
0
  {
515
0
    WLog_ERR(TAG, "thread %d, unable to set current thread value", pthread_self());
516
0
    goto exit;
517
0
  }
518
519
365k
  if (!(fkt = thread->lpStartAddress))
520
0
  {
521
0
    WLog_ERR(TAG, "Thread function argument is %p", (void*)fkt);
522
0
    goto exit;
523
0
  }
524
525
365k
  if (!signal_and_wait_for_ready(thread))
526
0
    goto exit;
527
528
365k
  rc = fkt(thread->lpParameter);
529
365k
exit:
530
531
364k
  if (thread)
532
364k
  {
533
364k
    apc_cleanupThread(thread);
534
535
364k
    if (!thread->exited)
536
365k
      thread->dwExitCode = rc;
537
538
364k
    set_event(thread);
539
540
364k
    signal_thread_ready(thread);
541
542
364k
    if (thread->detached || !thread->started)
543
0
      cleanup_handle(thread);
544
364k
  }
545
546
364k
  return NULL;
547
365k
}
548
549
static BOOL winpr_StartThread(WINPR_THREAD* thread)
550
365k
{
551
365k
  BOOL rc = FALSE;
552
365k
  BOOL locked = FALSE;
553
365k
  pthread_attr_t attr = { 0 };
554
555
365k
  if (!mux_condition_bundle_lock(&thread->isCreated))
556
0
    return FALSE;
557
365k
  locked = TRUE;
558
559
365k
  pthread_attr_init(&attr);
560
365k
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
561
562
365k
  if (thread->dwStackSize > 0)
563
0
    pthread_attr_setstacksize(&attr, (size_t)thread->dwStackSize);
564
565
365k
  thread->started = TRUE;
566
365k
  reset_event(thread);
567
568
#if defined(WITH_THREAD_LIST)
569
  if (!ListDictionary_Add(thread_list, &thread->thread, thread))
570
  {
571
    WLog_ERR(TAG, "failed to add the thread to the thread list");
572
    goto error;
573
  }
574
#endif
575
576
365k
  if (pthread_create(&thread->thread, &attr, thread_launcher, thread))
577
0
    goto error;
578
579
365k
  if (!mux_condition_bundle_wait(&thread->isCreated, "threadIsCreated"))
580
0
    goto error;
581
582
365k
  locked = FALSE;
583
365k
  if (!mux_condition_bundle_unlock(&thread->isCreated))
584
0
    goto error;
585
586
365k
  if (!signal_thread_is_running(thread))
587
0
  {
588
0
    WLog_ERR(TAG, "failed to signal the thread was ready");
589
0
    goto error;
590
0
  }
591
592
365k
  rc = TRUE;
593
365k
error:
594
365k
  if (locked)
595
0
  {
596
0
    if (!mux_condition_bundle_unlock(&thread->isCreated))
597
0
      rc = FALSE;
598
0
  }
599
600
365k
  pthread_attr_destroy(&attr);
601
602
365k
  if (rc)
603
365k
    dump_thread(thread);
604
605
365k
  return rc;
606
365k
}
607
608
HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize,
609
                    LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter,
610
                    DWORD dwCreationFlags, LPDWORD lpThreadId)
611
365k
{
612
365k
  HANDLE handle = NULL;
613
365k
  WINPR_THREAD* thread = (WINPR_THREAD*)calloc(1, sizeof(WINPR_THREAD));
614
615
365k
  if (!thread)
616
0
    return NULL;
617
618
365k
  thread->dwStackSize = dwStackSize;
619
365k
  thread->lpParameter = lpParameter;
620
365k
  thread->lpStartAddress = lpStartAddress;
621
365k
  thread->lpThreadAttributes = lpThreadAttributes;
622
365k
  thread->common.ops = &ops;
623
#if defined(WITH_DEBUG_THREADS)
624
  thread->create_stack = winpr_backtrace(20);
625
  dump_thread(thread);
626
#endif
627
628
365k
  if (!winpr_event_init(&thread->event))
629
0
  {
630
0
    WLog_ERR(TAG, "failed to create event");
631
0
    goto fail;
632
0
  }
633
634
365k
  if (!run_mutex_init(pthread_mutex_init, &thread->mutex, NULL))
635
0
  {
636
0
    WLog_ERR(TAG, "failed to initialize thread mutex");
637
0
    goto fail;
638
0
  }
639
640
365k
  if (!apc_init(&thread->apc))
641
0
  {
642
0
    WLog_ERR(TAG, "failed to initialize APC");
643
0
    goto fail;
644
0
  }
645
646
365k
  if (!mux_condition_bundle_init(&thread->isCreated))
647
0
    goto fail;
648
365k
  if (!mux_condition_bundle_init(&thread->isRunning))
649
0
    goto fail;
650
651
365k
  WINPR_HANDLE_SET_TYPE_AND_MODE(thread, HANDLE_TYPE_THREAD, WINPR_FD_READ);
652
365k
  handle = (HANDLE)thread;
653
654
365k
  InitOnceExecuteOnce(&threads_InitOnce, initializeThreads, NULL, NULL);
655
656
365k
  if (!(dwCreationFlags & CREATE_SUSPENDED))
657
365k
  {
658
365k
    if (!winpr_StartThread(thread))
659
0
      goto fail;
660
365k
  }
661
0
  else
662
0
  {
663
0
    if (!set_event(thread))
664
0
      goto fail;
665
0
  }
666
667
365k
  return handle;
668
0
fail:
669
0
  cleanup_handle(thread);
670
0
  return NULL;
671
365k
}
672
673
void cleanup_handle(void* obj)
674
365k
{
675
365k
  WINPR_THREAD* thread = (WINPR_THREAD*)obj;
676
365k
  if (!thread)
677
0
    return;
678
679
365k
  if (!apc_uninit(&thread->apc))
680
365k
    WLog_ERR(TAG, "failed to destroy APC");
681
682
365k
  mux_condition_bundle_uninit(&thread->isCreated);
683
365k
  mux_condition_bundle_uninit(&thread->isRunning);
684
365k
  run_mutex_fkt(pthread_mutex_destroy, &thread->mutex);
685
686
365k
  winpr_event_uninit(&thread->event);
687
688
#if defined(WITH_THREAD_LIST)
689
  ListDictionary_Remove(thread_list, &thread->thread);
690
#endif
691
#if defined(WITH_DEBUG_THREADS)
692
693
  if (thread->create_stack)
694
    winpr_backtrace_free(thread->create_stack);
695
696
  if (thread->exit_stack)
697
    winpr_backtrace_free(thread->exit_stack);
698
699
#endif
700
365k
  free(thread);
701
365k
}
702
703
BOOL ThreadCloseHandle(HANDLE handle)
704
365k
{
705
365k
  WINPR_THREAD* thread = (WINPR_THREAD*)handle;
706
707
#if defined(WITH_THREAD_LIST)
708
  if (!thread_list)
709
  {
710
    WLog_ERR(TAG, "Thread list does not exist, check call!");
711
    dump_thread(thread);
712
  }
713
  else if (!ListDictionary_Contains(thread_list, &thread->thread))
714
  {
715
    WLog_ERR(TAG, "Thread list does not contain this thread! check call!");
716
    dump_thread(thread);
717
  }
718
  else
719
  {
720
    ListDictionary_Lock(thread_list);
721
#endif
722
365k
    dump_thread(thread);
723
724
365k
    if ((thread->started) && (WaitForSingleObject(thread, 0) != WAIT_OBJECT_0))
725
0
    {
726
0
      WLog_DBG(TAG, "Thread running, setting to detached state!");
727
0
      thread->detached = TRUE;
728
0
      pthread_detach(thread->thread);
729
0
    }
730
365k
    else
731
365k
    {
732
365k
      cleanup_handle(thread);
733
365k
    }
734
735
#if defined(WITH_THREAD_LIST)
736
    ListDictionary_Unlock(thread_list);
737
  }
738
#endif
739
740
365k
  return TRUE;
741
365k
}
742
743
HANDLE CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes,
744
                          SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
745
                          LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId)
746
0
{
747
0
  WLog_ERR(TAG, "not implemented");
748
0
  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
749
0
  return NULL;
750
0
}
751
752
VOID ExitThread(DWORD dwExitCode)
753
364k
{
754
#if defined(WITH_THREAD_LIST)
755
  DWORD rc;
756
  pthread_t tid = pthread_self();
757
758
  if (!thread_list)
759
  {
760
    WLog_ERR(TAG, "function called without existing thread list!");
761
#if defined(WITH_DEBUG_THREADS)
762
    DumpThreadHandles();
763
#endif
764
    pthread_exit(0);
765
  }
766
  else if (!ListDictionary_Contains(thread_list, &tid))
767
  {
768
    WLog_ERR(TAG, "function called, but no matching entry in thread list!");
769
#if defined(WITH_DEBUG_THREADS)
770
    DumpThreadHandles();
771
#endif
772
    pthread_exit(0);
773
  }
774
  else
775
  {
776
    WINPR_THREAD* thread;
777
    ListDictionary_Lock(thread_list);
778
    thread = ListDictionary_GetItemValue(thread_list, &tid);
779
    WINPR_ASSERT(thread);
780
    thread->exited = TRUE;
781
    thread->dwExitCode = dwExitCode;
782
#if defined(WITH_DEBUG_THREADS)
783
    thread->exit_stack = winpr_backtrace(20);
784
#endif
785
    ListDictionary_Unlock(thread_list);
786
    set_event(thread);
787
    rc = thread->dwExitCode;
788
789
    if (thread->detached || !thread->started)
790
      cleanup_handle(thread);
791
792
    pthread_exit((void*)(size_t)rc);
793
  }
794
#else
795
364k
  WINPR_UNUSED(dwExitCode);
796
364k
#endif
797
364k
}
798
799
BOOL GetExitCodeThread(HANDLE hThread, LPDWORD lpExitCode)
800
0
{
801
0
  ULONG Type = 0;
802
0
  WINPR_HANDLE* Object = NULL;
803
0
  WINPR_THREAD* thread = NULL;
804
805
0
  if (!winpr_Handle_GetInfo(hThread, &Type, &Object) || Object->Type != HANDLE_TYPE_THREAD)
806
0
  {
807
0
    WLog_ERR(TAG, "hThread is not a thread");
808
0
    SetLastError(ERROR_INVALID_PARAMETER);
809
0
    return FALSE;
810
0
  }
811
812
0
  thread = (WINPR_THREAD*)Object;
813
0
  *lpExitCode = thread->dwExitCode;
814
0
  return TRUE;
815
0
}
816
817
WINPR_THREAD* winpr_GetCurrentThread(VOID)
818
0
{
819
0
  WINPR_THREAD* ret = NULL;
820
821
0
  InitOnceExecuteOnce(&threads_InitOnce, initializeThreads, NULL, NULL);
822
0
  if (mainThreadId == pthread_self())
823
0
    return (HANDLE)&mainThread;
824
825
0
  ret = TlsGetValue(currentThreadTlsIndex);
826
0
  return ret;
827
0
}
828
829
HANDLE _GetCurrentThread(VOID)
830
0
{
831
0
  return (HANDLE)winpr_GetCurrentThread();
832
0
}
833
834
DWORD GetCurrentThreadId(VOID)
835
7.86M
{
836
7.86M
  pthread_t tid = 0;
837
7.86M
  tid = pthread_self();
838
  /* Since pthread_t can be 64-bits on some systems, take just the    */
839
  /* lower 32-bits of it for the thread ID returned by this function. */
840
7.86M
  return (DWORD)tid & 0xffffffffUL;
841
7.86M
}
842
843
typedef struct
844
{
845
  WINPR_APC_ITEM apc;
846
  PAPCFUNC completion;
847
  ULONG_PTR completionArg;
848
} UserApcItem;
849
850
static void userAPC(LPVOID arg)
851
0
{
852
0
  UserApcItem* userApc = (UserApcItem*)arg;
853
854
0
  userApc->completion(userApc->completionArg);
855
856
0
  userApc->apc.markedForRemove = TRUE;
857
0
}
858
859
DWORD QueueUserAPC(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData)
860
0
{
861
0
  ULONG Type = 0;
862
0
  WINPR_HANDLE* Object = NULL;
863
0
  WINPR_APC_ITEM* apc = NULL;
864
0
  UserApcItem* apcItem = NULL;
865
866
0
  if (!pfnAPC)
867
0
    return 1;
868
869
0
  if (!winpr_Handle_GetInfo(hThread, &Type, &Object) || Object->Type != HANDLE_TYPE_THREAD)
870
0
  {
871
0
    WLog_ERR(TAG, "hThread is not a thread");
872
0
    SetLastError(ERROR_INVALID_PARAMETER);
873
0
    return (DWORD)0;
874
0
  }
875
876
0
  apcItem = calloc(1, sizeof(*apcItem));
877
0
  if (!apcItem)
878
0
  {
879
0
    SetLastError(ERROR_INVALID_PARAMETER);
880
0
    return (DWORD)0;
881
0
  }
882
883
0
  apc = &apcItem->apc;
884
0
  apc->type = APC_TYPE_USER;
885
0
  apc->markedForFree = TRUE;
886
0
  apc->alwaysSignaled = TRUE;
887
0
  apc->completion = userAPC;
888
0
  apc->completionArgs = apc;
889
0
  apcItem->completion = pfnAPC;
890
0
  apcItem->completionArg = dwData;
891
0
  apc_register(hThread, apc);
892
0
  return 1;
893
0
}
894
895
DWORD ResumeThread(HANDLE hThread)
896
0
{
897
0
  ULONG Type = 0;
898
0
  WINPR_HANDLE* Object = NULL;
899
0
  WINPR_THREAD* thread = NULL;
900
901
0
  if (!winpr_Handle_GetInfo(hThread, &Type, &Object) || Object->Type != HANDLE_TYPE_THREAD)
902
0
  {
903
0
    WLog_ERR(TAG, "hThread is not a thread");
904
0
    SetLastError(ERROR_INVALID_PARAMETER);
905
0
    return (DWORD)-1;
906
0
  }
907
908
0
  thread = (WINPR_THREAD*)Object;
909
910
0
  if (!run_mutex_fkt(pthread_mutex_lock, &thread->mutex))
911
0
    return (DWORD)-1;
912
913
0
  if (!thread->started)
914
0
  {
915
0
    if (!winpr_StartThread(thread))
916
0
    {
917
0
      run_mutex_fkt(pthread_mutex_checked_unlock, &thread->mutex);
918
0
      return (DWORD)-1;
919
0
    }
920
0
  }
921
0
  else
922
0
    WLog_WARN(TAG, "Thread already started!");
923
924
0
  if (!run_mutex_fkt(pthread_mutex_checked_unlock, &thread->mutex))
925
0
    return (DWORD)-1;
926
927
0
  return 0;
928
0
}
929
930
DWORD SuspendThread(HANDLE hThread)
931
0
{
932
0
  WLog_ERR(TAG, "not implemented");
933
0
  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
934
0
  return (DWORD)-1;
935
0
}
936
937
BOOL SwitchToThread(VOID)
938
0
{
939
  /**
940
   * Note: on some operating systems sched_yield is a stub returning -1.
941
   * usleep should at least trigger a context switch if any thread is waiting.
942
   */
943
0
  if (sched_yield() != 0)
944
0
    usleep(1);
945
946
0
  return TRUE;
947
0
}
948
949
BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode)
950
0
{
951
0
  ULONG Type = 0;
952
0
  WINPR_HANDLE* Object = NULL;
953
0
  WINPR_THREAD* thread = NULL;
954
955
0
  if (!winpr_Handle_GetInfo(hThread, &Type, &Object))
956
0
    return FALSE;
957
958
0
  thread = (WINPR_THREAD*)Object;
959
0
  thread->exited = TRUE;
960
0
  thread->dwExitCode = dwExitCode;
961
962
0
  if (!run_mutex_fkt(pthread_mutex_lock, &thread->mutex))
963
0
    return FALSE;
964
965
0
#ifndef ANDROID
966
0
  pthread_cancel(thread->thread);
967
#else
968
  WLog_ERR(TAG, "Function not supported on this platform!");
969
#endif
970
971
0
  if (!run_mutex_fkt(pthread_mutex_checked_unlock, &thread->mutex))
972
0
    return FALSE;
973
974
0
  set_event(thread);
975
0
  return TRUE;
976
0
}
977
978
VOID DumpThreadHandles(void)
979
0
{
980
#if defined(WITH_DEBUG_THREADS)
981
  char** msg = NULL;
982
  size_t used = 0;
983
  void* stack = winpr_backtrace(20);
984
  WLog_DBG(TAG, "---------------- Called from ----------------------------");
985
  msg = winpr_backtrace_symbols(stack, &used);
986
987
  for (size_t i = 0; i < used; i++)
988
  {
989
    WLog_DBG(TAG, "[%" PRIdz "]: %s", i, msg[i]);
990
  }
991
992
  free(msg);
993
  winpr_backtrace_free(stack);
994
  WLog_DBG(TAG, "---------------- Start Dumping thread handles -----------");
995
996
#if defined(WITH_THREAD_LIST)
997
  if (!thread_list)
998
  {
999
    WLog_DBG(TAG, "All threads properly shut down and disposed of.");
1000
  }
1001
  else
1002
  {
1003
    ULONG_PTR* keys = NULL;
1004
    ListDictionary_Lock(thread_list);
1005
    int x, count = ListDictionary_GetKeys(thread_list, &keys);
1006
    WLog_DBG(TAG, "Dumping %d elements", count);
1007
1008
    for (size_t x = 0; x < count; x++)
1009
    {
1010
      WINPR_THREAD* thread = ListDictionary_GetItemValue(thread_list, (void*)keys[x]);
1011
      WLog_DBG(TAG, "Thread [%d] handle created still not closed!", x);
1012
      msg = winpr_backtrace_symbols(thread->create_stack, &used);
1013
1014
      for (size_t i = 0; i < used; i++)
1015
      {
1016
        WLog_DBG(TAG, "[%" PRIdz "]: %s", i, msg[i]);
1017
      }
1018
1019
      free(msg);
1020
1021
      if (thread->started)
1022
      {
1023
        WLog_DBG(TAG, "Thread [%d] still running!", x);
1024
      }
1025
      else
1026
      {
1027
        WLog_DBG(TAG, "Thread [%d] exited at:", x);
1028
        msg = winpr_backtrace_symbols(thread->exit_stack, &used);
1029
1030
        for (size_t i = 0; i < used; i++)
1031
          WLog_DBG(TAG, "[%" PRIdz "]: %s", i, msg[i]);
1032
1033
        free(msg);
1034
      }
1035
    }
1036
1037
    free(keys);
1038
    ListDictionary_Unlock(thread_list);
1039
  }
1040
#endif
1041
1042
  WLog_DBG(TAG, "---------------- End Dumping thread handles -------------");
1043
#endif
1044
0
}
1045
#endif