VirtualBox

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

Last change on this file since 76553 was 76553, checked in by vboxsync, 5 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 13.6 KB
Line 
1/* $Id: thread-posix.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * IPRT - Threads, POSIX.
4 */
5
6/*
7 * Copyright (C) 2006-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP RTLOGGROUP_THREAD
32#include <errno.h>
33#include <pthread.h>
34#include <signal.h>
35#if defined(RT_OS_LINUX)
36# include <unistd.h>
37# include <sys/syscall.h>
38#endif
39#if defined(RT_OS_SOLARIS)
40# include <sched.h>
41# include <sys/resource.h>
42#endif
43#if defined(RT_OS_DARWIN)
44# include <mach/thread_act.h>
45# include <mach/thread_info.h>
46# include <mach/host_info.h>
47# include <mach/mach_init.h>
48# include <mach/mach_host.h>
49#endif
50#if defined(RT_OS_DARWIN) /*|| defined(RT_OS_FREEBSD) - later */ \
51 || (defined(RT_OS_LINUX) && !defined(IN_RT_STATIC) /* static + dlsym = trouble */) \
52 || defined(IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP)
53# define IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP
54# include <dlfcn.h>
55#endif
56#if defined(RT_OS_HAIKU)
57# include <OS.h>
58#endif
59
60#include <iprt/thread.h>
61#include <iprt/log.h>
62#include <iprt/assert.h>
63#include <iprt/asm.h>
64#include <iprt/err.h>
65#include <iprt/initterm.h>
66#include <iprt/string.h>
67#include "internal/thread.h"
68
69
70/*********************************************************************************************************************************
71* Defined Constants And Macros *
72*********************************************************************************************************************************/
73#ifndef IN_GUEST
74/** Includes RTThreadPoke. */
75# define RTTHREAD_POSIX_WITH_POKE
76#endif
77
78
79/*********************************************************************************************************************************
80* Global Variables *
81*********************************************************************************************************************************/
82/** The pthread key in which we store the pointer to our own PRTTHREAD structure. */
83static pthread_key_t g_SelfKey;
84#ifdef RTTHREAD_POSIX_WITH_POKE
85/** The signal we use for poking threads.
86 * This is set to -1 if no available signal was found. */
87static int g_iSigPokeThread = -1;
88#endif
89
90#ifdef IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP
91# if defined(RT_OS_DARWIN)
92/**
93 * The Mac OS X (10.6 and later) variant of pthread_setname_np.
94 *
95 * @returns errno.h
96 * @param pszName The new thread name.
97 */
98typedef int (*PFNPTHREADSETNAME)(const char *pszName);
99# else
100/**
101 * The variant of pthread_setname_np most other unix-like systems implement.
102 *
103 * @returns errno.h
104 * @param hThread The thread.
105 * @param pszName The new thread name.
106 */
107typedef int (*PFNPTHREADSETNAME)(pthread_t hThread, const char *pszName);
108# endif
109
110/** Pointer to pthread_setname_np if found. */
111static PFNPTHREADSETNAME g_pfnThreadSetName = NULL;
112#endif /* IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP */
113
114
115/*********************************************************************************************************************************
116* Internal Functions *
117*********************************************************************************************************************************/
118static void *rtThreadNativeMain(void *pvArgs);
119static void rtThreadKeyDestruct(void *pvValue);
120#ifdef RTTHREAD_POSIX_WITH_POKE
121static void rtThreadPosixPokeSignal(int iSignal);
122#endif
123
124
125#ifdef RTTHREAD_POSIX_WITH_POKE
126/**
127 * Try register the dummy signal handler for RTThreadPoke.
128 */
129static void rtThreadPosixSelectPokeSignal(void)
130{
131 /*
132 * Note! Avoid SIGRTMIN thru SIGRTMIN+2 because of LinuxThreads.
133 */
134 static const int s_aiSigCandidates[] =
135 {
136# ifdef SIGRTMAX
137 SIGRTMAX-3,
138 SIGRTMAX-2,
139 SIGRTMAX-1,
140# endif
141# ifndef RT_OS_SOLARIS
142 SIGUSR2,
143# endif
144 SIGWINCH
145 };
146
147 g_iSigPokeThread = -1;
148 if (!RTR3InitIsUnobtrusive())
149 {
150 for (unsigned iSig = 0; iSig < RT_ELEMENTS(s_aiSigCandidates); iSig++)
151 {
152 struct sigaction SigActOld;
153 if (!sigaction(s_aiSigCandidates[iSig], NULL, &SigActOld))
154 {
155 if ( SigActOld.sa_handler == SIG_DFL
156 || SigActOld.sa_handler == rtThreadPosixPokeSignal)
157 {
158 struct sigaction SigAct;
159 RT_ZERO(SigAct);
160 SigAct.sa_handler = rtThreadPosixPokeSignal;
161 SigAct.sa_flags = 0;
162 sigfillset(&SigAct.sa_mask);
163
164 /* ASSUMES no sigaction race... (lazy bird) */
165 if (!sigaction(s_aiSigCandidates[iSig], &SigAct, NULL))
166 {
167 g_iSigPokeThread = s_aiSigCandidates[iSig];
168 break;
169 }
170 AssertMsgFailed(("rc=%Rrc errno=%d\n", RTErrConvertFromErrno(errno), errno));
171 }
172 }
173 else
174 AssertMsgFailed(("rc=%Rrc errno=%d\n", RTErrConvertFromErrno(errno), errno));
175 }
176 }
177}
178#endif /* RTTHREAD_POSIX_WITH_POKE */
179
180
181DECLHIDDEN(int) rtThreadNativeInit(void)
182{
183 /*
184 * Allocate the TLS (key in posix terms) where we store the pointer to
185 * a threads RTTHREADINT structure.
186 */
187 int rc = pthread_key_create(&g_SelfKey, rtThreadKeyDestruct);
188 if (rc)
189 return VERR_NO_TLS_FOR_SELF;
190
191#ifdef RTTHREAD_POSIX_WITH_POKE
192 rtThreadPosixSelectPokeSignal();
193#endif
194
195#ifdef IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP
196 if (RT_SUCCESS(rc))
197 g_pfnThreadSetName = (PFNPTHREADSETNAME)(uintptr_t)dlsym(RTLD_DEFAULT, "pthread_setname_np");
198#endif
199 return rc;
200}
201
202static void rtThreadPosixBlockSignals(void)
203{
204 /*
205 * Block SIGALRM - required for timer-posix.cpp.
206 * This is done to limit harm done by OSes which doesn't do special SIGALRM scheduling.
207 * It will not help much if someone creates threads directly using pthread_create. :/
208 */
209 if (!RTR3InitIsUnobtrusive())
210 {
211 sigset_t SigSet;
212 sigemptyset(&SigSet);
213 sigaddset(&SigSet, SIGALRM);
214 sigprocmask(SIG_BLOCK, &SigSet, NULL);
215 }
216#ifdef RTTHREAD_POSIX_WITH_POKE
217 if (g_iSigPokeThread != -1)
218 siginterrupt(g_iSigPokeThread, 1);
219#endif
220}
221
222DECLHIDDEN(void) rtThreadNativeReInitObtrusive(void)
223{
224#ifdef RTTHREAD_POSIX_WITH_POKE
225 Assert(!RTR3InitIsUnobtrusive());
226 rtThreadPosixSelectPokeSignal();
227#endif
228 rtThreadPosixBlockSignals();
229}
230
231
232/**
233 * Destructor called when a thread terminates.
234 * @param pvValue The key value. PRTTHREAD in our case.
235 */
236static void rtThreadKeyDestruct(void *pvValue)
237{
238 /*
239 * Deal with alien threads.
240 */
241 PRTTHREADINT pThread = (PRTTHREADINT)pvValue;
242 if (pThread->fIntFlags & RTTHREADINT_FLAGS_ALIEN)
243 {
244 pthread_setspecific(g_SelfKey, pThread);
245 rtThreadTerminate(pThread, 0);
246 pthread_setspecific(g_SelfKey, NULL);
247 }
248}
249
250
251#ifdef RTTHREAD_POSIX_WITH_POKE
252/**
253 * Dummy signal handler for the poke signal.
254 *
255 * @param iSignal The signal number.
256 */
257static void rtThreadPosixPokeSignal(int iSignal)
258{
259 Assert(iSignal == g_iSigPokeThread);
260 NOREF(iSignal);
261}
262#endif
263
264
265/**
266 * Adopts a thread, this is called immediately after allocating the
267 * thread structure.
268 *
269 * @param pThread Pointer to the thread structure.
270 */
271DECLHIDDEN(int) rtThreadNativeAdopt(PRTTHREADINT pThread)
272{
273 rtThreadPosixBlockSignals();
274
275 int rc = pthread_setspecific(g_SelfKey, pThread);
276 if (!rc)
277 return VINF_SUCCESS;
278 return VERR_FAILED_TO_SET_SELF_TLS;
279}
280
281
282DECLHIDDEN(void) rtThreadNativeDestroy(PRTTHREADINT pThread)
283{
284 if (pThread == (PRTTHREADINT)pthread_getspecific(g_SelfKey))
285 pthread_setspecific(g_SelfKey, NULL);
286}
287
288
289/**
290 * Wrapper which unpacks the params and calls thread function.
291 */
292static void *rtThreadNativeMain(void *pvArgs)
293{
294 PRTTHREADINT pThread = (PRTTHREADINT)pvArgs;
295 pthread_t Self = pthread_self();
296 Assert((uintptr_t)Self != NIL_RTNATIVETHREAD);
297 Assert(Self == (pthread_t)(RTNATIVETHREAD)Self);
298
299#if defined(RT_OS_LINUX)
300 /*
301 * Set the TID.
302 */
303 pThread->tid = syscall(__NR_gettid);
304 ASMMemoryFence();
305#endif
306
307 rtThreadPosixBlockSignals();
308
309 /*
310 * Set the TLS entry and, if possible, the thread name.
311 */
312 int rc = pthread_setspecific(g_SelfKey, pThread);
313 AssertReleaseMsg(!rc, ("failed to set self TLS. rc=%d thread '%s'\n", rc, pThread->szName));
314
315#ifdef IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP
316 if (g_pfnThreadSetName)
317# ifdef RT_OS_DARWIN
318 g_pfnThreadSetName(pThread->szName);
319# else
320 g_pfnThreadSetName(Self, pThread->szName);
321# endif
322#endif
323
324 /*
325 * Call common main.
326 */
327 rc = rtThreadMain(pThread, (uintptr_t)Self, &pThread->szName[0]);
328
329 pthread_setspecific(g_SelfKey, NULL);
330 pthread_exit((void *)(intptr_t)rc);
331 return (void *)(intptr_t)rc;
332}
333
334
335DECLHIDDEN(int) rtThreadNativeCreate(PRTTHREADINT pThread, PRTNATIVETHREAD pNativeThread)
336{
337 /*
338 * Set the default stack size.
339 */
340 if (!pThread->cbStack)
341 pThread->cbStack = 512*1024;
342
343#ifdef RT_OS_LINUX
344 pThread->tid = -1;
345#endif
346
347 /*
348 * Setup thread attributes.
349 */
350 pthread_attr_t ThreadAttr;
351 int rc = pthread_attr_init(&ThreadAttr);
352 if (!rc)
353 {
354 rc = pthread_attr_setdetachstate(&ThreadAttr, PTHREAD_CREATE_DETACHED);
355 if (!rc)
356 {
357 rc = pthread_attr_setstacksize(&ThreadAttr, pThread->cbStack);
358 if (!rc)
359 {
360 /*
361 * Create the thread.
362 */
363 pthread_t ThreadId;
364 rc = pthread_create(&ThreadId, &ThreadAttr, rtThreadNativeMain, pThread);
365 if (!rc)
366 {
367 pthread_attr_destroy(&ThreadAttr);
368 *pNativeThread = (uintptr_t)ThreadId;
369 return VINF_SUCCESS;
370 }
371 }
372 }
373 pthread_attr_destroy(&ThreadAttr);
374 }
375 return RTErrConvertFromErrno(rc);
376}
377
378
379RTDECL(RTTHREAD) RTThreadSelf(void)
380{
381 PRTTHREADINT pThread = (PRTTHREADINT)pthread_getspecific(g_SelfKey);
382 /** @todo import alien threads? */
383 return pThread;
384}
385
386
387#ifdef RTTHREAD_POSIX_WITH_POKE
388RTDECL(int) RTThreadPoke(RTTHREAD hThread)
389{
390 AssertReturn(hThread != RTThreadSelf(), VERR_INVALID_PARAMETER);
391 PRTTHREADINT pThread = rtThreadGet(hThread);
392 AssertReturn(pThread, VERR_INVALID_HANDLE);
393
394 int rc;
395 if (g_iSigPokeThread != -1)
396 {
397 rc = pthread_kill((pthread_t)(uintptr_t)pThread->Core.Key, g_iSigPokeThread);
398 rc = RTErrConvertFromErrno(rc);
399 }
400 else
401 rc = VERR_NOT_SUPPORTED;
402
403 rtThreadRelease(pThread);
404 return rc;
405}
406#endif
407
408/** @todo move this into platform specific files. */
409RTR3DECL(int) RTThreadGetExecutionTimeMilli(uint64_t *pKernelTime, uint64_t *pUserTime)
410{
411#if defined(RT_OS_SOLARIS)
412 struct rusage ts;
413 int rc = getrusage(RUSAGE_LWP, &ts);
414 if (rc)
415 return RTErrConvertFromErrno(rc);
416
417 *pKernelTime = ts.ru_stime.tv_sec * 1000 + ts.ru_stime.tv_usec / 1000;
418 *pUserTime = ts.ru_utime.tv_sec * 1000 + ts.ru_utime.tv_usec / 1000;
419 return VINF_SUCCESS;
420
421#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
422 /* on Linux, getrusage(RUSAGE_THREAD, ...) is available since 2.6.26 */
423 struct timespec ts;
424 int rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
425 if (rc)
426 return RTErrConvertFromErrno(rc);
427
428 *pKernelTime = 0;
429 *pUserTime = (uint64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
430 return VINF_SUCCESS;
431
432#elif defined(RT_OS_DARWIN)
433 thread_basic_info ThreadInfo;
434 mach_msg_type_number_t Count = THREAD_BASIC_INFO_COUNT;
435 kern_return_t krc = thread_info(mach_thread_self(), THREAD_BASIC_INFO, (thread_info_t)&ThreadInfo, &Count);
436 AssertReturn(krc == KERN_SUCCESS, RTErrConvertFromDarwinKern(krc));
437
438 *pKernelTime = ThreadInfo.system_time.seconds * 1000 + ThreadInfo.system_time.microseconds / 1000;
439 *pUserTime = ThreadInfo.user_time.seconds * 1000 + ThreadInfo.user_time.microseconds / 1000;
440
441 return VINF_SUCCESS;
442#elif defined(RT_OS_HAIKU)
443 thread_info ThreadInfo;
444 status_t status = get_thread_info(find_thread(NULL), &ThreadInfo);
445 AssertReturn(status == B_OK, RTErrConvertFromErrno(status));
446
447 *pKernelTime = ThreadInfo.kernel_time / 1000;
448 *pUserTime = ThreadInfo.user_time / 1000;
449
450 return VINF_SUCCESS;
451#else
452 return VERR_NOT_IMPLEMENTED;
453#endif
454}
455
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use