1 /**
2  * Contains the implementation for object monitors.
3  *
4  * Copyright: Copyright Digital Mars 2000 - 2011.
5  * License:   <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
6  * Authors:   Walter Bright, Sean Kelly
7  */
8 
9 /**
10  * D implementation written and ported to tango by Iain Buclaw.
11  */
12 
13 module rt.compiler.gdc.monitor_;
14 
15 //debug=PRINTF;
16 
17 private
18 {
19     debug(PRINTF) import tango.stdc.stdio;
20     import tango.stdc.stdlib;
21 
22     version( linux )
23     {
24         version = USE_PTHREADS;
25     }
26     else version( FreeBSD )
27     {
28         version = USE_PTHREADS;
29     }
30     else version( OSX )
31     {
32         version = USE_PTHREADS;
33     }
34     else version( Solaris )
35     {
36         version = USE_PTHREADS;
37     }
38 
39     // This is what the monitor reference in Object points to
40     alias Object.Monitor        IMonitor;
41     alias void delegate(Object) DEvent;
42 
43     version( Windows )
44     {
45         import tango.sys.win32.UserGdi;
46 
47         struct Monitor
48         {
49             IMonitor impl; // for user-level monitors
50             DEvent[] devt; // for internal monitors
51             CRITICAL_SECTION mon;
52         }
53     }
54     else version( USE_PTHREADS )
55     {
56         import tango.stdc.posix.pthread;
57 
58         struct Monitor
59         {
60             IMonitor impl; // for user-level monitors
61             DEvent[] devt; // for internal monitors
62             pthread_mutex_t mon;
63         }
64     }
65     else
66     {
67         version = NoSystem;
68 
69         struct Monitor
70         {
71             IMonitor impl; // for user-level monitors
72             DEvent[] devt; // for internal monitors
73         }
74     }
75 
76     Monitor* getMonitor(Object h)
77     {
78         return cast(Monitor*) h.__monitor;
79     }
80 
81     void setMonitor(Object h, Monitor* m)
82     {
83         h.__monitor = m;
84     }
85 
86     static int inited;
87 }
88 
89 
90 /* =============================== Win32 ============================ */
91 
92 version( Windows )
93 {
94     static CRITICAL_SECTION _monitor_critsec;
95 
96     extern (C) void _STI_monitor_staticctor()
97     {
98         debug(PRINTF) printf("+_STI_monitor_staticctor()\n");
99         if (!inited)
100         {
101             InitializeCriticalSection(&_monitor_critsec);
102             inited = 1;
103         }
104         debug(PRINTF) printf("-_STI_monitor_staticctor()\n");
105     }
106 
107     extern (C) void _STD_monitor_staticdtor()
108     {
109         debug(PRINTF) printf("+_STI_monitor_staticdtor() - d\n");
110         if (inited)
111         {
112             inited = 0;
113             DeleteCriticalSection(&_monitor_critsec);
114         }
115         debug(PRINTF) printf("-_STI_monitor_staticdtor() - d\n");
116     }
117 
118     extern (C) void _d_monitor_create(Object h)
119     {
120         /*
121          * NOTE: Assume this is only called when h.__monitor is null prior to the
122          * call.  However, please note that another thread may call this function
123          * at the same time, so we can not assert this here.  Instead, try and
124          * create a lock, and if one already exists then forget about it.
125          */
126 
127         debug(PRINTF) printf("+_d_monitor_create(%p)\n", h);
128         assert(h);
129         Monitor *cs;
130         EnterCriticalSection(&_monitor_critsec);
131         if (!h.__monitor)
132         {
133             cs = cast(Monitor *)calloc(Monitor.sizeof, 1);
134             assert(cs);
135             InitializeCriticalSection(&cs.mon);
136             setMonitor(h, cs);
137             cs = null;
138         }
139         LeaveCriticalSection(&_monitor_critsec);
140         if (cs)
141             free(cs);
142         debug(PRINTF) printf("-_d_monitor_create(%p)\n", h);
143     }
144 
145     extern (C) void _d_monitor_destroy(Object h)
146     {
147         debug(PRINTF) printf("+_d_monitor_destroy(%p)\n", h);
148         assert(h && h.__monitor && !getMonitor(h).impl);
149         DeleteCriticalSection(&getMonitor(h).mon);
150         free(h.__monitor);
151         setMonitor(h, null);
152         debug(PRINTF) printf("-_d_monitor_destroy(%p)\n", h);
153     }
154 
155     extern (C) void _d_monitor_lock(Object h)
156     {
157         debug(PRINTF) printf("+_d_monitor_acquire(%p)\n", h);
158         assert(h && h.__monitor && !getMonitor(h).impl);
159         EnterCriticalSection(&getMonitor(h).mon);
160         debug(PRINTF) printf("-_d_monitor_acquire(%p)\n", h);
161     }
162 
163     extern (C) void _d_monitor_unlock(Object h)
164     {
165         debug(PRINTF) printf("+_d_monitor_release(%p)\n", h);
166         assert(h && h.__monitor && !getMonitor(h).impl);
167         LeaveCriticalSection(&getMonitor(h).mon);
168         debug(PRINTF) printf("-_d_monitor_release(%p)\n", h);
169     }
170 }
171 
172 /* =============================== linux ============================ */
173 
174 version( USE_PTHREADS )
175 {
176     // Includes attribute fixes from David Friedman's GDC port
177     static pthread_mutex_t _monitor_critsec;
178     static pthread_mutexattr_t _monitors_attr;
179 
180     extern (C) void _STI_monitor_staticctor()
181     {
182         if (!inited)
183         {
184             pthread_mutexattr_init(&_monitors_attr);
185             pthread_mutexattr_settype(&_monitors_attr, PTHREAD_MUTEX_RECURSIVE);
186             pthread_mutex_init(&_monitor_critsec, &_monitors_attr);
187             inited = 1;
188         }
189     }
190 
191     extern (C) void _STD_monitor_staticdtor()
192     {
193         if (inited)
194         {
195             inited = 0;
196             pthread_mutex_destroy(&_monitor_critsec);
197             pthread_mutexattr_destroy(&_monitors_attr);
198         }
199     }
200 
201     extern (C) void _d_monitor_create(Object h)
202     {
203         /*
204          * NOTE: Assume this is only called when h.__monitor is null prior to the
205          * call.  However, please note that another thread may call this function
206          * at the same time, so we can not assert this here.  Instead, try and
207          * create a lock, and if one already exists then forget about it.
208          */
209 
210         debug(PRINTF) printf("+_d_monitor_create(%p)\n", h);
211         assert(h);
212         Monitor *cs;
213         pthread_mutex_lock(&_monitor_critsec);
214         if (!h.__monitor)
215         {
216             cs = cast(Monitor *)calloc(Monitor.sizeof, 1);
217             assert(cs);
218             pthread_mutex_init(&cs.mon, &_monitors_attr);
219             setMonitor(h, cs);
220             cs = null;
221         }
222         pthread_mutex_unlock(&_monitor_critsec);
223         if (cs)
224             free(cs);
225         debug(PRINTF) printf("-_d_monitor_create(%p)\n", h);
226     }
227 
228     extern (C) void _d_monitor_destroy(Object h)
229     {
230         debug(PRINTF) printf("+_d_monitor_destroy(%p)\n", h);
231         assert(h && h.__monitor && !getMonitor(h).impl);
232         pthread_mutex_destroy(&getMonitor(h).mon);
233         free(h.__monitor);
234         setMonitor(h, null);
235         debug(PRINTF) printf("-_d_monitor_destroy(%p)\n", h);
236     }
237 
238     extern (C) void _d_monitor_lock(Object h)
239     {
240         debug(PRINTF) printf("+_d_monitor_acquire(%p)\n", h);
241         assert(h && h.__monitor && !getMonitor(h).impl);
242         pthread_mutex_lock(&getMonitor(h).mon);
243         debug(PRINTF) printf("-_d_monitor_acquire(%p)\n", h);
244     }
245 
246     extern (C) void _d_monitor_unlock(Object h)
247     {
248         debug(PRINTF) printf("+_d_monitor_release(%p)\n", h);
249         assert(h && h.__monitor && !getMonitor(h).impl);
250         pthread_mutex_unlock(&getMonitor(h).mon);
251         debug(PRINTF) printf("-_d_monitor_release(%p)\n", h);
252     }
253 }
254 
255 /* ================================= No System ============================ */
256 
257 version( NoSystem )
258 {
259     void _STI_monitor_staticctor() { }
260     void _STD_monitor_staticdtor() { }
261 
262     void _d_monitor_create(Object h)
263     {
264         debug(PRINTF) printf("+_d_monitor_create(%p)\n", h);
265         assert(h);
266         Monitor *cs;
267         if (!h.__monitor)
268         {
269             cs = cast(Monitor *)calloc(Monitor.sizeof, 1);
270             assert(cs);
271             setMonitor(h, cs);
272             cs = null;
273         }
274         if (cs)
275             free(cs);
276         debug(PRINTF) printf("-_d_monitor_create(%p)\n", h);
277     }
278 
279     void _d_monitor_destroy(Object h)
280     {
281         debug(PRINTF) printf("+_d_monitor_destroy(%p)\n", h);
282         assert(h && h.__monitor && !getMonitor(h).impl);
283         free(h.__monitor);
284         setMonitor(h, null);
285         debug(PRINTF) printf("-_d_monitor_destroy(%p)\n", h);
286     }
287 
288     void _d_monitor_lock(Object h)
289     {
290         debug(PRINTF) printf("+_d_monitor_acquire(%p)\n", h);
291         assert(h && h.__monitor && !getMonitor(h).impl);
292         debug(PRINTF) printf("-_d_monitor_acquire(%p)\n", h);
293     }
294 
295     void _d_monitor_unlock(Object h)
296     {
297         debug(PRINTF) printf("+_d_monitor_release(%p)\n", h);
298         assert(h && h.__monitor && !getMonitor(h).impl);
299         debug(PRINTF) printf("-_d_monitor_release(%p)\n", h);
300     }
301 }
302 
303