1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS system libraries 4 * FILE: lib/rtl/resource.c 5 * PURPOSE: Resource (multiple-reader-single-writer lock) functions 6 * PROGRAMMER: Partially takem from Wine: 7 * Copyright 1996-1998 Marcus Meissner 8 * 1999 Alex Korobka 9 */ 10 11 /* INCLUDES *****************************************************************/ 12 13 #include <rtl.h> 14 15 #define NDEBUG 16 #include <debug.h> 17 18 /* FUNCTIONS ***************************************************************/ 19 20 /* 21 * @implemented 22 */ 23 VOID 24 NTAPI 25 RtlInitializeResource(PRTL_RESOURCE Resource) 26 { 27 NTSTATUS Status; 28 29 Status = RtlInitializeCriticalSection(&Resource->Lock); 30 if (!NT_SUCCESS(Status)) 31 { 32 RtlRaiseStatus(Status); 33 } 34 35 Status = NtCreateSemaphore(&Resource->SharedSemaphore, 36 SEMAPHORE_ALL_ACCESS, 37 NULL, 38 0, 39 65535); 40 if (!NT_SUCCESS(Status)) 41 { 42 RtlRaiseStatus(Status); 43 } 44 Resource->SharedWaiters = 0; 45 46 Status = NtCreateSemaphore(&Resource->ExclusiveSemaphore, 47 SEMAPHORE_ALL_ACCESS, 48 NULL, 49 0, 50 65535); 51 if (!NT_SUCCESS(Status)) 52 { 53 RtlRaiseStatus(Status); 54 } 55 56 Resource->ExclusiveWaiters = 0; 57 Resource->NumberActive = 0; 58 Resource->OwningThread = NULL; 59 Resource->TimeoutBoost = 0; /* no info on this one, default value is 0 */ 60 } 61 62 63 /* 64 * @implemented 65 */ 66 VOID 67 NTAPI 68 RtlDeleteResource(PRTL_RESOURCE Resource) 69 { 70 RtlDeleteCriticalSection(&Resource->Lock); 71 NtClose(Resource->ExclusiveSemaphore); 72 NtClose(Resource->SharedSemaphore); 73 Resource->OwningThread = NULL; 74 Resource->ExclusiveWaiters = 0; 75 Resource->SharedWaiters = 0; 76 Resource->NumberActive = 0; 77 } 78 79 80 /* 81 * @implemented 82 */ 83 BOOLEAN 84 NTAPI 85 RtlAcquireResourceExclusive( 86 PRTL_RESOURCE Resource, 87 BOOLEAN Wait) 88 { 89 NTSTATUS Status; 90 BOOLEAN retVal = FALSE; 91 92 start: 93 RtlEnterCriticalSection(&Resource->Lock); 94 if (Resource->NumberActive == 0) /* lock is free */ 95 { 96 Resource->NumberActive = -1; 97 retVal = TRUE; 98 } 99 else if (Resource->NumberActive < 0) /* exclusive lock in progress */ 100 { 101 if (Resource->OwningThread == NtCurrentTeb()->ClientId.UniqueThread) 102 { 103 retVal = TRUE; 104 Resource->NumberActive--; 105 goto done; 106 } 107 wait: 108 if (Wait) 109 { 110 Resource->ExclusiveWaiters++; 111 112 RtlLeaveCriticalSection(&Resource->Lock); 113 Status = NtWaitForSingleObject(Resource->ExclusiveSemaphore, 114 FALSE, 115 NULL); 116 if (!NT_SUCCESS(Status)) 117 goto done; 118 goto start; /* restart the acquisition to avoid deadlocks */ 119 } 120 } 121 else /* one or more shared locks are in progress */ 122 { 123 if (Wait) 124 goto wait; 125 } 126 if (retVal) 127 Resource->OwningThread = NtCurrentTeb()->ClientId.UniqueThread; 128 done: 129 RtlLeaveCriticalSection(&Resource->Lock); 130 return retVal; 131 } 132 133 134 /* 135 * @implemented 136 */ 137 BOOLEAN 138 NTAPI 139 RtlAcquireResourceShared( 140 PRTL_RESOURCE Resource, 141 BOOLEAN Wait) 142 { 143 NTSTATUS Status = STATUS_UNSUCCESSFUL; 144 BOOLEAN retVal = FALSE; 145 146 start: 147 RtlEnterCriticalSection(&Resource->Lock); 148 if (Resource->NumberActive < 0) 149 { 150 if (Resource->OwningThread == NtCurrentTeb()->ClientId.UniqueThread) 151 { 152 Resource->NumberActive--; 153 retVal = TRUE; 154 goto done; 155 } 156 157 if (Wait) 158 { 159 Resource->SharedWaiters++; 160 RtlLeaveCriticalSection(&Resource->Lock); 161 Status = NtWaitForSingleObject(Resource->SharedSemaphore, 162 FALSE, 163 NULL); 164 if (!NT_SUCCESS(Status)) 165 goto done; 166 goto start; 167 } 168 } 169 else 170 { 171 if (Status != STATUS_WAIT_0) /* otherwise RtlReleaseResource() has already done it */ 172 Resource->NumberActive++; 173 retVal = TRUE; 174 } 175 done: 176 RtlLeaveCriticalSection(&Resource->Lock); 177 return retVal; 178 } 179 180 181 /* 182 * @implemented 183 */ 184 VOID 185 NTAPI 186 RtlConvertExclusiveToShared(PRTL_RESOURCE Resource) 187 { 188 RtlEnterCriticalSection(&Resource->Lock); 189 190 if (Resource->NumberActive == -1) 191 { 192 Resource->OwningThread = NULL; 193 194 if (Resource->SharedWaiters > 0) 195 { 196 ULONG n; 197 /* prevent new writers from joining until 198 * all queued readers have done their thing */ 199 n = Resource->SharedWaiters; 200 Resource->NumberActive = Resource->SharedWaiters + 1; 201 Resource->SharedWaiters = 0; 202 NtReleaseSemaphore(Resource->SharedSemaphore, 203 n, 204 NULL); 205 } 206 else 207 { 208 Resource->NumberActive = 1; 209 } 210 } 211 212 RtlLeaveCriticalSection(&Resource->Lock); 213 } 214 215 216 /* 217 * @implemented 218 */ 219 VOID 220 NTAPI 221 RtlConvertSharedToExclusive(PRTL_RESOURCE Resource) 222 { 223 NTSTATUS Status; 224 225 RtlEnterCriticalSection(&Resource->Lock); 226 227 if (Resource->NumberActive == 1) 228 { 229 Resource->OwningThread = NtCurrentTeb()->ClientId.UniqueThread; 230 Resource->NumberActive = -1; 231 } 232 else 233 { 234 Resource->ExclusiveWaiters++; 235 236 RtlLeaveCriticalSection(&Resource->Lock); 237 Status = NtWaitForSingleObject(Resource->ExclusiveSemaphore, 238 FALSE, 239 NULL); 240 if (!NT_SUCCESS(Status)) 241 return; 242 243 RtlEnterCriticalSection(&Resource->Lock); 244 Resource->OwningThread = NtCurrentTeb()->ClientId.UniqueThread; 245 Resource->NumberActive = -1; 246 } 247 RtlLeaveCriticalSection(&Resource->Lock); 248 } 249 250 251 /* 252 * @implemented 253 */ 254 VOID 255 NTAPI 256 RtlReleaseResource(PRTL_RESOURCE Resource) 257 { 258 RtlEnterCriticalSection(&Resource->Lock); 259 260 if (Resource->NumberActive > 0) /* have one or more readers */ 261 { 262 Resource->NumberActive--; 263 if (Resource->NumberActive == 0) 264 { 265 if (Resource->ExclusiveWaiters > 0) 266 { 267 wake_exclusive: 268 Resource->ExclusiveWaiters--; 269 NtReleaseSemaphore(Resource->ExclusiveSemaphore, 270 1, 271 NULL); 272 } 273 } 274 } 275 else if (Resource->NumberActive < 0) /* have a writer, possibly recursive */ 276 { 277 Resource->NumberActive++; 278 if (Resource->NumberActive == 0) 279 { 280 Resource->OwningThread = 0; 281 if (Resource->ExclusiveWaiters > 0) 282 { 283 goto wake_exclusive; 284 } 285 else 286 { 287 if (Resource->SharedWaiters > 0) 288 { 289 ULONG n; 290 /* prevent new writers from joining until 291 * all queued readers have done their thing */ 292 n = Resource->SharedWaiters; 293 Resource->NumberActive = Resource->SharedWaiters; 294 Resource->SharedWaiters = 0; 295 NtReleaseSemaphore(Resource->SharedSemaphore, 296 n, 297 NULL); 298 } 299 } 300 } 301 } 302 RtlLeaveCriticalSection(&Resource->Lock); 303 } 304 305 306 /* 307 * @implemented 308 */ 309 VOID 310 NTAPI 311 RtlDumpResource(PRTL_RESOURCE Resource) 312 { 313 DbgPrint("RtlDumpResource(%p):\n\tactive count = %d\n\twaiting readers = %u\n\twaiting writers = %u\n", 314 Resource, 315 Resource->NumberActive, 316 Resource->SharedWaiters, 317 Resource->ExclusiveWaiters); 318 319 if (Resource->NumberActive != 0) 320 { 321 DbgPrint("\towner thread = %p\n", 322 Resource->OwningThread); 323 } 324 } 325 326 /* EOF */ 327