1 /* $Id: resource.c,v 1.3 2002/09/08 10:23:06 chorns Exp $
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
11 * NOTES: Partially take from Wine:
12 * Copyright 1996-1998 Marcus Meissner
17 * xxxResource() functions implement multiple-reader-single-writer lock.
18 * The code is based on information published in WDJ January 1999 issue.
21 #include <ddk/ntddk.h>
22 #include <ntdll/rtl.h>
23 #include <ntos/synch.h>
26 #include <ntdll/ntdll.h>
29 /* FUNCTIONS ****************************************************************/
32 RtlInitializeResource(PRTL_RESOURCE Resource
)
36 Status
= RtlInitializeCriticalSection(&Resource
->Lock
);
37 if (!NT_SUCCESS(Status
))
39 RtlRaiseStatus(Status
);
42 Status
= NtCreateSemaphore(&Resource
->SharedSemaphore
,
47 if (!NT_SUCCESS(Status
))
49 RtlRaiseStatus(Status
);
51 Resource
->SharedWaiters
= 0;
53 Status
= NtCreateSemaphore(&Resource
->ExclusiveSemaphore
,
58 if (!NT_SUCCESS(Status
))
60 RtlRaiseStatus(Status
);
62 Resource
->ExclusiveWaiters
= 0;
64 Resource
->NumberActive
= 0;
65 Resource
->OwningThread
= NULL
;
66 Resource
->TimeoutBoost
= 0; /* no info on this one, default value is 0 */
71 RtlDeleteResource(PRTL_RESOURCE Resource
)
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;
84 RtlAcquireResourceExclusive(PRTL_RESOURCE Resource
,
88 BOOLEAN retVal
= FALSE
;
91 RtlEnterCriticalSection(&Resource
->Lock
);
92 if (Resource
->NumberActive
== 0) /* lock is free */
94 Resource
->NumberActive
= -1;
97 else if (Resource
->NumberActive
< 0) /* exclusive lock in progress */
99 if (Resource
->OwningThread
== NtCurrentTeb()->Cid
.UniqueThread
)
102 Resource
->NumberActive
--;
108 Resource
->ExclusiveWaiters
++;
110 RtlLeaveCriticalSection(&Resource
->Lock
);
111 Status
= NtWaitForSingleObject(Resource
->ExclusiveSemaphore
,
114 if (!NT_SUCCESS(Status
))
116 goto start
; /* restart the acquisition to avoid deadlocks */
119 else /* one or more shared locks are in progress */
125 Resource
->OwningThread
= NtCurrentTeb()->Cid
.UniqueThread
;
127 RtlLeaveCriticalSection(&Resource
->Lock
);
133 RtlAcquireResourceShared(PRTL_RESOURCE Resource
,
136 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
137 BOOLEAN retVal
= FALSE
;
140 RtlEnterCriticalSection(&Resource
->Lock
);
141 if (Resource
->NumberActive
< 0)
143 if (Resource
->OwningThread
== NtCurrentTeb()->Cid
.UniqueThread
)
145 Resource
->NumberActive
--;
152 Resource
->SharedWaiters
++;
153 RtlLeaveCriticalSection(&Resource
->Lock
);
154 Status
= NtWaitForSingleObject(Resource
->SharedSemaphore
,
157 if (!NT_SUCCESS(Status
))
164 if (Status
!= STATUS_WAIT_0
) /* otherwise RtlReleaseResource() has already done it */
165 Resource
->NumberActive
++;
169 RtlLeaveCriticalSection(&Resource
->Lock
);
175 RtlConvertExclusiveToShared(PRTL_RESOURCE Resource
)
177 RtlEnterCriticalSection(&Resource
->Lock
);
179 if (Resource
->NumberActive
== -1)
181 Resource
->OwningThread
= NULL
;
183 if (Resource
->SharedWaiters
> 0)
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
,
197 Resource
->NumberActive
= 1;
201 RtlLeaveCriticalSection(&Resource
->Lock
);
206 RtlConvertSharedToExclusive(PRTL_RESOURCE Resource
)
210 RtlEnterCriticalSection(&Resource
->Lock
);
212 if (Resource
->NumberActive
== 1)
214 Resource
->OwningThread
= NtCurrentTeb()->Cid
.UniqueThread
;
215 Resource
->NumberActive
= -1;
219 Resource
->ExclusiveWaiters
++;
221 RtlLeaveCriticalSection(&Resource
->Lock
);
222 Status
= NtWaitForSingleObject(Resource
->ExclusiveSemaphore
,
225 if (!NT_SUCCESS(Status
))
228 RtlEnterCriticalSection(&Resource
->Lock
);
229 Resource
->OwningThread
= NtCurrentTeb()->Cid
.UniqueThread
;
230 Resource
->NumberActive
= -1;
232 RtlLeaveCriticalSection(&Resource
->Lock
);
237 RtlReleaseResource(PRTL_RESOURCE Resource
)
239 RtlEnterCriticalSection(&Resource
->Lock
);
241 if (Resource
->NumberActive
> 0) /* have one or more readers */
243 Resource
->NumberActive
--;
244 if (Resource
->NumberActive
== 0)
246 if (Resource
->ExclusiveWaiters
> 0)
249 Resource
->ExclusiveWaiters
--;
250 NtReleaseSemaphore(Resource
->ExclusiveSemaphore
,
256 else if (Resource
->NumberActive
< 0) /* have a writer, possibly recursive */
258 Resource
->NumberActive
++;
259 if (Resource
->NumberActive
== 0)
261 Resource
->OwningThread
= 0;
262 if (Resource
->ExclusiveWaiters
> 0)
268 if (Resource
->SharedWaiters
> 0)
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
,
283 RtlLeaveCriticalSection(&Resource
->Lock
);
288 RtlDumpResource(PRTL_RESOURCE Resource
)
290 DbgPrint("RtlDumpResource(%p):\n\tactive count = %i\n\twaiting readers = %i\n\twaiting writers = %i\n",
292 Resource
->NumberActive
,
293 Resource
->SharedWaiters
,
294 Resource
->ExclusiveWaiters
);
295 if (Resource
->NumberActive
!= 0)
297 DbgPrint("\towner thread = %08x\n",
298 Resource
->OwningThread
);