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
11 /* INCLUDES *****************************************************************/
18 /* FUNCTIONS ***************************************************************/
25 RtlInitializeResource(PRTL_RESOURCE Resource
)
29 Status
= RtlInitializeCriticalSection(&Resource
->Lock
);
30 if (!NT_SUCCESS(Status
))
32 RtlRaiseStatus(Status
);
35 Status
= NtCreateSemaphore(&Resource
->SharedSemaphore
,
40 if (!NT_SUCCESS(Status
))
42 RtlRaiseStatus(Status
);
44 Resource
->SharedWaiters
= 0;
46 Status
= NtCreateSemaphore(&Resource
->ExclusiveSemaphore
,
51 if (!NT_SUCCESS(Status
))
53 RtlRaiseStatus(Status
);
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 */
68 RtlDeleteResource(PRTL_RESOURCE Resource
)
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;
85 RtlAcquireResourceExclusive(
86 PRTL_RESOURCE Resource
,
90 BOOLEAN retVal
= FALSE
;
93 RtlEnterCriticalSection(&Resource
->Lock
);
94 if (Resource
->NumberActive
== 0) /* lock is free */
96 Resource
->NumberActive
= -1;
99 else if (Resource
->NumberActive
< 0) /* exclusive lock in progress */
101 if (Resource
->OwningThread
== NtCurrentTeb()->ClientId
.UniqueThread
)
104 Resource
->NumberActive
--;
110 Resource
->ExclusiveWaiters
++;
112 RtlLeaveCriticalSection(&Resource
->Lock
);
113 Status
= NtWaitForSingleObject(Resource
->ExclusiveSemaphore
,
116 if (!NT_SUCCESS(Status
))
118 goto start
; /* restart the acquisition to avoid deadlocks */
121 else /* one or more shared locks are in progress */
127 Resource
->OwningThread
= NtCurrentTeb()->ClientId
.UniqueThread
;
129 RtlLeaveCriticalSection(&Resource
->Lock
);
139 RtlAcquireResourceShared(
140 PRTL_RESOURCE Resource
,
143 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
144 BOOLEAN retVal
= FALSE
;
147 RtlEnterCriticalSection(&Resource
->Lock
);
148 if (Resource
->NumberActive
< 0)
150 if (Resource
->OwningThread
== NtCurrentTeb()->ClientId
.UniqueThread
)
152 Resource
->NumberActive
--;
159 Resource
->SharedWaiters
++;
160 RtlLeaveCriticalSection(&Resource
->Lock
);
161 Status
= NtWaitForSingleObject(Resource
->SharedSemaphore
,
164 if (!NT_SUCCESS(Status
))
171 if (Status
!= STATUS_WAIT_0
) /* otherwise RtlReleaseResource() has already done it */
172 Resource
->NumberActive
++;
176 RtlLeaveCriticalSection(&Resource
->Lock
);
186 RtlConvertExclusiveToShared(PRTL_RESOURCE Resource
)
188 RtlEnterCriticalSection(&Resource
->Lock
);
190 if (Resource
->NumberActive
== -1)
192 Resource
->OwningThread
= NULL
;
194 if (Resource
->SharedWaiters
> 0)
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
,
208 Resource
->NumberActive
= 1;
212 RtlLeaveCriticalSection(&Resource
->Lock
);
221 RtlConvertSharedToExclusive(PRTL_RESOURCE Resource
)
225 RtlEnterCriticalSection(&Resource
->Lock
);
227 if (Resource
->NumberActive
== 1)
229 Resource
->OwningThread
= NtCurrentTeb()->ClientId
.UniqueThread
;
230 Resource
->NumberActive
= -1;
234 Resource
->ExclusiveWaiters
++;
236 RtlLeaveCriticalSection(&Resource
->Lock
);
237 Status
= NtWaitForSingleObject(Resource
->ExclusiveSemaphore
,
240 if (!NT_SUCCESS(Status
))
243 RtlEnterCriticalSection(&Resource
->Lock
);
244 Resource
->OwningThread
= NtCurrentTeb()->ClientId
.UniqueThread
;
245 Resource
->NumberActive
= -1;
247 RtlLeaveCriticalSection(&Resource
->Lock
);
256 RtlReleaseResource(PRTL_RESOURCE Resource
)
258 RtlEnterCriticalSection(&Resource
->Lock
);
260 if (Resource
->NumberActive
> 0) /* have one or more readers */
262 Resource
->NumberActive
--;
263 if (Resource
->NumberActive
== 0)
265 if (Resource
->ExclusiveWaiters
> 0)
268 Resource
->ExclusiveWaiters
--;
269 NtReleaseSemaphore(Resource
->ExclusiveSemaphore
,
275 else if (Resource
->NumberActive
< 0) /* have a writer, possibly recursive */
277 Resource
->NumberActive
++;
278 if (Resource
->NumberActive
== 0)
280 Resource
->OwningThread
= 0;
281 if (Resource
->ExclusiveWaiters
> 0)
287 if (Resource
->SharedWaiters
> 0)
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
,
302 RtlLeaveCriticalSection(&Resource
->Lock
);
311 RtlDumpResource(PRTL_RESOURCE Resource
)
313 DbgPrint("RtlDumpResource(%p):\n\tactive count = %d\n\twaiting readers = %u\n\twaiting writers = %u\n",
315 Resource
->NumberActive
,
316 Resource
->SharedWaiters
,
317 Resource
->ExclusiveWaiters
);
319 if (Resource
->NumberActive
!= 0)
321 DbgPrint("\towner thread = %p\n",
322 Resource
->OwningThread
);