VirtualBox

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

Last change on this file since 36886 was 36555, checked in by vboxsync, 14 years ago

Use DECLHIDDEN, especially in IPRT.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 13.0 KB
Line 
1/* $Id: thread-posix.cpp 36555 2011-04-05 12:34:09Z vboxsync $ */
2/** @file
3 * IPRT - Threads, POSIX.
4 */
5
6/*
7 * Copyright (C) 2006-2007 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
51#include <iprt/thread.h>
52#include <iprt/log.h>
53#include <iprt/assert.h>
54#include <iprt/asm.h>
55#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
56# include <iprt/asm-amd64-x86.h>
57#endif
58#include <iprt/err.h>
59#include <iprt/string.h>
60#include "internal/thread.h"
61
62
63/*******************************************************************************
64* Defined Constants And Macros *
65*******************************************************************************/
66#ifndef IN_GUEST
67/** Includes RTThreadPoke. */
68# define RTTHREAD_POSIX_WITH_POKE
69#endif
70
71
72/*******************************************************************************
73* Global Variables *
74*******************************************************************************/
75/** The pthread key in which we store the pointer to our own PRTTHREAD structure. */
76static pthread_key_t g_SelfKey;
77#ifdef RTTHREAD_POSIX_WITH_POKE
78/** The signal we use for poking threads.
79 * This is set to -1 if no available signal was found. */
80static int g_iSigPokeThread = -1;
81#endif
82
83
84/*******************************************************************************
85* Internal Functions *
86*******************************************************************************/
87static void *rtThreadNativeMain(void *pvArgs);
88static void rtThreadKeyDestruct(void *pvValue);
89static void rtThreadPosixPokeSignal(int iSignal);
90
91
92DECLHIDDEN(int) rtThreadNativeInit(void)
93{
94 /*
95 * Allocate the TLS (key in posix terms) where we store the pointer to
96 * a threads RTTHREADINT structure.
97 */
98 int rc = pthread_key_create(&g_SelfKey, rtThreadKeyDestruct);
99 if (rc)
100 return VERR_NO_TLS_FOR_SELF;
101
102#ifdef RTTHREAD_POSIX_WITH_POKE
103 /*
104 * Try register the dummy signal handler for RTThreadPoke.
105 * Avoid SIGRTMIN thru SIGRTMIN+2 because of LinuxThreads.
106 */
107 static const int s_aiSigCandidates[] =
108 {
109# ifdef SIGRTMAX
110 SIGRTMAX-3,
111 SIGRTMAX-2,
112 SIGRTMAX-1,
113# endif
114# ifndef RT_OS_SOLARIS
115 SIGUSR2,
116# endif
117 SIGWINCH
118 };
119
120 g_iSigPokeThread = -1;
121 for (unsigned iSig = 0; iSig < RT_ELEMENTS(s_aiSigCandidates); iSig++)
122 {
123 struct sigaction SigActOld;
124 if (!sigaction(s_aiSigCandidates[iSig], NULL, &SigActOld))
125 {
126 if ( SigActOld.sa_handler == SIG_DFL
127 || SigActOld.sa_handler == rtThreadPosixPokeSignal)
128 {
129 struct sigaction SigAct;
130 RT_ZERO(SigAct);
131 SigAct.sa_handler = rtThreadPosixPokeSignal;
132 SigAct.sa_flags = 0;
133 sigfillset(&SigAct.sa_mask);
134
135 /* ASSUMES no sigaction race... (lazy bird) */
136 if (!sigaction(s_aiSigCandidates[iSig], &SigAct, NULL))
137 {
138 g_iSigPokeThread = s_aiSigCandidates[iSig];
139 break;
140 }
141 AssertMsgFailed(("rc=%Rrc errno=%d\n", RTErrConvertFromErrno(errno), errno));
142 }
143 }
144 else
145 AssertMsgFailed(("rc=%Rrc errno=%d\n", RTErrConvertFromErrno(errno), errno));
146 }
147#endif /* RTTHREAD_POSIX_WITH_POKE */
148 return rc;
149}
150
151
152/**
153 * Destructor called when a thread terminates.
154 * @param pvValue The key value. PRTTHREAD in our case.
155 */
156static void rtThreadKeyDestruct(void *pvValue)
157{
158 /*
159 * Deal with alien threads.
160 */
161 PRTTHREADINT pThread = (PRTTHREADINT)pvValue;
162 if (pThread->fIntFlags & RTTHREADINT_FLAGS_ALIEN)
163 {
164 pthread_setspecific(g_SelfKey, pThread);
165 rtThreadTerminate(pThread, 0);
166 pthread_setspecific(g_SelfKey, NULL);
167 }
168}
169
170
171#ifdef RTTHREAD_POSIX_WITH_POKE
172/**
173 * Dummy signal handler for the poke signal.
174 *
175 * @param iSignal The signal number.
176 */
177static void rtThreadPosixPokeSignal(int iSignal)
178{
179 Assert(iSignal == g_iSigPokeThread);
180 NOREF(iSignal);
181}
182#endif
183
184
185/**
186 * Adopts a thread, this is called immediately after allocating the
187 * thread structure.
188 *
189 * @param pThread Pointer to the thread structure.
190 */
191DECLHIDDEN(int) rtThreadNativeAdopt(PRTTHREADINT pThread)
192{
193 /*
194 * Block SIGALRM - required for timer-posix.cpp.
195 * This is done to limit harm done by OSes which doesn't do special SIGALRM scheduling.
196 * It will not help much if someone creates threads directly using pthread_create. :/
197 */
198 sigset_t SigSet;
199 sigemptyset(&SigSet);
200 sigaddset(&SigSet, SIGALRM);
201 sigprocmask(SIG_BLOCK, &SigSet, NULL);
202#ifdef RTTHREAD_POSIX_WITH_POKE
203 if (g_iSigPokeThread != -1)
204 siginterrupt(g_iSigPokeThread, 1);
205#endif
206
207 int rc = pthread_setspecific(g_SelfKey, pThread);
208 if (!rc)
209 return VINF_SUCCESS;
210 return VERR_FAILED_TO_SET_SELF_TLS;
211}
212
213
214DECLHIDDEN(void) rtThreadNativeDestroy(PRTTHREADINT pThread)
215{
216 if (pThread == (PRTTHREADINT)pthread_getspecific(g_SelfKey))
217 pthread_setspecific(g_SelfKey, NULL);
218}
219
220
221/**
222 * Wrapper which unpacks the params and calls thread function.
223 */
224static void *rtThreadNativeMain(void *pvArgs)
225{
226 PRTTHREADINT pThread = (PRTTHREADINT)pvArgs;
227
228#if defined(RT_OS_LINUX)
229 /*
230 * Set the TID.
231 */
232 pThread->tid = syscall(__NR_gettid);
233 ASMMemoryFence();
234#endif
235
236 /*
237 * Block SIGALRM - required for timer-posix.cpp.
238 * This is done to limit harm done by OSes which doesn't do special SIGALRM scheduling.
239 * It will not help much if someone creates threads directly using pthread_create. :/
240 */
241 sigset_t SigSet;
242 sigemptyset(&SigSet);
243 sigaddset(&SigSet, SIGALRM);
244 sigprocmask(SIG_BLOCK, &SigSet, NULL);
245#ifdef RTTHREAD_POSIX_WITH_POKE
246 if (g_iSigPokeThread != -1)
247 siginterrupt(g_iSigPokeThread, 1);
248#endif
249
250 int rc = pthread_setspecific(g_SelfKey, pThread);
251 AssertReleaseMsg(!rc, ("failed to set self TLS. rc=%d thread '%s'\n", rc, pThread->szName));
252
253 /*
254 * Call common main.
255 */
256 pthread_t Self = pthread_self();
257 Assert((uintptr_t)Self == (RTNATIVETHREAD)Self && (uintptr_t)Self != NIL_RTNATIVETHREAD);
258 rc = rtThreadMain(pThread, (uintptr_t)Self, &pThread->szName[0]);
259
260 pthread_setspecific(g_SelfKey, NULL);
261 pthread_exit((void *)rc);
262 return (void *)rc;
263}
264
265
266DECLHIDDEN(int) rtThreadNativeCreate(PRTTHREADINT pThread, PRTNATIVETHREAD pNativeThread)
267{
268 /*
269 * Set the default stack size.
270 */
271 if (!pThread->cbStack)
272 pThread->cbStack = 512*1024;
273
274#ifdef RT_OS_LINUX
275 pThread->tid = -1;
276#endif
277
278 /*
279 * Setup thread attributes.
280 */
281 pthread_attr_t ThreadAttr;
282 int rc = pthread_attr_init(&ThreadAttr);
283 if (!rc)
284 {
285 rc = pthread_attr_setdetachstate(&ThreadAttr, PTHREAD_CREATE_DETACHED);
286 if (!rc)
287 {
288 rc = pthread_attr_setstacksize(&ThreadAttr, pThread->cbStack);
289 if (!rc)
290 {
291 /*
292 * Create the thread.
293 */
294 pthread_t ThreadId;
295 rc = pthread_create(&ThreadId, &ThreadAttr, rtThreadNativeMain, pThread);
296 if (!rc)
297 {
298 *pNativeThread = (uintptr_t)ThreadId;
299 return VINF_SUCCESS;
300 }
301 }
302 }
303 pthread_attr_destroy(&ThreadAttr);
304 }
305 return RTErrConvertFromErrno(rc);
306}
307
308
309RTDECL(RTTHREAD) RTThreadSelf(void)
310{
311 PRTTHREADINT pThread = (PRTTHREADINT)pthread_getspecific(g_SelfKey);
312 /** @todo import alien threads? */
313 return pThread;
314}
315
316
317RTDECL(RTNATIVETHREAD) RTThreadNativeSelf(void)
318{
319 return (RTNATIVETHREAD)pthread_self();
320}
321
322
323RTDECL(int) RTThreadSleep(RTMSINTERVAL cMillies)
324{
325 LogFlow(("RTThreadSleep: cMillies=%d\n", cMillies));
326 if (!cMillies)
327 {
328 /* pthread_yield() isn't part of SuS, thus this fun. */
329#ifdef RT_OS_DARWIN
330 pthread_yield_np();
331#elif defined(RT_OS_FREEBSD) /* void pthread_yield */
332 pthread_yield();
333#elif defined(RT_OS_SOLARIS)
334 sched_yield();
335#else
336 if (!pthread_yield())
337#endif
338 {
339 LogFlow(("RTThreadSleep: returning %Rrc (cMillies=%d)\n", VINF_SUCCESS, cMillies));
340 return VINF_SUCCESS;
341 }
342 }
343 else
344 {
345 struct timespec ts;
346 struct timespec tsrem = {0,0};
347
348 ts.tv_nsec = (cMillies % 1000) * 1000000;
349 ts.tv_sec = cMillies / 1000;
350 if (!nanosleep(&ts, &tsrem))
351 {
352 LogFlow(("RTThreadSleep: returning %Rrc (cMillies=%d)\n", VINF_SUCCESS, cMillies));
353 return VINF_SUCCESS;
354 }
355 }
356
357 int rc = RTErrConvertFromErrno(errno);
358 LogFlow(("RTThreadSleep: returning %Rrc (cMillies=%d)\n", rc, cMillies));
359 return rc;
360}
361
362
363RTDECL(bool) RTThreadYield(void)
364{
365#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
366 uint64_t u64TS = ASMReadTSC();
367#endif
368#ifdef RT_OS_DARWIN
369 pthread_yield_np();
370#elif defined(RT_OS_SOLARIS)
371 sched_yield();
372#else
373 pthread_yield();
374#endif
375#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
376 u64TS = ASMReadTSC() - u64TS;
377 bool fRc = u64TS > 1500;
378 LogFlow(("RTThreadYield: returning %d (%llu ticks)\n", fRc, u64TS));
379#else
380 bool fRc = true; /* PORTME: Add heuristics for determining whether the cpus was yielded. */
381#endif
382 return fRc;
383}
384
385
386RTR3DECL(uint64_t) RTThreadGetAffinity(void)
387{
388 return 1;
389}
390
391
392RTR3DECL(int) RTThreadSetAffinity(uint64_t u64Mask)
393{
394 if (u64Mask != 1)
395 return VERR_INVALID_PARAMETER;
396 return VINF_SUCCESS;
397}
398
399
400#ifdef RTTHREAD_POSIX_WITH_POKE
401RTDECL(int) RTThreadPoke(RTTHREAD hThread)
402{
403 AssertReturn(hThread != RTThreadSelf(), VERR_INVALID_PARAMETER);
404 PRTTHREADINT pThread = rtThreadGet(hThread);
405 AssertReturn(pThread, VERR_INVALID_HANDLE);
406
407 int rc;
408 if (g_iSigPokeThread != -1)
409 {
410 rc = pthread_kill((pthread_t)(uintptr_t)pThread->Core.Key, g_iSigPokeThread);
411 rc = RTErrConvertFromErrno(rc);
412 }
413 else
414 rc = VERR_NOT_SUPPORTED;
415
416 rtThreadRelease(pThread);
417 return rc;
418}
419#endif
420
421/** @todo move this into platform specific files. */
422RTR3DECL(int) RTThreadGetExecutionTimeMilli(uint64_t *pKernelTime, uint64_t *pUserTime)
423{
424#if defined(RT_OS_SOLARIS)
425 struct rusage ts;
426 int rc = getrusage(RUSAGE_LWP, &ts);
427 if (rc)
428 return RTErrConvertFromErrno(rc);
429
430 *pKernelTime = ts.ru_stime.tv_sec * 1000 + ts.ru_stime.tv_usec / 1000;
431 *pUserTime = ts.ru_utime.tv_sec * 1000 + ts.ru_utime.tv_usec / 1000;
432 return VINF_SUCCESS;
433
434#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
435 /* on Linux, getrusage(RUSAGE_THREAD, ...) is available since 2.6.26 */
436 struct timespec ts;
437 int rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
438 if (rc)
439 return RTErrConvertFromErrno(rc);
440
441 *pKernelTime = 0;
442 *pUserTime = (uint64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
443 return VINF_SUCCESS;
444
445#elif defined(RT_OS_DARWIN)
446 thread_basic_info ThreadInfo;
447 mach_msg_type_number_t Count = THREAD_BASIC_INFO_COUNT;
448 kern_return_t krc = thread_info(mach_thread_self(), THREAD_BASIC_INFO, (thread_info_t)&ThreadInfo, &Count);
449 AssertReturn(krc == KERN_SUCCESS, RTErrConvertFromDarwinKern(krc));
450
451 *pKernelTime = ThreadInfo.system_time.seconds * 1000 + ThreadInfo.system_time.microseconds / 1000;
452 *pUserTime = ThreadInfo.user_time.seconds * 1000 + ThreadInfo.user_time.microseconds / 1000;
453
454 return VINF_SUCCESS;
455#else
456 return VERR_NOT_IMPLEMENTED;
457#endif
458}
459
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