VirtualBox

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

Last change on this file since 62643 was 62570, checked in by vboxsync, 9 years ago

IPRT: More unused parameters.

  • 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 62570 2016-07-26 15:45:53Z vboxsync $ */
2/** @file
3 * IPRT - Threads, POSIX.
4 */
5
6/*
7 * Copyright (C) 2006-2016 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 == (RTNATIVETHREAD)Self && (uintptr_t)Self != NIL_RTNATIVETHREAD);
297
298#if defined(RT_OS_LINUX)
299 /*
300 * Set the TID.
301 */
302 pThread->tid = syscall(__NR_gettid);
303 ASMMemoryFence();
304#endif
305
306 rtThreadPosixBlockSignals();
307
308 /*
309 * Set the TLS entry and, if possible, the thread name.
310 */
311 int rc = pthread_setspecific(g_SelfKey, pThread);
312 AssertReleaseMsg(!rc, ("failed to set self TLS. rc=%d thread '%s'\n", rc, pThread->szName));
313
314#ifdef IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP
315 if (g_pfnThreadSetName)
316# ifdef RT_OS_DARWIN
317 g_pfnThreadSetName(pThread->szName);
318# else
319 g_pfnThreadSetName(Self, pThread->szName);
320# endif
321#endif
322
323 /*
324 * Call common main.
325 */
326 rc = rtThreadMain(pThread, (uintptr_t)Self, &pThread->szName[0]);
327
328 pthread_setspecific(g_SelfKey, NULL);
329 pthread_exit((void *)(intptr_t)rc);
330 return (void *)(intptr_t)rc;
331}
332
333
334DECLHIDDEN(int) rtThreadNativeCreate(PRTTHREADINT pThread, PRTNATIVETHREAD pNativeThread)
335{
336 /*
337 * Set the default stack size.
338 */
339 if (!pThread->cbStack)
340 pThread->cbStack = 512*1024;
341
342#ifdef RT_OS_LINUX
343 pThread->tid = -1;
344#endif
345
346 /*
347 * Setup thread attributes.
348 */
349 pthread_attr_t ThreadAttr;
350 int rc = pthread_attr_init(&ThreadAttr);
351 if (!rc)
352 {
353 rc = pthread_attr_setdetachstate(&ThreadAttr, PTHREAD_CREATE_DETACHED);
354 if (!rc)
355 {
356 rc = pthread_attr_setstacksize(&ThreadAttr, pThread->cbStack);
357 if (!rc)
358 {
359 /*
360 * Create the thread.
361 */
362 pthread_t ThreadId;
363 rc = pthread_create(&ThreadId, &ThreadAttr, rtThreadNativeMain, pThread);
364 if (!rc)
365 {
366 pthread_attr_destroy(&ThreadAttr);
367 *pNativeThread = (uintptr_t)ThreadId;
368 return VINF_SUCCESS;
369 }
370 }
371 }
372 pthread_attr_destroy(&ThreadAttr);
373 }
374 return RTErrConvertFromErrno(rc);
375}
376
377
378RTDECL(RTTHREAD) RTThreadSelf(void)
379{
380 PRTTHREADINT pThread = (PRTTHREADINT)pthread_getspecific(g_SelfKey);
381 /** @todo import alien threads? */
382 return pThread;
383}
384
385
386#ifdef RTTHREAD_POSIX_WITH_POKE
387RTDECL(int) RTThreadPoke(RTTHREAD hThread)
388{
389 AssertReturn(hThread != RTThreadSelf(), VERR_INVALID_PARAMETER);
390 PRTTHREADINT pThread = rtThreadGet(hThread);
391 AssertReturn(pThread, VERR_INVALID_HANDLE);
392
393 int rc;
394 if (g_iSigPokeThread != -1)
395 {
396 rc = pthread_kill((pthread_t)(uintptr_t)pThread->Core.Key, g_iSigPokeThread);
397 rc = RTErrConvertFromErrno(rc);
398 }
399 else
400 rc = VERR_NOT_SUPPORTED;
401
402 rtThreadRelease(pThread);
403 return rc;
404}
405#endif
406
407/** @todo move this into platform specific files. */
408RTR3DECL(int) RTThreadGetExecutionTimeMilli(uint64_t *pKernelTime, uint64_t *pUserTime)
409{
410#if defined(RT_OS_SOLARIS)
411 struct rusage ts;
412 int rc = getrusage(RUSAGE_LWP, &ts);
413 if (rc)
414 return RTErrConvertFromErrno(rc);
415
416 *pKernelTime = ts.ru_stime.tv_sec * 1000 + ts.ru_stime.tv_usec / 1000;
417 *pUserTime = ts.ru_utime.tv_sec * 1000 + ts.ru_utime.tv_usec / 1000;
418 return VINF_SUCCESS;
419
420#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
421 /* on Linux, getrusage(RUSAGE_THREAD, ...) is available since 2.6.26 */
422 struct timespec ts;
423 int rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
424 if (rc)
425 return RTErrConvertFromErrno(rc);
426
427 *pKernelTime = 0;
428 *pUserTime = (uint64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
429 return VINF_SUCCESS;
430
431#elif defined(RT_OS_DARWIN)
432 thread_basic_info ThreadInfo;
433 mach_msg_type_number_t Count = THREAD_BASIC_INFO_COUNT;
434 kern_return_t krc = thread_info(mach_thread_self(), THREAD_BASIC_INFO, (thread_info_t)&ThreadInfo, &Count);
435 AssertReturn(krc == KERN_SUCCESS, RTErrConvertFromDarwinKern(krc));
436
437 *pKernelTime = ThreadInfo.system_time.seconds * 1000 + ThreadInfo.system_time.microseconds / 1000;
438 *pUserTime = ThreadInfo.user_time.seconds * 1000 + ThreadInfo.user_time.microseconds / 1000;
439
440 return VINF_SUCCESS;
441#elif defined(RT_OS_HAIKU)
442 thread_info ThreadInfo;
443 status_t status = get_thread_info(find_thread(NULL), &ThreadInfo);
444 AssertReturn(status == B_OK, RTErrConvertFromErrno(status));
445
446 *pKernelTime = ThreadInfo.kernel_time / 1000;
447 *pUserTime = ThreadInfo.user_time / 1000;
448
449 return VINF_SUCCESS;
450#else
451 return VERR_NOT_IMPLEMENTED;
452#endif
453}
454
Note: See TracBrowser for help on using the repository browser.

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