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 ****************************************************************/
32 RtlInitializeResource(PRTL_RESOURCE Resource)
36 Status = RtlInitializeCriticalSection(&Resource->Lock);
37 if (!NT_SUCCESS(Status))
39 RtlRaiseStatus(Status);
42 Status = NtCreateSemaphore(&Resource->SharedSemaphore,
47 if (!NT_SUCCESS(Status))
49 RtlRaiseStatus(Status);
51 Resource->SharedWaiters = 0;
53 Status = NtCreateSemaphore(&Resource->ExclusiveSemaphore,
58 if (!NT_SUCCESS(Status))
60 RtlRaiseStatus(Status);
62 Resource->ExclusiveWaiters = 0;
64 Resource->NumberActive = 0;
65 Resource->OwningThread = NULL;
66 Resource->TimeoutBoost = 0; /* no info on this one, default value is 0 */
71 RtlDeleteResource(PRTL_RESOURCE Resource)
73 RtlDeleteCriticalSection(&Resource->Lock);
74 NtClose(Resource->ExclusiveSemaphore);
75 NtClose(Resource->SharedSemaphore);
76 Resource->OwningThread = NULL;
77 Resource->ExclusiveWaiters = 0;
78 Resource->SharedWaiters = 0;
79 Resource->NumberActive = 0;
84 RtlAcquireResourceExclusive(PRTL_RESOURCE Resource,
88 BOOLEAN retVal = FALSE;
91 RtlEnterCriticalSection(&Resource->Lock);
92 if (Resource->NumberActive == 0) /* lock is free */
94 Resource->NumberActive = -1;
97 else if (Resource->NumberActive < 0) /* exclusive lock in progress */
99 if (Resource->OwningThread == NtCurrentTeb()->Cid.UniqueThread)
102 Resource->NumberActive--;
108 Resource->ExclusiveWaiters++;
110 RtlLeaveCriticalSection(&Resource->Lock);
111 Status = NtWaitForSingleObject(Resource->ExclusiveSemaphore,
114 if (!NT_SUCCESS(Status))
116 goto start; /* restart the acquisition to avoid deadlocks */
119 else /* one or more shared locks are in progress */
125 Resource->OwningThread = NtCurrentTeb()->Cid.UniqueThread;
127 RtlLeaveCriticalSection(&Resource->Lock);
133 RtlAcquireResourceShared(PRTL_RESOURCE Resource,
136 NTSTATUS Status = STATUS_UNSUCCESSFUL;
137 BOOLEAN retVal = FALSE;
140 RtlEnterCriticalSection(&Resource->Lock);
141 if (Resource->NumberActive < 0)
143 if (Resource->OwningThread == NtCurrentTeb()->Cid.UniqueThread)
145 Resource->NumberActive--;
152 Resource->SharedWaiters++;
153 RtlLeaveCriticalSection(&Resource->Lock);
154 Status = NtWaitForSingleObject(Resource->SharedSemaphore,
157 if (!NT_SUCCESS(Status))
164 if (Status != STATUS_WAIT_0) /* otherwise RtlReleaseResource() has already done it */
165 Resource->NumberActive++;
169 RtlLeaveCriticalSection(&Resource->Lock);
175 RtlConvertExclusiveToShared(PRTL_RESOURCE Resource)
177 RtlEnterCriticalSection(&Resource->Lock);
179 if (Resource->NumberActive == -1)
181 Resource->OwningThread = NULL;
183 if (Resource->SharedWaiters > 0)
186 /* prevent new writers from joining until
187 * all queued readers have done their thing */
188 n = Resource->SharedWaiters;
189 Resource->NumberActive = Resource->SharedWaiters + 1;
190 Resource->SharedWaiters = 0;
191 NtReleaseSemaphore(Resource->SharedSemaphore,
197 Resource->NumberActive = 1;
201 RtlLeaveCriticalSection(&Resource->Lock);
206 RtlConvertSharedToExclusive(PRTL_RESOURCE Resource)
210 RtlEnterCriticalSection(&Resource->Lock);
212 if (Resource->NumberActive == 1)
214 Resource->OwningThread = NtCurrentTeb()->Cid.UniqueThread;
215 Resource->NumberActive = -1;
219 Resource->ExclusiveWaiters++;
221 RtlLeaveCriticalSection(&Resource->Lock);
222 Status = NtWaitForSingleObject(Resource->ExclusiveSemaphore,
225 if (!NT_SUCCESS(Status))
228 RtlEnterCriticalSection(&Resource->Lock);
229 Resource->OwningThread = NtCurrentTeb()->Cid.UniqueThread;
230 Resource->NumberActive = -1;
232 RtlLeaveCriticalSection(&Resource->Lock);
237 RtlReleaseResource(PRTL_RESOURCE Resource)
239 RtlEnterCriticalSection(&Resource->Lock);
241 if (Resource->NumberActive > 0) /* have one or more readers */
243 Resource->NumberActive--;
244 if (Resource->NumberActive == 0)
246 if (Resource->ExclusiveWaiters > 0)
249 Resource->ExclusiveWaiters--;
250 NtReleaseSemaphore(Resource->ExclusiveSemaphore,
256 else if (Resource->NumberActive < 0) /* have a writer, possibly recursive */
258 Resource->NumberActive++;
259 if (Resource->NumberActive == 0)
261 Resource->OwningThread = 0;
262 if (Resource->ExclusiveWaiters > 0)
268 if (Resource->SharedWaiters > 0)
271 /* prevent new writers from joining until
272 * all queued readers have done their thing */
273 n = Resource->SharedWaiters;
274 Resource->NumberActive = Resource->SharedWaiters;
275 Resource->SharedWaiters = 0;
276 NtReleaseSemaphore(Resource->SharedSemaphore,
283 RtlLeaveCriticalSection(&Resource->Lock);
288 RtlDumpResource(PRTL_RESOURCE Resource)
290 DbgPrint("RtlDumpResource(%p):\n\tactive count = %i\n\twaiting readers = %i\n\twaiting writers = %i\n",
292 Resource->NumberActive,
293 Resource->SharedWaiters,
294 Resource->ExclusiveWaiters);
295 if (Resource->NumberActive != 0)
297 DbgPrint("\towner thread = %08x\n",
298 Resource->OwningThread);