1 module rt.monitor_; 2 3 version(LDC) 4 pragma(LDC_no_moduleinfo); 5 6 version(LWDR_Sync): 7 8 import rtoslink; 9 import lwdr.tracking; 10 11 import core.atomic; 12 13 /++ 14 First field of any Object monitor must be a reference to Object.Monitor, even for custom implementations. 15 Failure to do so will result in memory corruption. 16 ++/ 17 18 package struct Monitor 19 { 20 Object.Monitor userMonitor; 21 size_t referenceCount; 22 void* mutex; 23 } 24 25 /++ 26 Called on entry to a `synchronized` statement. If `o` does not already have a monitor, it will be created. 27 The monitor will then be locked. 28 29 `o` must not be null. 30 ++/ 31 extern(C) void _d_monitorenter(Object o) 32 in(o !is null, "Cannot sync null object") 33 { 34 auto m = cast(Monitor*)ensureMonitor(o); 35 if(m.userMonitor is null) 36 rtosbackend_mutexLock(m.mutex); 37 else 38 m.userMonitor.lock; 39 } 40 41 /++ 42 Called on exit from a `synchronized` statement. It will will unlock the monitor. 43 ++/ 44 extern(C) void _d_monitorexit(Object o) 45 { 46 // don't apply null checking, as thread will have already crashed. 47 auto m = cast(Monitor*)getMonitor(o); 48 if(m.userMonitor is null) 49 rtosbackend_mutexUnlock(m.mutex); 50 else 51 m.userMonitor.unlock; 52 } 53 54 /++ 55 INTERNAL USE! 56 Called during finalisation to remove monitor. 57 ++/ 58 void _lwdr_monitorDelete(Object o) @nogc nothrow 59 { 60 auto m = getMonitor(o); 61 if(m is null) 62 return; 63 64 scope(exit) setMonitor(o, null); 65 66 // user monitor should outlive object (ie, core.sync.Mutex) or be destroyed in dtor. 67 if(m.userMonitor !is null) 68 return; 69 70 if(atomicOp!"-="(m.referenceCount, cast(size_t)1) == 0) 71 { 72 // referenceCount == 0 means unshared -> no sync needed 73 deleteMonitor(cast(Monitor*)m); 74 } 75 } 76 77 private 78 { 79 __gshared void* globalMutex; 80 81 @property ref shared(Monitor*) monitor(return Object o) pure nothrow @nogc 82 { return *cast(shared Monitor**)&o.__monitor; } 83 84 shared(Monitor)* getMonitor(Object o) pure @nogc nothrow 85 { return atomicLoad!(MemoryOrder.acq)(o.monitor); } 86 87 void setMonitor(Object o, shared(Monitor)* m) pure @nogc nothrow 88 { atomicStore!(MemoryOrder.rel)(o.monitor, m); } 89 90 /// Gets existing monitor, or assigns one. 91 shared(Monitor)* ensureMonitor(Object o) 92 { 93 if(auto m = getMonitor(o)) 94 return m; 95 96 auto monitor = cast(Monitor*)lwdrInternal_alloc(Monitor.sizeof); 97 assert(monitor !is null); 98 *monitor = Monitor(); 99 100 monitor.mutex = rtosbackend_mutexInit(); 101 102 bool success; 103 rtosbackend_mutexLock(globalMutex); 104 if(getMonitor(o) is null) 105 { 106 monitor.referenceCount = 1; 107 setMonitor(o, cast(shared)monitor); 108 success = true; 109 } 110 rtosbackend_mutexUnlock(globalMutex); 111 112 if(success) 113 return cast(shared(Monitor)*)monitor; 114 else 115 { 116 deleteMonitor(monitor); 117 return getMonitor(o); 118 } 119 } 120 121 /// Deletes mutex and monitor 122 void deleteMonitor(Monitor* m) @nogc nothrow 123 { 124 rtosbackend_mutexDestroy(m.mutex); 125 lwdrInternal_free(m); 126 } 127 } 128 129 void __lwdr_monitor_init() nothrow @nogc 130 { 131 globalMutex = rtosbackend_globalMutexInit; 132 assert(globalMutex !is null); 133 } 134 135 void __lwdr_monitor_deinit() nothrow @nogc 136 { 137 rtosbackend_globalMutexDestroy(globalMutex); 138 globalMutex = null; 139 }