Reverted latest changes.
[reactos.git] / reactos / lib / ntdll / rtl / resource.c
1 /* $Id: resource.c,v 1.3 2002/09/08 10:23:06 chorns Exp $
2 *
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
7 * PROGRAMMER:
8 * UPDATE HISTORY:
9 * Created 24/05/2001
10 *
11 * NOTES: Partially take from Wine:
12 * Copyright 1996-1998 Marcus Meissner
13 * 1999 Alex Korobka
14 */
15
16 /*
17 * xxxResource() functions implement multiple-reader-single-writer lock.
18 * The code is based on information published in WDJ January 1999 issue.
19 */
20
21 #include <ddk/ntddk.h>
22 #include <ntdll/rtl.h>
23 #include <ntos/synch.h>
24
25 #define NDEBUG
26 #include <ntdll/ntdll.h>
27
28
29 /* FUNCTIONS ****************************************************************/
30
31 VOID STDCALL
32 RtlInitializeResource(PRTL_RESOURCE Resource)
33 {
34 NTSTATUS Status;
35
36 Status = RtlInitializeCriticalSection(&Resource->Lock);
37 if (!NT_SUCCESS(Status))
38 {
39 RtlRaiseStatus(Status);
40 }
41
42 Status = NtCreateSemaphore(&Resource->SharedSemaphore,
43 SEMAPHORE_ALL_ACCESS,
44 NULL,
45 0,
46 65535);
47 if (!NT_SUCCESS(Status))
48 {
49 RtlRaiseStatus(Status);
50 }
51 Resource->SharedWaiters = 0;
52
53 Status = NtCreateSemaphore(&Resource->ExclusiveSemaphore,
54 SEMAPHORE_ALL_ACCESS,
55 NULL,
56 0,
57 65535);
58 if (!NT_SUCCESS(Status))
59 {
60 RtlRaiseStatus(Status);
61 }
62 Resource->ExclusiveWaiters = 0;
63
64 Resource->NumberActive = 0;
65 Resource->OwningThread = NULL;
66 Resource->TimeoutBoost = 0; /* no info on this one, default value is 0 */
67 }
68
69
70 VOID STDCALL
71 RtlDeleteResource(PRTL_RESOURCE Resource)
72 {
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;
80 }
81
82
83 BOOLEAN STDCALL
84 RtlAcquireResourceExclusive(PRTL_RESOURCE Resource,
85 BOOLEAN Wait)
86 {
87 NTSTATUS Status;
88 BOOLEAN retVal = FALSE;
89
90 start:
91 RtlEnterCriticalSection(&Resource->Lock);
92 if (Resource->NumberActive == 0) /* lock is free */
93 {
94 Resource->NumberActive = -1;
95 retVal = TRUE;
96 }
97 else if (Resource->NumberActive < 0) /* exclusive lock in progress */
98 {
99 if (Resource->OwningThread == NtCurrentTeb()->Cid.UniqueThread)
100 {
101 retVal = TRUE;
102 Resource->NumberActive--;
103 goto done;
104 }
105 wait:
106 if (Wait == TRUE)
107 {
108 Resource->ExclusiveWaiters++;
109
110 RtlLeaveCriticalSection(&Resource->Lock);
111 Status = NtWaitForSingleObject(Resource->ExclusiveSemaphore,
112 FALSE,
113 NULL);
114 if (!NT_SUCCESS(Status))
115 goto done;
116 goto start; /* restart the acquisition to avoid deadlocks */
117 }
118 }
119 else /* one or more shared locks are in progress */
120 {
121 if (Wait == TRUE)
122 goto wait;
123 }
124 if (retVal == TRUE)
125 Resource->OwningThread = NtCurrentTeb()->Cid.UniqueThread;
126 done:
127 RtlLeaveCriticalSection(&Resource->Lock);
128 return retVal;
129 }
130
131
132 BOOLEAN STDCALL
133 RtlAcquireResourceShared(PRTL_RESOURCE Resource,
134 BOOLEAN Wait)
135 {
136 NTSTATUS Status = STATUS_UNSUCCESSFUL;
137 BOOLEAN retVal = FALSE;
138
139 start:
140 RtlEnterCriticalSection(&Resource->Lock);
141 if (Resource->NumberActive < 0)
142 {
143 if (Resource->OwningThread == NtCurrentTeb()->Cid.UniqueThread)
144 {
145 Resource->NumberActive--;
146 retVal = TRUE;
147 goto done;
148 }
149
150 if (Wait == TRUE)
151 {
152 Resource->SharedWaiters++;
153 RtlLeaveCriticalSection(&Resource->Lock);
154 Status = NtWaitForSingleObject(Resource->SharedSemaphore,
155 FALSE,
156 NULL);
157 if (!NT_SUCCESS(Status))
158 goto done;
159 goto start;
160 }
161 }
162 else
163 {
164 if (Status != STATUS_WAIT_0) /* otherwise RtlReleaseResource() has already done it */
165 Resource->NumberActive++;
166 retVal = TRUE;
167 }
168 done:
169 RtlLeaveCriticalSection(&Resource->Lock);
170 return retVal;
171 }
172
173
174 VOID STDCALL
175 RtlConvertExclusiveToShared(PRTL_RESOURCE Resource)
176 {
177 RtlEnterCriticalSection(&Resource->Lock);
178
179 if (Resource->NumberActive == -1)
180 {
181 Resource->OwningThread = NULL;
182
183 if (Resource->SharedWaiters > 0)
184 {
185 ULONG n;
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,
192 n,
193 NULL);
194 }
195 else
196 {
197 Resource->NumberActive = 1;
198 }
199 }
200
201 RtlLeaveCriticalSection(&Resource->Lock);
202 }
203
204
205 VOID STDCALL
206 RtlConvertSharedToExclusive(PRTL_RESOURCE Resource)
207 {
208 NTSTATUS Status;
209
210 RtlEnterCriticalSection(&Resource->Lock);
211
212 if (Resource->NumberActive == 1)
213 {
214 Resource->OwningThread = NtCurrentTeb()->Cid.UniqueThread;
215 Resource->NumberActive = -1;
216 }
217 else
218 {
219 Resource->ExclusiveWaiters++;
220
221 RtlLeaveCriticalSection(&Resource->Lock);
222 Status = NtWaitForSingleObject(Resource->ExclusiveSemaphore,
223 FALSE,
224 NULL);
225 if (!NT_SUCCESS(Status))
226 return;
227
228 RtlEnterCriticalSection(&Resource->Lock);
229 Resource->OwningThread = NtCurrentTeb()->Cid.UniqueThread;
230 Resource->NumberActive = -1;
231 }
232 RtlLeaveCriticalSection(&Resource->Lock);
233 }
234
235
236 VOID STDCALL
237 RtlReleaseResource(PRTL_RESOURCE Resource)
238 {
239 RtlEnterCriticalSection(&Resource->Lock);
240
241 if (Resource->NumberActive > 0) /* have one or more readers */
242 {
243 Resource->NumberActive--;
244 if (Resource->NumberActive == 0)
245 {
246 if (Resource->ExclusiveWaiters > 0)
247 {
248 wake_exclusive:
249 Resource->ExclusiveWaiters--;
250 NtReleaseSemaphore(Resource->ExclusiveSemaphore,
251 1,
252 NULL);
253 }
254 }
255 }
256 else if (Resource->NumberActive < 0) /* have a writer, possibly recursive */
257 {
258 Resource->NumberActive++;
259 if (Resource->NumberActive == 0)
260 {
261 Resource->OwningThread = 0;
262 if (Resource->ExclusiveWaiters > 0)
263 {
264 goto wake_exclusive;
265 }
266 else
267 {
268 if (Resource->SharedWaiters > 0)
269 {
270 ULONG n;
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,
277 n,
278 NULL);
279 }
280 }
281 }
282 }
283 RtlLeaveCriticalSection(&Resource->Lock);
284 }
285
286
287 VOID STDCALL
288 RtlDumpResource(PRTL_RESOURCE Resource)
289 {
290 DbgPrint("RtlDumpResource(%p):\n\tactive count = %i\n\twaiting readers = %i\n\twaiting writers = %i\n",
291 Resource,
292 Resource->NumberActive,
293 Resource->SharedWaiters,
294 Resource->ExclusiveWaiters);
295 if (Resource->NumberActive != 0)
296 {
297 DbgPrint("\towner thread = %08x\n",
298 Resource->OwningThread);
299 }
300 }
301
302 /* EOF */