Wolfgang Thallergcc16 merge934c3885 months agoHistory
318 lines · 7.4 KB · D
RawDownload
/** * Contains the implementation for object monitors. * * Copyright: Copyright Digital Mars 2000 - 2015. * License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors:   Walter Bright, Sean Kelly, Martin Nowak * Source: $(DRUNTIMESRC rt/_monitor_.d) */module rt.monitor_; import core.atomic;import core.stdc.stdlib : calloc, free, realloc;import core.stdc.string : memmove; version (Windows){    import core.sys.windows.winbase /+: CRITICAL_SECTION, DeleteCriticalSection,        EnterCriticalSection, InitializeCriticalSection, LeaveCriticalSection+/;}else version (Posix){    import core.sys.posix.pthread : pthread_mutex_destroy, pthread_mutex_init, pthread_mutex_lock,        PTHREAD_MUTEX_RECURSIVE, pthread_mutex_unlock, pthread_mutexattr_destroy, pthread_mutexattr_init,        pthread_mutexattr_settype;    import core.sys.posix.sys.types : pthread_mutex_t, pthread_mutexattr_t;}else{    static assert(0, "Unsupported platform");} // NOTE: The dtor callback feature is only supported for monitors that are not//       supplied by the user.  The assumption is that any object with a user-//       supplied monitor may have special storage or lifetime requirements and//       that as a result, storing references to local objects within Monitor//       may not be safe or desirable.  Thus, devt is only valid if impl is//       null. extern (C) void _d_setSameMutex(shared Object ownee, shared Object owner) @trusted nothrowin{    assert(ownee.__monitor is null);}do{    auto m = ensureMonitor(cast(Object) cast(void*) owner);    if (m.impl is null)    {        atomicOp!"+="(m.refs, size_t(1));    }    // Assume the monitor is garbage collected and simply copy the reference.    ownee.__monitor = owner.__monitor;} extern (C) void _d_monitordelete(Object h, bool det){    auto m = getMonitor(h);    if (m is null)        return;     if (m.impl)    {        // let the GC collect the monitor        setMonitor(h, null);    }    else if (!atomicOp!"-="(m.refs, size_t(1)))    {        // refcount == 0 means unshared => no synchronization required        disposeEvent(cast(Monitor*) m, h);        deleteMonitor(cast(Monitor*) m);        setMonitor(h, null);    }} // does not call dispose events, for internal use onlyextern (C) void _d_monitordelete_nogc(Object h) @nogc nothrow{    auto m = getMonitor(h);    if (m is null)        return;     if (m.impl)    {        // let the GC collect the monitor        setMonitor(h, null);    }    else if (!atomicOp!"-="(m.refs, size_t(1)))    {        // refcount == 0 means unshared => no synchronization required        deleteMonitor(cast(Monitor*) m);        setMonitor(h, null);    }} extern (C) void _d_monitorenter(Object h)in{    assert(h !is null, "Synchronized object must not be null.");}do{    auto m = cast(Monitor*) ensureMonitor(h);    auto i = m.impl;    if (i is null)        lockMutex(&m.mtx);    else        i.lock();} extern (C) void _d_monitorexit(Object h){    auto m = cast(Monitor*) getMonitor(h);    auto i = m.impl;    if (i is null)        unlockMutex(&m.mtx);    else        i.unlock();} extern (C) void rt_attachDisposeEvent(Object h, DEvent e){    synchronized (h)    {        auto m = cast(Monitor*) getMonitor(h);        assert(m.impl is null);         foreach (ref v; m.devt)        {            if (v is null || v == e)            {                v = e;                return;            }        }         auto len = m.devt.length + 4; // grow by 4 elements        auto pos = m.devt.length; // insert position        auto p = realloc(m.devt.ptr, DEvent.sizeof * len);        import core.exception : onOutOfMemoryError;         if (!p)            onOutOfMemoryError();        m.devt = (cast(DEvent*) p)[0 .. len];        m.devt[pos + 1 .. len] = null;        m.devt[pos] = e;    }} extern (C) void rt_detachDisposeEvent(Object h, DEvent e){    synchronized (h)    {        auto m = cast(Monitor*) getMonitor(h);        assert(m.impl is null);         foreach (p, v; m.devt)        {            if (v == e)            {                memmove(&m.devt[p], &m.devt[p + 1], (m.devt.length - p - 1) * DEvent.sizeof);                m.devt[$ - 1] = null;                return;            }        }    }} nothrow: extern (C) void _d_monitor_staticctor() @nogc nothrow{    version (Posix)    {        pthread_mutexattr_init(&gattr);        pthread_mutexattr_settype(&gattr, PTHREAD_MUTEX_RECURSIVE);    }    initMutex(&gmtx);} extern (C) void _d_monitor_staticdtor() @nogc nothrow{    destroyMutex(&gmtx);    version (Posix)        pthread_mutexattr_destroy(&gattr);} package: // This is what the monitor reference in Object points toalias IMonitor = Object.Monitor;alias DEvent = void delegate(Object); version (Windows){    alias Mutex = CRITICAL_SECTION;     alias initMutex = InitializeCriticalSection;    alias destroyMutex = DeleteCriticalSection;    alias lockMutex = EnterCriticalSection;    alias unlockMutex = LeaveCriticalSection;}else version (Posix){@nogc:    alias Mutex = pthread_mutex_t;    __gshared pthread_mutexattr_t gattr;     void initMutex(pthread_mutex_t* mtx)    {        pthread_mutex_init(mtx, &gattr) && assert(0);    }     void destroyMutex(pthread_mutex_t* mtx)    {        pthread_mutex_destroy(mtx) && assert(0);    }     void lockMutex(pthread_mutex_t* mtx)    {        pthread_mutex_lock(mtx) && assert(0);    }     void unlockMutex(pthread_mutex_t* mtx)    {        pthread_mutex_unlock(mtx) && assert(0);    }} struct Monitor{    IMonitor impl; // for user-level monitors    DEvent[] devt; // for internal monitors    size_t refs; // reference count    Mutex mtx;} private: __gshared Mutex gmtx; shared(Monitor*)* monitorPtr(return scope Object h) pure nothrow @nogc @trusted{    return cast(shared(Monitor*)*) &h.__monitor;} shared(Monitor)* getMonitor(Object h) pure @nogc{    return atomicLoad!(MemoryOrder.acq)(*monitorPtr(h));} void setMonitor(Object h, shared(Monitor)* m) pure @nogc{    atomicStore!(MemoryOrder.rel)(*monitorPtr(h), m);} shared(Monitor)* ensureMonitor(Object h){    if (auto m = getMonitor(h))        return m;     auto m = cast(Monitor*) calloc(Monitor.sizeof, 1);    assert(m);    initMutex(&m.mtx);     bool success;    lockMutex(&gmtx);    if (getMonitor(h) is null)    {        m.refs = 1;        setMonitor(h, cast(shared) m);        success = true;    }    unlockMutex(&gmtx);     if (success)    {        // Set the finalize bit so that the monitor gets collected (Bugzilla 14573)        import core.memory : GC;         if (!(typeid(h).m_flags & TypeInfo_Class.ClassFlags.hasDtor))            GC.setAttr(cast(void*) h, GC.BlkAttr.FINALIZE);        return cast(shared(Monitor)*) m;    }    else // another thread succeeded instead    {        deleteMonitor(m);        return getMonitor(h);    }} void deleteMonitor(Monitor* m) @nogc{    destroyMutex(&m.mtx);    free(m);} void disposeEvent(Monitor* m, Object h){    foreach (v; m.devt)    {        if (v)            v(h);    }    if (m.devt.ptr)        free(m.devt.ptr);} // Bugzilla 14573unittest{    import core.memory : GC;     auto obj = new Object;    assert(!(GC.getAttr(cast(void*) obj) & GC.BlkAttr.FINALIZE));    ensureMonitor(obj);    assert(getMonitor(obj) !is null);    assert(GC.getAttr(cast(void*) obj) & GC.BlkAttr.FINALIZE);}

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