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 }