1 /**
2  * Implementation of support routines for synchronized blocks.
3  *
4  * Copyright: Copyright Digital Mars 2000 - 2011.
5  * License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
6  * Authors:   Walter Bright, Sean Kelly
7  * Source: $(DRUNTIMESRC rt/_critical_.d)
8  */
9 
10 /*          Copyright Digital Mars 2000 - 2011.
11  * Distributed under the Boost Software License, Version 1.0.
12  *    (See accompanying file LICENSE or copy at
13  *          http://www.boost.org/LICENSE_1_0.txt)
14  */
15 module rt.critical_;
16 
17 nothrow:
18 
19 import rt.monitor_, core.atomic;
20 
21 extern (C) void _d_critical_init() @nogc nothrow
22 {
23     initMutex(cast(Mutex*)&gcs.mtx);
24     head = &gcs;
25 }
26 
27 extern (C) void _d_critical_term() @nogc nothrow
28 {
29     // This function is only ever called by the runtime shutdown code
30     // and therefore is single threaded so the following cast is fine.
31     auto h = cast()head;
32     for (auto p = h; p; p = p.next)
33         destroyMutex(cast(Mutex*)&p.mtx);
34 }
35 
36 extern (C) void _d_criticalenter(D_CRITICAL_SECTION* cs)
37 {
38     assert(cs !is null);
39     ensureMutex(cast(shared(D_CRITICAL_SECTION*)) cs);
40     lockMutex(&cs.mtx);
41 }
42 
43 extern (C) void _d_criticalenter2(D_CRITICAL_SECTION** pcs)
44 {
45     if (atomicLoad!(MemoryOrder.acq)(*cast(shared) pcs) is null)
46     {
47         lockMutex(cast(Mutex*)&gcs.mtx);
48         if (atomicLoad!(MemoryOrder.raw)(*cast(shared) pcs) is null)
49         {
50             auto cs = new shared D_CRITICAL_SECTION;
51             initMutex(cast(Mutex*)&cs.mtx);
52             atomicStore!(MemoryOrder.rel)(*cast(shared) pcs, cs);
53         }
54         unlockMutex(cast(Mutex*)&gcs.mtx);
55     }
56     lockMutex(&(*pcs).mtx);
57 }
58 
59 extern (C) void _d_criticalexit(D_CRITICAL_SECTION* cs)
60 {
61     assert(cs !is null);
62     unlockMutex(&cs.mtx);
63 }
64 
65 private:
66 
67 shared D_CRITICAL_SECTION* head;
68 shared D_CRITICAL_SECTION gcs;
69 
70 struct D_CRITICAL_SECTION
71 {
72     D_CRITICAL_SECTION* next;
73     Mutex mtx;
74 }
75 
76 void ensureMutex(shared(D_CRITICAL_SECTION)* cs)
77 {
78     if (atomicLoad!(MemoryOrder.acq)(cs.next) is null)
79     {
80         lockMutex(cast(Mutex*)&gcs.mtx);
81         if (atomicLoad!(MemoryOrder.raw)(cs.next) is null)
82         {
83             initMutex(cast(Mutex*)&cs.mtx);
84             auto ohead = head;
85             head = cs;
86             atomicStore!(MemoryOrder.rel)(cs.next, ohead);
87         }
88         unlockMutex(cast(Mutex*)&gcs.mtx);
89     }
90 }