VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/thread-posix.cpp

Last change on this file was 104390, checked in by vboxsync, 4 weeks ago

Runtime/thread-posix.cpp: Return the status of the actual request or the caller will assume the thread has spawned when thread creation failed (too small stack size for example), bugref:10391

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 25.4 KB
Line 
1/* $Id: thread-posix.cpp 104390 2024-04-22 07:12:25Z vboxsync $ */
2/** @file
3 * IPRT - Threads, POSIX.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define LOG_GROUP RTLOGGROUP_THREAD
42#include <errno.h>
43#include <limits.h>
44#include <pthread.h>
45#include <signal.h>
46#include <stdlib.h>
47#if defined(RT_OS_LINUX)
48# include <unistd.h>
49# include <sys/syscall.h>
50#endif
51#if defined(RT_OS_SOLARIS)
52# include <sched.h>
53# include <sys/resource.h>
54#endif
55#if defined(RT_OS_DARWIN)
56# include <mach/thread_act.h>
57# include <mach/thread_info.h>
58# include <mach/host_info.h>
59# include <mach/mach_init.h>
60# include <mach/mach_host.h>
61#endif
62#if defined(RT_OS_DARWIN) /*|| defined(RT_OS_FREEBSD) - later */ \
63 || (defined(RT_OS_LINUX) && !defined(IN_RT_STATIC) /* static + dlsym = trouble */) \
64 || defined(IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP)
65# define IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP
66# include <dlfcn.h>
67#endif
68#if defined(RT_OS_HAIKU)
69# include <OS.h>
70#endif
71#if defined(RT_OS_DARWIN)
72# define sigprocmask pthread_sigmask /* On xnu sigprocmask works on the process, not the calling thread as elsewhere. */
73#endif
74
75#include <iprt/thread.h>
76#include <iprt/log.h>
77#include <iprt/assert.h>
78#include <iprt/asm.h>
79#include <iprt/err.h>
80#include <iprt/initterm.h>
81#include <iprt/string.h>
82#include <iprt/semaphore.h>
83#include <iprt/list.h>
84#include <iprt/once.h>
85#include <iprt/critsect.h>
86#include <iprt/req.h>
87#include "internal/thread.h"
88
89
90/*********************************************************************************************************************************
91* Defined Constants And Macros *
92*********************************************************************************************************************************/
93/*#ifndef IN_GUEST - shouldn't need to exclude this now with the non-obtrusive init option. */
94/** Includes RTThreadPoke. */
95# define RTTHREAD_POSIX_WITH_POKE
96/*#endif*/
97
98
99/*********************************************************************************************************************************
100* Global Variables *
101*********************************************************************************************************************************/
102/** The pthread key in which we store the pointer to our own PRTTHREAD structure.
103 * @note There is a defined NIL value here, nor can we really assume this is an
104 * integer. However, zero is a valid key on Linux, so we get into trouble
105 * if we accidentally use it uninitialized.
106 *
107 * So, we ASSUME it's a integer value and the valid range is in approx 0
108 * to PTHREAD_KEYS_MAX. Solaris has at least one negative value (-1)
109 * defined. Thus, we go for 16 MAX values below zero and keep our fingers
110 * cross that it will always be an invalid key value everywhere...
111 *
112 * See also NIL_RTTLS, which is -1.
113 */
114static pthread_key_t g_SelfKey = (pthread_key_t)(-PTHREAD_KEYS_MAX * 16);
115#ifdef RTTHREAD_POSIX_WITH_POKE
116/** The signal we use for poking threads.
117 * This is set to -1 if no available signal was found. */
118static int volatile g_iSigPokeThread = -1;
119#endif
120
121#ifdef IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP
122# if defined(RT_OS_DARWIN)
123/**
124 * The Mac OS X (10.6 and later) variant of pthread_setname_np.
125 *
126 * @returns errno.h
127 * @param pszName The new thread name.
128 */
129typedef int (*PFNPTHREADSETNAME)(const char *pszName);
130# else
131/**
132 * The variant of pthread_setname_np most other unix-like systems implement.
133 *
134 * @returns errno.h
135 * @param hThread The thread.
136 * @param pszName The new thread name.
137 */
138typedef int (*PFNPTHREADSETNAME)(pthread_t hThread, const char *pszName);
139# endif
140
141/** Pointer to pthread_setname_np if found. */
142static PFNPTHREADSETNAME g_pfnThreadSetName = NULL;
143#endif /* IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP */
144
145#ifdef RTTHREAD_POSIX_WITH_CREATE_PRIORITY_PROXY
146/** Atomic indicator of whether the priority proxy thread has been (attempted) started.
147 *
148 * The priority proxy thread is started under these circumstances:
149 * - RTThreadCreate
150 * - RTThreadSetType
151 * - RTProcSetPriority
152 *
153 * Which means that we'll be single threaded when this is modified.
154 *
155 * Speical values:
156 * - VERR_TRY_AGAIN: Not yet started.
157 * - VERR_WRONG_ORDER: Starting.
158 * - VINF_SUCCESS: Started successfully.
159 * - VERR_PROCESS_NOT_FOUND: Stopping or stopped
160 * - Other error status if failed to start.
161 *
162 * @note We could potentially optimize this by only start it when we lower the
163 * priority of ourselves, the process, or a newly created thread. But
164 * that would means we would need to take multi-threading into account, so
165 * let's not do that for now.
166 */
167static int32_t volatile g_rcPriorityProxyThreadStart = VERR_TRY_AGAIN;
168/** The IPRT thread handle for the priority proxy. */
169static RTTHREAD g_hRTThreadPosixPriorityProxyThread = NIL_RTTHREAD;
170/** The priority proxy queue. */
171static RTREQQUEUE g_hRTThreadPosixPriorityProxyQueue = NIL_RTREQQUEUE;
172#endif /* RTTHREAD_POSIX_WITH_CREATE_PRIORITY_PROXY */
173
174
175/*********************************************************************************************************************************
176* Internal Functions *
177*********************************************************************************************************************************/
178static void *rtThreadNativeMain(void *pvArgs);
179static void rtThreadKeyDestruct(void *pvValue);
180#ifdef RTTHREAD_POSIX_WITH_POKE
181static void rtThreadPosixPokeSignal(int iSignal);
182#endif
183
184
185#ifdef RTTHREAD_POSIX_WITH_POKE
186/**
187 * Try register the dummy signal handler for RTThreadPoke.
188 */
189static void rtThreadPosixSelectPokeSignal(void)
190{
191 /*
192 * Note! Avoid SIGRTMIN thru SIGRTMIN+2 because of LinuxThreads.
193 */
194# if !defined(RT_OS_LINUX) && !defined(RT_OS_SOLARIS) /* glibc defines SIGRTMAX to __libc_current_sigrtmax() and Solaris libc defines it relying on _sysconf(), causing compiler to deploy serialization here. */
195 static
196# endif
197 const int s_aiSigCandidates[] =
198 {
199# ifdef SIGRTMAX
200 SIGRTMAX-3,
201 SIGRTMAX-2,
202 SIGRTMAX-1,
203# endif
204# ifndef RT_OS_SOLARIS
205 SIGUSR2,
206# endif
207 SIGWINCH
208 };
209
210 g_iSigPokeThread = -1;
211 if (!RTR3InitIsUnobtrusive())
212 {
213 for (unsigned iSig = 0; iSig < RT_ELEMENTS(s_aiSigCandidates); iSig++)
214 {
215 struct sigaction SigActOld;
216 if (!sigaction(s_aiSigCandidates[iSig], NULL, &SigActOld))
217 {
218 if ( SigActOld.sa_handler == SIG_DFL
219 || SigActOld.sa_handler == rtThreadPosixPokeSignal)
220 {
221 struct sigaction SigAct;
222 RT_ZERO(SigAct);
223 SigAct.sa_handler = rtThreadPosixPokeSignal;
224 SigAct.sa_flags = 0; /* no SA_RESTART! */
225 sigfillset(&SigAct.sa_mask);
226
227 /* ASSUMES no sigaction race... (lazy bird) */
228 if (!sigaction(s_aiSigCandidates[iSig], &SigAct, NULL))
229 {
230 g_iSigPokeThread = s_aiSigCandidates[iSig];
231 break;
232 }
233 AssertMsgFailed(("rc=%Rrc errno=%d\n", RTErrConvertFromErrno(errno), errno));
234 }
235 }
236 else
237 AssertMsgFailed(("rc=%Rrc errno=%d\n", RTErrConvertFromErrno(errno), errno));
238 }
239 }
240}
241#endif /* RTTHREAD_POSIX_WITH_POKE */
242
243
244DECLHIDDEN(int) rtThreadNativeInit(void)
245{
246 /*
247 * Allocate the TLS (key in posix terms) where we store the pointer to
248 * a threads RTTHREADINT structure.
249 */
250 int rc = pthread_key_create(&g_SelfKey, rtThreadKeyDestruct);
251 if (rc)
252 return VERR_NO_TLS_FOR_SELF;
253
254#ifdef RTTHREAD_POSIX_WITH_POKE
255 rtThreadPosixSelectPokeSignal();
256#endif
257
258#ifdef IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP
259 if (RT_SUCCESS(rc))
260 g_pfnThreadSetName = (PFNPTHREADSETNAME)(uintptr_t)dlsym(RTLD_DEFAULT, "pthread_setname_np");
261#endif
262 return rc;
263}
264
265static void rtThreadPosixBlockSignals(PRTTHREADINT pThread)
266{
267 /*
268 * Mask all signals, including the poke one, if requested.
269 */
270 if ( pThread
271 && (pThread->fFlags & RTTHREADFLAGS_NO_SIGNALS))
272 {
273 sigset_t SigSet;
274 sigfillset(&SigSet);
275 sigdelset(&SigSet, SIGILL); /* On the m1 we end up spinning on UDF ... */
276 sigdelset(&SigSet, SIGTRAP); /* ... and BRK instruction if these signals are masked. */
277 sigdelset(&SigSet, SIGFPE); /* Just adding the rest here to be on the safe side. */
278 sigdelset(&SigSet, SIGBUS);
279 sigdelset(&SigSet, SIGSEGV);
280 int rc = sigprocmask(SIG_BLOCK, &SigSet, NULL);
281 AssertMsg(rc == 0, ("rc=%Rrc errno=%d\n", RTErrConvertFromErrno(errno), errno)); RT_NOREF(rc);
282 }
283 /*
284 * Block SIGALRM - required for timer-posix.cpp.
285 * This is done to limit harm done by OSes which doesn't do special SIGALRM scheduling.
286 * It will not help much if someone creates threads directly using pthread_create. :/
287 */
288 else if (!RTR3InitIsUnobtrusive())
289 {
290 sigset_t SigSet;
291 sigemptyset(&SigSet);
292 sigaddset(&SigSet, SIGALRM);
293 sigprocmask(SIG_BLOCK, &SigSet, NULL);
294 }
295
296#ifdef RTTHREAD_POSIX_WITH_POKE
297 /*
298 * bird 2020-10-28: Not entirely sure why we do this, but it makes sure the signal works
299 * on the new thread. Probably some pre-NPTL linux reasons.
300 */
301 if (g_iSigPokeThread != -1)
302 {
303# if 1 /* siginterrupt() is typically implemented as two sigaction calls, this should be faster and w/o deprecations: */
304 struct sigaction SigActOld;
305 RT_ZERO(SigActOld);
306
307 struct sigaction SigAct;
308 RT_ZERO(SigAct);
309 SigAct.sa_handler = rtThreadPosixPokeSignal;
310 SigAct.sa_flags = 0; /* no SA_RESTART! */
311 sigfillset(&SigAct.sa_mask);
312
313 int rc = sigaction(g_iSigPokeThread, &SigAct, &SigActOld);
314 AssertMsg(rc == 0, ("rc=%Rrc errno=%d\n", RTErrConvertFromErrno(errno), errno)); RT_NOREF(rc);
315 AssertMsg(rc || SigActOld.sa_handler == rtThreadPosixPokeSignal, ("%p\n", SigActOld.sa_handler));
316# else
317 siginterrupt(g_iSigPokeThread, 1);
318# endif
319 }
320#endif
321}
322
323DECLHIDDEN(void) rtThreadNativeReInitObtrusive(void)
324{
325#ifdef RTTHREAD_POSIX_WITH_POKE
326 Assert(!RTR3InitIsUnobtrusive());
327 rtThreadPosixSelectPokeSignal();
328#endif
329 rtThreadPosixBlockSignals(NULL);
330}
331
332
333/**
334 * Destructor called when a thread terminates.
335 * @param pvValue The key value. PRTTHREAD in our case.
336 */
337static void rtThreadKeyDestruct(void *pvValue)
338{
339 /*
340 * Deal with alien threads.
341 */
342 PRTTHREADINT pThread = (PRTTHREADINT)pvValue;
343 if (pThread->fIntFlags & RTTHREADINT_FLAGS_ALIEN)
344 {
345 pthread_setspecific(g_SelfKey, pThread);
346 rtThreadTerminate(pThread, 0);
347 pthread_setspecific(g_SelfKey, NULL);
348 }
349}
350
351
352#ifdef RTTHREAD_POSIX_WITH_POKE
353/**
354 * Dummy signal handler for the poke signal.
355 *
356 * @param iSignal The signal number.
357 */
358static void rtThreadPosixPokeSignal(int iSignal)
359{
360 Assert(iSignal == g_iSigPokeThread);
361 NOREF(iSignal);
362}
363#endif
364
365
366/**
367 * Adopts a thread, this is called immediately after allocating the
368 * thread structure.
369 *
370 * @param pThread Pointer to the thread structure.
371 */
372DECLHIDDEN(int) rtThreadNativeAdopt(PRTTHREADINT pThread)
373{
374 rtThreadPosixBlockSignals(pThread);
375
376 int rc = pthread_setspecific(g_SelfKey, pThread);
377 if (!rc)
378 return VINF_SUCCESS;
379 return VERR_FAILED_TO_SET_SELF_TLS;
380}
381
382
383DECLHIDDEN(void) rtThreadNativeDestroy(PRTTHREADINT pThread)
384{
385 if (pThread == (PRTTHREADINT)pthread_getspecific(g_SelfKey))
386 pthread_setspecific(g_SelfKey, NULL);
387}
388
389
390/**
391 * Wrapper which unpacks the params and calls thread function.
392 */
393static void *rtThreadNativeMain(void *pvArgs)
394{
395 PRTTHREADINT pThread = (PRTTHREADINT)pvArgs;
396 pthread_t Self = pthread_self();
397#if !defined(RT_OS_SOLARIS) /* On Solaris sizeof(pthread_t) = 4 and sizeof(NIL_RTNATIVETHREAD) = 8 */
398 Assert((uintptr_t)Self != NIL_RTNATIVETHREAD);
399#endif
400 Assert(Self == (pthread_t)(RTNATIVETHREAD)Self);
401
402#if defined(RT_OS_LINUX)
403 /*
404 * Set the TID.
405 */
406 pThread->tid = syscall(__NR_gettid);
407 ASMMemoryFence();
408#endif
409
410 rtThreadPosixBlockSignals(pThread);
411
412 /*
413 * Set the TLS entry and, if possible, the thread name.
414 */
415 int rc = pthread_setspecific(g_SelfKey, pThread);
416 AssertReleaseMsg(!rc, ("failed to set self TLS. rc=%d thread '%s'\n", rc, pThread->szName));
417
418#ifdef IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP
419 if (g_pfnThreadSetName)
420# ifdef RT_OS_DARWIN
421 g_pfnThreadSetName(pThread->szName);
422# else
423 g_pfnThreadSetName(Self, pThread->szName);
424# endif
425#endif
426
427 /*
428 * Call common main.
429 */
430 rc = rtThreadMain(pThread, (uintptr_t)Self, &pThread->szName[0]);
431
432 pthread_setspecific(g_SelfKey, NULL);
433 pthread_exit((void *)(intptr_t)rc);
434 return (void *)(intptr_t)rc;
435}
436
437#ifdef RTTHREAD_POSIX_WITH_CREATE_PRIORITY_PROXY
438
439/**
440 * @callback_method_impl{FNRTTHREAD,
441 * Priority proxy thread that services g_hRTThreadPosixPriorityProxyQueue.}
442 */
443static DECLCALLBACK(int) rtThreadPosixPriorityProxyThread(PRTTHREADINT, void *)
444{
445 for (;;)
446 {
447 RTREQQUEUE hReqQueue = g_hRTThreadPosixPriorityProxyQueue;
448 if (hReqQueue != NIL_RTREQQUEUE)
449 RTReqQueueProcess(hReqQueue, RT_INDEFINITE_WAIT);
450 else
451 break;
452
453 int32_t rc = ASMAtomicUoReadS32(&g_rcPriorityProxyThreadStart);
454 if (rc != VINF_SUCCESS && rc != VERR_WRONG_ORDER)
455 break;
456 }
457
458 return VINF_SUCCESS;
459}
460
461
462/**
463 * Just returns a non-success status codes to force the thread to re-evaluate
464 * the global shutdown variable.
465 */
466static DECLCALLBACK(int) rtThreadPosixPriorityProxyStopper(void)
467{
468 return VERR_CANCELLED;
469}
470
471
472/**
473 * An atexit() callback that stops the proxy creation/priority thread.
474 */
475static void rtThreadStopProxyThread(void)
476{
477 /*
478 * Signal to the thread that it's time to shut down.
479 */
480 int32_t rc = ASMAtomicXchgS32(&g_rcPriorityProxyThreadStart, VERR_PROCESS_NOT_FOUND);
481 if (RT_SUCCESS(rc))
482 {
483 /*
484 * Grab the associated handles.
485 */
486 RTTHREAD hThread = g_hRTThreadPosixPriorityProxyThread;
487 RTREQQUEUE hQueue = g_hRTThreadPosixPriorityProxyQueue;
488 g_hRTThreadPosixPriorityProxyQueue = NIL_RTREQQUEUE;
489 g_hRTThreadPosixPriorityProxyThread = NIL_RTTHREAD;
490 ASMCompilerBarrier(); /* paranoia */
491
492 AssertReturnVoid(hThread != NIL_RTTHREAD);
493 AssertReturnVoid(hQueue != NIL_RTREQQUEUE);
494
495 /*
496 * Kick the thread so it gets out of any pending RTReqQueueProcess call ASAP.
497 */
498 rc = RTReqQueueCallEx(hQueue, NULL, 0 /*cMillies*/, RTREQFLAGS_IPRT_STATUS | RTREQFLAGS_NO_WAIT,
499 (PFNRT)rtThreadPosixPriorityProxyStopper, 0);
500
501 /*
502 * Wait for the thread to complete.
503 */
504 rc = RTThreadWait(hThread, RT_SUCCESS(rc) ? RT_MS_1SEC * 5 : 32, NULL);
505 if (RT_SUCCESS(rc))
506 RTReqQueueDestroy(hQueue);
507 /* else: just leak the stuff, we're exitting, so nobody cares... */
508 }
509}
510
511
512/**
513 * Ensure that the proxy priority proxy thread has been started.
514 *
515 * Since we will always start a proxy thread when asked to create a thread,
516 * there is no need for serialization here.
517 *
518 * @retval true if started
519 * @retval false if it failed to start (caller must handle this scenario).
520 */
521DECLHIDDEN(bool) rtThreadPosixPriorityProxyStart(void)
522{
523 /*
524 * Read the result.
525 */
526 int rc = ASMAtomicUoReadS32(&g_rcPriorityProxyThreadStart);
527 if (rc != VERR_TRY_AGAIN)
528 return RT_SUCCESS(rc);
529
530 /* If this triggers then there is a very unexpected race somewhere. It
531 should be harmless though. */
532 AssertReturn(ASMAtomicCmpXchgS32(&g_rcPriorityProxyThreadStart, VERR_WRONG_ORDER, VERR_TRY_AGAIN), false);
533
534 /*
535 * Not yet started, so do that.
536 */
537 rc = RTReqQueueCreate(&g_hRTThreadPosixPriorityProxyQueue);
538 if (RT_SUCCESS(rc))
539 {
540 rc = RTThreadCreate(&g_hRTThreadPosixPriorityProxyThread, rtThreadPosixPriorityProxyThread, NULL, 0 /*cbStack*/,
541 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "RTThrdPP");
542 if (RT_SUCCESS(rc))
543 {
544 ASMAtomicWriteS32(&g_rcPriorityProxyThreadStart, VINF_SUCCESS);
545
546 atexit(rtThreadStopProxyThread);
547 return true;
548 }
549 RTReqQueueCreate(&g_hRTThreadPosixPriorityProxyQueue);
550 }
551 ASMAtomicWriteS32(&g_rcPriorityProxyThreadStart, rc != VERR_WRONG_ORDER ? rc : VERR_PROCESS_NOT_FOUND);
552 return false;
553}
554
555
556/**
557 * Calls @a pfnFunction from the priority proxy thread.
558 *
559 * Caller must have called rtThreadPosixStartProxy() to check that the priority
560 * proxy thread is running.
561 *
562 * @returns
563 * @param pTargetThread The target thread, NULL if not applicable. This is
564 * so we can skip calls pertaining to the priority
565 * proxy thread itself.
566 * @param pfnFunction The function to call. Must return IPRT status code.
567 * @param cArgs Number of arguments (see also RTReqQueueCall).
568 * @param ... Arguments (see also RTReqQueueCall).
569 */
570DECLHIDDEN(int) rtThreadPosixPriorityProxyCall(PRTTHREADINT pTargetThread, PFNRT pfnFunction, int cArgs, ...)
571{
572 int rc;
573 if ( !pTargetThread
574 || pTargetThread->pfnThread != rtThreadPosixPriorityProxyThread)
575 {
576 va_list va;
577 va_start(va, cArgs);
578 PRTREQ pReq;
579 rc = RTReqQueueCallV(g_hRTThreadPosixPriorityProxyQueue, &pReq, RT_INDEFINITE_WAIT, RTREQFLAGS_IPRT_STATUS,
580 pfnFunction, cArgs, va);
581 va_end(va);
582 RTReqRelease(pReq);
583 }
584 else
585 rc = VINF_SUCCESS;
586 return rc;
587}
588
589#endif /* !RTTHREAD_POSIX_WITH_CREATE_PRIORITY_PROXY */
590
591/**
592 * Worker for rtThreadNativeCreate that's either called on the priority proxy
593 * thread or directly on the calling thread depending on the proxy state.
594 */
595static DECLCALLBACK(int) rtThreadNativeInternalCreate(PRTTHREADINT pThread, PRTNATIVETHREAD pNativeThread)
596{
597 /*
598 * Set the default stack size.
599 */
600 if (!pThread->cbStack)
601 pThread->cbStack = 512*1024;
602
603#ifdef RT_OS_LINUX
604 pThread->tid = -1;
605#endif
606
607 /*
608 * Setup thread attributes.
609 */
610 pthread_attr_t ThreadAttr;
611 int rc = pthread_attr_init(&ThreadAttr);
612 if (!rc)
613 {
614 rc = pthread_attr_setdetachstate(&ThreadAttr, PTHREAD_CREATE_DETACHED);
615 if (!rc)
616 {
617 rc = pthread_attr_setstacksize(&ThreadAttr, pThread->cbStack);
618 if (!rc)
619 {
620 /*
621 * Create the thread.
622 */
623 pthread_t ThreadId;
624 rc = pthread_create(&ThreadId, &ThreadAttr, rtThreadNativeMain, pThread);
625 if (!rc)
626 {
627 pthread_attr_destroy(&ThreadAttr);
628 *pNativeThread = (uintptr_t)ThreadId;
629 return VINF_SUCCESS;
630 }
631 }
632 }
633 pthread_attr_destroy(&ThreadAttr);
634 }
635 return RTErrConvertFromErrno(rc);
636}
637
638
639DECLHIDDEN(int) rtThreadNativeCreate(PRTTHREADINT pThread, PRTNATIVETHREAD pNativeThread)
640{
641#ifdef RTTHREAD_POSIX_WITH_CREATE_PRIORITY_PROXY
642 /*
643 * If we have a priority proxy thread, use it. Make sure to ignore the
644 * staring of the proxy thread itself.
645 */
646 if ( pThread->pfnThread != rtThreadPosixPriorityProxyThread
647 && rtThreadPosixPriorityProxyStart())
648 {
649 PRTREQ pReq;
650 int rc = RTReqQueueCall(g_hRTThreadPosixPriorityProxyQueue, &pReq, RT_INDEFINITE_WAIT,
651 (PFNRT)rtThreadNativeInternalCreate, 2, pThread, pNativeThread);
652 if (RT_SUCCESS(rc))
653 rc = RTReqGetStatus(pReq);
654 RTReqRelease(pReq);
655 return rc;
656 }
657
658 /*
659 * Fall back on creating it directly without regard to priority proxying.
660 */
661#endif
662 return rtThreadNativeInternalCreate(pThread, pNativeThread);
663}
664
665
666RTDECL(RTTHREAD) RTThreadSelf(void)
667{
668 /** @todo import alien threads? */
669#if defined(RT_OS_DARWIN)
670 /* On darwin, there seems to be input checking with pthread_getspecific.
671 So, we must prevent using g_SelfKey before rtThreadNativeInit has run,
672 otherwise we might crash or starting working with total garbage pointer
673 values here (see _os_tsd_get_direct in znu/libsyscall/os/tsd.h).
674
675 Now, since the init value is a "negative" one, we just have to check
676 that it's positive or zero before calling the API. */
677 if (RT_LIKELY((intptr_t)g_SelfKey >= 0))
678 return (PRTTHREADINT)pthread_getspecific(g_SelfKey);
679 return NIL_RTTHREAD;
680#else
681 return (PRTTHREADINT)pthread_getspecific(g_SelfKey);
682#endif
683}
684
685
686#ifdef RTTHREAD_POSIX_WITH_POKE
687
688RTDECL(int) RTThreadPoke(RTTHREAD hThread)
689{
690 AssertReturn(hThread != RTThreadSelf(), VERR_INVALID_PARAMETER);
691 PRTTHREADINT pThread = rtThreadGet(hThread);
692 AssertReturn(pThread, VERR_INVALID_HANDLE);
693
694 int rc;
695 if (g_iSigPokeThread != -1)
696 {
697 rc = pthread_kill((pthread_t)(uintptr_t)pThread->Core.Key, g_iSigPokeThread);
698 rc = RTErrConvertFromErrno(rc);
699 }
700 else
701 rc = VERR_NOT_SUPPORTED;
702
703 rtThreadRelease(pThread);
704 return rc;
705}
706
707
708RTDECL(int) RTThreadControlPokeSignal(RTTHREAD hThread, bool fEnable)
709{
710 AssertReturn(hThread == RTThreadSelf() && hThread != NIL_RTTHREAD, VERR_INVALID_PARAMETER);
711 int rc;
712 if (g_iSigPokeThread != -1)
713 {
714 sigset_t SigSet;
715 sigemptyset(&SigSet);
716 sigaddset(&SigSet, g_iSigPokeThread);
717
718 int rc2 = sigprocmask(fEnable ? SIG_UNBLOCK : SIG_BLOCK, &SigSet, NULL);
719 if (rc2 == 0)
720 rc = VINF_SUCCESS;
721 else
722 {
723 rc = RTErrConvertFromErrno(errno);
724 AssertMsgFailed(("rc=%Rrc errno=%d (rc2=%d)\n", rc, errno, rc2));
725 }
726 }
727 else
728 rc = VERR_NOT_SUPPORTED;
729 return rc;
730}
731
732
733#endif
734
735/** @todo move this into platform specific files. */
736RTR3DECL(int) RTThreadGetExecutionTimeMilli(uint64_t *pcMsKernelTime, uint64_t *pcMsUserTime)
737{
738#if defined(RT_OS_SOLARIS)
739 struct rusage ts;
740 int const rc = getrusage(RUSAGE_LWP, &ts);
741 AssertReturn(rc == 0, RTErrConvertFromErrno(rc));
742
743 *pcMsKernelTime = ts.ru_stime.tv_sec * 1000 + ts.ru_stime.tv_usec / 1000;
744 *pcMsUserTime = ts.ru_utime.tv_sec * 1000 + ts.ru_utime.tv_usec / 1000;
745 return VINF_SUCCESS;
746
747#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
748 /* on Linux, getrusage(RUSAGE_THREAD, ...) is available since 2.6.26. maybe it's slower? */
749 struct timespec ts;
750 int const rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
751 AssertReturn(rc == 0, RTErrConvertFromErrno(rc));
752
753 *pcMsKernelTime = 0;
754 *pcMsUserTime = (uint64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
755 return VINF_SUCCESS;
756
757#elif defined(RT_OS_DARWIN)
758 thread_basic_info ThreadInfo;
759 mach_msg_type_number_t Count = THREAD_BASIC_INFO_COUNT;
760 kern_return_t krc = thread_info(mach_thread_self(), THREAD_BASIC_INFO, (thread_info_t)&ThreadInfo, &Count);
761 AssertReturn(krc == KERN_SUCCESS, RTErrConvertFromDarwinKern(krc));
762
763 *pcMsKernelTime = ThreadInfo.system_time.seconds * 1000 + ThreadInfo.system_time.microseconds / 1000;
764 *pcMsUserTime = ThreadInfo.user_time.seconds * 1000 + ThreadInfo.user_time.microseconds / 1000;
765 return VINF_SUCCESS;
766
767#elif defined(RT_OS_HAIKU)
768 thread_info ThreadInfo;
769 status_t status = get_thread_info(find_thread(NULL), &ThreadInfo);
770 AssertReturn(status == B_OK, RTErrConvertFromErrno(status));
771
772 *pcMsKernelTime = ThreadInfo.kernel_time / 1000;
773 *pcMsUserTime = ThreadInfo.user_time / 1000;
774 return VINF_SUCCESS;
775
776#else
777 RT_NOREF(pcMsKernelTime, pcMsUserTime);
778 return VERR_NOT_IMPLEMENTED;
779#endif
780}
781
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use