1 /// Access to creation and deletion of object monitors abstracted out by the runtime. 2 module tern.experimental.monitor; 3 4 import core.atomic, core.stdc.stdlib, core.stdc.string; 5 import core.sync.mutex; 6 import std.traits; 7 version (Windows) 8 { 9 version (CRuntime_DigitalMars) 10 { 11 pragma(lib, "snn.lib"); 12 } 13 import core.sys.windows.winbase /+: CRITICAL_SECTION, DeleteCriticalSection, 14 EnterCriticalSection, InitializeCriticalSection, LeaveCriticalSection+/; 15 } 16 17 version (Windows) 18 { 19 private alias Mutex = CRITICAL_SECTION; 20 21 private alias initMutex = InitializeCriticalSection; 22 private alias destroyMutex = DeleteCriticalSection; 23 private alias lockMutex = EnterCriticalSection; 24 private alias unlockMutex = LeaveCriticalSection; 25 } 26 else version (Posix) 27 { 28 import core.sys.posix.pthread; 29 30 private alias Mutex = pthread_mutex_t; 31 private __gshared pthread_mutexattr_t gattr; 32 33 private void initMutex(pthread_mutex_t* mtx) 34 { 35 pthread_mutex_init(mtx, &gattr) && assert(0); 36 } 37 38 private void destroyMutex(pthread_mutex_t* mtx) 39 { 40 pthread_mutex_destroy(mtx) && assert(0); 41 } 42 43 private void lockMutex(pthread_mutex_t* mtx) 44 { 45 pthread_mutex_lock(mtx) && assert(0); 46 } 47 48 private void unlockMutex(pthread_mutex_t* mtx) 49 { 50 pthread_mutex_unlock(mtx) && assert(0); 51 } 52 } 53 else 54 { 55 static assert(0, "Unsupported platform"); 56 } 57 58 alias IMonitor = Object.Monitor; 59 alias DEvent = void delegate(Object); 60 61 private struct Monitor 62 { 63 public: 64 final: 65 IMonitor impl; // for user-level monitors 66 DEvent[] devt; // for internal monitors 67 size_t refs; // reference count 68 Mutex mtx; 69 } 70 71 private shared static core.sync.mutex.Mutex mutex; 72 73 public: 74 static: 75 shared static this() 76 { 77 mutex = new shared core.sync.mutex.Mutex(); 78 } 79 80 /** 81 * Creates a monitor for `val`. 82 * 83 * Params: 84 * val = Value to create a monitor for. 85 * 86 * Returns: 87 * True if the monitor was successfully created. 88 */ 89 bool createMonitor(T)(ref T val) 90 if (isAssignable!(T, Object)) 91 { 92 if (auto m = val.getMonitor() !is null) 93 return m; 94 95 Monitor* m = cast(Monitor*)calloc(Monitor.sizeof, 1); 96 initMutex(&m.mtx); 97 98 synchronized (mutex) 99 { 100 if (val.getMonitor() is null) 101 { 102 m.refs = 1; 103 val.setMonitor(cast(shared)m); 104 return true; 105 } 106 destroyMonitor(m); 107 return false; 108 } 109 } 110 111 /** 112 * Deletes the monitor `m`. 113 * 114 * Params: 115 * m = Pointer to the monitor to be deleted. 116 */ 117 void destroyMonitor(Monitor* m) 118 { 119 destroyMutex(&m.mtx); 120 free(m); 121 } 122 123 pure: 124 @property ref shared(Monitor*) monitor(T)(return scope T val) 125 if (isAssignable!(T, Object)) 126 { 127 return *cast(shared Monitor**)&val.__monitor; 128 } 129 130 /** 131 * Gets the monitor of `val`. 132 * 133 * Params: 134 * val = Value to get the monitor of. 135 * 136 * Returns: 137 * The monitor of `val`. 138 */ 139 shared(Monitor)* getMonitor(T)(T val) 140 if (isAssignable!(T, Object)) 141 { 142 return atomicLoad!(MemoryOrder.acq)(val.monitor); 143 } 144 145 /** 146 * Sets the monitor of `val`. 147 * 148 * Params: 149 * val = Value to set the monitor of. 150 * m = The new monitor of `val`. 151 */ 152 void setMonitor(T)(T val, shared(Monitor)* m) 153 if (isAssignable!(T, Object)) 154 { 155 atomicStore!(MemoryOrder.rel)(val.monitor, m); 156 }