2 * Contains the implementation for object monitors.
4 * Copyright: Copyright Digital Mars 2000 - 2015.
5 * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
6 * Authors: Walter Bright, Sean Kelly, Martin Nowak
7 * Source: $(DRUNTIMESRC rt/_monitor_.d)
10 /* NOTE: This file has been patched from the original DMD distribution to
11 * work with the GDC compiler.
15 import core
.atomic
, core
.stdc
.stdlib
, core
.stdc
.string
;
17 // NOTE: The dtor callback feature is only supported for monitors that are not
18 // supplied by the user. The assumption is that any object with a user-
19 // supplied monitor may have special storage or lifetime requirements and
20 // that as a result, storing references to local objects within Monitor
21 // may not be safe or desirable. Thus, devt is only valid if impl is
24 extern (C
) void _d_setSameMutex(shared Object ownee
, shared Object owner
) nothrow
27 assert(ownee
.__monitor
is null);
31 auto m
= ensureMonitor(cast(Object
) owner
);
34 atomicOp
!("+=")(m
.refs
, cast(size_t
) 1);
36 // Assume the monitor is garbage collected and simply copy the reference.
37 ownee
.__monitor
= owner
.__monitor
;
40 extern (C
) void _d_monitordelete(Object h
, bool det
)
42 auto m
= getMonitor(h
);
48 // let the GC collect the monitor
51 else if (!atomicOp
!("-=")(m
.refs
, cast(size_t
) 1))
53 // refcount == 0 means unshared => no synchronization required
54 disposeEvent(cast(Monitor
*) m
, h
);
55 deleteMonitor(cast(Monitor
*) m
);
60 // does not call dispose events, for internal use only
61 extern (C
) void _d_monitordelete_nogc(Object h
) @nogc
63 auto m
= getMonitor(h
);
69 // let the GC collect the monitor
72 else if (!atomicOp
!("-=")(m
.refs
, cast(size_t
) 1))
74 // refcount == 0 means unshared => no synchronization required
75 deleteMonitor(cast(Monitor
*) m
);
80 extern (C
) void _d_monitorenter(Object h
)
83 assert(h
!is null, "Synchronized object must not be null.");
87 auto m
= cast(Monitor
*) ensureMonitor(h
);
95 extern (C
) void _d_monitorexit(Object h
)
97 auto m
= cast(Monitor
*) getMonitor(h
);
105 extern (C
) void rt_attachDisposeEvent(Object h
, DEvent e
)
109 auto m
= cast(Monitor
*) getMonitor(h
);
110 assert(m
.impl
is null);
112 foreach (ref v
; m
.devt
)
114 if (v
is null || v
== e
)
121 auto len
= m
.devt
.length
+ 4; // grow by 4 elements
122 auto pos
= m
.devt
.length
; // insert position
123 auto p
= realloc(m
.devt
.ptr
, DEvent
.sizeof
* len
);
124 import core
.exception
: onOutOfMemoryError
;
127 onOutOfMemoryError();
128 m
.devt
= (cast(DEvent
*) p
)[0 .. len
];
129 m
.devt
[pos
+ 1 .. len
] = null;
134 extern (C
) void rt_detachDisposeEvent(Object h
, DEvent e
)
138 auto m
= cast(Monitor
*) getMonitor(h
);
139 assert(m
.impl
is null);
141 foreach (p
, v
; m
.devt
)
145 memmove(&m
.devt
[p
], &m
.devt
[p
+ 1], (m
.devt
.length
- p
- 1) * DEvent
.sizeof
);
146 m
.devt
[$ - 1] = null;
155 extern (C
) void _d_monitor_staticctor()
159 pthread_mutexattr_init(&gattr
);
160 pthread_mutexattr_settype(&gattr
, PTHREAD_MUTEX_RECURSIVE
);
165 extern (C
) void _d_monitor_staticdtor()
169 pthread_mutexattr_destroy(&gattr
);
174 // This is what the monitor reference in Object points to
175 alias IMonitor
= Object
.Monitor
;
176 alias DEvent
= void delegate(Object
);
181 static if (GNU_Thread_Model
== ThreadModel
.Single
)
182 version = SingleThreaded
;
183 // Ignore ThreadModel, we don't want posix threads on windows and
184 // will always use native threading instead.
187 version (SingleThreaded
)
192 void initMutex(Mutex
* mtx
)
196 void destroyMutex(Mutex
* mtx
)
200 void lockMutex(Mutex
* mtx
)
204 void unlockMutex(Mutex
* mtx
)
208 else version (Windows
)
210 version (CRuntime_DigitalMars
)
212 pragma(lib
, "snn.lib");
214 import core
.sys
.windows
.winbase
/+: CRITICAL_SECTION, DeleteCriticalSection,
215 EnterCriticalSection, InitializeCriticalSection, LeaveCriticalSection+/;
217 alias Mutex
= CRITICAL_SECTION
;
219 alias initMutex
= InitializeCriticalSection
;
220 alias destroyMutex
= DeleteCriticalSection
;
221 alias lockMutex
= EnterCriticalSection
;
222 alias unlockMutex
= LeaveCriticalSection
;
226 import core
.sys
.posix
.pthread
;
229 alias Mutex
= pthread_mutex_t
;
230 __gshared pthread_mutexattr_t gattr
;
232 void initMutex(pthread_mutex_t
* mtx
)
234 pthread_mutex_init(mtx
, &gattr
) && assert(0);
237 void destroyMutex(pthread_mutex_t
* mtx
)
239 pthread_mutex_destroy(mtx
) && assert(0);
242 void lockMutex(pthread_mutex_t
* mtx
)
244 pthread_mutex_lock(mtx
) && assert(0);
247 void unlockMutex(pthread_mutex_t
* mtx
)
249 pthread_mutex_unlock(mtx
) && assert(0);
254 static assert(0, "Unsupported platform");
259 IMonitor impl
; // for user-level monitors
260 DEvent
[] devt
; // for internal monitors
261 size_t refs
; // reference count
267 @property ref shared(Monitor
*) monitor(return scope Object h
) pure nothrow @nogc
269 return *cast(shared Monitor
**)&h
.__monitor
;
272 private shared(Monitor
)* getMonitor(Object h
) pure @nogc
274 return atomicLoad
!(MemoryOrder
.acq
)(h
.monitor);
277 void setMonitor(Object h
, shared(Monitor
)* m
) pure @nogc
279 atomicStore
!(MemoryOrder
.rel
)(h
.monitor, m
);
282 __gshared Mutex gmtx
;
284 shared(Monitor
)* ensureMonitor(Object h
)
286 if (auto m
= getMonitor(h
))
289 auto m
= cast(Monitor
*) calloc(Monitor
.sizeof
, 1);
295 if (getMonitor(h
) is null)
298 setMonitor(h
, cast(shared) m
);
305 // Set the finalize bit so that the monitor gets collected (Bugzilla 14573)
306 import core
.memory
: GC
;
308 if (!(typeid(h
).m_flags
& TypeInfo_Class
.ClassFlags
.hasDtor
))
309 GC
.setAttr(cast(void*) h
, GC
.BlkAttr
.FINALIZE
);
310 return cast(shared(Monitor
)*) m
;
312 else // another thread succeeded instead
315 return getMonitor(h
);
319 void deleteMonitor(Monitor
* m
) @nogc
321 destroyMutex(&m
.mtx
);
325 void disposeEvent(Monitor
* m
, Object h
)
339 import core
.memory
: GC
;
341 auto obj
= new Object
;
342 assert(!(GC
.getAttr(cast(void*) obj
) & GC
.BlkAttr
.FINALIZE
));
344 assert(getMonitor(obj
) !is null);
345 assert(GC
.getAttr(cast(void*) obj
) & GC
.BlkAttr
.FINALIZE
);