VirtualBox

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

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

fixed small memory leaks on certain hosts (Solaris) when using pthread_*attr functions

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