Wolfgang Thallergcc16 merge934c3885 months agoHistory
725 lines · 22.3 KB · D
RawDownload
/** * Contains druntime startup and shutdown routines. * * Copyright: Copyright Digital Mars 2000 - 2018. * License: Distributed under the *      $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). *    (See accompanying file LICENSE) * Authors:   Walter Bright, Sean Kelly * Source: $(DRUNTIMESRC rt/_dmain2.d) */ module rt.dmain2; import core.atomic;import core.internal.parseoptions : rt_parseOption;import core.stdc.errno : errno;import core.stdc.stdio : fflush, fprintf, fwrite, stderr, stdout;import core.stdc.stdlib : alloca, EXIT_FAILURE, EXIT_SUCCESS, free, malloc, realloc;import core.stdc.string : strerror;import rt.config : rt_cmdline_enabled, rt_configOption;import rt.memory;import rt.sections; version (Windows){    import core.stdc.stdio : fileno;    import core.stdc.wchar_ : wcslen;    import core.sys.windows.basetsd : HANDLE;    import core.sys.windows.shellapi : CommandLineToArgvW;    import core.sys.windows.winbase : FreeLibrary, GetCommandLineW, GetProcAddress, IsDebuggerPresent, LoadLibraryW,        LocalFree, WriteFile;    import core.sys.windows.wincon : CONSOLE_SCREEN_BUFFER_INFO, GetConsoleOutputCP,        GetConsoleScreenBufferInfo;    import core.sys.windows.winnls : CP_UTF8, MultiByteToWideChar, WideCharToMultiByte;    import core.sys.windows.winnt : WCHAR;    import core.sys.windows.winuser : MB_ICONERROR, MessageBoxW;     pragma(lib, "shell32.lib"); // needed for CommandLineToArgvW     import core.stdc.stdio : _get_osfhandle;}else version (Posix){    import core.stdc.string : strlen;} version (DigitalMars) version (AArch64)    version = UseMalloc;   // cuz alloca() is not implemented yet // not sure why we can't define this in one place, but this is to keep this// module from importing core.runtime.struct UnitTestResult{    size_t executed;    size_t passed;    bool runMain;    bool summarize;} extern (C) void _d_monitor_staticctor() @nogc nothrow;extern (C) void _d_monitor_staticdtor() @nogc nothrow;extern (C) void _d_critical_init() @nogc nothrow;extern (C) void _d_critical_term() @nogc nothrow;extern (C) void gc_init();extern (C) void gc_term();extern (C) void thread_init() @nogc nothrow;extern (C) void thread_term() @nogc nothrow;extern (C) void rt_moduleCtor();extern (C) void rt_moduleTlsCtor();extern (C) void rt_moduleDtor();extern (C) void rt_moduleTlsDtor();extern (C) void thread_joinAll();extern (C) UnitTestResult runModuleUnitTests();extern (C) void _d_initMonoTime() @nogc nothrow; version (CRuntime_Microsoft){    extern(C) void init_msvc();} /* To get out-of-band access to the args[] passed to main(). */ __gshared string[] _d_args = null; extern (C) string[] rt_args(){    return _d_args;} // This variable is only ever set by a debugger on initialization so it should// be fine to leave it as __gshared.extern (C) __gshared bool rt_trapExceptions = true; alias ExceptionHandler = void delegate(Throwable); /** * Keep track of how often rt_init/rt_term were called. */private shared size_t _initCount; /********************************************** * Initialize druntime. * If a C program wishes to call D code, and there's no D main(), then it * must call rt_init() and rt_term(). */extern (C) int rt_init(){    /* @@BUG 11380 @@ Need to synchronize rt_init/rt_term calls for       version (Shared) druntime, because multiple C threads might       initialize different D libraries without knowing about the       shared druntime. Also we need to attach any thread that calls       rt_init. */    if (atomicOp!"+="(_initCount, 1) > 1) return 1;     version (CRuntime_Microsoft)        init_msvc();     _d_monitor_staticctor();    _d_critical_init();     try    {        initSections();        // this initializes mono time before anything else to allow usage        // in other druntime systems.        _d_initMonoTime();        thread_init();        // TODO: fixme - calls GC.addRange -> Initializes GC        initStaticDataGC();        rt_moduleCtor();        rt_moduleTlsCtor();        return 1;    }    catch (Throwable t)    {        atomicStore!(MemoryOrder.raw)(_initCount, 0);        _d_print_throwable(t);    }    _d_critical_term();    _d_monitor_staticdtor();    return 0;} /********************************************** * Terminate use of druntime. */extern (C) int rt_term(){    if (atomicLoad!(MemoryOrder.raw)(_initCount) == 0) return 0; // was never initialized    if (atomicOp!"-="(_initCount, 1)) return 1;     try    {        rt_moduleTlsDtor();        thread_joinAll();        rt_moduleDtor();        gc_term();        thread_term();        return 1;    }    catch (Throwable t)    {        _d_print_throwable(t);    }    finally    {        finiSections();        _d_critical_term();        _d_monitor_staticdtor();    }    return 0;} /** * Indicates whether druntime has been or is being initialized. */bool isRuntimeInitialized() @nogc nothrow {    return atomicLoad!(MemoryOrder.raw)(_initCount) != 0;} /********************************************** * Trace handler */alias TraceHandler = Throwable.TraceInfo function(void* ptr);private __gshared TraceHandler traceHandler = null;private __gshared Throwable.TraceDeallocator traceDeallocator = null;  /** * Overrides the default trace hander with a user-supplied version. * * Params: *  h = The new trace handler.  Set to null to use the default handler. *  d = The new dealloactor to use. */extern (C) void  rt_setTraceHandler(TraceHandler h, Throwable.TraceDeallocator d = null){    traceHandler = h;    traceDeallocator = d;} /** * Return the current trace handler */extern (C) TraceHandler rt_getTraceHandler(){    return traceHandler;} extern (C) Throwable.TraceDeallocator rt_getTraceDeallocator(){    return traceDeallocator;} /** * This function will be called when an exception is constructed.  The * user-supplied trace handler will be called if one has been supplied, * otherwise no trace will be generated. * * Params: *  ptr = A pointer to the location from which to generate the trace, or null *        if the trace should be generated from within the trace handler *        itself. * * Returns: *  An object describing the current calling context or null if no handler is *  supplied. */extern (C) Throwable.TraceInfo _d_traceContext(void* ptr = null){    if (traceHandler is null)        return null;    return traceHandler(ptr);} /*********************************** * Provide out-of-band access to the original C argc/argv * passed to this program via main(argc,argv). */ struct CArgs{    int argc;    char** argv;} __gshared CArgs _cArgs; extern (C) CArgs rt_cArgs() @nogc{    return _cArgs;} /// Type of the D main() function (`_Dmain`).private alias MainFunc = extern(C) int function(char[][] args); /** * Sets up the D char[][] command-line args, initializes druntime, * runs embedded unittests and then runs the given D main() function, * optionally catching and printing any unhandled exceptions. */extern (C) int _d_run_main(int argc, char** argv, MainFunc mainFunc){    // Set up _cArgs and array of D char[] slices, then forward to _d_run_main2     // Remember the original C argc/argv    _cArgs.argc = argc;    _cArgs.argv = argv;     version (Windows)    {        /* Because we want args[] to be UTF-8, and Windows doesn't guarantee that,         * we ignore argc/argv and go get the Windows command line again as UTF-16.         * Then, reparse into wargc/wargs, and then use Windows API to convert         * to UTF-8.         */        const wCommandLine = GetCommandLineW();        immutable size_t wCommandLineLength = wcslen(wCommandLine);        int wargc;        auto wargs = CommandLineToArgvW(wCommandLine, &wargc);        // assert(wargc == argc); /* argc can be broken by Unicode arguments */         // Allocate args[] on the stack - use wargc        version (UseMalloc)        {            char[][] args = (cast(char[]*) malloc(wargc * (char[]).sizeof))[0 .. wargc];            if (wargc)                assert(args.ptr);            scope (exit) free(args.ptr);        }        else            char[][] args = (cast(char[]*) alloca(wargc * (char[]).sizeof))[0 .. wargc];         // This is required because WideCharToMultiByte requires int as input.        assert(wCommandLineLength <= cast(size_t) int.max, "Wide char command line length must not exceed int.max");         immutable size_t totalArgsLength = WideCharToMultiByte(CP_UTF8, 0, wCommandLine, cast(int)wCommandLineLength, null, 0, null, null);        {            version (UseMalloc)            {                char* totalArgsBuff = cast(char*) malloc(totalArgsLength);                if (totalArgsLength)                    assert(totalArgsBuff);                scope (exit) free(totalArgsBuff);            }            else                char* totalArgsBuff = cast(char*) alloca(totalArgsLength);            size_t j = 0;            foreach (i; 0 .. wargc)            {                immutable size_t wlen = wcslen(wargs[i]);                assert(wlen <= cast(size_t) int.max, "wlen cannot exceed int.max");                immutable int len = WideCharToMultiByte(CP_UTF8, 0, &wargs[i][0], cast(int) wlen, null, 0, null, null);                args[i] = totalArgsBuff[j .. j + len];                if (len == 0)                    continue;                j += len;                assert(j <= totalArgsLength);                WideCharToMultiByte(CP_UTF8, 0, &wargs[i][0], cast(int) wlen, &args[i][0], len, null, null);            }        }        LocalFree(wargs);        wargs = null;        wargc = 0;    }    else version (Posix)    {        // Allocate args[] on the stack        version (UseMalloc)        {            char[][] args = (cast(char[]*) malloc(argc * (char[]).sizeof))[0 .. argc];            if (argc)                assert(args.ptr);            scope (exit) free(args.ptr);        }        else            char[][] args = (cast(char[]*) alloca(argc * (char[]).sizeof))[0 .. argc];         size_t totalArgsLength = 0;        foreach (i, ref arg; args)        {            arg = argv[i][0 .. strlen(argv[i])];            totalArgsLength += arg.length;        }    }    else        static assert(0);     return _d_run_main2(args, totalArgsLength, mainFunc);} /** * Windows-specific version for wide command-line arguments, e.g., * from a wmain/wWinMain C entry point. * This wide version uses the specified arguments, unlike narrow * _d_run_main which uses the actual (wide) process arguments instead. */version (Windows)extern (C) int _d_wrun_main(int argc, wchar** wargv, MainFunc mainFunc){     // Allocate args[] on the stack    char[][] args = (cast(char[]*) alloca(argc * (char[]).sizeof))[0 .. argc];     // 1st pass: compute each argument's length as UTF-16 and UTF-8    size_t totalArgsLength = 0;    foreach (i; 0 .. argc)    {        const warg = wargv[i];        const size_t wlen = wcslen(warg) + 1; // incl. terminating null        assert(wlen <= cast(size_t) int.max, "wlen cannot exceed int.max");        const int len = WideCharToMultiByte(CP_UTF8, 0, warg, cast(int) wlen, null, 0, null, null);        args[i] = (cast(char*) wlen)[0 .. len]; // args[i].ptr = wlen, args[i].length = len        totalArgsLength += len;    }     // Allocate a single buffer for all (null-terminated) argument strings in UTF-8 on the stack    char* utf8Buffer = cast(char*) alloca(totalArgsLength);     // 2nd pass: convert to UTF-8 and finalize `args`    char* utf8 = utf8Buffer;    foreach (i; 0 .. argc)    {        const wlen = cast(int) args[i].ptr;        const len = cast(int) args[i].length;        WideCharToMultiByte(CP_UTF8, 0, wargv[i], wlen, utf8, len, null, null);        args[i] = utf8[0 .. len-1]; // excl. terminating null        utf8 += len;    }     // Set C argc/argv; argv is a new stack-allocated array of UTF-8 C strings    char*[] argv = (cast(char**) alloca(argc * (char*).sizeof))[0 .. argc];    foreach (i, ref arg; argv)        arg = args[i].ptr;    _cArgs.argc = argc;    _cArgs.argv = argv.ptr;     totalArgsLength -= argc; // excl. null terminator per arg    return _d_run_main2(args, totalArgsLength, mainFunc);} private extern (C) int _d_run_main2(char[][] args, size_t totalArgsLength, MainFunc mainFunc){    int result;     version (FreeBSD) version (D_InlineAsm_X86)    {        /*         * FreeBSD/i386 sets the FPU precision mode to 53 bit double.         * Make it 64 bit extended.         */        ushort fpucw;        asm        {            fstsw   fpucw;            or      fpucw, 0b11_00_111111; // 11: use 64 bit extended-precision                                           // 111111: mask all FP exceptions            fldcw   fpucw;        }    }    version (CRuntime_Microsoft)    {        // enable full precision for reals        version (D_InlineAsm_X86_64)        {            asm            {                push    RAX;                fstcw   word ptr [RSP];                or      [RSP], 0b11_00_111111; // 11: use 64 bit extended-precision                                               // 111111: mask all FP exceptions                fldcw   word ptr [RSP];                pop     RAX;            }        }        else version (D_InlineAsm_X86)        {            asm            {                push    EAX;                fstcw   word ptr [ESP];                or      [ESP], 0b11_00_111111; // 11: use 64 bit extended-precision                // 111111: mask all FP exceptions                fldcw   word ptr [ESP];                pop     EAX;            }        }        else version (GNU_InlineAsm)        {            size_t fpu_cw;            asm { "fstcw %0" : "=m" (fpu_cw); }            fpu_cw |= 0b11_00_111111;  // 11: use 64 bit extended-precision                                       // 111111: mask all FP exceptions            asm { "fldcw %0" : "=m" (fpu_cw); }        }    }     /* Create a copy of args[] on the stack to be used for main, so that rt_args()     * cannot be modified by the user.     * Note that when this function returns, _d_args will refer to garbage.     */    {        _d_args = cast(string[]) args;         auto length = args.length * (char[]).sizeof + totalArgsLength;        version (UseMalloc)        {            auto buff = cast(char[]*) malloc(length);            if (length)                assert(buff);            //scope (exit) buff;        }        else            auto buff = cast(char[]*) alloca(length);         char[][] argsCopy = buff[0 .. args.length];        auto argBuff = cast(char*) (buff + args.length);        size_t j = 0;        bool parseOpts = rt_cmdline_enabled!();        foreach (arg; args)        {            // Do not pass Druntime options to the program            if (parseOpts && arg.length >= 6 && arg[0 .. 6] == "--DRT-")                continue;            // https://issues.dlang.org/show_bug.cgi?id=20459            if (arg == "--")                parseOpts = false;            argsCopy[j++] = (argBuff[0 .. arg.length] = arg[]);            argBuff += arg.length;        }        args = argsCopy[0..j];    }     auto useExceptionTrap = parseExceptionOptions();     version (Windows)    {        if (IsDebuggerPresent())            useExceptionTrap = false;    }

Lines 1–500 of 725.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t