/** * Internal initialization worker. * * @returns IPRT status code. * @param fFlags Flags, see RTR3INIT_XXX. * @param cArgs Pointer to the argument count. * @param ppapszArgs Pointer to the argument vector pointer. NULL * allowed if @a cArgs is 0. * @param pszProgramPath The program path. Pass NULL if we're to figure it * out ourselves. */ static int rtR3Init(uint32_t fFlags, int cArgs, char ***papszArgs, const char *pszProgramPath) { /* no entry log flow, because prefixes and thread may freak out. */ Assert(!(fFlags & ~(RTR3INIT_FLAGS_DLL | RTR3INIT_FLAGS_SUPLIB))); Assert(!(fFlags & RTR3INIT_FLAGS_DLL) || cArgs == 0); /* * Do reference counting, only initialize the first time around. * * We are ASSUMING that nobody will be able to race RTR3Init* calls when the * first one, the real init, is running (second assertion). */ int32_t cUsers = ASMAtomicIncS32(&g_cUsers); if (cUsers != 1) { AssertMsg(cUsers > 1, ("%d\n", cUsers)); Assert(!g_fInitializing); #if !defined(IN_GUEST) && !defined(RT_NO_GIP) if (fFlags & RTR3INIT_FLAGS_SUPLIB) SUPR3Init(NULL); #endif if (!pszProgramPath) return VINF_SUCCESS; int rc = rtR3InitProgramPath(pszProgramPath); if (RT_SUCCESS(rc)) rc = rtR3InitArgv(fFlags, cArgs, papszArgs); return rc; } ASMAtomicWriteBool(&g_fInitializing, true); /* * Do the initialization. */ int rc = rtR3InitBody(fFlags, cArgs, papszArgs, pszProgramPath); if (RT_FAILURE(rc)) { /* failure */ ASMAtomicWriteBool(&g_fInitializing, false); ASMAtomicDecS32(&g_cUsers); return rc; } /* success */ LogFlow(("rtR3Init: returns VINF_SUCCESS\n")); ASMAtomicWriteBool(&g_fInitializing, false); return VINF_SUCCESS; }
/** * rtR3Init worker. */ static int rtR3InitBody(uint32_t fFlags, int cArgs, char ***papszArgs, const char *pszProgramPath) { /* * Early native initialization. */ int rc = rtR3InitNativeFirst(fFlags); AssertMsgRCReturn(rc, ("rtR3InitNativeFirst failed with %Rrc\n", rc), rc); /* * Disable error popups. */ #if defined(RT_OS_OS2) /** @todo move to private code. */ DosError(FERR_DISABLEHARDERR); #endif /* * Init C runtime locale before we do anything that may end up converting * paths or we'll end up using the "C" locale for path conversion. */ setlocale(LC_CTYPE, ""); /* * The Process ID. */ #ifdef _MSC_VER g_ProcessSelf = _getpid(); /* crappy ansi compiler */ #else g_ProcessSelf = getpid(); #endif /* * Save the init flags. */ g_fInitFlags |= fFlags; #if !defined(IN_GUEST) && !defined(RT_NO_GIP) # ifdef VBOX /* * This MUST be done as the very first thing, before any file is opened. * The log is opened on demand, but the first log entries may be caused * by rtThreadInit() below. */ const char *pszDisableHostCache = getenv("VBOX_DISABLE_HOST_DISK_CACHE"); if ( pszDisableHostCache != NULL && *pszDisableHostCache && strcmp(pszDisableHostCache, "0") != 0) { RTFileSetForceFlags(RTFILE_O_WRITE, RTFILE_O_WRITE_THROUGH, 0); RTFileSetForceFlags(RTFILE_O_READWRITE, RTFILE_O_WRITE_THROUGH, 0); } # endif /* VBOX */ #endif /* !IN_GUEST && !RT_NO_GIP */ /* * Thread Thread database and adopt the caller thread as 'main'. * This must be done before everything else or else we'll call into threading * without having initialized TLS entries and suchlike. */ rc = rtThreadInit(); AssertMsgRCReturn(rc, ("Failed to initialize threads, rc=%Rrc!\n", rc), rc); #if !defined(IN_GUEST) && !defined(RT_NO_GIP) if (fFlags & RTR3INIT_FLAGS_SUPLIB) { /* * Init GIP first. * (The more time for updates before real use, the better.) */ rc = SUPR3Init(NULL); AssertMsgRCReturn(rc, ("Failed to initializable the support library, rc=%Rrc!\n", rc), rc); } #endif /* * The executable path, name and directory. Convert arguments. */ rc = rtR3InitProgramPath(pszProgramPath); AssertLogRelMsgRCReturn(rc, ("Failed to get executable directory path, rc=%Rrc!\n", rc), rc); rc = rtR3InitArgv(fFlags, cArgs, papszArgs); AssertLogRelMsgRCReturn(rc, ("Failed to convert the arguments, rc=%Rrc!\n", rc), rc); #if !defined(IN_GUEST) && !defined(RT_NO_GIP) /* * The threading is initialized we can safely sleep a bit if GIP * needs some time to update itself updating. */ if ((fFlags & RTR3INIT_FLAGS_SUPLIB) && g_pSUPGlobalInfoPage) { RTThreadSleep(20); RTTimeNanoTS(); } #endif /* * Init the program start TSes. * Do that here to be sure that the GIP time was properly updated the 1st time. */ g_u64ProgramStartNanoTS = RTTimeNanoTS(); g_u64ProgramStartMicroTS = g_u64ProgramStartNanoTS / 1000; g_u64ProgramStartMilliTS = g_u64ProgramStartNanoTS / 1000000; /* * The remainder cannot easily be undone, so it has to go last. */ /* Fork and exit callbacks. */ #if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2) rc = pthread_atfork(NULL, NULL, rtR3ForkChildCallback); AssertMsg(rc == 0, ("%d\n", rc)); #endif atexit(rtR3ExitCallback); #ifdef IPRT_USE_SIG_CHILD_DUMMY /* * SIGCHLD must not be ignored (that's default), otherwise posix compliant waitpid * implementations won't work right. */ for (;;) { struct sigaction saOld; rc = sigaction(SIGCHLD, 0, &saOld); AssertMsg(rc == 0, ("%d/%d\n", rc, errno)); if ( rc != 0 || (saOld.sa_flags & SA_SIGINFO) || ( saOld.sa_handler != SIG_IGN && saOld.sa_handler != SIG_DFL) ) break; /* Try install dummy handler. */ struct sigaction saNew = saOld; saNew.sa_flags = SA_NOCLDSTOP | SA_RESTART; saNew.sa_handler = rtR3SigChildHandler; rc = sigemptyset(&saNew.sa_mask); AssertMsg(rc == 0, ("%d/%d\n", rc, errno)); struct sigaction saOld2; rc = sigaction(SIGCHLD, &saNew, &saOld2); AssertMsg(rc == 0, ("%d/%d\n", rc, errno)); if ( rc != 0 || ( saOld2.sa_handler == saOld.sa_handler && !(saOld2.sa_flags & SA_SIGINFO)) ) break; /* Race during dynamic load, restore and try again... */ sigaction(SIGCHLD, &saOld2, NULL); RTThreadYield(); } #endif /* IPRT_USE_SIG_CHILD_DUMMY */ #ifdef IPRT_WITH_ALIGNMENT_CHECKS /* * Enable alignment checks. */ const char *pszAlignmentChecks = getenv("IPRT_ALIGNMENT_CHECKS"); g_fRTAlignmentChecks = pszAlignmentChecks != NULL && pszAlignmentChecks[0] == '1' && pszAlignmentChecks[1] == '\0'; if (g_fRTAlignmentChecks) IPRT_ALIGNMENT_CHECKS_ENABLE(); #endif /* * Final native initialization. */ rc = rtR3InitNativeFinal(fFlags); AssertMsgRCReturn(rc, ("rtR3InitNativeFinal failed with %Rrc\n", rc), rc); return VINF_SUCCESS; }