Wolfgang Thallergcc16 merge934c3885 months agoHistory
3139 lines · 99.7 KB · D
RawDownload
/** * The osthread module provides low-level, OS-dependent code * for thread creation and management. * * Copyright: Copyright Sean Kelly 2005 - 2012. * License: Distributed under the *      $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). *    (See accompanying file LICENSE) * Authors:   Sean Kelly, Walter Bright, Alex Rønne Petersen, Martin Nowak * Source:    $(DRUNTIMESRC core/thread/osthread.d) */ module core.thread.osthread; import core.atomic;import core.exception : onOutOfMemoryError;import core.internal.traits : externDFunc;import core.memory : GC, pageSize;import core.thread.context;import core.thread.threadbase;import core.thread.types;import core.time; ///////////////////////////////////////////////////////////////////////////////// Platform Detection and Memory Allocation/////////////////////////////////////////////////////////////////////////////// version (OSX)    version = Darwin;else version (iOS)    version = Darwin;else version (TVOS)    version = Darwin;else version (WatchOS)    version = Darwin; version (D_InlineAsm_X86){    version (Windows)        version = AsmX86_Windows;    else version (Posix)        version = AsmX86_Posix;}else version (D_InlineAsm_X86_64){    version (Windows)    {        version = AsmX86_64_Windows;    }    else version (Posix)    {        version = AsmX86_64_Posix;    }} version (Windows){    import core.stdc.stdint : uintptr_t; // for _beginthreadex decl below    import core.stdc.stdlib : free, malloc, realloc;    import core.sys.windows.basetsd /+: HANDLE+/;    import core.sys.windows.threadaux /+: getThreadStackBottom, impersonate_thread, OpenThreadHandle+/;    import core.sys.windows.winbase /+: CloseHandle, CREATE_SUSPENDED, DuplicateHandle, GetCurrentThread,        GetCurrentThreadId, GetCurrentProcess, GetExitCodeThread, GetSystemInfo, GetThreadContext,        GetThreadPriority, INFINITE, ResumeThread, SetThreadPriority, Sleep,  STILL_ACTIVE,        SuspendThread, SwitchToThread, SYSTEM_INFO, THREAD_PRIORITY_IDLE, THREAD_PRIORITY_NORMAL,        THREAD_PRIORITY_TIME_CRITICAL, WAIT_OBJECT_0, WaitForSingleObject+/;    import core.sys.windows.windef /+: TRUE+/;    import core.sys.windows.winnt /+: CONTEXT, CONTEXT_CONTROL, CONTEXT_INTEGER+/;     private extern (Windows) alias btex_fptr = uint function(void*);    private extern (C) uintptr_t _beginthreadex(void*, uint, btex_fptr, void*, uint, uint*) nothrow @nogc;}else version (Posix){    static import core.sys.posix.pthread;    static import core.sys.posix.signal;    import core.stdc.errno : EINTR, errno;    import core.sys.posix.pthread : pthread_atfork, pthread_attr_destroy, pthread_attr_getstack, pthread_attr_init,        pthread_attr_setstacksize, pthread_create, pthread_detach, pthread_getschedparam, pthread_join, pthread_self,        pthread_setschedparam, sched_get_priority_max, sched_get_priority_min, sched_param, sched_yield;    import core.sys.posix.semaphore : sem_init, sem_post, sem_t, sem_wait;    import core.sys.posix.signal : pthread_kill, sigaction, sigaction_t, sigdelset, sigfillset, sigset_t, sigsuspend,        SIGUSR1, stack_t;    import core.sys.posix.stdlib : free, malloc, realloc;    import core.sys.posix.sys.types : pthread_attr_t, pthread_key_t, pthread_t;    import core.sys.posix.time : nanosleep, timespec;     version (Darwin)    {        // Use macOS threads for suspend/resume        import core.sys.darwin.mach.kern_return : KERN_SUCCESS;        import core.sys.darwin.mach.port : mach_port_t;        import core.sys.darwin.mach.thread_act : mach_msg_type_number_t,            thread_get_state, thread_resume, thread_suspend;        import core.sys.darwin.pthread : pthread_mach_thread_np;        version (X86)        {            import core.sys.darwin.mach.thread_act :             x86_THREAD_STATE32, x86_THREAD_STATE32_COUNT, x86_thread_state32_t;        }        else version (X86_64)        {            import core.sys.darwin.mach.thread_act :             x86_THREAD_STATE64, x86_THREAD_STATE64_COUNT, x86_thread_state64_t;        }        else version (AArch64)        {            import core.sys.darwin.mach.thread_act :             ARM_THREAD_STATE64, ARM_THREAD_STATE64_COUNT, arm_thread_state64_t;        }        else version (PPC)        {            import core.sys.darwin.mach.thread_act :             PPC_THREAD_STATE, PPC_THREAD_STATE_COUNT, ppc_thread_state_t;        }        else version (PPC64)        {            import core.sys.darwin.mach.thread_act :             PPC_THREAD_STATE64, PPC_THREAD_STATE64_COUNT, ppc_thread_state64_t;        }    }    else version (Solaris)    {        // Use Solaris threads for suspend/resume        import core.sys.posix.sys.wait : idtype_t;        import core.sys.solaris.sys.priocntl : PC_CLNULL, PC_GETCLINFO, PC_GETPARMS, PC_SETPARMS, pcinfo_t, pcparms_t, priocntl;        import core.sys.solaris.sys.types : P_MYID, pri_t;        import core.sys.solaris.thread : thr_stksegment, thr_suspend, thr_continue;        import core.sys.solaris.sys.procfs : PR_STOPPED, lwpstatus_t;    }    else    {        // Use POSIX threads for suspend/resume    }} version (GNU){    import gcc.builtins;} /** * Hook for whatever EH implementation is used to save/restore some data * per stack. * * Params: *     newContext = The return value of the prior call to this function *         where the stack was last swapped out, or null when a fiber stack *         is switched in for the first time. */private extern(C) void* _d_eh_swapContext(void* newContext) nothrow @nogc; version (DigitalMars){    version (Windows)    {        extern(D) void* swapContext(void* newContext) nothrow @nogc        {            return _d_eh_swapContext(newContext);        }    }    else    {        extern(C) void* _d_eh_swapContextDwarf(void* newContext) nothrow @nogc;         extern(D) void* swapContext(void* newContext) nothrow @nogc        {            /* Detect at runtime which scheme is being used.             * Eventually, determine it statically.             */            static int which = 0;            final switch (which)            {                case 0:                {                    assert(newContext == null);                    auto p = _d_eh_swapContext(newContext);                    auto pdwarf = _d_eh_swapContextDwarf(newContext);                    if (p)                    {                        which = 1;                        return p;                    }                    else if (pdwarf)                    {                        which = 2;                        return pdwarf;                    }                    return null;                }                case 1:                    return _d_eh_swapContext(newContext);                case 2:                    return _d_eh_swapContextDwarf(newContext);            }        }    }}else{    extern(D) void* swapContext(void* newContext) nothrow @nogc    {        return _d_eh_swapContext(newContext);    }} ///////////////////////////////////////////////////////////////////////////////// Thread/////////////////////////////////////////////////////////////////////////////// /** * This class encapsulates all threading functionality for the D * programming language.  As thread manipulation is a required facility * for garbage collection, all user threads should derive from this * class, and instances of this class should never be explicitly deleted. * A new thread may be created using either derivation or composition, as * in the following example. */class Thread : ThreadBase{    //    // Standard thread data    //    version (Windows)    {        private HANDLE          m_hndl;    }     version (Posix)    {        private shared bool     m_isRunning;    }     version (Darwin)    {        private mach_port_t     m_tmach;    }     version (Solaris)    {        private __gshared bool m_isRTClass;    }     //    // Standard types    //    version (Windows)    {        alias TLSKey = uint;    }    else version (Posix)    {        alias TLSKey = pthread_key_t;    }     ///////////////////////////////////////////////////////////////////////////    // Initialization    ///////////////////////////////////////////////////////////////////////////      /**     * Initializes a thread object which is associated with a static     * D function.     *     * Params:     *  fn = The thread function.     *  sz = The stack size for this thread.     *     * In:     *  fn must not be null.     */    this( void function() fn, size_t sz = 0 ) @safe pure nothrow @nogc    {        super(fn, sz);    }      /**     * Initializes a thread object which is associated with a dynamic     * D function.     *     * Params:     *  dg = The thread function.     *  sz = The stack size for this thread.     *     * In:     *  dg must not be null.     */    this( void delegate() dg, size_t sz = 0 ) @safe pure nothrow @nogc    {        super(dg, sz);    }     package this( size_t sz = 0 ) @safe pure nothrow @nogc    {        super(sz);    }     /**     * Cleans up any remaining resources used by this object.     */    ~this() nothrow @nogc    {        if (super.destructBeforeDtor())            return;         version (Windows)        {            m_addr = m_addr.init;            CloseHandle( m_hndl );            m_hndl = m_hndl.init;        }        else version (Posix)        {            if (m_addr != m_addr.init)                pthread_detach( m_addr );            m_addr = m_addr.init;        }        version (Darwin)        {            m_tmach = m_tmach.init;        }    }     //    // Thread entry point.  Invokes the function or delegate passed on    // construction (if any).    //    private final void run()    {        super.run();    }     /**     * Provides a reference to the calling thread.     *     * Returns:     *  The thread object representing the calling thread.  The result of     *  deleting this object is undefined.  If the current thread is not     *  attached to the runtime, a null reference is returned.     */    static Thread getThis() @safe nothrow @nogc    {        return ThreadBase.getThis().toThread;    }     ///////////////////////////////////////////////////////////////////////////    // Thread Context and GC Scanning Support    ///////////////////////////////////////////////////////////////////////////      version (Windows)    {        version (X86)        {            uint[8]         m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax        }        else version (X86_64)        {            ulong[16]       m_reg; // rdi,rsi,rbp,rsp,rbx,rdx,rcx,rax                                   // r8,r9,r10,r11,r12,r13,r14,r15        }        else        {            static assert(false, "Architecture not supported." );        }    }    else version (Darwin)    {        version (X86)        {            uint[8]         m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax        }        else version (X86_64)        {            ulong[16]       m_reg; // rdi,rsi,rbp,rsp,rbx,rdx,rcx,rax                                   // r8,r9,r10,r11,r12,r13,r14,r15        }        else version (AArch64)        {            ulong[33]       m_reg; // x0-x31, pc        }        else version (ARM)        {            uint[16]        m_reg; // r0-r15        }        else version (PPC)        {            // Make the assumption that we only care about non-fp and non-vr regs.            // ??? : it seems plausible that a valid address can be copied into a VR.            uint[32]        m_reg; // r0-31        }        else version (PPC64)        {            // As above.            ulong[32]       m_reg; // r0-31        }        else        {            static assert(false, "Architecture not supported." );        }    }    else version (Solaris)    {        version (X86)        {            uint[8]         m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax        }        else version (X86_64)        {            ulong[16]       m_reg; // rdi,rsi,rbp,rsp,rbx,rdx,rcx,rax                                   // r8,r9,r10,r11,r12,r13,r14,r15        }        else version (SPARC)        {            int[33]         m_reg; // g0-7, o0-7, l0-7, i0-7, pc        }        else version (SPARC64)        {            long[33]        m_reg; // g0-7, o0-7, l0-7, i0-7, pc        }        else        {            static assert(false, "Architecture not supported." );        }    }     override final void[] savedRegisters() nothrow @nogc    {        version (Windows)        {            return m_reg;        }        else version (Darwin)        {            return m_reg;        }        else version (Solaris)        {            return m_reg;        }        else        {            return null;        }    }     ///////////////////////////////////////////////////////////////////////////    // General Actions    ///////////////////////////////////////////////////////////////////////////      /**     * Starts the thread and invokes the function or delegate passed upon     * construction.     *     * In:     *  This routine may only be called once per thread instance.     *     * Throws:     *  ThreadException if the thread fails to start.     */    final Thread start() nothrow    in    {        assert( !next && !prev );    }    do    {        auto wasThreaded  = multiThreadedFlag;        multiThreadedFlag = true;        scope( failure )        {            if ( !wasThreaded )                multiThreadedFlag = false;        }         version (Windows) {} else        version (Posix)        {            size_t stksz = adjustStackSize( m_sz );             pthread_attr_t  attr;             if ( pthread_attr_init( &attr ) )                onThreadError( "Error initializing thread attributes" );            if ( stksz && pthread_attr_setstacksize( &attr, stksz ) )                onThreadError( "Error initializing thread stack size" );        }         version (Windows)        {            // NOTE: If a thread is just executing DllMain()            //       while another thread is started here, it holds an OS internal            //       lock that serializes DllMain with CreateThread. As the code            //       might request a synchronization on slock (e.g. in thread_findByAddr()),            //       we cannot hold that lock while creating the thread without            //       creating a deadlock            //            // Solution: Create the thread in suspended state and then

Lines 1–500 of 3139.

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