3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/ntdll/rtl/resource.c
6 * PURPOSE: Resource (multiple-reader-single-writer lock) functions
11 * NOTES: Partially take from Wine:
12 * Copyright 1996-1998 Marcus Meissner
17 * xxxResource() functions implement multiple-reader-single-writer lock.
18 * The code is based on information published in WDJ January 1999 issue.
21 #include <ddk/ntddk.h>
22 #include <ntdll/rtl.h>
23 #include <ntos/synch.h>
26 #include <ntdll/ntdll.h>
29 /* FUNCTIONS ****************************************************************/
35 RtlInitializeResource(PRTL_RESOURCE Resource)
39 Status = RtlInitializeCriticalSection(&Resource->Lock);
40 if (!NT_SUCCESS(Status))
42 RtlRaiseStatus(Status);
45 Status = NtCreateSemaphore(&Resource->SharedSemaphore,
50 if (!NT_SUCCESS(Status))
52 RtlRaiseStatus(Status);
54 Resource->SharedWaiters = 0;
56 Status = NtCreateSemaphore(&Resource->ExclusiveSemaphore,
61 if (!NT_SUCCESS(Status))
63 RtlRaiseStatus(Status);
65 Resource->ExclusiveWaiters = 0;
67 Resource->NumberActive = 0;
68 Resource->OwningThread = NULL;
69 Resource->TimeoutBoost = 0; /* no info on this one, default value is 0 */
77 RtlDeleteResource(PRTL_RESOURCE Resource)
79 RtlDeleteCriticalSection(&Resource->Lock);
80 NtClose(Resource->ExclusiveSemaphore);
81 NtClose(Resource->SharedSemaphore);
82 Resource->OwningThread = NULL;
83 Resource->ExclusiveWaiters = 0;
84 Resource->SharedWaiters = 0;
85 Resource->NumberActive = 0;
93 RtlAcquireResourceExclusive(PRTL_RESOURCE Resource,
97 BOOLEAN retVal = FALSE;
100 RtlEnterCriticalSection(&Resource->Lock);
101 if (Resource->NumberActive == 0) /* lock is free */
103 Resource->NumberActive = -1;
106 else if (Resource->NumberActive < 0) /* exclusive lock in progress */
108 if (Resource->OwningThread == NtCurrentTeb()->Cid.UniqueThread)
111 Resource->NumberActive--;
117 Resource->ExclusiveWaiters++;
119 RtlLeaveCriticalSection(&Resource->Lock);
120 Status = NtWaitForSingleObject(Resource->ExclusiveSemaphore,
123 if (!NT_SUCCESS(Status))
125 goto start; /* restart the acquisition to avoid deadlocks */
128 else /* one or more shared locks are in progress */
134 Resource->OwningThread = NtCurrentTeb()->Cid.UniqueThread;
136 RtlLeaveCriticalSection(&Resource->Lock);
145 RtlAcquireResourceShared(PRTL_RESOURCE Resource,
148 NTSTATUS Status = STATUS_UNSUCCESSFUL;
149 BOOLEAN retVal = FALSE;
152 RtlEnterCriticalSection(&Resource->Lock);
153 if (Resource->NumberActive < 0)
155 if (Resource->OwningThread == NtCurrentTeb()->Cid.UniqueThread)
157 Resource->NumberActive--;
164 Resource->SharedWaiters++;
165 RtlLeaveCriticalSection(&Resource->Lock);
166 Status = NtWaitForSingleObject(Resource->SharedSemaphore,
169 if (!NT_SUCCESS(Status))
176 if (Status != STATUS_WAIT_0) /* otherwise RtlReleaseResource() has already done it */
177 Resource->NumberActive++;
181 RtlLeaveCriticalSection(&Resource->Lock);
190 RtlConvertExclusiveToShared(PRTL_RESOURCE Resource)
192 RtlEnterCriticalSection(&Resource->Lock);
194 if (Resource->NumberActive == -1)
196 Resource->OwningThread = NULL;
198 if (Resource->SharedWaiters > 0)
201 /* prevent new writers from joining until
202 * all queued readers have done their thing */
203 n = Resource->SharedWaiters;
204 Resource->NumberActive = Resource->SharedWaiters + 1;
205 Resource->SharedWaiters = 0;
206 NtReleaseSemaphore(Resource->SharedSemaphore,
212 Resource->NumberActive = 1;
216 RtlLeaveCriticalSection(&Resource->Lock);
224 RtlConvertSharedToExclusive(PRTL_RESOURCE Resource)
228 RtlEnterCriticalSection(&Resource->Lock);
230 if (Resource->NumberActive == 1)
232 Resource->OwningThread = NtCurrentTeb()->Cid.UniqueThread;
233 Resource->NumberActive = -1;
237 Resource->ExclusiveWaiters++;
239 RtlLeaveCriticalSection(&Resource->Lock);
240 Status = NtWaitForSingleObject(Resource->ExclusiveSemaphore,
243 if (!NT_SUCCESS(Status))
246 RtlEnterCriticalSection(&Resource->Lock);
247 Resource->OwningThread = NtCurrentTeb()->Cid.UniqueThread;
248 Resource->NumberActive = -1;
250 RtlLeaveCriticalSection(&Resource->Lock);
258 RtlReleaseResource(PRTL_RESOURCE Resource)
260 RtlEnterCriticalSection(&Resource->Lock);
262 if (Resource->NumberActive > 0) /* have one or more readers */
264 Resource->NumberActive--;
265 if (Resource->NumberActive == 0)
267 if (Resource->ExclusiveWaiters > 0)
270 Resource->ExclusiveWaiters--;
271 NtReleaseSemaphore(Resource->ExclusiveSemaphore,
277 else if (Resource->NumberActive < 0) /* have a writer, possibly recursive */
279 Resource->NumberActive++;
280 if (Resource->NumberActive == 0)
282 Resource->OwningThread = 0;
283 if (Resource->ExclusiveWaiters > 0)
289 if (Resource->SharedWaiters > 0)
292 /* prevent new writers from joining until
293 * all queued readers have done their thing */
294 n = Resource->SharedWaiters;
295 Resource->NumberActive = Resource->SharedWaiters;
296 Resource->SharedWaiters = 0;
297 NtReleaseSemaphore(Resource->SharedSemaphore,
304 RtlLeaveCriticalSection(&Resource->Lock);
312 RtlDumpResource(PRTL_RESOURCE Resource)
314 DbgPrint("RtlDumpResource(%p):\n\tactive count = %i\n\twaiting readers = %i\n\twaiting writers = %i\n",
316 Resource->NumberActive,
317 Resource->SharedWaiters,
318 Resource->ExclusiveWaiters);
319 if (Resource->NumberActive != 0)
321 DbgPrint("\towner thread = %08x\n",
322 Resource->OwningThread);