VirtualBox

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

Last change on this file since 44456 was 44456, checked in by vboxsync, 12 years ago

Runtime: add unobtrusive initialisation option which does not block SIGALRM.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 13.0 KB
Line 
1/* $Id: thread-posix.cpp 44456 2013-01-30 10:59:47Z vboxsync $ */
2/** @file
3 * IPRT - Threads, POSIX.
4 */
5
6/*
7 * Copyright (C) 2006-2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. 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);
120static void rtThreadPosixPokeSignal(int iSignal);
121
122
123DECLHIDDEN(int) rtThreadNativeInit(void)
124{
125 /*
126 * Allocate the TLS (key in posix terms) where we store the pointer to
127 * a threads RTTHREADINT structure.
128 */
129 int rc = pthread_key_create(&g_SelfKey, rtThreadKeyDestruct);
130 if (rc)
131 return VERR_NO_TLS_FOR_SELF;
132
133#ifdef RTTHREAD_POSIX_WITH_POKE
134 /*
135 * Try register the dummy signal handler for RTThreadPoke.
136 * Avoid SIGRTMIN thru SIGRTMIN+2 because of LinuxThreads.
137 */
138 static const int s_aiSigCandidates[] =
139 {
140# ifdef SIGRTMAX
141 SIGRTMAX-3,
142 SIGRTMAX-2,
143 SIGRTMAX-1,
144# endif
145# ifndef RT_OS_SOLARIS
146 SIGUSR2,
147# endif
148 SIGWINCH
149 };
150
151 g_iSigPokeThread = -1;
152 if (!RTR3InitIsUnobtrusive())
153 {
154 for (unsigned iSig = 0; iSig < RT_ELEMENTS(s_aiSigCandidates); iSig++)
155 {
156 struct sigaction SigActOld;
157 if (!sigaction(s_aiSigCandidates[iSig], NULL, &SigActOld))
158 {
159 if ( SigActOld.sa_handler == SIG_DFL
160 || SigActOld.sa_handler == rtThreadPosixPokeSignal)
161 {
162 struct sigaction SigAct;
163 RT_ZERO(SigAct);
164 SigAct.sa_handler = rtThreadPosixPokeSignal;
165 SigAct.sa_flags = 0;
166 sigfillset(&SigAct.sa_mask);
167
168 /* ASSUMES no sigaction race... (lazy bird) */
169 if (!sigaction(s_aiSigCandidates[iSig], &SigAct, NULL))
170 {
171 g_iSigPokeThread = s_aiSigCandidates[iSig];
172 break;
173 }
174 AssertMsgFailed(("rc=%Rrc errno=%d\n", RTErrConvertFromErrno(errno), errno));
175 }
176 }
177 else
178 AssertMsgFailed(("rc=%Rrc errno=%d\n", RTErrConvertFromErrno(errno), errno));
179 }
180 }
181#endif /* RTTHREAD_POSIX_WITH_POKE */
182
183#ifdef IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP
184 if (RT_SUCCESS(rc))
185 g_pfnThreadSetName = (PFNPTHREADSETNAME)(uintptr_t)dlsym(RTLD_DEFAULT, "pthread_setname_np");
186#endif
187 return rc;
188}
189
190
191/**
192 * Destructor called when a thread terminates.
193 * @param pvValue The key value. PRTTHREAD in our case.
194 */
195static void rtThreadKeyDestruct(void *pvValue)
196{
197 /*
198 * Deal with alien threads.
199 */
200 PRTTHREADINT pThread = (PRTTHREADINT)pvValue;
201 if (pThread->fIntFlags & RTTHREADINT_FLAGS_ALIEN)
202 {
203 pthread_setspecific(g_SelfKey, pThread);
204 rtThreadTerminate(pThread, 0);
205 pthread_setspecific(g_SelfKey, NULL);
206 }
207}
208
209
210#ifdef RTTHREAD_POSIX_WITH_POKE
211/**
212 * Dummy signal handler for the poke signal.
213 *
214 * @param iSignal The signal number.
215 */
216static void rtThreadPosixPokeSignal(int iSignal)
217{
218 Assert(iSignal == g_iSigPokeThread);
219 NOREF(iSignal);
220}
221#endif
222
223
224/**
225 * Adopts a thread, this is called immediately after allocating the
226 * thread structure.
227 *
228 * @param pThread Pointer to the thread structure.
229 */
230DECLHIDDEN(int) rtThreadNativeAdopt(PRTTHREADINT pThread)
231{
232 /*
233 * Block SIGALRM - required for timer-posix.cpp.
234 * This is done to limit harm done by OSes which doesn't do special SIGALRM scheduling.
235 * It will not help much if someone creates threads directly using pthread_create. :/
236 */
237 if (!RTR3InitIsUnobtrusive())
238 {
239 sigset_t SigSet;
240 sigemptyset(&SigSet);
241 sigaddset(&SigSet, SIGALRM);
242 sigprocmask(SIG_BLOCK, &SigSet, NULL);
243 }
244#ifdef RTTHREAD_POSIX_WITH_POKE
245 if (g_iSigPokeThread != -1)
246 siginterrupt(g_iSigPokeThread, 1);
247#endif
248
249 int rc = pthread_setspecific(g_SelfKey, pThread);
250 if (!rc)
251 return VINF_SUCCESS;
252 return VERR_FAILED_TO_SET_SELF_TLS;
253}
254
255
256DECLHIDDEN(void) rtThreadNativeDestroy(PRTTHREADINT pThread)
257{
258 if (pThread == (PRTTHREADINT)pthread_getspecific(g_SelfKey))
259 pthread_setspecific(g_SelfKey, NULL);
260}
261
262
263/**
264 * Wrapper which unpacks the params and calls thread function.
265 */
266static void *rtThreadNativeMain(void *pvArgs)
267{
268 PRTTHREADINT pThread = (PRTTHREADINT)pvArgs;
269 pthread_t Self = pthread_self();
270 Assert((uintptr_t)Self == (RTNATIVETHREAD)Self && (uintptr_t)Self != NIL_RTNATIVETHREAD);
271
272#if defined(RT_OS_LINUX)
273 /*
274 * Set the TID.
275 */
276 pThread->tid = syscall(__NR_gettid);
277 ASMMemoryFence();
278#endif
279
280 /*
281 * Block SIGALRM - required for timer-posix.cpp.
282 * This is done to limit harm done by OSes which doesn't do special SIGALRM scheduling.
283 * It will not help much if someone creates threads directly using pthread_create. :/
284 */
285 sigset_t SigSet;
286 sigemptyset(&SigSet);
287 sigaddset(&SigSet, SIGALRM);
288 sigprocmask(SIG_BLOCK, &SigSet, NULL);
289#ifdef RTTHREAD_POSIX_WITH_POKE
290 if (g_iSigPokeThread != -1)
291 siginterrupt(g_iSigPokeThread, 1);
292#endif
293
294 /*
295 * Set the TLS entry and, if possible, the thread name.
296 */
297 int rc = pthread_setspecific(g_SelfKey, pThread);
298 AssertReleaseMsg(!rc, ("failed to set self TLS. rc=%d thread '%s'\n", rc, pThread->szName));
299
300#ifdef IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP
301 if (g_pfnThreadSetName)
302# ifdef RT_OS_DARWIN
303 g_pfnThreadSetName(pThread->szName);
304# else
305 g_pfnThreadSetName(Self, pThread->szName);
306# endif
307#endif
308
309 /*
310 * Call common main.
311 */
312 rc = rtThreadMain(pThread, (uintptr_t)Self, &pThread->szName[0]);
313
314 pthread_setspecific(g_SelfKey, NULL);
315 pthread_exit((void *)(intptr_t)rc);
316 return (void *)(intptr_t)rc;
317}
318
319
320DECLHIDDEN(int) rtThreadNativeCreate(PRTTHREADINT pThread, PRTNATIVETHREAD pNativeThread)
321{
322 /*
323 * Set the default stack size.
324 */
325 if (!pThread->cbStack)
326 pThread->cbStack = 512*1024;
327
328#ifdef RT_OS_LINUX
329 pThread->tid = -1;
330#endif
331
332 /*
333 * Setup thread attributes.
334 */
335 pthread_attr_t ThreadAttr;
336 int rc = pthread_attr_init(&ThreadAttr);
337 if (!rc)
338 {
339 rc = pthread_attr_setdetachstate(&ThreadAttr, PTHREAD_CREATE_DETACHED);
340 if (!rc)
341 {
342 rc = pthread_attr_setstacksize(&ThreadAttr, pThread->cbStack);
343 if (!rc)
344 {
345 /*
346 * Create the thread.
347 */
348 pthread_t ThreadId;
349 rc = pthread_create(&ThreadId, &ThreadAttr, rtThreadNativeMain, pThread);
350 if (!rc)
351 {
352 *pNativeThread = (uintptr_t)ThreadId;
353 return VINF_SUCCESS;
354 }
355 }
356 }
357 pthread_attr_destroy(&ThreadAttr);
358 }
359 return RTErrConvertFromErrno(rc);
360}
361
362
363RTDECL(RTTHREAD) RTThreadSelf(void)
364{
365 PRTTHREADINT pThread = (PRTTHREADINT)pthread_getspecific(g_SelfKey);
366 /** @todo import alien threads? */
367 return pThread;
368}
369
370
371#ifdef RTTHREAD_POSIX_WITH_POKE
372RTDECL(int) RTThreadPoke(RTTHREAD hThread)
373{
374 AssertReturn(hThread != RTThreadSelf(), VERR_INVALID_PARAMETER);
375 PRTTHREADINT pThread = rtThreadGet(hThread);
376 AssertReturn(pThread, VERR_INVALID_HANDLE);
377
378 int rc;
379 if (g_iSigPokeThread != -1)
380 {
381 rc = pthread_kill((pthread_t)(uintptr_t)pThread->Core.Key, g_iSigPokeThread);
382 rc = RTErrConvertFromErrno(rc);
383 }
384 else
385 rc = VERR_NOT_SUPPORTED;
386
387 rtThreadRelease(pThread);
388 return rc;
389}
390#endif
391
392/** @todo move this into platform specific files. */
393RTR3DECL(int) RTThreadGetExecutionTimeMilli(uint64_t *pKernelTime, uint64_t *pUserTime)
394{
395#if defined(RT_OS_SOLARIS)
396 struct rusage ts;
397 int rc = getrusage(RUSAGE_LWP, &ts);
398 if (rc)
399 return RTErrConvertFromErrno(rc);
400
401 *pKernelTime = ts.ru_stime.tv_sec * 1000 + ts.ru_stime.tv_usec / 1000;
402 *pUserTime = ts.ru_utime.tv_sec * 1000 + ts.ru_utime.tv_usec / 1000;
403 return VINF_SUCCESS;
404
405#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
406 /* on Linux, getrusage(RUSAGE_THREAD, ...) is available since 2.6.26 */
407 struct timespec ts;
408 int rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
409 if (rc)
410 return RTErrConvertFromErrno(rc);
411
412 *pKernelTime = 0;
413 *pUserTime = (uint64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
414 return VINF_SUCCESS;
415
416#elif defined(RT_OS_DARWIN)
417 thread_basic_info ThreadInfo;
418 mach_msg_type_number_t Count = THREAD_BASIC_INFO_COUNT;
419 kern_return_t krc = thread_info(mach_thread_self(), THREAD_BASIC_INFO, (thread_info_t)&ThreadInfo, &Count);
420 AssertReturn(krc == KERN_SUCCESS, RTErrConvertFromDarwinKern(krc));
421
422 *pKernelTime = ThreadInfo.system_time.seconds * 1000 + ThreadInfo.system_time.microseconds / 1000;
423 *pUserTime = ThreadInfo.user_time.seconds * 1000 + ThreadInfo.user_time.microseconds / 1000;
424
425 return VINF_SUCCESS;
426#elif defined(RT_OS_HAIKU)
427 thread_info ThreadInfo;
428 status_t status = get_thread_info(find_thread(NULL), &ThreadInfo);
429 AssertReturn(status == B_OK, RTErrConvertFromErrno(status));
430
431 *pKernelTime = ThreadInfo.kernel_time / 1000;
432 *pUserTime = ThreadInfo.user_time / 1000;
433
434 return VINF_SUCCESS;
435#else
436 return VERR_NOT_IMPLEMENTED;
437#endif
438}
439
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette