Wolfgang Thallergcc16 merge934c3885 months agoHistory
2925 lines · 78.4 KB · D
RawDownload
/** * $(SCRIPT inhibitQuickIndex = 1;) * $(DIVC quickindex, * $(BOOKTABLE, * $(TR $(TH Category) $(TH Symbols)) * $(TR $(TD Tid) $(TD *     $(MYREF join) *     $(MYREF locate) *     $(MYREF ownerTid) *     $(MYREF register) *     $(MYREF spawn) *     $(MYREF spawnLinked) *     $(MYREF thisTid) *     $(MYREF Tid) *     $(MYREF TidMissingException) *     $(MYREF unregister) * )) * $(TR $(TD Message passing) $(TD *     $(MYREF prioritySend) *     $(MYREF receive) *     $(MYREF receiveOnly) *     $(MYREF receiveTimeout) *     $(MYREF send) *     $(MYREF setMaxMailboxSize) * )) * $(TR $(TD Message-related types) $(TD *     $(MYREF LinkTerminated) *     $(MYREF MailboxFull) *     $(MYREF MessageMismatch) *     $(MYREF OnCrowding) *     $(MYREF OwnerTerminated) *     $(MYREF PriorityMessageException) * )) * $(TR $(TD Scheduler) $(TD *     $(MYREF FiberScheduler) *     $(MYREF Generator) *     $(MYREF Scheduler) *     $(MYREF scheduler) *     $(MYREF ThreadInfo) *     $(MYREF ThreadScheduler) *     $(MYREF yield) * )) * $(TR $(TD Misc) $(TD *     $(MYREF initOnce) * )) * )) * * This is a low-level messaging API upon which more structured or restrictive * APIs may be built.  The general idea is that every messageable entity is * represented by a common handle type called a `Tid`, which allows messages to * be sent to logical threads that are executing in both the current process * and in external processes using the same interface.  This is an important * aspect of scalability because it allows the components of a program to be * spread across available resources with few to no changes to the actual * implementation. * * A logical thread is an execution context that has its own stack and which * runs asynchronously to other logical threads.  These may be preemptively * scheduled kernel threads, $(MREF_ALTTEXT fibers, core, thread, fiber) * (cooperative user-space threads), or some other concept with similar behavior. * * The type of concurrency used when logical threads are created is determined * by the $(LREF Scheduler) selected at initialization time.  The default behavior is * currently to create a new kernel thread per call to spawn, but other * schedulers are available that multiplex fibers across the main thread or * use some combination of the two approaches. * * Copyright: Copyright Sean Kelly 2009 - 2014. * License:   <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>. * Authors:   Sean Kelly, Alex Rønne Petersen, Martin Nowak * Source:    $(PHOBOSSRC std/concurrency.d) *//*          Copyright Sean Kelly 2009 - 2014. * Distributed under the Boost Software License, Version 1.0. *    (See accompanying file LICENSE_1_0.txt or copy at *          http://www.boost.org/LICENSE_1_0.txt) */module std.concurrency; public import std.variant; import core.atomic;import core.sync.condition;import core.sync.mutex;import core.thread;import std.range.primitives;import std.range.interfaces : InputRange;import std.traits; ///@system unittest{    __gshared string received;    static void spawnedFunc(Tid ownerTid)    {        import std.conv : text;        // Receive a message from the owner thread.        receive((int i){            received = text("Received the number ", i);             // Send a message back to the owner thread            // indicating success.            send(ownerTid, true);        });    }     // Start spawnedFunc in a new thread.    auto childTid = spawn(&spawnedFunc, thisTid);     // Send the number 42 to this new thread.    send(childTid, 42);     // Receive the result code.    auto wasSuccessful = receiveOnly!(bool);    assert(wasSuccessful);    assert(received == "Received the number 42");} private{    bool hasLocalAliasing(Types...)()    {        import std.typecons : Rebindable;         // Works around "statement is not reachable"        bool doesIt = false;        static foreach (T; Types)        {            static if (is(T == Tid))            { /* Allowed */ }            else static if (is(T : Rebindable!R, R))                doesIt |= hasLocalAliasing!R;            else static if (is(T == struct))                doesIt |= hasLocalAliasing!(typeof(T.tupleof));            else                doesIt |= std.traits.hasUnsharedAliasing!(T);        }        return doesIt;    }     @safe unittest    {        static struct Container { Tid t; }        static assert(!hasLocalAliasing!(Tid, Container, int));    }     // https://issues.dlang.org/show_bug.cgi?id=20097    @safe unittest    {        import std.datetime.systime : SysTime;        static struct Container { SysTime time; }        static assert(!hasLocalAliasing!(SysTime, Container));    }     enum MsgType    {        standard,        priority,        linkDead,    }     struct Message    {        MsgType type;        Variant data;         this(T...)(MsgType t, T vals)        if (T.length > 0)        {            static if (T.length == 1)            {                type = t;                data = vals[0];            }            else            {                import std.typecons : Tuple;                 type = t;                data = Tuple!(T)(vals);            }        }         @property auto convertsTo(T...)()        {            static if (T.length == 1)            {                return is(T[0] == Variant) || data.convertsTo!(T);            }            else            {                import std.typecons : Tuple;                return data.convertsTo!(Tuple!(T));            }        }         @property auto get(T...)()        {            static if (T.length == 1)            {                static if (is(T[0] == Variant))                    return data;                else                    return data.get!(T);            }            else            {                import std.typecons : Tuple;                return data.get!(Tuple!(T));            }        }         auto map(Op)(Op op)        {            alias Args = Parameters!(Op);             static if (Args.length == 1)            {                static if (is(Args[0] == Variant))                    return op(data);                else                    return op(data.get!(Args));            }            else            {                import std.typecons : Tuple;                return op(data.get!(Tuple!(Args)).expand);            }        }    }     void checkops(T...)(T ops)    {        import std.format : format;         foreach (i, t1; T)        {            static assert(isFunctionPointer!t1 || isDelegate!t1,                    format!"T %d is not a function pointer or delegates"(i));            alias a1 = Parameters!(t1);            alias r1 = ReturnType!(t1);             static if (i < T.length - 1 && is(r1 == void))            {                static assert(a1.length != 1 || !is(a1[0] == Variant),                              "function with arguments " ~ a1.stringof ~                              " occludes successive function");                 foreach (t2; T[i + 1 .. $])                {                    alias a2 = Parameters!(t2);                     static assert(!is(a1 == a2),                        "function with arguments " ~ a1.stringof ~ " occludes successive function");                }            }        }    }     @property ref ThreadInfo thisInfo() nothrow    {        import core.atomic : atomicLoad;         auto localScheduler = atomicLoad(scheduler);        if (localScheduler is null)            return ThreadInfo.thisInfo;        return localScheduler.thisInfo;    }} static ~this(){    thisInfo.cleanup();} // Exceptions /** * Thrown on calls to $(LREF receiveOnly) if a message other than the type * the receiving thread expected is sent. */class MessageMismatch : Exception{    ///    this(string msg = "Unexpected message type") @safe pure nothrow @nogc    {        super(msg);    }} /** * Thrown on calls to $(LREF receive) if the thread that spawned the receiving * thread has terminated and no more messages exist. */class OwnerTerminated : Exception{    ///    this(Tid t, string msg = "Owner terminated") @safe pure nothrow @nogc    {        super(msg);        tid = t;    }     Tid tid;} /** * Thrown if a linked thread has terminated. */class LinkTerminated : Exception{    ///    this(Tid t, string msg = "Link terminated") @safe pure nothrow @nogc    {        super(msg);        tid = t;    }     Tid tid;} /** * Thrown if a message was sent to a thread via * $(REF prioritySend, std,concurrency) and the receiver does not have a handler * for a message of this type. */class PriorityMessageException : Exception{    ///    this(Variant vals)    {        super("Priority message");        message = vals;    }     /**     * The message that was sent.     */    Variant message;} /** * Thrown on mailbox crowding if the mailbox is configured with * `OnCrowding.throwException`. */class MailboxFull : Exception{    ///    this(Tid t, string msg = "Mailbox full") @safe pure nothrow @nogc    {        super(msg);        tid = t;    }     Tid tid;} /** * Thrown when a `Tid` is missing, e.g. when $(LREF ownerTid) doesn't * find an owner thread. */class TidMissingException : Exception{    import std.exception : basicExceptionCtors;    ///    mixin basicExceptionCtors;}  // Thread ID  /** * An opaque type used to represent a logical thread. */struct Tid{private:    this(MessageBox m) @safe pure nothrow @nogc    {        mbox = m;    }     MessageBox mbox; public:     /**     * Generate a convenient string for identifying this `Tid`.  This is only     * useful to see if `Tid`'s that are currently executing are the same or     * different, e.g. for logging and debugging.  It is potentially possible     * that a `Tid` executed in the future will have the same `toString()` output     * as another `Tid` that has already terminated.     */    void toString(W)(ref W w) const    {        import std.format.write : formattedWrite;        auto p = () @trusted { return cast(void*) mbox; }();        formattedWrite(w, "Tid(%x)", p);    } } @safe unittest{    import std.conv : text;    Tid tid;    assert(text(tid) == "Tid(0)");    auto tid2 = thisTid;    assert(text(tid2) != "Tid(0)");    auto tid3 = tid2;    assert(text(tid2) == text(tid3));} // https://issues.dlang.org/show_bug.cgi?id=21512@system unittest{    import std.format : format;     const(Tid) b = spawn(() {});    assert(format!"%s"(b)[0 .. 4] == "Tid(");} /** * Returns: The `Tid` of the caller's thread. */@property Tid thisTid() @safe{    // TODO: remove when concurrency is safe    static auto trus() @trusted    {        if (thisInfo.ident != Tid.init)            return thisInfo.ident;        thisInfo.ident = Tid(new MessageBox);        return thisInfo.ident;    }     return trus();} /** * Return the `Tid` of the thread which spawned the caller's thread. * * Throws: A `TidMissingException` exception if * there is no owner thread. */@property Tid ownerTid(){    import std.exception : enforce;     enforce!TidMissingException(thisInfo.owner.mbox !is null, "Error: Thread has no owner thread.");    return thisInfo.owner;} @system unittest{    import std.exception : assertThrown;     static void fun()    {        string res = receiveOnly!string();        assert(res == "Main calling");        ownerTid.send("Child responding");    }     assertThrown!TidMissingException(ownerTid);    auto child = spawn(&fun);    child.send("Main calling");    string res = receiveOnly!string();    assert(res == "Child responding");} // Thread Creation private template isSpawnable(F, T...){    template isParamsImplicitlyConvertible(F1, F2, int i = 0)    {        alias param1 = Parameters!F1;        alias param2 = Parameters!F2;        static if (param1.length != param2.length)            enum isParamsImplicitlyConvertible = false;        else static if (param1.length == i)            enum isParamsImplicitlyConvertible = true;        else static if (is(param2[i] : param1[i]))            enum isParamsImplicitlyConvertible = isParamsImplicitlyConvertible!(F1,                    F2, i + 1);        else            enum isParamsImplicitlyConvertible = false;    }     enum isSpawnable = isCallable!F && is(ReturnType!F : void)            && isParamsImplicitlyConvertible!(F, void function(T))            && (isFunctionPointer!F || !hasUnsharedAliasing!F);} /** * Starts `fn(args)` in a new logical thread. * * Executes the supplied function in a new logical thread represented by

Lines 1–500 of 2925.

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