VirtualBox

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

Last change on this file since 25638 was 25638, checked in by vboxsync, 15 years ago

iprt,pdmcritsect: Added RTSemEvent[Set|Add|Remove]Signaller so that we can validate who is signalling an event if we like and, more importantly, detect deadlocks involving event semaphores. More attempts at dealing with the races (and bugs) in the all-other-threads-blocking detection in tstRTLockValidator.cpp, adding RTThreadGetReallySleeping and RTThreadGetNativeState in the process.

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