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 }