1 /**
2  * Implementation of support routines for synchronized blocks.
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.critical_;
14 
15 private
16 {
17     debug(PRINTF) import tango.stdc.stdio;
18     import tango.stdc.stdlib;
19 
20     version( linux )
21     {
22         version = USE_PTHREADS;
23     }
24     else version( FreeBSD )
25     {
26         version = USE_PTHREADS;
27     }
28     else version( OSX )
29     {
30         version = USE_PTHREADS;
31     }
32     else version( Solaris )
33     {
34         version = USE_PTHREADS;
35     }
36 
37     version( Windows )
38     {
39         import tango.sys.win32.UserGdi;
40 
41         /* We don't initialize critical sections unless we actually need them.
42          * So keep a linked list of the ones we do use, and in the static destructor
43          * code, walk the list and release them.
44          */
45         struct D_CRITICAL_SECTION
46         {
47             D_CRITICAL_SECTION *next;
48             CRITICAL_SECTION cs;
49         }
50     }
51     else version( USE_PTHREADS )
52     {
53         import tango.stdc.posix.pthread;
54 
55         /* We don't initialize critical sections unless we actually need them.
56          * So keep a linked list of the ones we do use, and in the static destructor
57          * code, walk the list and release them.
58          */
59         struct D_CRITICAL_SECTION
60         {
61             D_CRITICAL_SECTION *next;
62             pthread_mutex_t cs;
63         }
64     }
65     else
66     {
67         /* Define a stub type for systems that don't support.  */
68         version = NoSystem;
69 
70         struct D_CRITICAL_SECTION
71         {
72         }
73     }
74 }
75 
76 
77 /* ================================= Win32 ============================ */
78 
79 version( Windows )
80 {
81     /******************************************
82      * Enter/exit critical section.
83      */
84 
85     static D_CRITICAL_SECTION *dcs_list;
86     static D_CRITICAL_SECTION critical_section;
87     static int inited;
88 
89     extern (C) void _d_criticalenter(D_CRITICAL_SECTION *dcs)
90     {
91         debug(PRINTF) printf("_d_criticalenter(dcs = x%x)\n", dcs);
92         if (!dcs.next)
93         {
94             EnterCriticalSection(&critical_section.cs);
95             if (!dcs.next) // if, in the meantime, another thread didn't set it
96             {
97                 dcs.next = dcs_list;
98                 dcs_list = dcs;
99                 InitializeCriticalSection(&dcs.cs);
100             }
101             LeaveCriticalSection(&critical_section.cs);
102         }
103         EnterCriticalSection(&dcs.cs);
104     }
105 
106     extern (C) void _d_criticalexit(D_CRITICAL_SECTION *dcs)
107     {
108         debug(PRINTF) printf("_d_criticalexit(dcs = x%x)\n", dcs);
109         LeaveCriticalSection(&dcs.cs);
110     }
111 
112     extern (C) void _STI_critical_init()
113     {
114         if (!inited)
115         {
116             debug(PRINTF) printf("_STI_critical_init()\n");
117             InitializeCriticalSection(&critical_section.cs);
118             dcs_list = &critical_section;
119             inited = 1;
120         }
121     }
122 
123     extern (C) void _STD_critical_term()
124     {
125         if (inited)
126         {
127             debug(PRINTF) printf("_STI_critical_term()\n");
128             while (dcs_list)
129             {
130                 debug(PRINTF) printf("\tlooping... %x\n", dcs_list);
131                 DeleteCriticalSection(&dcs_list.cs);
132                 dcs_list = dcs_list.next;
133             }
134             inited = 0;
135         }
136     }
137 }
138 
139 /* ================================= linux ============================ */
140 
141 version( USE_PTHREADS )
142 {
143     /******************************************
144      * Enter/exit critical section.
145      */
146 
147     static D_CRITICAL_SECTION *dcs_list;
148     static D_CRITICAL_SECTION critical_section;
149     static pthread_mutexattr_t _criticals_attr;
150 
151     extern (C) void _d_criticalenter(D_CRITICAL_SECTION *dcs)
152     {
153         if (!dcs_list)
154         {
155             _STI_critical_init();
156             atexit(&_STD_critical_term);
157         }
158         debug(PRINTF) printf("_d_criticalenter(dcs = x%x)\n", dcs);
159         if (!dcs.next)
160         {
161             pthread_mutex_lock(&critical_section.cs);
162             if (!dcs.next) // if, in the meantime, another thread didn't set it
163             {
164                 dcs.next = dcs_list;
165                 dcs_list = dcs;
166                 pthread_mutex_init(&dcs.cs, &_criticals_attr);
167             }
168             pthread_mutex_unlock(&critical_section.cs);
169         }
170         pthread_mutex_lock(&dcs.cs);
171     }
172 
173     extern (C) void _d_criticalexit(D_CRITICAL_SECTION *dcs)
174     {
175         debug(PRINTF) printf("_d_criticalexit(dcs = x%x)\n", dcs);
176         pthread_mutex_unlock(&dcs.cs);
177     }
178 
179     extern (C) void _STI_critical_init()
180     {
181         if (!dcs_list)
182         {
183             debug(PRINTF) printf("_STI_critical_init()\n");
184             pthread_mutexattr_init(&_criticals_attr);
185             pthread_mutexattr_settype(&_criticals_attr, PTHREAD_MUTEX_RECURSIVE);
186 
187             // The global critical section doesn't need to be recursive
188             pthread_mutex_init(&critical_section.cs, null);
189             dcs_list = &critical_section;
190         }
191     }
192 
193     extern (C) void _STD_critical_term()
194     {
195         if (dcs_list)
196         {
197             debug(PRINTF) printf("_STI_critical_term()\n");
198             while (dcs_list)
199             {
200                 debug(PRINTF) printf("\tlooping... %x\n", dcs_list);
201                 pthread_mutex_destroy(&dcs_list.cs);
202                 dcs_list = dcs_list.next;
203             }
204         }
205     }
206 }
207 
208 /* ================================= NoSystem ============================ */
209 
210 version( NoSystem )
211 {
212     void _STI_critical_init() { }
213     void _STD_critical_term() { }
214 
215     void _d_criticalenter(D_CRITICAL_SECTION *dcs)
216     {
217     }
218 
219     void _d_criticalexit(D_CRITICAL_SECTION *dcs)
220     {
221     }
222 }