From eef723d5bb394033cd4887b845940b328607b067 Mon Sep 17 00:00:00 2001 From: Martin Nowak Date: Wed, 7 Feb 2018 14:14:19 +0100 Subject: [PATCH 1/3] make thread_init @nogc --- src/core/thread.d | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/core/thread.d b/src/core/thread.d index 83a4a26b53..ba3bdc02da 100644 --- a/src/core/thread.d +++ b/src/core/thread.d @@ -1727,7 +1727,7 @@ private: __gshared align(Mutex.alignof) void[__traits(classInstanceSize, Mutex)][2] _locks; - static void initLocks() + static void initLocks() @nogc { foreach (ref lock; _locks) { @@ -2020,7 +2020,7 @@ version( Posix ) * garbage collector on startup and before any other thread routines * are called. */ -extern (C) void thread_init() +extern (C) void thread_init() @nogc { // NOTE: If thread_init itself performs any allocations then the thread // routines reserved for garbage collector use may be called while @@ -2090,7 +2090,10 @@ extern (C) void thread_init() status = sem_init( &suspendCount, 0, 0 ); assert( status == 0 ); } - Thread.sm_main = thread_attachThis(); + __gshared align(Thread.alignof) void[__traits(classInstanceSize, Thread)] mainThread; + if (typeid(Thread).initializer.ptr) + mainThread[] = typeid(Thread).initializer[]; + Thread.sm_main = attachThread((cast(Thread)mainThread.ptr).__ctor()); } @@ -2135,12 +2138,14 @@ extern (C) bool thread_isMainThread() nothrow @nogc */ extern (C) Thread thread_attachThis() { - GC.disable(); scope(exit) GC.enable(); - if (auto t = Thread.getThis()) return t; - Thread thisThread = new Thread(); + return attachThread(new Thread()); +} + +private Thread attachThread(Thread thisThread) @nogc +{ Thread.Context* thisContext = &thisThread.m_main; assert( thisContext == thisThread.m_curr ); From e79a687d32551b23c734560c899fec2b20d10890 Mon Sep 17 00:00:00 2001 From: Martin Nowak Date: Wed, 7 Feb 2018 14:34:58 +0100 Subject: [PATCH 2/3] make thread_term @nogc - needed to replace destroy with manual destruction - use custom monitor deletion that does not call any event hooks --- src/core/thread.d | 20 ++++++++++++++------ src/rt/monitor_.d | 29 +++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/core/thread.d b/src/core/thread.d index ba3bdc02da..f59752b701 100644 --- a/src/core/thread.d +++ b/src/core/thread.d @@ -1736,7 +1736,7 @@ private: } } - static void termLocks() + static void termLocks() @nogc { foreach (ref lock; _locks) (cast(Mutex)lock.ptr).__dtor(); @@ -2090,20 +2090,28 @@ extern (C) void thread_init() @nogc status = sem_init( &suspendCount, 0, 0 ); assert( status == 0 ); } - __gshared align(Thread.alignof) void[__traits(classInstanceSize, Thread)] mainThread; if (typeid(Thread).initializer.ptr) - mainThread[] = typeid(Thread).initializer[]; - Thread.sm_main = attachThread((cast(Thread)mainThread.ptr).__ctor()); + _mainThreadStore[] = typeid(Thread).initializer[]; + Thread.sm_main = attachThread((cast(Thread)_mainThreadStore.ptr).__ctor()); } +private __gshared align(Thread.alignof) void[__traits(classInstanceSize, Thread)] _mainThreadStore; + +extern (C) void _d_monitordelete_nogc(Object h) @nogc; /** * Terminates the thread module. No other thread routine may be called * afterwards. */ -extern (C) void thread_term() +extern (C) void thread_term() @nogc { - destroy(Thread.sm_main); + assert(_mainThreadStore.ptr is cast(void*) Thread.sm_main); + + // destruct manually as object.destroy is not @nogc + Thread.sm_main.__dtor(); + _d_monitordelete_nogc(Thread.sm_main); + if (typeid(Thread).initializer.ptr) + _mainThreadStore[] = typeid(Thread).initializer[]; Thread.sm_main = null; assert(Thread.sm_tbeg && Thread.sm_tlen == 1); diff --git a/src/rt/monitor_.d b/src/rt/monitor_.d index 6a3f9db0f6..c9e5964461 100644 --- a/src/rt/monitor_.d +++ b/src/rt/monitor_.d @@ -56,6 +56,26 @@ extern (C) void _d_monitordelete(Object h, bool det) } } +// does not call dispose events, for internal use only +extern (C) void _d_monitordelete_nogc(Object h) @nogc +{ + 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, cast(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 { @@ -173,6 +193,7 @@ else version (Posix) { import core.sys.posix.pthread; +@nogc: alias Mutex = pthread_mutex_t; __gshared pthread_mutexattr_t gattr; @@ -211,17 +232,17 @@ struct Monitor private: -@property ref shared(Monitor*) monitor(Object h) pure nothrow +@property ref shared(Monitor*) monitor(Object h) pure nothrow @nogc { return *cast(shared Monitor**)&h.__monitor; } -private shared(Monitor)* getMonitor(Object h) pure +private shared(Monitor)* getMonitor(Object h) pure @nogc { return atomicLoad!(MemoryOrder.acq)(h.monitor); } -void setMonitor(Object h, shared(Monitor)* m) pure +void setMonitor(Object h, shared(Monitor)* m) pure @nogc { atomicStore!(MemoryOrder.rel)(h.monitor, m); } @@ -263,7 +284,7 @@ shared(Monitor)* ensureMonitor(Object h) } } -void deleteMonitor(Monitor* m) +void deleteMonitor(Monitor* m) @nogc { destroyMutex(&m.mtx); free(m); From 00e194595b69cd30bd1399d8a36180f8fbae00f7 Mon Sep 17 00:00:00 2001 From: Martin Nowak Date: Wed, 7 Feb 2018 14:54:34 +0100 Subject: [PATCH 3/3] separate thread_init/term from gc_init/term --- src/gc/proxy.d | 9 --------- src/rt/dmain2.d | 4 ++++ 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/gc/proxy.d b/src/gc/proxy.d index afe09a13c0..68877e1489 100644 --- a/src/gc/proxy.d +++ b/src/gc/proxy.d @@ -25,9 +25,6 @@ private static import core.memory; alias BlkInfo = core.memory.GC.BlkInfo; - extern (C) void thread_init(); - extern (C) void thread_term(); - __gshared GC instance; __gshared GC proxiedGC; // used to iterate roots of Windows DLLs @@ -50,10 +47,6 @@ extern (C) fprintf(stderr, "No GC was initialized, please recheck the name of the selected GC ('%.*s').\n", cast(int)config.gc.length, config.gc.ptr); exit(1); } - - // NOTE: The GC must initialize the thread library - // before its first collection. - thread_init(); } void gc_term() @@ -71,8 +64,6 @@ extern (C) instance.collectNoStack(); // not really a 'collect all' -- still scans // static data area, roots, and ranges. - thread_term(); - ManualGC.finalize(instance); ConservativeGC.finalize(instance); } diff --git a/src/rt/dmain2.d b/src/rt/dmain2.d index 5ab13b6d80..b09bbb5c1b 100644 --- a/src/rt/dmain2.d +++ b/src/rt/dmain2.d @@ -56,6 +56,8 @@ extern (C) void _d_critical_init(); extern (C) void _d_critical_term(); extern (C) void gc_init(); extern (C) void gc_term(); +extern (C) void thread_init() @nogc; +extern (C) void thread_term() @nogc; extern (C) void lifetime_init(); extern (C) void rt_moduleCtor(); extern (C) void rt_moduleTlsCtor(); @@ -190,6 +192,7 @@ extern (C) int rt_init() // this initializes mono time before anything else to allow usage // in other druntime systems. _d_initMonoTime(); + thread_init(); gc_init(); initStaticDataGC(); lifetime_init(); @@ -221,6 +224,7 @@ extern (C) int rt_term() thread_joinAll(); rt_moduleDtor(); gc_term(); + thread_term(); return 1; } catch (Throwable t)