Fixed a slight bug that was included in the change from WND ptr to
[wine] / dlls / ntdll / rtl.c
1 /*
2  * NT basis DLL
3  * 
4  * This file contains the Rtl* API functions. These should be implementable.
5  * 
6  * Copyright 1996-1998 Marcus Meissner
7  *                1999 Alex Korobka
8  */
9
10 #include <stdlib.h>
11 #include <string.h>
12 #include "heap.h"
13 #include "debug.h"
14 #include "winuser.h"
15 #include "winerror.h"
16 #include "stackframe.h"
17
18 #include "ntddk.h"
19 #include "winreg.h"
20
21
22 /*
23  *      resource functions
24  */
25
26 /***********************************************************************
27  *           RtlInitializeResource      (NTDLL.409)
28  *
29  * xxxResource() functions implement multiple-reader-single-writer lock.
30  * The code is based on information published in WDJ January 1999 issue.
31  */
32 void WINAPI RtlInitializeResource(LPRTL_RWLOCK rwl)
33 {
34     if( rwl )
35     {
36         rwl->iNumberActive = 0;
37         rwl->uExclusiveWaiters = 0;
38         rwl->uSharedWaiters = 0;
39         rwl->hOwningThreadId = 0;
40         rwl->dwTimeoutBoost = 0; /* no info on this one, default value is 0 */
41         InitializeCriticalSection( &rwl->rtlCS );
42         rwl->hExclusiveReleaseSemaphore = CreateSemaphoreA( NULL, 0, 65535, NULL );
43         rwl->hSharedReleaseSemaphore = CreateSemaphoreA( NULL, 0, 65535, NULL );
44     }
45 }
46
47
48 /***********************************************************************
49  *           RtlDeleteResource          (NTDLL.330)
50  */
51 void WINAPI RtlDeleteResource(LPRTL_RWLOCK rwl)
52 {
53     if( rwl )
54     {
55         EnterCriticalSection( &rwl->rtlCS );
56         if( rwl->iNumberActive || rwl->uExclusiveWaiters || rwl->uSharedWaiters )
57             MSG("Deleting active MRSW lock (%p), expect failure\n", rwl );
58         rwl->hOwningThreadId = 0;
59         rwl->uExclusiveWaiters = rwl->uSharedWaiters = 0;
60         rwl->iNumberActive = 0;
61         CloseHandle( rwl->hExclusiveReleaseSemaphore );
62         CloseHandle( rwl->hSharedReleaseSemaphore );
63         LeaveCriticalSection( &rwl->rtlCS );
64         DeleteCriticalSection( &rwl->rtlCS );
65     }
66 }
67
68
69 /***********************************************************************
70  *          RtlAcquireResourceExclusive (NTDLL.256)
71  */
72 BYTE WINAPI RtlAcquireResourceExclusive(LPRTL_RWLOCK rwl, BYTE fWait)
73 {
74     BYTE retVal = 0;
75     if( !rwl ) return 0;
76
77 start:
78     EnterCriticalSection( &rwl->rtlCS );
79     if( rwl->iNumberActive == 0 ) /* lock is free */
80     {
81         rwl->iNumberActive = -1;
82         retVal = 1;
83     }
84     else if( rwl->iNumberActive < 0 ) /* exclusive lock in progress */
85     {
86          if( rwl->hOwningThreadId == GetCurrentThreadId() )
87          {
88              retVal = 1;
89              rwl->iNumberActive--;
90              goto done;
91          }
92 wait:
93          if( fWait )
94          {
95              rwl->uExclusiveWaiters++;
96
97              LeaveCriticalSection( &rwl->rtlCS );
98              if( WaitForSingleObject( rwl->hExclusiveReleaseSemaphore, INFINITE ) == WAIT_FAILED )
99                  goto done;
100              goto start; /* restart the acquisition to avoid deadlocks */
101          }
102     }
103     else  /* one or more shared locks are in progress */
104          if( fWait )
105              goto wait;
106          
107     if( retVal == 1 )
108         rwl->hOwningThreadId = GetCurrentThreadId();
109 done:
110     LeaveCriticalSection( &rwl->rtlCS );
111     return retVal;
112 }
113
114 /***********************************************************************
115  *          RtlAcquireResourceShared    (NTDLL.257)
116  */
117 BYTE WINAPI RtlAcquireResourceShared(LPRTL_RWLOCK rwl, BYTE fWait)
118 {
119     DWORD dwWait = WAIT_FAILED;
120     BYTE retVal = 0;
121     if( !rwl ) return 0;
122
123 start:
124     EnterCriticalSection( &rwl->rtlCS );
125     if( rwl->iNumberActive < 0 )
126     {
127         if( rwl->hOwningThreadId == GetCurrentThreadId() )
128         {
129             rwl->iNumberActive--;
130             retVal = 1;
131             goto done;
132         }
133         
134         if( fWait )
135         {
136             rwl->uSharedWaiters++;
137             LeaveCriticalSection( &rwl->rtlCS );
138             if( (dwWait = WaitForSingleObject( rwl->hSharedReleaseSemaphore, INFINITE )) == WAIT_FAILED )
139                 goto done;
140             goto start;
141         }
142     }
143     else 
144     {
145         if( dwWait != WAIT_OBJECT_0 ) /* otherwise RtlReleaseResource() has already done it */
146             rwl->iNumberActive++;
147         retVal = 1;
148     }
149 done:
150     LeaveCriticalSection( &rwl->rtlCS );
151     return retVal;
152 }
153
154
155 /***********************************************************************
156  *           RtlReleaseResource         (NTDLL.471)
157  */
158 void WINAPI RtlReleaseResource(LPRTL_RWLOCK rwl)
159 {
160     EnterCriticalSection( &rwl->rtlCS );
161
162     if( rwl->iNumberActive > 0 ) /* have one or more readers */
163     {
164         if( --rwl->iNumberActive == 0 )
165         {
166             if( rwl->uExclusiveWaiters )
167             {
168 wake_exclusive:
169                 rwl->uExclusiveWaiters--;
170                 ReleaseSemaphore( rwl->hExclusiveReleaseSemaphore, 1, NULL );
171             }
172         }
173     }
174     else 
175     if( rwl->iNumberActive < 0 ) /* have a writer, possibly recursive */
176     {
177         if( ++rwl->iNumberActive == 0 )
178         {
179             rwl->hOwningThreadId = 0;
180             if( rwl->uExclusiveWaiters )
181                 goto wake_exclusive;
182             else
183                 if( rwl->uSharedWaiters )
184                 {
185                     UINT n = rwl->uSharedWaiters;
186                     rwl->iNumberActive = rwl->uSharedWaiters; /* prevent new writers from joining until
187                                                                * all queued readers have done their thing */
188                     rwl->uSharedWaiters = 0;
189                     ReleaseSemaphore( rwl->hSharedReleaseSemaphore, n, NULL );
190                 }
191         }
192     }
193     LeaveCriticalSection( &rwl->rtlCS );
194 }
195
196
197 /***********************************************************************
198  *           RtlDumpResource            (NTDLL.340)
199  */
200 void WINAPI RtlDumpResource(LPRTL_RWLOCK rwl)
201 {
202     if( rwl )
203     {
204         MSG("RtlDumpResource(%p):\n\tactive count = %i\n\twaiting readers = %i\n\twaiting writers = %i\n",  
205                 rwl, rwl->iNumberActive, rwl->uSharedWaiters, rwl->uExclusiveWaiters );
206         if( rwl->iNumberActive )
207             MSG("\towner thread = %08x\n", rwl->hOwningThreadId );
208     }
209 }
210
211 /*
212  *      heap functions
213  */
214
215 /******************************************************************************
216  *  RtlCreateHeap               [NTDLL] 
217  */
218 HANDLE WINAPI RtlCreateHeap(
219         ULONG Flags,
220         PVOID BaseAddress,
221         ULONG SizeToReserve,
222         ULONG SizeToCommit,
223         PVOID Unknown,
224         PRTL_HEAP_DEFINITION Definition)
225 {
226         FIXME (ntdll,"(0x%08lx, %p, 0x%08lx, 0x%08lx, %p, %p) semi-stub\n",
227         Flags, BaseAddress, SizeToReserve, SizeToCommit, Unknown, Definition);
228         
229         return HeapCreate ( Flags, SizeToCommit, SizeToReserve);
230
231 }       
232 /******************************************************************************
233  *  RtlAllocateHeap             [NTDLL] 
234  */
235 PVOID WINAPI RtlAllocateHeap(
236         HANDLE Heap,
237         ULONG Flags,
238         ULONG Size)
239 {
240         FIXME(ntdll,"(0x%08x, 0x%08lx, 0x%08lx) semi stub\n",
241         Heap, Flags, Size);
242         return HeapAlloc(Heap, Flags, Size);
243 }
244
245 /******************************************************************************
246  *  RtlFreeHeap         [NTDLL] 
247  */
248 BOOLEAN WINAPI RtlFreeHeap(
249         HANDLE Heap,
250         ULONG Flags,
251         PVOID Address)
252 {
253         FIXME(ntdll,"(0x%08x, 0x%08lx, %p) semi stub\n",
254         Heap, Flags, Address);
255         return HeapFree(Heap, Flags, Address);
256 }
257         
258 /******************************************************************************
259  *  RtlDestroyHeap              [NTDLL] 
260  *
261  * FIXME: prototype guessed
262  */
263 BOOLEAN WINAPI RtlDestroyHeap(
264         HANDLE Heap)
265 {
266         FIXME(ntdll,"(0x%08x) semi stub\n", Heap);
267         return HeapDestroy(Heap);
268 }
269         
270 /*
271  *      misc functions
272  */
273
274 /******************************************************************************
275  *      DbgPrint        [NTDLL] 
276  */
277 void __cdecl DbgPrint(LPCSTR fmt,LPVOID args) {
278         char buf[512];
279
280         wvsprintfA(buf,fmt,&args);
281         MSG("DbgPrint says: %s",buf);
282         /* hmm, raise exception? */
283 }
284 DWORD NtRaiseException ( DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments,CONST ULONG_PTR *lpArguments)
285 {       FIXME(ntdll,"0x%08lx 0x%08lx 0x%08lx %p\n", dwExceptionCode, dwExceptionFlags, nNumberOfArguments, lpArguments);
286         return 0;
287 }
288
289 DWORD RtlRaiseException ( DWORD x)
290 {       FIXME(ntdll, "0x%08lx\n", x);
291         return 0;
292 }
293 /******************************************************************************
294  *  RtlAcquirePebLock           [NTDLL] 
295  */
296 VOID WINAPI RtlAcquirePebLock(void) {
297         FIXME(ntdll,"()\n");
298         /* enter critical section ? */
299 }
300
301 /******************************************************************************
302  *  RtlReleasePebLock           [NTDLL] 
303  */
304 VOID WINAPI RtlReleasePebLock(void) {
305         FIXME(ntdll,"()\n");
306         /* leave critical section ? */
307 }
308
309 /******************************************************************************
310  *  RtlIntegerToChar    [NTDLL] 
311  */
312 DWORD WINAPI RtlIntegerToChar(DWORD x1,DWORD x2,DWORD x3,DWORD x4) {
313         FIXME(ntdll,"(0x%08lx,0x%08lx,0x%08lx,0x%08lx),stub!\n",x1,x2,x3,x4);
314         return 0;
315 }
316 /******************************************************************************
317  *  RtlSetEnvironmentVariable           [NTDLL] 
318  */
319 DWORD WINAPI RtlSetEnvironmentVariable(DWORD x1,PUNICODE_STRING key,PUNICODE_STRING val) {
320         FIXME(ntdll,"(0x%08lx,%s,%s),stub!\n",x1,debugstr_w(key->Buffer),debugstr_w(val->Buffer));
321         return 0;
322 }
323
324 /******************************************************************************
325  *  RtlNewSecurityObject                [NTDLL] 
326  */
327 DWORD WINAPI RtlNewSecurityObject(DWORD x1,DWORD x2,DWORD x3,DWORD x4,DWORD x5,DWORD x6) {
328         FIXME(ntdll,"(0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx),stub!\n",x1,x2,x3,x4,x5,x6);
329         return 0;
330 }
331
332 /******************************************************************************
333  *  RtlDeleteSecurityObject             [NTDLL] 
334  */
335 DWORD WINAPI RtlDeleteSecurityObject(DWORD x1) {
336         FIXME(ntdll,"(0x%08lx),stub!\n",x1);
337         return 0;
338 }
339
340 /**************************************************************************
341  *                 RtlNormalizeProcessParams            [NTDLL.441]
342  */
343 LPVOID WINAPI RtlNormalizeProcessParams(LPVOID x)
344 {
345     FIXME(ntdll,"(%p), stub\n",x);
346     return x;
347 }
348
349 /**************************************************************************
350  *                 RtlNtStatusToDosError                        [NTDLL.442]
351  */
352 DWORD WINAPI RtlNtStatusToDosError(DWORD error)
353 {
354         FIXME(ntdll, "(%lx): map STATUS_ to ERROR_\n",error);
355         switch (error)
356         { case STATUS_SUCCESS:                  return ERROR_SUCCESS;
357           case STATUS_INVALID_PARAMETER:        return ERROR_BAD_ARGUMENTS;
358           case STATUS_BUFFER_TOO_SMALL:         return ERROR_INSUFFICIENT_BUFFER;
359 /*        case STATUS_INVALID_SECURITY_DESCR:   return ERROR_INVALID_SECURITY_DESCR;*/
360           case STATUS_NO_MEMORY:                return ERROR_NOT_ENOUGH_MEMORY;
361 /*        case STATUS_UNKNOWN_REVISION:
362           case STATUS_BUFFER_OVERFLOW:*/
363         }
364         FIXME(ntdll, "unknown status (%lx)\n",error);
365         return ERROR_SUCCESS;
366 }
367
368 /**************************************************************************
369  *                 RtlGetNtProductType                  [NTDLL.390]
370  */
371 BOOLEAN WINAPI RtlGetNtProductType(LPDWORD type)
372 {
373     FIXME(ntdll, "(%p): stub\n", type);
374     *type=3; /* dunno. 1 for client, 3 for server? */
375     return 1;
376 }
377
378 /**************************************************************************
379  *                 NTDLL_chkstk                         [NTDLL.862]
380  *                 NTDLL_alloca_probe                           [NTDLL.861]
381  * Glorified "enter xxxx".
382  */
383 REGS_ENTRYPOINT(NTDLL_chkstk)
384 {
385     ESP_reg(context) -= EAX_reg(context);
386 }
387 REGS_ENTRYPOINT(NTDLL_alloca_probe)
388 {
389     ESP_reg(context) -= EAX_reg(context);
390 }
391
392 /******************************************************************************
393  * RtlExtendedLargeIntegerDivide [NTDLL.359]
394  */
395 INT WINAPI RtlExtendedLargeIntegerDivide(
396         LARGE_INTEGER dividend,
397         DWORD divisor,
398         LPDWORD rest
399 ) {
400 #if SIZEOF_LONG_LONG==8
401         long long x1 = *(long long*)&dividend;
402
403         if (*rest)
404                 *rest = x1 % divisor;
405         return x1/divisor;
406 #else
407         FIXME(ntdll,"((%d<<32)+%d,%d,%p), implement this using normal integer arithmetic!\n",dividend.HighPart,dividend.LowPart,divisor,rest);
408         return 0;
409 #endif
410 }
411
412 /******************************************************************************
413  * RtlExtendedLargeIntegerMultiply [NTDLL.359]
414  * Note: This even works, since gcc returns 64bit values in eax/edx just like
415  * the caller expects. However... The relay code won't grok this I think.
416  */
417 long long WINAPI RtlExtendedIntegerMultiply(
418         LARGE_INTEGER factor1,
419         INT factor2) 
420 {
421 #if SIZEOF_LONG_LONG==8
422         return (*(long long*)&factor1) * factor2;
423 #else
424         FIXME(ntdll,"((%d<<32)+%d,%ld), implement this using normal integer arithmetic!\n",factor1.HighPart,factor1.LowPart,factor2);
425         return 0;
426 #endif
427 }
428
429 /******************************************************************************
430  *  RtlFormatCurrentUserKeyPath         [NTDLL.371] 
431  */
432 DWORD WINAPI RtlFormatCurrentUserKeyPath(DWORD x)
433 {
434     FIXME(ntdll,"(0x%08lx): stub\n",x);
435     return 1;
436 }
437
438 /******************************************************************************
439  *  RtlOpenCurrentUser          [NTDLL] 
440  */
441 DWORD WINAPI RtlOpenCurrentUser(DWORD x1, DWORD *x2)
442 {
443 /* Note: this is not the correct solution, 
444  * But this works pretty good on wine and NT4.0 binaries
445  */
446         if  ( x1 == 0x2000000 )  {
447                 *x2 = HKEY_CURRENT_USER; 
448                 return TRUE;
449         }
450                 
451         return FALSE;
452 }
453 /**************************************************************************
454  *                 RtlDosPathNameToNtPathName_U         [NTDLL.338]
455  *
456  * FIXME: convert to UNC or whatever is expected here
457  */
458 BOOLEAN  WINAPI RtlDosPathNameToNtPathName_U(
459         LPWSTR from,PUNICODE_STRING us,DWORD x2,DWORD x3)
460 {
461         LPSTR   fromA = HEAP_strdupWtoA(GetProcessHeap(),0,from);
462
463         FIXME(ntdll,"(%s,%p,%08lx,%08lx)\n",fromA,us,x2,x3);
464         if (us)
465                 RtlInitUnicodeString(us,HEAP_strdupW(GetProcessHeap(),0,from));
466         return TRUE;
467 }
468
469 /******************************************************************************
470  *  RtlCreateEnvironment                [NTDLL] 
471  */
472 DWORD WINAPI RtlCreateEnvironment(DWORD x1,DWORD x2) {
473         FIXME(ntdll,"(0x%08lx,0x%08lx),stub!\n",x1,x2);
474         return 0;
475 }
476
477
478 /******************************************************************************
479  *  RtlDestroyEnvironment               [NTDLL] 
480  */
481 DWORD WINAPI RtlDestroyEnvironment(DWORD x) {
482         FIXME(ntdll,"(0x%08lx),stub!\n",x);
483         return 0;
484 }
485
486 /******************************************************************************
487  *  RtlQueryEnvironmentVariable_U               [NTDLL] 
488  */
489 DWORD WINAPI RtlQueryEnvironmentVariable_U(DWORD x1,PUNICODE_STRING key,PUNICODE_STRING val) {
490         FIXME(ntdll,"(0x%08lx,%s,%p),stub!\n",x1,debugstr_w(key->Buffer),val);
491         return 0;
492 }