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 }