VirtualBox

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

Last change on this file since 95818 was 95818, checked in by vboxsync, 2 years ago

IPRT: More IPRT_NO_CRT work on windows. bugref:10261

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 21.9 KB
Line 
1/* $Id: init.cpp 95818 2022-07-25 14:48:00Z vboxsync $ */
2/** @file
3 * IPRT - Init Ring-3.
4 */
5
6/*
7 * Copyright (C) 2006-2022 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 <iprt/win/windows.h>
36#else
37# include <unistd.h>
38# ifndef RT_OS_OS2
39# include <pthread.h>
40# include <signal.h>
41# include <errno.h>
42# define IPRT_USE_SIG_CHILD_DUMMY
43# endif
44#endif
45#ifdef RT_OS_OS2
46# include <InnoTekLIBC/fork.h>
47# define INCL_DOSMISC
48# include <os2.h>
49#endif
50#ifndef IPRT_NO_CRT
51# include <locale.h>
52#endif
53
54#include <iprt/initterm.h>
55#include <iprt/asm.h>
56#include <iprt/assert.h>
57#include <iprt/env.h>
58#include <iprt/errcore.h>
59#include <iprt/log.h>
60#include <iprt/mem.h>
61#include <iprt/path.h>
62#include <iprt/time.h>
63#include <iprt/string.h>
64#include <iprt/param.h>
65#ifdef RT_OS_WINDOWS
66# include <iprt/getopt.h>
67# include <iprt/utf16.h>
68#endif
69#if !defined(IN_GUEST) && !defined(RT_NO_GIP)
70# include <iprt/file.h>
71# include <VBox/sup.h>
72#endif
73#include <stdlib.h>
74
75#include "init.h"
76#include "internal/alignmentchecks.h"
77#include "internal/path.h"
78#include "internal/process.h"
79#include "internal/thread.h"
80#include "internal/time.h"
81
82
83/*********************************************************************************************************************************
84* Global Variables *
85*********************************************************************************************************************************/
86/** The number of calls to RTR3Init*. */
87static int32_t volatile g_cUsers = 0;
88/** Whether we're currently initializing the IPRT. */
89static bool volatile g_fInitializing = false;
90
91#if !defined(IPRT_NO_CRT) || !defined(RT_OS_WINDOWS)
92/** The process path.
93 * This is used by RTPathExecDir and RTProcGetExecutablePath and set by rtProcInitName. */
94DECL_HIDDEN_DATA(char) g_szrtProcExePath[RTPATH_MAX];
95/** The length of g_szrtProcExePath. */
96DECL_HIDDEN_DATA(size_t) g_cchrtProcExePath;
97/** The offset of the process name into g_szrtProcExePath. */
98DECL_HIDDEN_DATA(size_t) g_offrtProcName;
99#endif
100/** The length of directory path component of g_szrtProcExePath. */
101DECL_HIDDEN_DATA(size_t) g_cchrtProcDir;
102
103/** The IPRT init flags. */
104static uint32_t g_fInitFlags;
105
106/** The argument count of the program. */
107static int g_crtArgs = -1;
108/** The arguments of the program (UTF-8). This is "leaked". */
109static char ** g_papszrtArgs;
110/** The original argument vector of the program. */
111static char ** g_papszrtOrgArgs;
112
113/**
114 * Program start nanosecond TS.
115 */
116DECL_HIDDEN_DATA(uint64_t) g_u64ProgramStartNanoTS;
117
118/**
119 * The process identifier of the running process.
120 */
121DECL_HIDDEN_DATA(RTPROCESS) g_ProcessSelf = NIL_RTPROCESS;
122
123/**
124 * The current process priority.
125 */
126DECL_HIDDEN_DATA(RTPROCPRIORITY) g_enmProcessPriority = RTPROCPRIORITY_DEFAULT;
127
128/**
129 * Set if the atexit callback has been called, i.e. indicating
130 * that the process is terminating.
131 */
132DECL_HIDDEN_DATA(bool volatile) g_frtAtExitCalled = false;
133
134#ifdef IPRT_WITH_ALIGNMENT_CHECKS
135/**
136 * Whether alignment checks are enabled.
137 * This is set if the environment variable IPRT_ALIGNMENT_CHECKS is 1.
138 */
139RTDATADECL(bool) g_fRTAlignmentChecks = false;
140#endif
141
142
143#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) || defined(RT_OS_NETBSD) || defined(RT_OS_HAIKU) \
144 || defined(RT_OS_LINUX) || defined(RT_OS_OS2) || defined(RT_OS_SOLARIS) /** @todo add host init hooks everywhere. */
145/* Stubs */
146DECLHIDDEN(int) rtR3InitNativeFirst(uint32_t fFlags) { RT_NOREF_PV(fFlags); return VINF_SUCCESS; }
147DECLHIDDEN(int) rtR3InitNativeFinal(uint32_t fFlags) { RT_NOREF_PV(fFlags); return VINF_SUCCESS; }
148DECLHIDDEN(void) rtR3InitNativeObtrusive(uint32_t fFlags) { RT_NOREF_PV(fFlags); }
149#endif
150
151
152/**
153 * atexit callback.
154 *
155 * This makes sure any loggers are flushed and will later also work the
156 * termination callback chain.
157 */
158static void rtR3ExitCallback(void) RT_NOTHROW_DEF
159{
160 ASMAtomicWriteBool(&g_frtAtExitCalled, true);
161
162 if (g_cUsers > 0)
163 {
164 PRTLOGGER pLogger = RTLogGetDefaultInstance();
165 if (pLogger)
166 RTLogFlush(pLogger);
167
168 pLogger = RTLogRelGetDefaultInstance();
169 if (pLogger)
170 RTLogFlush(pLogger);
171 }
172}
173
174
175#ifndef RT_OS_WINDOWS
176/**
177 * Fork callback, child context.
178 */
179static void rtR3ForkChildCallback(void)
180{
181 g_ProcessSelf = getpid();
182}
183#endif /* RT_OS_WINDOWS */
184
185#ifdef RT_OS_OS2
186/** Fork completion callback for OS/2. Only called in the child. */
187static void rtR3ForkOs2ChildCompletionCallback(void *pvArg, int rc, __LIBC_FORKCTX enmCtx)
188{
189 Assert(enmCtx == __LIBC_FORK_CTX_CHILD); NOREF(enmCtx);
190 NOREF(pvArg);
191
192 if (!rc)
193 rtR3ForkChildCallback();
194}
195
196/** Low-level fork callback for OS/2. */
197int rtR3ForkOs2Child(__LIBC_PFORKHANDLE pForkHandle, __LIBC_FORKOP enmOperation)
198{
199 if (enmOperation == __LIBC_FORK_OP_EXEC_CHILD)
200 return pForkHandle->pfnCompletionCallback(pForkHandle, rtR3ForkOs2ChildCompletionCallback, NULL, __LIBC_FORK_CTX_CHILD);
201 return 0;
202}
203
204# define static static volatile /** @todo _FORK_CHILD1 causes unresolved externals in optimized builds. Fix macro. */
205_FORK_CHILD1(0, rtR3ForkOs2Child);
206# undef static
207#endif /* RT_OS_OS2 */
208
209
210
211/**
212 * Internal worker which initializes or re-initializes the
213 * program path, name and directory globals.
214 *
215 * @returns IPRT status code.
216 * @param pszProgramPath The program path, NULL if not specified.
217 */
218static int rtR3InitProgramPath(const char *pszProgramPath)
219{
220 /*
221 * We're reserving 32 bytes here for file names as what not.
222 */
223 if (!pszProgramPath)
224 {
225 int rc = rtProcInitExePath(g_szrtProcExePath, sizeof(g_szrtProcExePath) - 32);
226 if (RT_FAILURE(rc))
227 return rc;
228 }
229 else
230 {
231 size_t cch = strlen(pszProgramPath);
232 Assert(cch > 1);
233 AssertMsgReturn(cch < sizeof(g_szrtProcExePath) - 32, ("%zu\n", cch), VERR_BUFFER_OVERFLOW);
234 memcpy(g_szrtProcExePath, pszProgramPath, cch + 1);
235 }
236
237 /*
238 * Parse the name.
239 */
240 ssize_t offName;
241 g_cchrtProcExePath = RTPathParseSimple(g_szrtProcExePath, &g_cchrtProcDir, &offName, NULL);
242 g_offrtProcName = offName;
243 return VINF_SUCCESS;
244}
245
246
247#ifdef RT_OS_WINDOWS
248/**
249 * Checks the two argument vectors contains the same strings.
250 */
251DECLINLINE(bool) rtR3InitArgvEquals(int cArgs, char **papszArgs1, char **papszArgs2)
252{
253 if (papszArgs1 != papszArgs2)
254 while (cArgs-- > 0)
255 if (strcmp(papszArgs1[cArgs], papszArgs2[cArgs]) != 0)
256 return false;
257 return true;
258}
259#endif
260
261
262/**
263 * Internal worker which initializes or re-initializes the
264 * program path, name and directory globals.
265 *
266 * @returns IPRT status code.
267 * @param fFlags Flags, see RTR3INIT_XXX.
268 * @param cArgs Pointer to the argument count.
269 * @param ppapszArgs Pointer to the argument vector pointer. NULL
270 * allowed if @a cArgs is 0.
271 */
272static int rtR3InitArgv(uint32_t fFlags, int cArgs, char ***ppapszArgs)
273{
274 NOREF(fFlags);
275 if (cArgs)
276 {
277 AssertPtr(ppapszArgs);
278 AssertPtr(*ppapszArgs);
279 char **papszOrgArgs = *ppapszArgs;
280
281 /*
282 * Normally we should only be asked to convert arguments once. If we
283 * are though, it should be the already convered arguments.
284 */
285 if (g_crtArgs != -1)
286 {
287 AssertReturn( g_crtArgs == cArgs
288 && g_papszrtArgs == papszOrgArgs,
289 VERR_WRONG_ORDER); /* only init once! */
290 return VINF_SUCCESS;
291 }
292
293#if !defined(IPRT_NO_CRT) || !defined(RT_OS_WINDOWS)
294 if (!(fFlags & RTR3INIT_FLAGS_UTF8_ARGV))
295 {
296 /*
297 * Convert the arguments.
298 */
299 char **papszArgs;
300
301# ifdef RT_OS_WINDOWS
302 /* HACK ALERT! Try convert from unicode versions if possible.
303 Unfortunately for us, __wargv is only initialized if we have a unicode
304 main function. So, use getoptarv.cpp code to do the conversions and
305 hope it gives us the same result. (CommandLineToArgvW was not in NT 3.1.) */
306 if ( cArgs == __argc
307 && rtR3InitArgvEquals(cArgs, papszOrgArgs, __argv))
308 {
309 char *pszCmdLine = NULL;
310 int rc = RTUtf16ToUtf8Tag(GetCommandLineW(), &pszCmdLine, "will-leak:rtR3InitArgv");
311 AssertRCReturn(rc, rc);
312
313 int cArgsFromCmdLine = -1;
314 rc = RTGetOptArgvFromString(&papszArgs, &cArgsFromCmdLine, pszCmdLine,
315 RTGETOPTARGV_CNV_QUOTE_MS_CRT | RTGETOPTARGV_CNV_MODIFY_INPUT, NULL);
316 AssertMsgRCReturn(rc, ("pszCmdLine='%s' rc=%Rrc\n", pszCmdLine, rc), rc);
317 AssertMsg(cArgsFromCmdLine == cArgs,
318 ("cArgsFromCmdLine=%d cArgs=%d pszCmdLine='%s' rc=%Rrc\n", cArgsFromCmdLine, cArgs, pszCmdLine));
319 }
320 else
321# endif
322 {
323 papszArgs = (char **)RTMemAllocZTag((cArgs + 1) * sizeof(char *), "will-leak:rtR3InitArgv");
324 if (!papszArgs)
325 return VERR_NO_MEMORY;
326
327 for (int i = 0; i < cArgs; i++)
328 {
329 int rc = RTStrCurrentCPToUtf8(&papszArgs[i], papszOrgArgs[i]);
330 if (RT_FAILURE(rc))
331 {
332 while (i--)
333 RTStrFree(papszArgs[i]);
334 RTMemFree(papszArgs);
335 return rc;
336 }
337 }
338 }
339
340 papszArgs[cArgs] = NULL;
341
342 g_papszrtOrgArgs = papszOrgArgs;
343 g_papszrtArgs = papszArgs;
344 g_crtArgs = cArgs;
345
346 *ppapszArgs = papszArgs;
347 }
348 else
349#endif /* !IPRT_NO_CRT || !RT_OS_WINDOWS */
350 {
351 /*
352 * The arguments are already UTF-8, no conversion needed.
353 */
354 g_papszrtOrgArgs = papszOrgArgs;
355 g_papszrtArgs = papszOrgArgs;
356 g_crtArgs = cArgs;
357 }
358 }
359
360 return VINF_SUCCESS;
361}
362
363
364#ifdef IPRT_USE_SIG_CHILD_DUMMY
365/**
366 * Dummy SIGCHILD handler.
367 *
368 * Assigned on rtR3Init only when SIGCHILD handler is set SIGIGN or SIGDEF to
369 * ensure waitpid works properly for the terminated processes.
370 */
371static void rtR3SigChildHandler(int iSignal)
372{
373 NOREF(iSignal);
374}
375#endif /* IPRT_USE_SIG_CHILD_DUMMY */
376
377
378/**
379 * rtR3Init worker.
380 */
381static int rtR3InitBody(uint32_t fFlags, int cArgs, char ***ppapszArgs, const char *pszProgramPath)
382{
383 /*
384 * Early native initialization.
385 */
386 int rc = rtR3InitNativeFirst(fFlags);
387 AssertMsgRCReturn(rc, ("rtR3InitNativeFirst failed with %Rrc\n", rc), rc);
388
389 /*
390 * Disable error popups.
391 */
392#if defined(RT_OS_OS2) /** @todo move to private code. */
393 DosError(FERR_DISABLEHARDERR);
394#endif
395
396#ifndef IPRT_NO_CRT
397 /*
398 * Init C runtime locale before we do anything that may end up converting
399 * paths or we'll end up using the "C" locale for path conversion.
400 */
401 setlocale(LC_CTYPE, "");
402#endif
403
404 /*
405 * The Process ID.
406 */
407#ifdef _MSC_VER
408 g_ProcessSelf = GetCurrentProcessId(); /* since NT 3.1, not 3.51+ as listed on geoffchappell.com */
409#else
410 g_ProcessSelf = getpid();
411#endif
412
413 /*
414 * Save the init flags.
415 */
416 g_fInitFlags |= fFlags;
417
418#if !defined(IN_GUEST) && !defined(RT_NO_GIP)
419# ifdef VBOX
420 /*
421 * This MUST be done as the very first thing, before any file is opened.
422 * The log is opened on demand, but the first log entries may be caused
423 * by rtThreadInit() below.
424 */
425 const char *pszDisableHostCache = getenv("VBOX_DISABLE_HOST_DISK_CACHE");
426 if ( pszDisableHostCache != NULL
427 && *pszDisableHostCache
428 && strcmp(pszDisableHostCache, "0") != 0)
429 {
430 RTFileSetForceFlags(RTFILE_O_WRITE, RTFILE_O_WRITE_THROUGH, 0);
431 RTFileSetForceFlags(RTFILE_O_READWRITE, RTFILE_O_WRITE_THROUGH, 0);
432 }
433# endif /* VBOX */
434#endif /* !IN_GUEST && !RT_NO_GIP */
435
436 /*
437 * Thread Thread database and adopt the caller thread as 'main'.
438 * This must be done before everything else or else we'll call into threading
439 * without having initialized TLS entries and suchlike.
440 */
441 rc = rtThreadInit();
442 AssertMsgRCReturn(rc, ("Failed to initialize threads, rc=%Rrc!\n", rc), rc);
443
444 /*
445 * The executable path before SUPLib (windows requirement).
446 */
447 rc = rtR3InitProgramPath(pszProgramPath);
448 AssertLogRelMsgRCReturn(rc, ("Failed to get executable directory path, rc=%Rrc!\n", rc), rc);
449
450#if !defined(IN_GUEST) && !defined(RT_NO_GIP)
451 /*
452 * Initialize SUPLib here so the GIP can get going as early as possible
453 * (improves accuracy for the first client).
454 */
455 if (fFlags & (RTR3INIT_FLAGS_SUPLIB | RTR3INIT_FLAGS_TRY_SUPLIB))
456 {
457 if (!(fFlags & ((SUPR3INIT_F_UNRESTRICTED | SUPR3INIT_F_LIMITED) << RTR3INIT_FLAGS_SUPLIB_SHIFT)))
458 g_fInitFlags |= fFlags |= SUPR3INIT_F_UNRESTRICTED << RTR3INIT_FLAGS_SUPLIB_SHIFT;
459 rc = SUPR3InitEx(fFlags >> RTR3INIT_FLAGS_SUPLIB_SHIFT, NULL /*ppSession*/);
460 AssertMsgReturn(RT_SUCCESS(rc) || (fFlags & RTR3INIT_FLAGS_TRY_SUPLIB),
461 ("Failed to initialize the support library, rc=%Rrc!\n", rc), rc);
462 }
463#endif
464
465 /*
466 * Convert arguments.
467 */
468 rc = rtR3InitArgv(fFlags, cArgs, ppapszArgs);
469 AssertLogRelMsgRCReturn(rc, ("Failed to convert the arguments, rc=%Rrc!\n", rc), rc);
470
471#if !defined(IN_GUEST) && !defined(RT_NO_GIP)
472 /*
473 * The threading is initialized, so we can safely sleep a bit if GIP
474 * needs some time to start updating itself. Currently limited to
475 * the first mapping of GIP (u32TransactionId <= 4), quite possible we
476 * could just ditch this now.
477 */
478 /** @todo consider dropping this... */
479 PSUPGLOBALINFOPAGE pGip;
480 if ( (fFlags & (RTR3INIT_FLAGS_SUPLIB | RTR3INIT_FLAGS_TRY_SUPLIB))
481 && (pGip = g_pSUPGlobalInfoPage) != NULL
482 && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC)
483 {
484 PSUPGIPCPU pGipCpu = SUPGetGipCpuPtr(pGip);
485 if ( pGipCpu
486 && pGipCpu->u32TransactionId <= 4)
487 {
488 RTThreadSleep(pGip->u32UpdateIntervalNS / RT_NS_1MS + 2);
489 RTTimeNanoTS();
490 }
491 }
492#endif
493
494 /*
495 * Init the program start timestamp TS.
496 * Do that here to be sure that the GIP time was properly updated the 1st time.
497 */
498 g_u64ProgramStartNanoTS = RTTimeNanoTS();
499
500 /*
501 * The remainder cannot easily be undone, so it has to go last.
502 */
503
504 /* Fork and exit callbacks. */
505#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
506 rc = pthread_atfork(NULL, NULL, rtR3ForkChildCallback);
507 AssertMsg(rc == 0, ("%d\n", rc));
508#endif
509 atexit(rtR3ExitCallback);
510
511#ifdef IPRT_USE_SIG_CHILD_DUMMY
512 /*
513 * SIGCHLD must not be ignored (that's default), otherwise posix compliant waitpid
514 * implementations won't work right.
515 */
516 for (;;)
517 {
518 struct sigaction saOld;
519 rc = sigaction(SIGCHLD, 0, &saOld); AssertMsg(rc == 0, ("%d/%d\n", rc, errno));
520 if ( rc != 0
521 || (saOld.sa_flags & SA_SIGINFO)
522 || ( saOld.sa_handler != SIG_IGN
523 && saOld.sa_handler != SIG_DFL)
524 )
525 break;
526
527 /* Try install dummy handler. */
528 struct sigaction saNew = saOld;
529 saNew.sa_flags = SA_NOCLDSTOP | SA_RESTART;
530 saNew.sa_handler = rtR3SigChildHandler;
531 rc = sigemptyset(&saNew.sa_mask); AssertMsg(rc == 0, ("%d/%d\n", rc, errno));
532 struct sigaction saOld2;
533 rc = sigaction(SIGCHLD, &saNew, &saOld2); AssertMsg(rc == 0, ("%d/%d\n", rc, errno));
534 if ( rc != 0
535 || ( saOld2.sa_handler == saOld.sa_handler
536 && !(saOld2.sa_flags & SA_SIGINFO))
537 )
538 break;
539
540 /* Race during dynamic load, restore and try again... */
541 sigaction(SIGCHLD, &saOld2, NULL);
542 RTThreadYield();
543 }
544#endif /* IPRT_USE_SIG_CHILD_DUMMY */
545
546#ifdef IPRT_WITH_ALIGNMENT_CHECKS
547 /*
548 * Enable alignment checks.
549 */
550 const char *pszAlignmentChecks = RTEnvGet("IPRT_ALIGNMENT_CHECKS"); /** @todo add RTEnvGetBool */
551 g_fRTAlignmentChecks = pszAlignmentChecks != NULL
552 && pszAlignmentChecks[0] == '1'
553 && pszAlignmentChecks[1] == '\0';
554 if (g_fRTAlignmentChecks)
555 IPRT_ALIGNMENT_CHECKS_ENABLE();
556#endif
557
558 /*
559 * Final native initialization.
560 */
561 rc = rtR3InitNativeFinal(fFlags);
562 AssertMsgRCReturn(rc, ("rtR3InitNativeFinal failed with %Rrc\n", rc), rc);
563
564 return VINF_SUCCESS;
565}
566
567
568/**
569 * Internal initialization worker.
570 *
571 * @returns IPRT status code.
572 * @param fFlags Flags, see RTR3INIT_XXX.
573 * @param cArgs Pointer to the argument count.
574 * @param ppapszArgs Pointer to the argument vector pointer. NULL
575 * allowed if @a cArgs is 0.
576 * @param pszProgramPath The program path. Pass NULL if we're to figure it
577 * out ourselves.
578 */
579static int rtR3Init(uint32_t fFlags, int cArgs, char ***ppapszArgs, const char *pszProgramPath)
580{
581 /* no entry log flow, because prefixes and thread may freak out. */
582 Assert(!(fFlags & ~RTR3INIT_FLAGS_VALID_MASK));
583 Assert(!(fFlags & RTR3INIT_FLAGS_DLL) || cArgs == 0);
584
585 /*
586 * Do reference counting, only initialize the first time around.
587 *
588 * We are ASSUMING that nobody will be able to race RTR3Init* calls when the
589 * first one, the real init, is running (second assertion).
590 */
591 int32_t cUsers = ASMAtomicIncS32(&g_cUsers);
592 if (cUsers != 1)
593 {
594 AssertMsg(cUsers > 1, ("%d\n", cUsers));
595 Assert(!g_fInitializing);
596
597#if !defined(IN_GUEST) && !defined(RT_NO_GIP)
598 /* Initialize the support library if requested. We've always ignored the
599 status code here for some reason, making the two flags same. */
600 if (fFlags & (RTR3INIT_FLAGS_SUPLIB | RTR3INIT_FLAGS_TRY_SUPLIB))
601 {
602 if (!(fFlags & ((SUPR3INIT_F_UNRESTRICTED | SUPR3INIT_F_LIMITED) << RTR3INIT_FLAGS_SUPLIB_SHIFT)))
603 fFlags |= SUPR3INIT_F_UNRESTRICTED << RTR3INIT_FLAGS_SUPLIB_SHIFT;
604 SUPR3InitEx(fFlags >> RTR3INIT_FLAGS_SUPLIB_SHIFT, NULL /*ppSession*/);
605 g_fInitFlags |= fFlags & (RTR3INIT_FLAGS_SUPLIB | RTR3INIT_FLAGS_TRY_SUPLIB | RTR3INIT_FLAGS_SUPLIB_MASK);
606 }
607#endif
608 g_fInitFlags |= fFlags & RTR3INIT_FLAGS_UTF8_ARGV;
609
610 if ( !(fFlags & RTR3INIT_FLAGS_UNOBTRUSIVE)
611 && (g_fInitFlags & RTR3INIT_FLAGS_UNOBTRUSIVE))
612 {
613 g_fInitFlags &= ~RTR3INIT_FLAGS_UNOBTRUSIVE;
614 g_fInitFlags |= fFlags & RTR3INIT_FLAGS_STANDALONE_APP;
615 rtR3InitNativeObtrusive(g_fInitFlags | fFlags);
616 rtThreadReInitObtrusive();
617 }
618 else
619 Assert(!(fFlags & RTR3INIT_FLAGS_STANDALONE_APP) || (g_fInitFlags & RTR3INIT_FLAGS_STANDALONE_APP));
620
621 int rc = VINF_SUCCESS;
622 if (pszProgramPath)
623 rc = rtR3InitProgramPath(pszProgramPath);
624 if (RT_SUCCESS(rc))
625 rc = rtR3InitArgv(fFlags, cArgs, ppapszArgs);
626 return rc;
627 }
628
629 /*
630 * Do the initialization.
631 */
632 ASMAtomicWriteBool(&g_fInitializing, true);
633 int rc = rtR3InitBody(fFlags, cArgs, ppapszArgs, pszProgramPath);
634 ASMAtomicWriteBool(&g_fInitializing, false);
635 if (RT_FAILURE(rc))
636 {
637 /* failure */
638 ASMAtomicDecS32(&g_cUsers);
639 return rc;
640 }
641
642 /* success */
643 LogFlow(("rtR3Init: returns VINF_SUCCESS\n"));
644 return VINF_SUCCESS;
645}
646
647
648RTR3DECL(int) RTR3InitExe(int cArgs, char ***ppapszArgs, uint32_t fFlags)
649{
650 Assert(!(fFlags & RTR3INIT_FLAGS_DLL));
651 return rtR3Init(fFlags, cArgs, ppapszArgs, NULL);
652}
653
654
655RTR3DECL(int) RTR3InitExeNoArguments(uint32_t fFlags)
656{
657 Assert(!(fFlags & RTR3INIT_FLAGS_DLL));
658 return rtR3Init(fFlags, 0, NULL, NULL);
659}
660
661
662RTR3DECL(int) RTR3InitDll(uint32_t fFlags)
663{
664 Assert(!(fFlags & RTR3INIT_FLAGS_DLL));
665 return rtR3Init(fFlags | RTR3INIT_FLAGS_DLL, 0, NULL, NULL);
666}
667
668
669RTR3DECL(int) RTR3InitEx(uint32_t iVersion, uint32_t fFlags, int cArgs, char ***ppapszArgs, const char *pszProgramPath)
670{
671 AssertReturn(iVersion == RTR3INIT_VER_CUR, VERR_NOT_SUPPORTED);
672 return rtR3Init(fFlags, cArgs, ppapszArgs, pszProgramPath);
673}
674
675
676RTR3DECL(bool) RTR3InitIsInitialized(void)
677{
678 return g_cUsers >= 1 && !g_fInitializing;
679}
680
681
682RTR3DECL(bool) RTR3InitIsUnobtrusive(void)
683{
684 return RT_BOOL(g_fInitFlags & RTR3INIT_FLAGS_UNOBTRUSIVE);
685}
686
687
688#if 0 /** @todo implement RTR3Term. */
689RTR3DECL(void) RTR3Term(void)
690{
691}
692#endif
693
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