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
RtlInitializeResource(PRTL_RESOURCE Resource)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
RtlDeleteResource(PRTL_RESOURCE Resource)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
RtlAcquireResourceExclusive(PRTL_RESOURCE Resource,BOOLEAN Wait)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
RtlAcquireResourceShared(PRTL_RESOURCE Resource,BOOLEAN Wait)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
RtlConvertExclusiveToShared(PRTL_RESOURCE Resource)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
RtlConvertSharedToExclusive(PRTL_RESOURCE Resource)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
RtlReleaseResource(PRTL_RESOURCE Resource)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
RtlDumpResource(PRTL_RESOURCE Resource)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