2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NT User Mode Library
4 * FILE: dll/ntdll/ldr/ldrapi.c
5 * PURPOSE: PE Loader Public APIs
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Aleksey Bragin (aleksey@reactos.org)
10 /* INCLUDES *****************************************************************/
16 /* GLOBALS *******************************************************************/
18 #define LDR_LOCK_HELD 0x2
19 #define LDR_LOCK_FREE 0x1
21 LONG LdrpLoaderLockAcquisitonCount
;
23 /* FUNCTIONS *****************************************************************/
30 LdrUnlockLoaderLock(IN ULONG Flags
,
31 IN ULONG Cookie OPTIONAL
)
33 NTSTATUS Status
= STATUS_SUCCESS
;
35 DPRINT("LdrUnlockLoaderLock(%x %x)\n", Flags
, Cookie
);
37 /* Check for valid flags */
40 /* Flags are invalid, check how to fail */
41 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS
)
43 /* The caller wants us to raise status */
44 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1
);
48 /* A normal failure */
49 return STATUS_INVALID_PARAMETER_1
;
53 /* If we don't have a cookie, just return */
54 if (!Cookie
) return STATUS_SUCCESS
;
56 /* Validate the cookie */
57 if ((Cookie
& 0xF0000000) ||
58 ((Cookie
>> 16) ^ ((ULONG
)(NtCurrentTeb()->RealClientId
.UniqueThread
) & 0xFFF)))
60 DPRINT1("LdrUnlockLoaderLock() called with an invalid cookie!\n");
62 /* Invalid cookie, check how to fail */
63 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS
)
65 /* The caller wants us to raise status */
66 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2
);
70 /* A normal failure */
71 return STATUS_INVALID_PARAMETER_2
;
75 /* Ready to release the lock */
76 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS
)
78 /* Do a direct leave */
79 RtlLeaveCriticalSection(&LdrpLoaderLock
);
83 /* Wrap this in SEH, since we're not supposed to raise */
87 RtlLeaveCriticalSection(&LdrpLoaderLock
);
89 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
91 /* We should use the LDR Filter instead */
92 Status
= _SEH2_GetExceptionCode();
106 LdrLockLoaderLock(IN ULONG Flags
,
107 OUT PULONG Result OPTIONAL
,
108 OUT PULONG Cookie OPTIONAL
)
111 NTSTATUS Status
= STATUS_SUCCESS
;
112 BOOLEAN InInit
= FALSE
; // FIXME
113 //BOOLEAN InInit = LdrpInLdrInit;
115 DPRINT("LdrLockLoaderLock(%x %p %p)\n", Flags
, Result
, Cookie
);
117 /* Zero out the outputs */
118 if (Result
) *Result
= 0;
119 if (Cookie
) *Cookie
= 0;
121 /* Validate the flags */
122 if (Flags
& ~(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS
|
123 LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
))
125 /* Flags are invalid, check how to fail */
126 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS
)
128 /* The caller wants us to raise status */
129 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1
);
132 /* A normal failure */
133 return STATUS_INVALID_PARAMETER_1
;
136 /* Make sure we got a cookie */
139 /* No cookie check how to fail */
140 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS
)
142 /* The caller wants us to raise status */
143 RtlRaiseStatus(STATUS_INVALID_PARAMETER_3
);
146 /* A normal failure */
147 return STATUS_INVALID_PARAMETER_3
;
150 /* If the flag is set, make sure we have a valid pointer to use */
151 if ((Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
) && !(Result
))
153 /* No pointer to return the data to */
154 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS
)
156 /* The caller wants us to raise status */
157 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2
);
161 return STATUS_INVALID_PARAMETER_2
;
164 /* Return now if we are in the init phase */
165 if (InInit
) return STATUS_SUCCESS
;
167 /* Check what locking semantic to use */
168 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS
)
170 /* Check if we should enter or simply try */
171 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
)
174 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock
))
177 *Result
= LDR_LOCK_HELD
;
183 *Result
= LDR_LOCK_FREE
;
189 RtlEnterCriticalSection(&LdrpLoaderLock
);
191 /* See if result was requested */
192 if (Result
) *Result
= LDR_LOCK_FREE
;
195 /* Increase the acquisition count */
196 OldCount
= _InterlockedIncrement(&LdrpLoaderLockAcquisitonCount
);
198 /* Generate a cookie */
199 *Cookie
= (((ULONG
)NtCurrentTeb()->RealClientId
.UniqueThread
& 0xFFF) << 16) | OldCount
;
203 /* Wrap this in SEH, since we're not supposed to raise */
206 /* Check if we should enter or simply try */
207 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
)
210 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock
))
213 *Result
= LDR_LOCK_HELD
;
214 _SEH2_YIELD(return STATUS_SUCCESS
);
219 *Result
= LDR_LOCK_FREE
;
225 RtlEnterCriticalSection(&LdrpLoaderLock
);
227 /* See if result was requested */
228 if (Result
) *Result
= LDR_LOCK_FREE
;
231 /* Increase the acquisition count */
232 OldCount
= _InterlockedIncrement(&LdrpLoaderLockAcquisitonCount
);
234 /* Generate a cookie */
235 *Cookie
= (((ULONG
)NtCurrentTeb()->RealClientId
.UniqueThread
& 0xFFF) << 16) | OldCount
;
237 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
239 /* We should use the LDR Filter instead */
240 Status
= _SEH2_GetExceptionCode();