VirtualBox

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

Last change on this file since 28877 was 28800, checked in by vboxsync, 14 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 10.5 KB
Line 
1/* $Id: thread-posix.cpp 28800 2010-04-27 08:22:32Z 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#endif
42
43#include <iprt/thread.h>
44#include <iprt/log.h>
45#include <iprt/assert.h>
46#include <iprt/asm.h>
47#include <iprt/err.h>
48#include <iprt/string.h>
49#include "internal/thread.h"
50
51
52/*******************************************************************************
53* Defined Constants And Macros *
54*******************************************************************************/
55#ifndef IN_GUEST
56/** The signal we're using for RTThreadPoke. */
57# define RTTHREAD_POSIX_POKE_SIG SIGUSR2
58#endif
59
60
61/*******************************************************************************
62* Global Variables *
63*******************************************************************************/
64/** The pthread key in which we store the pointer to our own PRTTHREAD structure. */
65static pthread_key_t g_SelfKey;
66#ifdef RTTHREAD_POSIX_POKE_SIG
67/** Set if we can poke a thread, clear if we cannot. */
68static bool g_fCanPokeThread;
69#endif
70
71
72/*******************************************************************************
73* Internal Functions *
74*******************************************************************************/
75static void *rtThreadNativeMain(void *pvArgs);
76static void rtThreadKeyDestruct(void *pvValue);
77static void rtThreadPosixPokeSignal(int iSignal);
78
79
80int rtThreadNativeInit(void)
81{
82 /*
83 * Allocate the TLS (key in posix terms) where we store the pointer to
84 * a threads RTTHREADINT structure.
85 */
86 int rc = pthread_key_create(&g_SelfKey, rtThreadKeyDestruct);
87 if (rc)
88 return VERR_NO_TLS_FOR_SELF;
89
90#ifdef RTTHREAD_POSIX_POKE_SIG
91 /*
92 * Try register the dummy signal handler for RTThreadPoke.
93 */
94 g_fCanPokeThread = false;
95 struct sigaction SigActOld;
96 if (!sigaction(RTTHREAD_POSIX_POKE_SIG, NULL, &SigActOld))
97 {
98 if ( SigActOld.sa_handler == SIG_DFL
99 || SigActOld.sa_handler == rtThreadPosixPokeSignal)
100 {
101 struct sigaction SigAct;
102 memset(&SigAct, '\0', sizeof(SigAct));
103 SigAct.sa_handler = rtThreadPosixPokeSignal;
104 sigfillset(&SigAct.sa_mask);
105 SigAct.sa_flags = 0;
106
107 /* ASSUMES no sigaction race... (lazy bird) */
108 if (!sigaction(RTTHREAD_POSIX_POKE_SIG, &SigAct, NULL))
109 g_fCanPokeThread = true;
110 else
111 {
112 AssertMsgFailed(("rc=%Rrc errno=%d\n", RTErrConvertFromErrno(errno), errno));
113 pthread_key_delete(g_SelfKey);
114 g_SelfKey = 0;
115 }
116 }
117 }
118 else
119 AssertMsgFailed(("rc=%Rrc errno=%d\n", RTErrConvertFromErrno(errno), errno));
120#endif /* RTTHREAD_POSIX_POKE_SIG */
121 return rc;
122}
123
124
125/**
126 * Destructor called when a thread terminates.
127 * @param pvValue The key value. PRTTHREAD in our case.
128 */
129static void rtThreadKeyDestruct(void *pvValue)
130{
131 /*
132 * Deal with alien threads.
133 */
134 PRTTHREADINT pThread = (PRTTHREADINT)pvValue;
135 if (pThread->fIntFlags & RTTHREADINT_FLAGS_ALIEN)
136 {
137 pthread_setspecific(g_SelfKey, pThread);
138 rtThreadTerminate(pThread, 0);
139 pthread_setspecific(g_SelfKey, NULL);
140 }
141}
142
143
144#ifdef RTTHREAD_POSIX_POKE_SIG
145/**
146 * Dummy signal handler for the poke signal.
147 *
148 * @param iSignal The signal number.
149 */
150static void rtThreadPosixPokeSignal(int iSignal)
151{
152 Assert(iSignal == RTTHREAD_POSIX_POKE_SIG);
153 NOREF(iSignal);
154}
155#endif
156
157
158/**
159 * Adopts a thread, this is called immediately after allocating the
160 * thread structure.
161 *
162 * @param pThread Pointer to the thread structure.
163 */
164int rtThreadNativeAdopt(PRTTHREADINT pThread)
165{
166 /*
167 * Block SIGALRM - required for timer-posix.cpp.
168 * This is done to limit harm done by OSes which doesn't do special SIGALRM scheduling.
169 * It will not help much if someone creates threads directly using pthread_create. :/
170 */
171 sigset_t SigSet;
172 sigemptyset(&SigSet);
173 sigaddset(&SigSet, SIGALRM);
174 sigprocmask(SIG_BLOCK, &SigSet, NULL);
175#ifdef RTTHREAD_POSIX_POKE_SIG
176 if (g_fCanPokeThread)
177 siginterrupt(RTTHREAD_POSIX_POKE_SIG, 1);
178#endif
179
180 int rc = pthread_setspecific(g_SelfKey, pThread);
181 if (!rc)
182 return VINF_SUCCESS;
183 return VERR_FAILED_TO_SET_SELF_TLS;
184}
185
186
187/**
188 * Wrapper which unpacks the params and calls thread function.
189 */
190static void *rtThreadNativeMain(void *pvArgs)
191{
192 PRTTHREADINT pThread = (PRTTHREADINT)pvArgs;
193
194#if defined(RT_OS_LINUX)
195 /*
196 * Set the TID.
197 */
198 pThread->tid = syscall(__NR_gettid);
199 ASMMemoryFence();
200#endif
201
202 /*
203 * Block SIGALRM - required for timer-posix.cpp.
204 * This is done to limit harm done by OSes which doesn't do special SIGALRM scheduling.
205 * It will not help much if someone creates threads directly using pthread_create. :/
206 */
207 sigset_t SigSet;
208 sigemptyset(&SigSet);
209 sigaddset(&SigSet, SIGALRM);
210 sigprocmask(SIG_BLOCK, &SigSet, NULL);
211#ifdef RTTHREAD_POSIX_POKE_SIG
212 if (g_fCanPokeThread)
213 siginterrupt(RTTHREAD_POSIX_POKE_SIG, 1);
214#endif
215
216 int rc = pthread_setspecific(g_SelfKey, pThread);
217 AssertReleaseMsg(!rc, ("failed to set self TLS. rc=%d thread '%s'\n", rc, pThread->szName));
218
219 /*
220 * Call common main.
221 */
222 pthread_t Self = pthread_self();
223 Assert((uintptr_t)Self == (RTNATIVETHREAD)Self && (uintptr_t)Self != NIL_RTNATIVETHREAD);
224 rc = rtThreadMain(pThread, (uintptr_t)Self, &pThread->szName[0]);
225
226 pthread_setspecific(g_SelfKey, NULL);
227 pthread_exit((void *)rc);
228 return (void *)rc;
229}
230
231
232int rtThreadNativeCreate(PRTTHREADINT pThread, PRTNATIVETHREAD pNativeThread)
233{
234 /*
235 * Set the default stack size.
236 */
237 if (!pThread->cbStack)
238 pThread->cbStack = 512*1024;
239
240#ifdef RT_OS_LINUX
241 pThread->tid = -1;
242#endif
243
244 /*
245 * Setup thread attributes.
246 */
247 pthread_attr_t ThreadAttr;
248 int rc = pthread_attr_init(&ThreadAttr);
249 if (!rc)
250 {
251 rc = pthread_attr_setdetachstate(&ThreadAttr, PTHREAD_CREATE_DETACHED);
252 if (!rc)
253 {
254 rc = pthread_attr_setstacksize(&ThreadAttr, pThread->cbStack);
255 if (!rc)
256 {
257 /*
258 * Create the thread.
259 */
260 pthread_t ThreadId;
261 rc = pthread_create(&ThreadId, &ThreadAttr, rtThreadNativeMain, pThread);
262 if (!rc)
263 {
264 *pNativeThread = (uintptr_t)ThreadId;
265 return VINF_SUCCESS;
266 }
267 }
268 }
269 pthread_attr_destroy(&ThreadAttr);
270 }
271 return RTErrConvertFromErrno(rc);
272}
273
274
275RTDECL(RTTHREAD) RTThreadSelf(void)
276{
277 PRTTHREADINT pThread = (PRTTHREADINT)pthread_getspecific(g_SelfKey);
278 /** @todo import alien threads? */
279 return pThread;
280}
281
282
283RTDECL(RTNATIVETHREAD) RTThreadNativeSelf(void)
284{
285 return (RTNATIVETHREAD)pthread_self();
286}
287
288
289RTDECL(int) RTThreadSleep(RTMSINTERVAL cMillies)
290{
291 LogFlow(("RTThreadSleep: cMillies=%d\n", cMillies));
292 if (!cMillies)
293 {
294 /* pthread_yield() isn't part of SuS, thus this fun. */
295#ifdef RT_OS_DARWIN
296 pthread_yield_np();
297#elif defined(RT_OS_FREEBSD) /* void pthread_yield */
298 pthread_yield();
299#elif defined(RT_OS_SOLARIS)
300 sched_yield();
301#else
302 if (!pthread_yield())
303#endif
304 {
305 LogFlow(("RTThreadSleep: returning %Rrc (cMillies=%d)\n", VINF_SUCCESS, cMillies));
306 return VINF_SUCCESS;
307 }
308 }
309 else
310 {
311 struct timespec ts;
312 struct timespec tsrem = {0,0};
313
314 ts.tv_nsec = (cMillies % 1000) * 1000000;
315 ts.tv_sec = cMillies / 1000;
316 if (!nanosleep(&ts, &tsrem))
317 {
318 LogFlow(("RTThreadSleep: returning %Rrc (cMillies=%d)\n", VINF_SUCCESS, cMillies));
319 return VINF_SUCCESS;
320 }
321 }
322
323 int rc = RTErrConvertFromErrno(errno);
324 LogFlow(("RTThreadSleep: returning %Rrc (cMillies=%d)\n", rc, cMillies));
325 return rc;
326}
327
328
329RTDECL(bool) RTThreadYield(void)
330{
331 uint64_t u64TS = ASMReadTSC();
332#ifdef RT_OS_DARWIN
333 pthread_yield_np();
334#elif defined(RT_OS_SOLARIS)
335 sched_yield();
336#else
337 pthread_yield();
338#endif
339 u64TS = ASMReadTSC() - u64TS;
340 bool fRc = u64TS > 1500;
341 LogFlow(("RTThreadYield: returning %d (%llu ticks)\n", fRc, u64TS));
342 return fRc;
343}
344
345
346RTR3DECL(uint64_t) RTThreadGetAffinity(void)
347{
348 return 1;
349}
350
351
352RTR3DECL(int) RTThreadSetAffinity(uint64_t u64Mask)
353{
354 if (u64Mask != 1)
355 return VERR_INVALID_PARAMETER;
356 return VINF_SUCCESS;
357}
358
359
360#ifdef RTTHREAD_POSIX_POKE_SIG
361RTDECL(int) RTThreadPoke(RTTHREAD hThread)
362{
363 AssertReturn(hThread != RTThreadSelf(), VERR_INVALID_PARAMETER);
364 PRTTHREADINT pThread = rtThreadGet(hThread);
365 AssertReturn(pThread, VERR_INVALID_HANDLE);
366 int rc;
367 if (g_fCanPokeThread)
368 {
369 rc = pthread_kill((pthread_t)(uintptr_t)pThread->Core.Key, RTTHREAD_POSIX_POKE_SIG);
370 rc = RTErrConvertFromErrno(rc);
371 }
372 else
373 rc = VERR_NOT_SUPPORTED;
374
375 rtThreadRelease(pThread);
376 return rc;
377}
378#endif
379
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