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 ***************************************************************/
24 RtlInitializeResource(PRTL_RESOURCE Resource
)
28 Status
= RtlInitializeCriticalSection(&Resource
->Lock
);
29 if (!NT_SUCCESS(Status
))
31 RtlRaiseStatus(Status
);
34 Status
= NtCreateSemaphore(&Resource
->SharedSemaphore
,
39 if (!NT_SUCCESS(Status
))
41 RtlRaiseStatus(Status
);
43 Resource
->SharedWaiters
= 0;
45 Status
= NtCreateSemaphore(&Resource
->ExclusiveSemaphore
,
50 if (!NT_SUCCESS(Status
))
52 RtlRaiseStatus(Status
);
54 Resource
->ExclusiveWaiters
= 0;
56 Resource
->NumberActive
= 0;
57 Resource
->OwningThread
= NULL
;
58 Resource
->TimeoutBoost
= 0; /* no info on this one, default value is 0 */
66 RtlDeleteResource(PRTL_RESOURCE Resource
)
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;
82 RtlAcquireResourceExclusive(PRTL_RESOURCE Resource
,
86 BOOLEAN retVal
= FALSE
;
89 RtlEnterCriticalSection(&Resource
->Lock
);
90 if (Resource
->NumberActive
== 0) /* lock is free */
92 Resource
->NumberActive
= -1;
95 else if (Resource
->NumberActive
< 0) /* exclusive lock in progress */
97 if (Resource
->OwningThread
== NtCurrentTeb()->Cid
.UniqueThread
)
100 Resource
->NumberActive
--;
106 Resource
->ExclusiveWaiters
++;
108 RtlLeaveCriticalSection(&Resource
->Lock
);
109 Status
= NtWaitForSingleObject(Resource
->ExclusiveSemaphore
,
112 if (!NT_SUCCESS(Status
))
114 goto start
; /* restart the acquisition to avoid deadlocks */
117 else /* one or more shared locks are in progress */
123 Resource
->OwningThread
= NtCurrentTeb()->Cid
.UniqueThread
;
125 RtlLeaveCriticalSection(&Resource
->Lock
);
134 RtlAcquireResourceShared(PRTL_RESOURCE Resource
,
137 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
138 BOOLEAN retVal
= FALSE
;
141 RtlEnterCriticalSection(&Resource
->Lock
);
142 if (Resource
->NumberActive
< 0)
144 if (Resource
->OwningThread
== NtCurrentTeb()->Cid
.UniqueThread
)
146 Resource
->NumberActive
--;
153 Resource
->SharedWaiters
++;
154 RtlLeaveCriticalSection(&Resource
->Lock
);
155 Status
= NtWaitForSingleObject(Resource
->SharedSemaphore
,
158 if (!NT_SUCCESS(Status
))
165 if (Status
!= STATUS_WAIT_0
) /* otherwise RtlReleaseResource() has already done it */
166 Resource
->NumberActive
++;
170 RtlLeaveCriticalSection(&Resource
->Lock
);
179 RtlConvertExclusiveToShared(PRTL_RESOURCE Resource
)
181 RtlEnterCriticalSection(&Resource
->Lock
);
183 if (Resource
->NumberActive
== -1)
185 Resource
->OwningThread
= NULL
;
187 if (Resource
->SharedWaiters
> 0)
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
,
201 Resource
->NumberActive
= 1;
205 RtlLeaveCriticalSection(&Resource
->Lock
);
213 RtlConvertSharedToExclusive(PRTL_RESOURCE Resource
)
217 RtlEnterCriticalSection(&Resource
->Lock
);
219 if (Resource
->NumberActive
== 1)
221 Resource
->OwningThread
= NtCurrentTeb()->Cid
.UniqueThread
;
222 Resource
->NumberActive
= -1;
226 Resource
->ExclusiveWaiters
++;
228 RtlLeaveCriticalSection(&Resource
->Lock
);
229 Status
= NtWaitForSingleObject(Resource
->ExclusiveSemaphore
,
232 if (!NT_SUCCESS(Status
))
235 RtlEnterCriticalSection(&Resource
->Lock
);
236 Resource
->OwningThread
= NtCurrentTeb()->Cid
.UniqueThread
;
237 Resource
->NumberActive
= -1;
239 RtlLeaveCriticalSection(&Resource
->Lock
);
247 RtlReleaseResource(PRTL_RESOURCE Resource
)
249 RtlEnterCriticalSection(&Resource
->Lock
);
251 if (Resource
->NumberActive
> 0) /* have one or more readers */
253 Resource
->NumberActive
--;
254 if (Resource
->NumberActive
== 0)
256 if (Resource
->ExclusiveWaiters
> 0)
259 Resource
->ExclusiveWaiters
--;
260 NtReleaseSemaphore(Resource
->ExclusiveSemaphore
,
266 else if (Resource
->NumberActive
< 0) /* have a writer, possibly recursive */
268 Resource
->NumberActive
++;
269 if (Resource
->NumberActive
== 0)
271 Resource
->OwningThread
= 0;
272 if (Resource
->ExclusiveWaiters
> 0)
278 if (Resource
->SharedWaiters
> 0)
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
,
293 RtlLeaveCriticalSection(&Resource
->Lock
);
301 RtlDumpResource(PRTL_RESOURCE Resource
)
303 DbgPrint("RtlDumpResource(%p):\n\tactive count = %i\n\twaiting readers = %i\n\twaiting writers = %i\n",
305 Resource
->NumberActive
,
306 Resource
->SharedWaiters
,
307 Resource
->ExclusiveWaiters
);
308 if (Resource
->NumberActive
!= 0)
310 DbgPrint("\towner thread = %08x\n",
311 Resource
->OwningThread
);