Wolfgang Thallergcc16 merge934c3885 months agoHistory
1335 lines · 38.5 KB · D
RawDownload
/** * The threadbase module provides OS-independent code * for thread storage 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/threadbase.d) */ /* NOTE: This file has been patched from the original DMD distribution to * work with the GDC compiler. */module core.thread.threadbase; import core.thread.context;import core.thread.types;import core.time;import core.sync.mutex;import core.stdc.stdlib : free, realloc; private{    import core.internal.traits : externDFunc;     // interface to rt.tlsgc    alias rt_tlsgc_init = externDFunc!("rt.tlsgc.init", void* function() nothrow @nogc);    alias rt_tlsgc_destroy = externDFunc!("rt.tlsgc.destroy", void function(void*) nothrow @nogc);     alias ScanDg = void delegate(void* pstart, void* pend) nothrow;    alias rt_tlsgc_scan =        externDFunc!("rt.tlsgc.scan", void function(void*, scope ScanDg) nothrow);}  ///////////////////////////////////////////////////////////////////////////////// Thread and Fiber Exceptions///////////////////////////////////////////////////////////////////////////////  /** * Base class for thread exceptions. */class ThreadException : Exception{    @nogc @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null)    {        super(msg, file, line, next);    }     @nogc @safe pure nothrow this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__)    {        super(msg, file, line, next);    }}  /*** Base class for thread errors to be used for function inside GC when allocations are unavailable.*/class ThreadError : Error{    @nogc @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null)    {        super(msg, file, line, next);    }     @nogc @safe pure nothrow this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__)    {        super(msg, file, line, next);    }} private{    // Handling unaligned mutexes are not supported on all platforms, so we must    // ensure that the address of all shared data are appropriately aligned.    enum mutexAlign = __traits(classInstanceAlignment, Mutex);    enum mutexClassInstanceSize = __traits(classInstanceSize, Mutex);     alias swapContext = externDFunc!("core.thread.osthread.swapContext", void* function(void*) nothrow @nogc);} package{    alias getStackBottom = externDFunc!("core.thread.osthread.getStackBottom", void* function() nothrow @nogc);    alias getStackTop = externDFunc!("core.thread.osthread.getStackTop", void* function() nothrow @nogc);}  ///////////////////////////////////////////////////////////////////////////////// Thread///////////////////////////////////////////////////////////////////////////////  class ThreadBase{    ///////////////////////////////////////////////////////////////////////////    // Initialization    ///////////////////////////////////////////////////////////////////////////     this(void function() fn, size_t sz = 0) @safe pure nothrow @nogc    in(fn)    {        this(sz);        m_call = fn;    }     this(void delegate() dg, size_t sz = 0) @trusted pure nothrow @nogc    in( cast(const void delegate()) dg)    {        this(sz);        m_call = dg;    }     /**     * Cleans up any remaining resources used by this object.     */    package bool destructBeforeDtor() nothrow @nogc    {        destroyDataStorageIfAvail();         bool no_context = m_addr == m_addr.init;        bool not_registered = !next && !prev && (sm_tbeg !is this);         return (no_context || not_registered);    }     ref void* tlsGCData() nothrow @nogc    {        return m_tlsgcdata;    }     package void tlsRTdataInit() nothrow @nogc    {        m_tlsrtdata = rt_tlsgc_init();         // Let the selected GC initialize anything it needs.        import core.internal.gc.proxy : gc_getProxy;        gc_getProxy().initThread(this);    }     package void initDataStorage() nothrow    {        assert(m_curr is &m_main);         m_main.bstack = getStackBottom();        m_main.tstack = m_main.bstack;        tlsRTdataInit();    }     package void destroyDataStorage() nothrow @nogc    {        rt_tlsgc_destroy(m_tlsrtdata);        m_tlsrtdata = null;    }     package void destroyDataStorageIfAvail() nothrow @nogc    {        if (m_tlsrtdata)            destroyDataStorage();    }      ///////////////////////////////////////////////////////////////////////////    // General Actions    ///////////////////////////////////////////////////////////////////////////      /**     * Waits for this thread to complete.  If the thread terminated as the     * result of an unhandled exception, this exception will be rethrown.     *     * Params:     *  rethrow = Rethrow any unhandled exception which may have caused this     *            thread to terminate.     *     * Throws:     *  ThreadException if the operation fails.     *  Any exception not handled by the joined thread.     *     * Returns:     *  Any exception not handled by this thread if rethrow = false, null     *  otherwise.     */    abstract Throwable join(bool rethrow = true);     /**     * Filter any exceptions that escaped the thread entry point.     * This enables a 'grave digger' approach to exceptions.     *     * By default this method will call the global handler in core.exception.     *     * Overriding this method allows a per-thread behavior.     *     * Params:     *         thrown = The thrown exception, may be null after returned.     */    void filterCaughtThrowable(ref Throwable thrown) @system nothrow    {        import core.exception : filterThreadThrowableHandler;        if (thrown is null)            return;        else if (auto handler = filterThreadThrowableHandler())            handler(thrown);    }     ///////////////////////////////////////////////////////////////////////////    // General Properties    ///////////////////////////////////////////////////////////////////////////      /**     * Gets the OS identifier for this thread.     *     * Returns:     *  If the thread hasn't been started yet, returns $(LREF ThreadID)$(D.init).     *  Otherwise, returns the result of $(D GetCurrentThreadId) on Windows,     *  and $(D pthread_self) on POSIX.     *     *  The value is unique for the current process.     */    final @property ThreadID id() @safe @nogc    {        synchronized(this)        {            return m_addr;        }    }      /**     * Gets the user-readable label for this thread.     *     * Returns:     *  The name of this thread.     */    final @property string name() @safe @nogc    {        synchronized(this)        {            return m_name;        }    }      /**     * Sets the user-readable label for this thread.     *     * Params:     *  val = The new name of this thread.     */    final @property void name(string val) @safe @nogc    {        synchronized(this)        {            m_name = val;        }    }      /**     * Gets the daemon status for this thread.  While the runtime will wait for     * all normal threads to complete before tearing down the process, daemon     * threads are effectively ignored and thus will not prevent the process     * from terminating.  In effect, daemon threads will be terminated     * automatically by the OS when the process exits.     *     * Returns:     *  true if this is a daemon thread.     */    final @property bool isDaemon() @safe @nogc    {        synchronized(this)        {            return m_isDaemon;        }    }      /**     * Sets the daemon status for this thread.  While the runtime will wait for     * all normal threads to complete before tearing down the process, daemon     * threads are effectively ignored and thus will not prevent the process     * from terminating.  In effect, daemon threads will be terminated     * automatically by the OS when the process exits.     *     * Params:     *  val = The new daemon status for this thread.     */    final @property void isDaemon(bool val) @safe @nogc    {        synchronized(this)        {            m_isDaemon = val;        }    }     /**     * Tests whether this thread is the main thread, i.e. the thread     * that initialized the runtime     *     * Returns:     *  true if the thread is the main thread     */    final @property bool isMainThread() nothrow @nogc    {        return this is sm_main;    }     /**     * Tests whether this thread is running.     *     * Returns:     *  true if the thread is running, false if not.     */    @property bool isRunning() nothrow @nogc    {        if (m_addr == m_addr.init)            return false;         return true;    }      ///////////////////////////////////////////////////////////////////////////    // Thread Accessors    ///////////////////////////////////////////////////////////////////////////     /**     * 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 ThreadBase getThis() @safe nothrow @nogc    {        // NOTE: This function may not be called until thread_init has        //       completed.  See thread_suspendAll for more information        //       on why this might occur.        version (GNU) pragma(inline, false);        return sm_this;    }      /**     * Provides a list of all threads currently being tracked by the system.     * Note that threads in the returned array might no longer run (see     * $(D ThreadBase.)$(LREF isRunning)).     *     * Returns:     *  An array containing references to all threads currently being     *  tracked by the system.  The result of deleting any contained     *  objects is undefined.     */    static ThreadBase[] getAll()    {        static void resize(ref ThreadBase[] buf, size_t nlen)        {            buf.length = nlen;        }        return getAllImpl!resize();    }      /**     * Operates on all threads currently being tracked by the system.  The     * result of deleting any Thread object is undefined.     * Note that threads passed to the callback might no longer run (see     * $(D ThreadBase.)$(LREF isRunning)).     *     * Params:     *  dg = The supplied code as a delegate.     *     * Returns:     *  Zero if all elemented are visited, nonzero if not.     */    static int opApply(scope int delegate(ref ThreadBase) dg)    {        static void resize(ref ThreadBase[] buf, size_t nlen)        {            import core.exception: onOutOfMemoryError;             auto newBuf = cast(ThreadBase*)realloc(buf.ptr, nlen * size_t.sizeof);            if (newBuf is null) onOutOfMemoryError();            buf = newBuf[0 .. nlen];        }        auto buf = getAllImpl!resize;        scope(exit) if (buf.ptr) free(buf.ptr);         foreach (t; buf)        {            if (auto res = dg(t))                return res;        }        return 0;    }     private static ThreadBase[] getAllImpl(alias resize)()    {        import core.atomic;         ThreadBase[] buf;        while (true)        {            immutable len = atomicLoad!(MemoryOrder.raw)(*cast(shared)&sm_tlen);            resize(buf, len);            assert(buf.length == len);            synchronized (slock)            {                if (len == sm_tlen)                {                    size_t pos;                    for (ThreadBase t = sm_tbeg; t; t = t.next)                        buf[pos++] = t;                    return buf;                }            }        }    }     ///////////////////////////////////////////////////////////////////////////    // Actions on Calling Thread    ///////////////////////////////////////////////////////////////////////////     /**     * Forces a context switch to occur away from the calling thread.     */    private static void yield() @nogc nothrow    {        thread_yield();    }     ///////////////////////////////////////////////////////////////////////////    // Stuff That Should Go Away    ///////////////////////////////////////////////////////////////////////////      //    // Initializes a thread object which has no associated executable function.    // This is used for the main thread initialized in thread_init().    //    package this(size_t sz = 0) @safe pure nothrow @nogc    {        m_sz = sz;        m_curr = &m_main;    }     //    // Thread entry point.  Invokes the function or delegate passed on    // construction (if any).    //    package final void run()    {        m_call();    } package:     //    // Local storage    //    static ThreadBase       sm_this;      //    // Main process thread    //    __gshared ThreadBase    sm_main;      //    // Standard thread data    //    ThreadID            m_addr;    Callable            m_call;    string              m_name;    size_t              m_sz;    bool                m_isDaemon;    Throwable           m_unhandled;     ///////////////////////////////////////////////////////////////////////////    // Storage of Active Thread    ///////////////////////////////////////////////////////////////////////////      //    // Sets a thread-local reference to the current thread object.    //    package static void setThis(ThreadBase t) nothrow @nogc    {        sm_this = t;    } package(core.thread): 

Lines 1–500 of 1335.

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