VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/init.cpp@ 25802

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

Made the common parts of the OS/2 additions build again.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 12.8 KB
Line 
1/* $Id: init.cpp 24287 2009-11-03 12:34:11Z vboxsync $ */
2/** @file
3 * IPRT - Init Ring-3.
4 */
5
6/*
7 * Copyright (C) 2006-2009 Sun Microsystems, Inc.
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 * 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_DEFAULT
36#include <iprt/types.h> /* darwin: UINT32_C and others. */
37
38#ifdef RT_OS_WINDOWS
39# include <process.h>
40#else
41# include <unistd.h>
42# ifndef RT_OS_OS2
43# include <pthread.h>
44# include <signal.h>
45# include <errno.h>
46# define IPRT_USE_SIG_CHILD_DUMMY
47# endif
48#endif
49#ifdef RT_OS_OS2
50# include <InnoTekLIBC/fork.h>
51#endif
52#include <locale.h>
53
54#include <iprt/initterm.h>
55#include <iprt/asm.h>
56#include <iprt/assert.h>
57#include <iprt/err.h>
58#include <iprt/log.h>
59#include <iprt/path.h>
60#include <iprt/time.h>
61#include <iprt/string.h>
62#include <iprt/param.h>
63#if !defined(IN_GUEST) && !defined(RT_NO_GIP)
64# include <iprt/file.h>
65# include <VBox/sup.h>
66#endif
67#include <stdlib.h>
68
69#include "internal/alignmentchecks.h"
70#include "internal/path.h"
71#include "internal/process.h"
72#include "internal/thread.h"
73#include "internal/thread.h"
74#include "internal/time.h"
75
76
77/*******************************************************************************
78* Global Variables *
79*******************************************************************************/
80/** The number of calls to RTR3Init. */
81static int32_t volatile g_cUsers = 0;
82/** Whether we're currently initializing the IPRT. */
83static bool volatile g_fInitializing = false;
84
85/** The process path.
86 * This is used by RTPathExecDir and RTProcGetExecutableName and set by rtProcInitName. */
87char g_szrtProcExePath[RTPATH_MAX];
88/** The length of g_szrtProcExePath. */
89size_t g_cchrtProcExePath;
90/** The length of directory path component of g_szrtProcExePath. */
91size_t g_cchrtProcDir;
92/** The offset of the process name into g_szrtProcExePath. */
93size_t g_offrtProcName;
94
95/**
96 * Program start nanosecond TS.
97 */
98uint64_t g_u64ProgramStartNanoTS;
99
100/**
101 * Program start microsecond TS.
102 */
103uint64_t g_u64ProgramStartMicroTS;
104
105/**
106 * Program start millisecond TS.
107 */
108uint64_t g_u64ProgramStartMilliTS;
109
110/**
111 * The process identifier of the running process.
112 */
113RTPROCESS g_ProcessSelf = NIL_RTPROCESS;
114
115/**
116 * The current process priority.
117 */
118RTPROCPRIORITY g_enmProcessPriority = RTPROCPRIORITY_DEFAULT;
119
120#ifdef IPRT_WITH_ALIGNMENT_CHECKS
121/**
122 * Whether alignment checks are enabled.
123 * This is set if the environment variable IPRT_ALIGNMENT_CHECKS is 1.
124 */
125RTDATADECL(bool) g_fRTAlignmentChecks = false;
126#endif
127
128
129/**
130 * atexit callback.
131 *
132 * This makes sure any loggers are flushed and will later also work the
133 * termination callback chain.
134 */
135static void rtR3ExitCallback(void)
136{
137 if (g_cUsers > 0)
138 {
139 PRTLOGGER pLogger = RTLogGetDefaultInstance();
140 if (pLogger)
141 RTLogFlush(pLogger);
142
143 pLogger = RTLogRelDefaultInstance();
144 if (pLogger)
145 RTLogFlush(pLogger);
146 }
147}
148
149
150#ifndef RT_OS_WINDOWS
151/**
152 * Fork callback, child context.
153 */
154static void rtR3ForkChildCallback(void)
155{
156 g_ProcessSelf = getpid();
157}
158#endif /* RT_OS_WINDOWS */
159
160#ifdef RT_OS_OS2
161/** Fork completion callback for OS/2. Only called in the child. */
162static void rtR3ForkOs2ChildCompletionCallback(void *pvArg, int rc, __LIBC_FORKCTX enmCtx)
163{
164 Assert(enmCtx == __LIBC_FORK_CTX_CHILD); NOREF(enmCtx);
165 NOREF(pvArg);
166
167 if (!rc)
168 rtR3ForkChildCallback();
169}
170
171/** Low-level fork callback for OS/2. */
172int rtR3ForkOs2Child(__LIBC_PFORKHANDLE pForkHandle, __LIBC_FORKOP enmOperation)
173{
174 if (enmOperation == __LIBC_FORK_OP_EXEC_CHILD)
175 return pForkHandle->pfnCompletionCallback(pForkHandle, rtR3ForkOs2ChildCompletionCallback, NULL, __LIBC_FORK_CTX_CHILD);
176 return 0;
177}
178
179_FORK_CHILD1(0, rtR3ForkOs2Child);
180#endif /* RT_OS_OS2 */
181
182
183
184/**
185 * Internal worker which initializes or re-initializes the
186 * program path, name and directory globals.
187 *
188 * @returns IPRT status code.
189 * @param pszProgramPath The program path, NULL if not specified.
190 */
191static int rtR3InitProgramPath(const char *pszProgramPath)
192{
193 /*
194 * We're reserving 32 bytes here for file names as what not.
195 */
196 if (!pszProgramPath)
197 {
198 int rc = rtProcInitExePath(g_szrtProcExePath, sizeof(g_szrtProcExePath) - 32);
199 if (RT_FAILURE(rc))
200 return rc;
201 }
202 else
203 {
204 size_t cch = strlen(pszProgramPath);
205 Assert(cch > 1);
206 AssertMsgReturn(cch < sizeof(g_szrtProcExePath) - 32, ("%zu\n", cch), VERR_BUFFER_OVERFLOW);
207 memcpy(g_szrtProcExePath, pszProgramPath, cch + 1);
208 }
209
210 /*
211 * Parse the name.
212 */
213 ssize_t offName;
214 g_cchrtProcExePath = RTPathParse(g_szrtProcExePath, &g_cchrtProcDir, &offName, NULL);
215 g_offrtProcName = offName;
216 return VINF_SUCCESS;
217}
218
219
220#ifdef IPRT_USE_SIG_CHILD_DUMMY
221/**
222 * Dummy SIGCHILD handler.
223 *
224 * Assigned on rtR3Init only when SIGCHILD handler is set SIGIGN or SIGDEF to
225 * ensure waitpid works properly for the terminated processes.
226 */
227static void rtR3SigChildHandler(int iSignal)
228{
229 NOREF(iSignal);
230}
231#endif /* IPRT_USE_SIG_CHILD_DUMMY */
232
233
234/**
235 * rtR3Init worker.
236 */
237static int rtR3InitBody(bool fInitSUPLib, const char *pszProgramPath)
238{
239 /*
240 * The Process ID.
241 */
242#ifdef _MSC_VER
243 g_ProcessSelf = _getpid(); /* crappy ansi compiler */
244#else
245 g_ProcessSelf = getpid();
246#endif
247
248#if !defined(IN_GUEST) && !defined(RT_NO_GIP)
249# ifdef VBOX
250 /*
251 * This MUST be done as the very first thing, before any file is opened.
252 * The log is opened on demand, but the first log entries may be caused
253 * by rtThreadInit() below.
254 */
255 const char *pszDisableHostCache = getenv("VBOX_DISABLE_HOST_DISK_CACHE");
256 if ( pszDisableHostCache != NULL
257 && *pszDisableHostCache
258 && strcmp(pszDisableHostCache, "0") != 0)
259 {
260 RTFileSetForceFlags(RTFILE_O_WRITE, RTFILE_O_WRITE_THROUGH, 0);
261 RTFileSetForceFlags(RTFILE_O_READWRITE, RTFILE_O_WRITE_THROUGH, 0);
262 }
263# endif /* VBOX */
264#endif /* !IN_GUEST && !RT_NO_GIP */
265
266 /*
267 * Thread Thread database and adopt the caller thread as 'main'.
268 * This must be done before everything else or else we'll call into threading
269 * without having initialized TLS entries and suchlike.
270 */
271 int rc = rtThreadInit();
272 AssertMsgRCReturn(rc, ("Failed to initialize threads, rc=%Rrc!\n", rc), rc);
273
274#if !defined(IN_GUEST) && !defined(RT_NO_GIP)
275 if (fInitSUPLib)
276 {
277 /*
278 * Init GIP first.
279 * (The more time for updates before real use, the better.)
280 */
281 rc = SUPR3Init(NULL);
282 AssertMsgRCReturn(rc, ("Failed to initializeble the support library, rc=%Rrc!\n", rc), rc);
283 }
284#endif
285
286 /*
287 * The executable path, name and directory.
288 */
289 rc = rtR3InitProgramPath(pszProgramPath);
290 AssertLogRelMsgRCReturn(rc, ("Failed to get executable directory path, rc=%Rrc!\n", rc), rc);
291
292#if !defined(IN_GUEST) && !defined(RT_NO_GIP)
293 /*
294 * The threading is initialized we can safely sleep a bit if GIP
295 * needs some time to update itself updating.
296 */
297 if (fInitSUPLib && g_pSUPGlobalInfoPage)
298 {
299 RTThreadSleep(20);
300 RTTimeNanoTS();
301 }
302#endif
303
304 /*
305 * Init the program start TSes.
306 * Do that here to be sure that the GIP time was properly updated the 1st time.
307 */
308 g_u64ProgramStartNanoTS = RTTimeNanoTS();
309 g_u64ProgramStartMicroTS = g_u64ProgramStartNanoTS / 1000;
310 g_u64ProgramStartMilliTS = g_u64ProgramStartNanoTS / 1000000;
311
312 /*
313 * The remainder cannot easily be undone, so it has to go last.
314 */
315
316 /* Init C runtime locale. */
317 setlocale(LC_CTYPE, "");
318
319 /* Fork and exit callbacks. */
320#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
321 rc = pthread_atfork(NULL, NULL, rtR3ForkChildCallback);
322 AssertMsg(rc == 0, ("%d\n", rc));
323#endif
324 atexit(rtR3ExitCallback);
325
326#ifdef IPRT_USE_SIG_CHILD_DUMMY
327 /*
328 * SIGCHLD must not be ignored (that's default), otherwise posix compliant waitpid
329 * implementations won't work right.
330 */
331 for (;;)
332 {
333 struct sigaction saOld;
334 rc = sigaction(SIGCHLD, 0, &saOld); AssertMsg(rc == 0, ("%d/%d\n", rc, errno));
335 if ( rc != 0
336 || (saOld.sa_flags & SA_SIGINFO)
337 || ( saOld.sa_handler != SIG_IGN
338 && saOld.sa_handler != SIG_DFL)
339 )
340 break;
341
342 /* Try install dummy handler. */
343 struct sigaction saNew = saOld;
344 saNew.sa_flags = SA_NOCLDSTOP | SA_RESTART;
345 saNew.sa_handler = rtR3SigChildHandler;
346 rc = sigemptyset(&saNew.sa_mask); AssertMsg(rc == 0, ("%d/%d\n", rc, errno));
347 struct sigaction saOld2;
348 rc = sigaction(SIGCHLD, &saNew, &saOld2); AssertMsg(rc == 0, ("%d/%d\n", rc, errno));
349 if ( rc != 0
350 || ( saOld2.sa_handler == saOld.sa_handler
351 && !(saOld2.sa_flags & SA_SIGINFO))
352 )
353 break;
354
355 /* Race during dynamic load, restore and try again... */
356 sigaction(SIGCHLD, &saOld2, NULL);
357 RTThreadYield();
358 }
359#endif /* IPRT_USE_SIG_CHILD_DUMMY */
360
361#ifdef IPRT_WITH_ALIGNMENT_CHECKS
362 /*
363 * Enable alignment checks.
364 */
365 const char *pszAlignmentChecks = getenv("IPRT_ALIGNMENT_CHECKS");
366 g_fRTAlignmentChecks = pszAlignmentChecks != NULL
367 && pszAlignmentChecks[0] == '1'
368 && pszAlignmentChecks[1] == '\0';
369 if (g_fRTAlignmentChecks)
370 IPRT_ALIGNMENT_CHECKS_ENABLE();
371#endif
372
373 return VINF_SUCCESS;
374}
375
376
377/**
378 * Internal initialization worker.
379 *
380 * @returns IPRT status code.
381 * @param fInitSUPLib Whether to call SUPR3Init.
382 * @param pszProgramPath The program path, NULL if not specified.
383 */
384static int rtR3Init(bool fInitSUPLib, const char *pszProgramPath)
385{
386 /* no entry log flow, because prefixes and thread may freak out. */
387
388 /*
389 * Do reference counting, only initialize the first time around.
390 *
391 * We are ASSUMING that nobody will be able to race RTR3Init calls when the
392 * first one, the real init, is running (second assertion).
393 */
394 int32_t cUsers = ASMAtomicIncS32(&g_cUsers);
395 if (cUsers != 1)
396 {
397 AssertMsg(cUsers > 1, ("%d\n", cUsers));
398 Assert(!g_fInitializing);
399#if !defined(IN_GUEST) && !defined(RT_NO_GIP)
400 if (fInitSUPLib)
401 SUPR3Init(NULL);
402#endif
403 if (!pszProgramPath)
404 return VINF_SUCCESS;
405 return rtR3InitProgramPath(pszProgramPath);
406 }
407 ASMAtomicWriteBool(&g_fInitializing, true);
408
409 /*
410 * Do the initialization.
411 */
412 int rc = rtR3InitBody(fInitSUPLib, pszProgramPath);
413 if (RT_FAILURE(rc))
414 {
415 /* failure */
416 ASMAtomicWriteBool(&g_fInitializing, false);
417 ASMAtomicDecS32(&g_cUsers);
418 return rc;
419 }
420
421 /* success */
422 LogFlow(("RTR3Init: returns VINF_SUCCESS\n"));
423 ASMAtomicWriteBool(&g_fInitializing, false);
424 return VINF_SUCCESS;
425}
426
427
428RTR3DECL(int) RTR3Init(void)
429{
430 return rtR3Init(false /* fInitSUPLib */, NULL);
431}
432
433
434RTR3DECL(int) RTR3InitEx(uint32_t iVersion, const char *pszProgramPath, bool fInitSUPLib)
435{
436 AssertReturn(iVersion == 0, VERR_NOT_SUPPORTED);
437 return rtR3Init(fInitSUPLib, pszProgramPath);
438}
439
440
441RTR3DECL(int) RTR3InitWithProgramPath(const char *pszProgramPath)
442{
443 return rtR3Init(false /* fInitSUPLib */, pszProgramPath);
444}
445
446
447RTR3DECL(int) RTR3InitAndSUPLib(void)
448{
449 return rtR3Init(true /* fInitSUPLib */, NULL /* pszProgramPath */);
450}
451
452
453RTR3DECL(int) RTR3InitAndSUPLibWithProgramPath(const char *pszProgramPath)
454{
455 return rtR3Init(true /* fInitSUPLib */, pszProgramPath);
456}
457
458
459#if 0 /** @todo implement RTR3Term. */
460RTR3DECL(void) RTR3Term(void)
461{
462}
463#endif
464
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