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