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