VirtualBox

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

Last change on this file since 44429 was 40317, checked in by vboxsync, 13 years ago

build fix.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 16.5 KB
Line 
1/* $Id: init.cpp 40317 2012-03-01 21:32:56Z vboxsync $ */
2/** @file
3 * IPRT - Init Ring-3.
4 */
5
6/*
7 * Copyright (C) 2006-2009 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_DEFAULT
32#include <iprt/types.h> /* darwin: UINT32_C and others. */
33
34#ifdef RT_OS_WINDOWS
35# include <process.h>
36# include <Windows.h>
37#else
38# include <unistd.h>
39# ifndef RT_OS_OS2
40# include <pthread.h>
41# include <signal.h>
42# include <errno.h>
43# define IPRT_USE_SIG_CHILD_DUMMY
44# endif
45#endif
46#ifdef RT_OS_OS2
47# include <InnoTekLIBC/fork.h>
48# define INCL_DOSMISC
49# include <os2.h>
50#endif
51#include <locale.h>
52
53#include <iprt/initterm.h>
54#include <iprt/asm.h>
55#include <iprt/assert.h>
56#include <iprt/err.h>
57#include <iprt/log.h>
58#include <iprt/mem.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 RTProcGetExecutablePath and set by rtProcInitName. */
87DECLHIDDEN(char) g_szrtProcExePath[RTPATH_MAX];
88/** The length of g_szrtProcExePath. */
89DECLHIDDEN(size_t) g_cchrtProcExePath;
90/** The length of directory path component of g_szrtProcExePath. */
91DECLHIDDEN(size_t) g_cchrtProcDir;
92/** The offset of the process name into g_szrtProcExePath. */
93DECLHIDDEN(size_t) g_offrtProcName;
94
95/** The argument count of the program. */
96static int g_crtArgs = -1;
97/** The arguments of the program (UTF-8). This is "leaked". */
98static char ** g_papszrtArgs;
99/** The original argument vector of the program. */
100static char ** g_papszrtOrgArgs;
101
102/**
103 * Program start nanosecond TS.
104 */
105DECLHIDDEN(uint64_t) g_u64ProgramStartNanoTS;
106
107/**
108 * Program start microsecond TS.
109 */
110DECLHIDDEN(uint64_t) g_u64ProgramStartMicroTS;
111
112/**
113 * Program start millisecond TS.
114 */
115DECLHIDDEN(uint64_t) g_u64ProgramStartMilliTS;
116
117/**
118 * The process identifier of the running process.
119 */
120DECLHIDDEN(RTPROCESS) g_ProcessSelf = NIL_RTPROCESS;
121
122/**
123 * The current process priority.
124 */
125DECLHIDDEN(RTPROCPRIORITY) g_enmProcessPriority = RTPROCPRIORITY_DEFAULT;
126
127/**
128 * Set if the atexit callback has been called, i.e. indicating
129 * that the process is terminating.
130 */
131DECLHIDDEN(bool volatile) g_frtAtExitCalled = false;
132
133#ifdef IPRT_WITH_ALIGNMENT_CHECKS
134/**
135 * Whether alignment checks are enabled.
136 * This is set if the environment variable IPRT_ALIGNMENT_CHECKS is 1.
137 */
138RTDATADECL(bool) g_fRTAlignmentChecks = false;
139#endif
140
141
142/**
143 * atexit callback.
144 *
145 * This makes sure any loggers are flushed and will later also work the
146 * termination callback chain.
147 */
148static void rtR3ExitCallback(void)
149{
150 ASMAtomicWriteBool(&g_frtAtExitCalled, true);
151
152 if (g_cUsers > 0)
153 {
154 PRTLOGGER pLogger = RTLogGetDefaultInstance();
155 if (pLogger)
156 RTLogFlush(pLogger);
157
158 pLogger = RTLogRelDefaultInstance();
159 if (pLogger)
160 RTLogFlush(pLogger);
161 }
162}
163
164
165#ifndef RT_OS_WINDOWS
166/**
167 * Fork callback, child context.
168 */
169static void rtR3ForkChildCallback(void)
170{
171 g_ProcessSelf = getpid();
172}
173#endif /* RT_OS_WINDOWS */
174
175#ifdef RT_OS_OS2
176/** Fork completion callback for OS/2. Only called in the child. */
177static void rtR3ForkOs2ChildCompletionCallback(void *pvArg, int rc, __LIBC_FORKCTX enmCtx)
178{
179 Assert(enmCtx == __LIBC_FORK_CTX_CHILD); NOREF(enmCtx);
180 NOREF(pvArg);
181
182 if (!rc)
183 rtR3ForkChildCallback();
184}
185
186/** Low-level fork callback for OS/2. */
187int rtR3ForkOs2Child(__LIBC_PFORKHANDLE pForkHandle, __LIBC_FORKOP enmOperation)
188{
189 if (enmOperation == __LIBC_FORK_OP_EXEC_CHILD)
190 return pForkHandle->pfnCompletionCallback(pForkHandle, rtR3ForkOs2ChildCompletionCallback, NULL, __LIBC_FORK_CTX_CHILD);
191 return 0;
192}
193
194# define static static volatile /** @todo _FORK_CHILD1 causes unresolved externals in optimized builds. Fix macro. */
195_FORK_CHILD1(0, rtR3ForkOs2Child);
196# undef static
197#endif /* RT_OS_OS2 */
198
199
200
201/**
202 * Internal worker which initializes or re-initializes the
203 * program path, name and directory globals.
204 *
205 * @returns IPRT status code.
206 * @param pszProgramPath The program path, NULL if not specified.
207 */
208static int rtR3InitProgramPath(const char *pszProgramPath)
209{
210 /*
211 * We're reserving 32 bytes here for file names as what not.
212 */
213 if (!pszProgramPath)
214 {
215 int rc = rtProcInitExePath(g_szrtProcExePath, sizeof(g_szrtProcExePath) - 32);
216 if (RT_FAILURE(rc))
217 return rc;
218 }
219 else
220 {
221 size_t cch = strlen(pszProgramPath);
222 Assert(cch > 1);
223 AssertMsgReturn(cch < sizeof(g_szrtProcExePath) - 32, ("%zu\n", cch), VERR_BUFFER_OVERFLOW);
224 memcpy(g_szrtProcExePath, pszProgramPath, cch + 1);
225 }
226
227 /*
228 * Parse the name.
229 */
230 ssize_t offName;
231 g_cchrtProcExePath = RTPathParse(g_szrtProcExePath, &g_cchrtProcDir, &offName, NULL);
232 g_offrtProcName = offName;
233 return VINF_SUCCESS;
234}
235
236
237/**
238 * Internal worker which initializes or re-initializes the
239 * program path, name and directory globals.
240 *
241 * @returns IPRT status code.
242 * @param fFlags Flags, see RTR3INIT_XXX.
243 * @param cArgs Pointer to the argument count.
244 * @param ppapszArgs Pointer to the argument vector pointer. NULL
245 * allowed if @a cArgs is 0.
246 */
247static int rtR3InitArgv(uint32_t fFlags, int cArgs, char ***ppapszArgs)
248{
249 NOREF(fFlags);
250 if (cArgs)
251 {
252 AssertPtr(ppapszArgs);
253 AssertPtr(*ppapszArgs);
254 char **papszOrgArgs = *ppapszArgs;
255
256 /*
257 * Normally we should only be asked to convert arguments once. If we
258 * are though, it should be the already convered arguments.
259 */
260 if (g_crtArgs != -1)
261 {
262 AssertReturn( g_crtArgs == cArgs
263 && g_papszrtArgs == papszOrgArgs,
264 VERR_WRONG_ORDER); /* only init once! */
265 return VINF_SUCCESS;
266 }
267
268 /*
269 * Convert the arguments.
270 */
271 char **papszArgs = (char **)RTMemAllocZ((cArgs + 1) * sizeof(char *));
272 if (!papszArgs)
273 return VERR_NO_MEMORY;
274
275 for (int i = 0; i < cArgs; i++)
276 {
277 int rc = RTStrCurrentCPToUtf8(&papszArgs[i], papszOrgArgs[i]);
278 if (RT_FAILURE(rc))
279 {
280 while (i--)
281 RTStrFree(papszArgs[i]);
282 RTMemFree(papszArgs);
283 return rc;
284 }
285 }
286 papszArgs[cArgs] = NULL;
287
288 g_papszrtOrgArgs = papszOrgArgs;
289 g_papszrtArgs = papszArgs;
290 g_crtArgs = cArgs;
291
292 *ppapszArgs = papszArgs;
293 }
294
295 return VINF_SUCCESS;
296}
297
298
299#ifdef IPRT_USE_SIG_CHILD_DUMMY
300/**
301 * Dummy SIGCHILD handler.
302 *
303 * Assigned on rtR3Init only when SIGCHILD handler is set SIGIGN or SIGDEF to
304 * ensure waitpid works properly for the terminated processes.
305 */
306static void rtR3SigChildHandler(int iSignal)
307{
308 NOREF(iSignal);
309}
310#endif /* IPRT_USE_SIG_CHILD_DUMMY */
311
312
313/**
314 * rtR3Init worker.
315 */
316static int rtR3InitBody(uint32_t fFlags, int cArgs, char ***papszArgs, const char *pszProgramPath)
317{
318 /*
319 * Init C runtime locale before we do anything that may end up converting
320 * paths or we'll end up using the "C" locale for path conversion.
321 */
322 setlocale(LC_CTYPE, "");
323
324 /*
325 * The Process ID.
326 */
327#ifdef _MSC_VER
328 g_ProcessSelf = _getpid(); /* crappy ansi compiler */
329#else
330 g_ProcessSelf = getpid();
331#endif
332
333 /*
334 * Disable error popups.
335 */
336#ifdef RT_OS_WINDOWS
337 UINT fOldErrMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
338 SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX | fOldErrMode);
339#elif defined(RT_OS_OS2)
340 DosError(FERR_DISABLEHARDERR);
341#endif
342
343#if !defined(IN_GUEST) && !defined(RT_NO_GIP)
344# ifdef VBOX
345 /*
346 * This MUST be done as the very first thing, before any file is opened.
347 * The log is opened on demand, but the first log entries may be caused
348 * by rtThreadInit() below.
349 */
350 const char *pszDisableHostCache = getenv("VBOX_DISABLE_HOST_DISK_CACHE");
351 if ( pszDisableHostCache != NULL
352 && *pszDisableHostCache
353 && strcmp(pszDisableHostCache, "0") != 0)
354 {
355 RTFileSetForceFlags(RTFILE_O_WRITE, RTFILE_O_WRITE_THROUGH, 0);
356 RTFileSetForceFlags(RTFILE_O_READWRITE, RTFILE_O_WRITE_THROUGH, 0);
357 }
358# endif /* VBOX */
359#endif /* !IN_GUEST && !RT_NO_GIP */
360
361 /*
362 * Thread Thread database and adopt the caller thread as 'main'.
363 * This must be done before everything else or else we'll call into threading
364 * without having initialized TLS entries and suchlike.
365 */
366 int rc = rtThreadInit();
367 AssertMsgRCReturn(rc, ("Failed to initialize threads, rc=%Rrc!\n", rc), rc);
368
369#if !defined(IN_GUEST) && !defined(RT_NO_GIP)
370 if (fFlags & RTR3INIT_FLAGS_SUPLIB)
371 {
372 /*
373 * Init GIP first.
374 * (The more time for updates before real use, the better.)
375 */
376 rc = SUPR3Init(NULL);
377 AssertMsgRCReturn(rc, ("Failed to initializable the support library, rc=%Rrc!\n", rc), rc);
378 }
379#endif
380
381 /*
382 * The executable path, name and directory. Convert arguments.
383 */
384 rc = rtR3InitProgramPath(pszProgramPath);
385 AssertLogRelMsgRCReturn(rc, ("Failed to get executable directory path, rc=%Rrc!\n", rc), rc);
386
387 rc = rtR3InitArgv(fFlags, cArgs, papszArgs);
388 AssertLogRelMsgRCReturn(rc, ("Failed to convert the arguments, rc=%Rrc!\n", rc), rc);
389
390#if !defined(IN_GUEST) && !defined(RT_NO_GIP)
391 /*
392 * The threading is initialized we can safely sleep a bit if GIP
393 * needs some time to update itself updating.
394 */
395 if ((fFlags & RTR3INIT_FLAGS_SUPLIB) && g_pSUPGlobalInfoPage)
396 {
397 RTThreadSleep(20);
398 RTTimeNanoTS();
399 }
400#endif
401
402 /*
403 * Init the program start TSes.
404 * Do that here to be sure that the GIP time was properly updated the 1st time.
405 */
406 g_u64ProgramStartNanoTS = RTTimeNanoTS();
407 g_u64ProgramStartMicroTS = g_u64ProgramStartNanoTS / 1000;
408 g_u64ProgramStartMilliTS = g_u64ProgramStartNanoTS / 1000000;
409
410 /*
411 * The remainder cannot easily be undone, so it has to go last.
412 */
413
414 /* Fork and exit callbacks. */
415#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
416 rc = pthread_atfork(NULL, NULL, rtR3ForkChildCallback);
417 AssertMsg(rc == 0, ("%d\n", rc));
418#endif
419 atexit(rtR3ExitCallback);
420
421#ifdef IPRT_USE_SIG_CHILD_DUMMY
422 /*
423 * SIGCHLD must not be ignored (that's default), otherwise posix compliant waitpid
424 * implementations won't work right.
425 */
426 for (;;)
427 {
428 struct sigaction saOld;
429 rc = sigaction(SIGCHLD, 0, &saOld); AssertMsg(rc == 0, ("%d/%d\n", rc, errno));
430 if ( rc != 0
431 || (saOld.sa_flags & SA_SIGINFO)
432 || ( saOld.sa_handler != SIG_IGN
433 && saOld.sa_handler != SIG_DFL)
434 )
435 break;
436
437 /* Try install dummy handler. */
438 struct sigaction saNew = saOld;
439 saNew.sa_flags = SA_NOCLDSTOP | SA_RESTART;
440 saNew.sa_handler = rtR3SigChildHandler;
441 rc = sigemptyset(&saNew.sa_mask); AssertMsg(rc == 0, ("%d/%d\n", rc, errno));
442 struct sigaction saOld2;
443 rc = sigaction(SIGCHLD, &saNew, &saOld2); AssertMsg(rc == 0, ("%d/%d\n", rc, errno));
444 if ( rc != 0
445 || ( saOld2.sa_handler == saOld.sa_handler
446 && !(saOld2.sa_flags & SA_SIGINFO))
447 )
448 break;
449
450 /* Race during dynamic load, restore and try again... */
451 sigaction(SIGCHLD, &saOld2, NULL);
452 RTThreadYield();
453 }
454#endif /* IPRT_USE_SIG_CHILD_DUMMY */
455
456#ifdef IPRT_WITH_ALIGNMENT_CHECKS
457 /*
458 * Enable alignment checks.
459 */
460 const char *pszAlignmentChecks = getenv("IPRT_ALIGNMENT_CHECKS");
461 g_fRTAlignmentChecks = pszAlignmentChecks != NULL
462 && pszAlignmentChecks[0] == '1'
463 && pszAlignmentChecks[1] == '\0';
464 if (g_fRTAlignmentChecks)
465 IPRT_ALIGNMENT_CHECKS_ENABLE();
466#endif
467
468 return VINF_SUCCESS;
469}
470
471
472/**
473 * Internal initialization worker.
474 *
475 * @returns IPRT status code.
476 * @param fFlags Flags, see RTR3INIT_XXX.
477 * @param cArgs Pointer to the argument count.
478 * @param ppapszArgs Pointer to the argument vector pointer. NULL
479 * allowed if @a cArgs is 0.
480 * @param pszProgramPath The program path. Pass NULL if we're to figure it
481 * out ourselves.
482 */
483static int rtR3Init(uint32_t fFlags, int cArgs, char ***papszArgs, const char *pszProgramPath)
484{
485 /* no entry log flow, because prefixes and thread may freak out. */
486 Assert(!(fFlags & ~(RTR3INIT_FLAGS_DLL | RTR3INIT_FLAGS_SUPLIB)));
487 Assert(!(fFlags & RTR3INIT_FLAGS_DLL) || cArgs == 0);
488
489 /*
490 * Do reference counting, only initialize the first time around.
491 *
492 * We are ASSUMING that nobody will be able to race RTR3Init* calls when the
493 * first one, the real init, is running (second assertion).
494 */
495 int32_t cUsers = ASMAtomicIncS32(&g_cUsers);
496 if (cUsers != 1)
497 {
498 AssertMsg(cUsers > 1, ("%d\n", cUsers));
499 Assert(!g_fInitializing);
500#if !defined(IN_GUEST) && !defined(RT_NO_GIP)
501 if (fFlags & RTR3INIT_FLAGS_SUPLIB)
502 SUPR3Init(NULL);
503#endif
504 if (!pszProgramPath)
505 return VINF_SUCCESS;
506
507 int rc = rtR3InitProgramPath(pszProgramPath);
508 if (RT_SUCCESS(rc))
509 rc = rtR3InitArgv(fFlags, cArgs, papszArgs);
510 return rc;
511 }
512 ASMAtomicWriteBool(&g_fInitializing, true);
513
514 /*
515 * Do the initialization.
516 */
517 int rc = rtR3InitBody(fFlags, cArgs, papszArgs, pszProgramPath);
518 if (RT_FAILURE(rc))
519 {
520 /* failure */
521 ASMAtomicWriteBool(&g_fInitializing, false);
522 ASMAtomicDecS32(&g_cUsers);
523 return rc;
524 }
525
526 /* success */
527 LogFlow(("rtR3Init: returns VINF_SUCCESS\n"));
528 ASMAtomicWriteBool(&g_fInitializing, false);
529 return VINF_SUCCESS;
530}
531
532
533RTR3DECL(int) RTR3InitExe(int cArgs, char ***papszArgs, uint32_t fFlags)
534{
535 Assert(!(fFlags & RTR3INIT_FLAGS_DLL));
536 return rtR3Init(fFlags, cArgs, papszArgs, NULL);
537}
538
539
540RTR3DECL(int) RTR3InitExeNoArguments(uint32_t fFlags)
541{
542 Assert(!(fFlags & RTR3INIT_FLAGS_DLL));
543 return rtR3Init(fFlags, 0, NULL, NULL);
544}
545
546
547RTR3DECL(int) RTR3InitDll(uint32_t fFlags)
548{
549 Assert(!(fFlags & RTR3INIT_FLAGS_DLL));
550 return rtR3Init(fFlags | RTR3INIT_FLAGS_DLL, 0, NULL, NULL);
551}
552
553
554RTR3DECL(int) RTR3InitEx(uint32_t iVersion, uint32_t fFlags, int cArgs, char ***papszArgs, const char *pszProgramPath)
555{
556 AssertReturn(iVersion == RTR3INIT_VER_CUR, VERR_NOT_SUPPORTED);
557 return rtR3Init(fFlags, cArgs, papszArgs, pszProgramPath);
558}
559
560
561#if 0 /** @todo implement RTR3Term. */
562RTR3DECL(void) RTR3Term(void)
563{
564}
565#endif
566
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