[NTDLL/LDR]
[reactos.git] / reactos / dll / ntdll / ldr / ldrapi.c
1 /*
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)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntdll.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS *******************************************************************/
17
18 #define LDR_LOCK_HELD 0x2
19 #define LDR_LOCK_FREE 0x1
20
21 LONG LdrpLoaderLockAcquisitonCount;
22
23 /* FUNCTIONS *****************************************************************/
24
25 /*
26 * @implemented
27 */
28 NTSTATUS
29 NTAPI
30 LdrUnlockLoaderLock(IN ULONG Flags,
31 IN ULONG Cookie OPTIONAL)
32 {
33 NTSTATUS Status = STATUS_SUCCESS;
34
35 DPRINT("LdrUnlockLoaderLock(%x %x)\n", Flags, Cookie);
36
37 /* Check for valid flags */
38 if (Flags & ~1)
39 {
40 /* Flags are invalid, check how to fail */
41 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS)
42 {
43 /* The caller wants us to raise status */
44 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1);
45 }
46 else
47 {
48 /* A normal failure */
49 return STATUS_INVALID_PARAMETER_1;
50 }
51 }
52
53 /* If we don't have a cookie, just return */
54 if (!Cookie) return STATUS_SUCCESS;
55
56 /* Validate the cookie */
57 if ((Cookie & 0xF0000000) ||
58 ((Cookie >> 16) ^ ((ULONG)(NtCurrentTeb()->RealClientId.UniqueThread) & 0xFFF)))
59 {
60 DPRINT1("LdrUnlockLoaderLock() called with an invalid cookie!\n");
61
62 /* Invalid cookie, check how to fail */
63 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS)
64 {
65 /* The caller wants us to raise status */
66 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2);
67 }
68 else
69 {
70 /* A normal failure */
71 return STATUS_INVALID_PARAMETER_2;
72 }
73 }
74
75 /* Ready to release the lock */
76 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS)
77 {
78 /* Do a direct leave */
79 RtlLeaveCriticalSection(&LdrpLoaderLock);
80 }
81 else
82 {
83 /* Wrap this in SEH, since we're not supposed to raise */
84 _SEH2_TRY
85 {
86 /* Leave the lock */
87 RtlLeaveCriticalSection(&LdrpLoaderLock);
88 }
89 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
90 {
91 /* We should use the LDR Filter instead */
92 Status = _SEH2_GetExceptionCode();
93 }
94 _SEH2_END;
95 }
96
97 /* All done */
98 return Status;
99 }
100
101 /*
102 * @implemented
103 */
104 NTSTATUS
105 NTAPI
106 LdrLockLoaderLock(IN ULONG Flags,
107 OUT PULONG Result OPTIONAL,
108 OUT PULONG Cookie OPTIONAL)
109 {
110 LONG OldCount;
111 NTSTATUS Status = STATUS_SUCCESS;
112 BOOLEAN InInit = FALSE; // FIXME
113 //BOOLEAN InInit = LdrpInLdrInit;
114
115 DPRINT("LdrLockLoaderLock(%x %p %p)\n", Flags, Result, Cookie);
116
117 /* Zero out the outputs */
118 if (Result) *Result = 0;
119 if (Cookie) *Cookie = 0;
120
121 /* Validate the flags */
122 if (Flags & ~(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS |
123 LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY))
124 {
125 /* Flags are invalid, check how to fail */
126 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS)
127 {
128 /* The caller wants us to raise status */
129 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1);
130 }
131
132 /* A normal failure */
133 return STATUS_INVALID_PARAMETER_1;
134 }
135
136 /* Make sure we got a cookie */
137 if (!Cookie)
138 {
139 /* No cookie check how to fail */
140 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS)
141 {
142 /* The caller wants us to raise status */
143 RtlRaiseStatus(STATUS_INVALID_PARAMETER_3);
144 }
145
146 /* A normal failure */
147 return STATUS_INVALID_PARAMETER_3;
148 }
149
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))
152 {
153 /* No pointer to return the data to */
154 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS)
155 {
156 /* The caller wants us to raise status */
157 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2);
158 }
159
160 /* Fail */
161 return STATUS_INVALID_PARAMETER_2;
162 }
163
164 /* Return now if we are in the init phase */
165 if (InInit) return STATUS_SUCCESS;
166
167 /* Check what locking semantic to use */
168 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS)
169 {
170 /* Check if we should enter or simply try */
171 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY)
172 {
173 /* Do a try */
174 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock))
175 {
176 /* It's locked */
177 *Result = LDR_LOCK_HELD;
178 goto Quickie;
179 }
180 else
181 {
182 /* It worked */
183 *Result = LDR_LOCK_FREE;
184 }
185 }
186 else
187 {
188 /* Do a enter */
189 RtlEnterCriticalSection(&LdrpLoaderLock);
190
191 /* See if result was requested */
192 if (Result) *Result = LDR_LOCK_FREE;
193 }
194
195 /* Increase the acquisition count */
196 OldCount = _InterlockedIncrement(&LdrpLoaderLockAcquisitonCount);
197
198 /* Generate a cookie */
199 *Cookie = (((ULONG)NtCurrentTeb()->RealClientId.UniqueThread & 0xFFF) << 16) | OldCount;
200 }
201 else
202 {
203 /* Wrap this in SEH, since we're not supposed to raise */
204 _SEH2_TRY
205 {
206 /* Check if we should enter or simply try */
207 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY)
208 {
209 /* Do a try */
210 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock))
211 {
212 /* It's locked */
213 *Result = LDR_LOCK_HELD;
214 _SEH2_YIELD(return STATUS_SUCCESS);
215 }
216 else
217 {
218 /* It worked */
219 *Result = LDR_LOCK_FREE;
220 }
221 }
222 else
223 {
224 /* Do an enter */
225 RtlEnterCriticalSection(&LdrpLoaderLock);
226
227 /* See if result was requested */
228 if (Result) *Result = LDR_LOCK_FREE;
229 }
230
231 /* Increase the acquisition count */
232 OldCount = _InterlockedIncrement(&LdrpLoaderLockAcquisitonCount);
233
234 /* Generate a cookie */
235 *Cookie = (((ULONG)NtCurrentTeb()->RealClientId.UniqueThread & 0xFFF) << 16) | OldCount;
236 }
237 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
238 {
239 /* We should use the LDR Filter instead */
240 Status = _SEH2_GetExceptionCode();
241 }
242 _SEH2_END;
243 }
244
245 Quickie:
246 return Status;
247 }
248
249 /* EOF */