[NTDLL]
[reactos.git] / reactos / dll / ntdll / rtl / libsupp.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NT User-Mode DLL
4 * FILE: lib/ntdll/rtl/libsup.c
5 * PURPOSE: RTL Support Routines
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Gunnar Dalsnes
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntdll.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 SIZE_T RtlpAllocDeallocQueryBufferSize = PAGE_SIZE;
18 PTEB LdrpTopLevelDllBeingLoadedTeb = NULL;
19 PVOID MmHighestUserAddress = (PVOID)MI_HIGHEST_USER_ADDRESS;
20
21 /* FUNCTIONS ***************************************************************/
22
23 BOOLEAN
24 NTAPI
25 RtlpCheckForActiveDebugger(VOID)
26 {
27 /* Return the flag in the PEB */
28 return NtCurrentPeb()->BeingDebugged;
29 }
30
31 BOOLEAN
32 NTAPI
33 RtlpSetInDbgPrint(VOID)
34 {
35 /* Check if it's already set and return TRUE if so */
36 if (NtCurrentTeb()->InDbgPrint) return TRUE;
37
38 /* Set it and return */
39 NtCurrentTeb()->InDbgPrint = TRUE;
40 return FALSE;
41 }
42
43 VOID
44 NTAPI
45 RtlpClearInDbgPrint(VOID)
46 {
47 /* Clear the flag */
48 NtCurrentTeb()->InDbgPrint = FALSE;
49 }
50
51 KPROCESSOR_MODE
52 NTAPI
53 RtlpGetMode(VOID)
54 {
55 return UserMode;
56 }
57
58 /*
59 * @implemented
60 */
61 PPEB
62 NTAPI
63 RtlGetCurrentPeb(VOID)
64 {
65 return NtCurrentPeb();
66 }
67
68 /*
69 * @implemented
70 */
71 VOID NTAPI
72 RtlAcquirePebLock(VOID)
73 {
74 PPEB Peb = NtCurrentPeb ();
75 RtlEnterCriticalSection(Peb->FastPebLock);
76 }
77
78 /*
79 * @implemented
80 */
81 VOID NTAPI
82 RtlReleasePebLock(VOID)
83 {
84 PPEB Peb = NtCurrentPeb ();
85 RtlLeaveCriticalSection(Peb->FastPebLock);
86 }
87
88 /*
89 * @implemented
90 */
91 ULONG
92 NTAPI
93 RtlGetNtGlobalFlags(VOID)
94 {
95 PPEB pPeb = NtCurrentPeb();
96 return pPeb->NtGlobalFlag;
97 }
98
99 NTSTATUS
100 NTAPI
101 RtlDeleteHeapLock(IN OUT PHEAP_LOCK Lock)
102 {
103 return RtlDeleteCriticalSection(&Lock->CriticalSection);
104 }
105
106 NTSTATUS
107 NTAPI
108 RtlEnterHeapLock(IN OUT PHEAP_LOCK Lock, IN BOOLEAN Exclusive)
109 {
110 UNREFERENCED_PARAMETER(Exclusive);
111
112 return RtlEnterCriticalSection(&Lock->CriticalSection);
113 }
114
115 BOOLEAN
116 NTAPI
117 RtlTryEnterHeapLock(IN OUT PHEAP_LOCK Lock, IN BOOLEAN Exclusive)
118 {
119 UNREFERENCED_PARAMETER(Exclusive);
120
121 return RtlTryEnterCriticalSection(&Lock->CriticalSection);
122 }
123
124 NTSTATUS
125 NTAPI
126 RtlInitializeHeapLock(IN OUT PHEAP_LOCK *Lock)
127 {
128 return RtlInitializeCriticalSection(&(*Lock)->CriticalSection);
129 }
130
131 NTSTATUS
132 NTAPI
133 RtlLeaveHeapLock(IN OUT PHEAP_LOCK Lock)
134 {
135 return RtlLeaveCriticalSection(&Lock->CriticalSection);
136 }
137
138 PVOID
139 NTAPI
140 RtlpAllocateMemory(UINT Bytes,
141 ULONG Tag)
142 {
143 UNREFERENCED_PARAMETER(Tag);
144
145 return RtlAllocateHeap(RtlGetProcessHeap(),
146 0,
147 Bytes);
148 }
149
150
151 VOID
152 NTAPI
153 RtlpFreeMemory(PVOID Mem,
154 ULONG Tag)
155 {
156 UNREFERENCED_PARAMETER(Tag);
157
158 RtlFreeHeap(RtlGetProcessHeap(),
159 0,
160 Mem);
161 }
162
163
164 #if DBG
165 VOID FASTCALL
166 CHECK_PAGED_CODE_RTL(char *file, int line)
167 {
168 /* meaningless in user mode */
169 }
170 #endif
171
172 VOID
173 NTAPI
174 RtlpSetHeapParameters(IN PRTL_HEAP_PARAMETERS Parameters)
175 {
176 PPEB Peb;
177
178 /* Get PEB */
179 Peb = RtlGetCurrentPeb();
180
181 /* Apply defaults for non-set parameters */
182 if (!Parameters->SegmentCommit) Parameters->SegmentCommit = Peb->HeapSegmentCommit;
183 if (!Parameters->SegmentReserve) Parameters->SegmentReserve = Peb->HeapSegmentReserve;
184 if (!Parameters->DeCommitFreeBlockThreshold) Parameters->DeCommitFreeBlockThreshold = Peb->HeapDeCommitFreeBlockThreshold;
185 if (!Parameters->DeCommitTotalFreeThreshold) Parameters->DeCommitTotalFreeThreshold = Peb->HeapDeCommitTotalFreeThreshold;
186 }
187
188 BOOLEAN
189 NTAPI
190 RtlpHandleDpcStackException(IN PEXCEPTION_REGISTRATION_RECORD RegistrationFrame,
191 IN ULONG_PTR RegistrationFrameEnd,
192 IN OUT PULONG_PTR StackLow,
193 IN OUT PULONG_PTR StackHigh)
194 {
195 /* There's no such thing as a DPC stack in user-mode */
196 return FALSE;
197 }
198
199 VOID
200 NTAPI
201 RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord,
202 IN PCONTEXT ContextRecord,
203 IN PVOID ContextData,
204 IN ULONG Size)
205 {
206 /* Exception logging is not done in user-mode */
207 }
208
209 BOOLEAN
210 NTAPI
211 RtlpCaptureStackLimits(IN ULONG_PTR Ebp,
212 IN ULONG_PTR *StackBegin,
213 IN ULONG_PTR *StackEnd)
214 {
215 /* FIXME: Verify */
216 *StackBegin = (ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit;
217 *StackEnd = (ULONG_PTR)NtCurrentTeb()->NtTib.StackBase;
218 return TRUE;
219 }
220
221 #ifndef _M_AMD64
222 /*
223 * @implemented
224 */
225 ULONG
226 NTAPI
227 RtlWalkFrameChain(OUT PVOID *Callers,
228 IN ULONG Count,
229 IN ULONG Flags)
230 {
231 ULONG_PTR Stack, NewStack, StackBegin, StackEnd = 0;
232 ULONG Eip;
233 BOOLEAN Result, StopSearch = FALSE;
234 ULONG i = 0;
235
236 /* Get current EBP */
237 #if defined(_M_IX86)
238 #if defined __GNUC__
239 __asm__("mov %%ebp, %0" : "=r" (Stack) : );
240 #elif defined(_MSC_VER)
241 __asm mov Stack, ebp
242 #endif
243 #elif defined(_M_MIPS)
244 __asm__("move $sp, %0" : "=r" (Stack) : );
245 #elif defined(_M_PPC)
246 __asm__("mr %0,1" : "=r" (Stack) : );
247 #elif defined(_M_ARM)
248 __asm__("mov sp, %0" : "=r"(Stack) : );
249 #else
250 #error Unknown architecture
251 #endif
252
253 /* Set it as the stack begin limit as well */
254 StackBegin = (ULONG_PTR)Stack;
255
256 /* Check if we're called for non-logging mode */
257 if (!Flags)
258 {
259 /* Get the actual safe limits */
260 Result = RtlpCaptureStackLimits((ULONG_PTR)Stack,
261 &StackBegin,
262 &StackEnd);
263 if (!Result) return 0;
264 }
265
266 /* Use a SEH block for maximum protection */
267 _SEH2_TRY
268 {
269 /* Loop the frames */
270 for (i = 0; i < Count; i++)
271 {
272 /*
273 * Leave if we're past the stack,
274 * if we're before the stack,
275 * or if we've reached ourselves.
276 */
277 if ((Stack >= StackEnd) ||
278 (!i ? (Stack < StackBegin) : (Stack <= StackBegin)) ||
279 ((StackEnd - Stack) < (2 * sizeof(ULONG_PTR))))
280 {
281 /* We're done or hit a bad address */
282 break;
283 }
284
285 /* Get new stack and EIP */
286 NewStack = *(PULONG_PTR)Stack;
287 Eip = *(PULONG_PTR)(Stack + sizeof(ULONG_PTR));
288
289 /* Check if the new pointer is above the oldone and past the end */
290 if (!((Stack < NewStack) && (NewStack < StackEnd)))
291 {
292 /* Stop searching after this entry */
293 StopSearch = TRUE;
294 }
295
296 /* Also make sure that the EIP isn't a stack address */
297 if ((StackBegin < Eip) && (Eip < StackEnd)) break;
298
299 /* FIXME: Check that EIP is inside a loaded module */
300
301 /* Save this frame */
302 Callers[i] = (PVOID)Eip;
303
304 /* Check if we should continue */
305 if (StopSearch)
306 {
307 /* Return the next index */
308 i++;
309 break;
310 }
311
312 /* Move to the next stack */
313 Stack = NewStack;
314 }
315 }
316 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
317 {
318 /* No index */
319 i = 0;
320 }
321 _SEH2_END;
322
323 /* Return frames parsed */
324 return i;
325 }
326 #endif
327
328 #ifdef _AMD64_
329 VOID
330 NTAPI
331 RtlpGetStackLimits(
332 OUT PULONG_PTR LowLimit,
333 OUT PULONG_PTR HighLimit)
334 {
335 *LowLimit = (ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit;
336 *HighLimit = (ULONG_PTR)NtCurrentTeb()->NtTib.StackBase;
337 return;
338 }
339 #endif
340
341 BOOLEAN
342 NTAPI
343 RtlIsThreadWithinLoaderCallout(VOID)
344 {
345 return LdrpTopLevelDllBeingLoadedTeb == NtCurrentTeb();
346 }
347
348 /* RTL Atom Tables ************************************************************/
349
350 typedef struct _RTL_ATOM_HANDLE
351 {
352 RTL_HANDLE_TABLE_ENTRY Handle;
353 PRTL_ATOM_TABLE_ENTRY AtomEntry;
354 } RTL_ATOM_HANDLE, *PRTL_ATOM_HANDLE;
355
356 NTSTATUS
357 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable)
358 {
359 RtlInitializeCriticalSection(&AtomTable->CriticalSection);
360 return STATUS_SUCCESS;
361 }
362
363
364 VOID
365 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable)
366 {
367 RtlDeleteCriticalSection(&AtomTable->CriticalSection);
368 }
369
370
371 BOOLEAN
372 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable)
373 {
374 RtlEnterCriticalSection(&AtomTable->CriticalSection);
375 return TRUE;
376 }
377
378
379 VOID
380 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable)
381 {
382 RtlLeaveCriticalSection(&AtomTable->CriticalSection);
383 }
384
385
386 /* handle functions */
387
388 BOOLEAN
389 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
390 {
391 RtlInitializeHandleTable(0xCFFF,
392 sizeof(RTL_ATOM_HANDLE),
393 &AtomTable->RtlHandleTable);
394
395 return TRUE;
396 }
397
398 VOID
399 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
400 {
401 RtlDestroyHandleTable(&AtomTable->RtlHandleTable);
402 }
403
404 PRTL_ATOM_TABLE
405 RtlpAllocAtomTable(ULONG Size)
406 {
407 return (PRTL_ATOM_TABLE)RtlAllocateHeap(RtlGetProcessHeap(),
408 HEAP_ZERO_MEMORY,
409 Size);
410 }
411
412 VOID
413 RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable)
414 {
415 RtlFreeHeap(RtlGetProcessHeap(),
416 0,
417 AtomTable);
418 }
419
420 PRTL_ATOM_TABLE_ENTRY
421 RtlpAllocAtomTableEntry(ULONG Size)
422 {
423 return (PRTL_ATOM_TABLE_ENTRY)RtlAllocateHeap(RtlGetProcessHeap(),
424 HEAP_ZERO_MEMORY,
425 Size);
426 }
427
428 VOID
429 RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry)
430 {
431 RtlFreeHeap(RtlGetProcessHeap(),
432 0,
433 Entry);
434 }
435
436 VOID
437 RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
438 {
439 PRTL_HANDLE_TABLE_ENTRY RtlHandleEntry;
440
441 if (RtlIsValidIndexHandle(&AtomTable->RtlHandleTable,
442 (ULONG)Entry->HandleIndex,
443 &RtlHandleEntry))
444 {
445 RtlFreeHandle(&AtomTable->RtlHandleTable,
446 RtlHandleEntry);
447 }
448 }
449
450 BOOLEAN
451 RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
452 {
453 ULONG HandleIndex;
454 PRTL_HANDLE_TABLE_ENTRY RtlHandle;
455
456 RtlHandle = RtlAllocateHandle(&AtomTable->RtlHandleTable,
457 &HandleIndex);
458 if (RtlHandle != NULL)
459 {
460 PRTL_ATOM_HANDLE AtomHandle = (PRTL_ATOM_HANDLE)RtlHandle;
461
462 /* FIXME - Handle Indexes >= 0xC000 ?! */
463 if (HandleIndex < 0xC000)
464 {
465 Entry->HandleIndex = (USHORT)HandleIndex;
466 Entry->Atom = 0xC000 + (USHORT)HandleIndex;
467
468 AtomHandle->AtomEntry = Entry;
469 AtomHandle->Handle.Flags = RTL_HANDLE_VALID;
470
471 return TRUE;
472 }
473 else
474 {
475 /* set the valid flag, otherwise RtlFreeHandle will fail! */
476 AtomHandle->Handle.Flags = RTL_HANDLE_VALID;
477
478 RtlFreeHandle(&AtomTable->RtlHandleTable,
479 RtlHandle);
480 }
481 }
482
483 return FALSE;
484 }
485
486 PRTL_ATOM_TABLE_ENTRY
487 RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable, ULONG Index)
488 {
489 PRTL_HANDLE_TABLE_ENTRY RtlHandle;
490
491 if (RtlIsValidIndexHandle(&AtomTable->RtlHandleTable,
492 Index,
493 &RtlHandle))
494 {
495 PRTL_ATOM_HANDLE AtomHandle = (PRTL_ATOM_HANDLE)RtlHandle;
496
497 return AtomHandle->AtomEntry;
498 }
499
500 return NULL;
501 }
502
503
504 /*
505 * Ldr Resource support code
506 */
507
508 IMAGE_RESOURCE_DIRECTORY *find_entry_by_name( IMAGE_RESOURCE_DIRECTORY *dir,
509 LPCWSTR name, void *root,
510 int want_dir );
511 IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( IMAGE_RESOURCE_DIRECTORY *dir,
512 WORD id, void *root, int want_dir );
513 IMAGE_RESOURCE_DIRECTORY *find_first_entry( IMAGE_RESOURCE_DIRECTORY *dir,
514 void *root, int want_dir );
515 int push_language( USHORT *list, ULONG pos, WORD lang );
516
517 /**********************************************************************
518 * find_entry
519 *
520 * Find a resource entry
521 */
522 NTSTATUS find_entry( PVOID BaseAddress, LDR_RESOURCE_INFO *info,
523 ULONG level, void **ret, int want_dir )
524 {
525 ULONG size;
526 void *root;
527 IMAGE_RESOURCE_DIRECTORY *resdirptr;
528 USHORT list[9]; /* list of languages to try */
529 int i, pos = 0;
530 LCID user_lcid, system_lcid;
531
532 root = RtlImageDirectoryEntryToData( BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size );
533 if (!root) return STATUS_RESOURCE_DATA_NOT_FOUND;
534 if (size < sizeof(*resdirptr)) return STATUS_RESOURCE_DATA_NOT_FOUND;
535 resdirptr = root;
536
537 if (!level--) goto done;
538 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Type, root, want_dir || level )))
539 return STATUS_RESOURCE_TYPE_NOT_FOUND;
540 if (!level--) return STATUS_SUCCESS;
541
542 resdirptr = *ret;
543 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Name, root, want_dir || level )))
544 return STATUS_RESOURCE_NAME_NOT_FOUND;
545 if (!level--) return STATUS_SUCCESS;
546 if (level) return STATUS_INVALID_PARAMETER; /* level > 3 */
547
548 /* 1. specified language */
549 pos = push_language( list, pos, info->Language );
550
551 /* 2. specified language with neutral sublanguage */
552 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(info->Language), SUBLANG_NEUTRAL ) );
553
554 /* 3. neutral language with neutral sublanguage */
555 pos = push_language( list, pos, MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ) );
556
557 /* if no explicitly specified language, try some defaults */
558 if (PRIMARYLANGID(info->Language) == LANG_NEUTRAL)
559 {
560 /* user defaults, unless SYS_DEFAULT sublanguage specified */
561 if (SUBLANGID(info->Language) != SUBLANG_SYS_DEFAULT)
562 {
563 /* 4. current thread locale language */
564 pos = push_language( list, pos, LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale) );
565
566 if (NT_SUCCESS(NtQueryDefaultLocale(TRUE, &user_lcid)))
567 {
568 /* 5. user locale language */
569 pos = push_language( list, pos, LANGIDFROMLCID(user_lcid) );
570
571 /* 6. user locale language with neutral sublanguage */
572 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(user_lcid), SUBLANG_NEUTRAL ) );
573 }
574 }
575
576 /* now system defaults */
577
578 if (NT_SUCCESS(NtQueryDefaultLocale(FALSE, &system_lcid)))
579 {
580 /* 7. system locale language */
581 pos = push_language( list, pos, LANGIDFROMLCID( system_lcid ) );
582
583 /* 8. system locale language with neutral sublanguage */
584 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(system_lcid), SUBLANG_NEUTRAL ) );
585 }
586
587 /* 9. English */
588 pos = push_language( list, pos, MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT ) );
589 }
590
591 resdirptr = *ret;
592 for (i = 0; i < pos; i++)
593 if ((*ret = find_entry_by_id( resdirptr, list[i], root, want_dir ))) return STATUS_SUCCESS;
594
595 /* if no explicitly specified language, return the first entry */
596 if (PRIMARYLANGID(info->Language) == LANG_NEUTRAL)
597 {
598 if ((*ret = find_first_entry( resdirptr, root, want_dir ))) return STATUS_SUCCESS;
599 }
600 return STATUS_RESOURCE_LANG_NOT_FOUND;
601
602 done:
603 *ret = resdirptr;
604 return STATUS_SUCCESS;
605 }
606
607 /*
608 * @implemented
609 */
610 PVOID NTAPI
611 RtlPcToFileHeader(IN PVOID PcValue,
612 PVOID* BaseOfImage)
613 {
614 PLIST_ENTRY ModuleListHead;
615 PLIST_ENTRY Entry;
616 PLDR_DATA_TABLE_ENTRY Module;
617 PVOID ImageBase = NULL;
618
619 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
620 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
621 Entry = ModuleListHead->Flink;
622 while (Entry != ModuleListHead)
623 {
624 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
625
626 if ((ULONG_PTR)PcValue >= (ULONG_PTR)Module->DllBase &&
627 (ULONG_PTR)PcValue < (ULONG_PTR)Module->DllBase + Module->SizeOfImage)
628 {
629 ImageBase = Module->DllBase;
630 break;
631 }
632 Entry = Entry->Flink;
633 }
634 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
635
636 *BaseOfImage = ImageBase;
637 return ImageBase;
638 }
639
640 /*
641 * @unimplemented
642 */
643 NTSYSAPI
644 NTSTATUS
645 NTAPI
646 RtlDosApplyFileIsolationRedirection_Ustr(IN ULONG Flags,
647 IN PUNICODE_STRING OriginalName,
648 IN PUNICODE_STRING Extension,
649 IN OUT PUNICODE_STRING StaticString,
650 IN OUT PUNICODE_STRING DynamicString,
651 IN OUT PUNICODE_STRING *NewName,
652 IN PULONG NewFlags,
653 IN PSIZE_T FileNameSize,
654 IN PSIZE_T RequiredLength)
655 {
656 return STATUS_SXS_KEY_NOT_FOUND;
657 }
658
659 /*
660 * @implemented
661 */
662 NTSYSAPI
663 NTSTATUS
664 NTAPI
665 RtlWow64EnableFsRedirection(IN BOOLEAN Wow64FsEnableRedirection)
666 {
667 /* This is what Windows returns on x86 */
668 return STATUS_NOT_IMPLEMENTED;
669 }
670
671 /*
672 * @implemented
673 */
674 NTSYSAPI
675 NTSTATUS
676 NTAPI
677 RtlWow64EnableFsRedirectionEx(IN PVOID Wow64FsEnableRedirection,
678 OUT PVOID *OldFsRedirectionLevel)
679 {
680 /* This is what Windows returns on x86 */
681 return STATUS_NOT_IMPLEMENTED;
682 }
683
684 /*
685 * @unimplemented
686 */
687 NTSYSAPI
688 NTSTATUS
689 NTAPI
690 RtlComputeImportTableHash(IN HANDLE FileHandle,
691 OUT PCHAR Hash,
692 IN ULONG ImportTableHashSize)
693 {
694 UNIMPLEMENTED;
695 return STATUS_NOT_IMPLEMENTED;
696 }
697
698 NTSTATUS
699 NTAPI
700 RtlpSafeCopyMemory(
701 _Out_writes_bytes_all_(Length) VOID UNALIGNED *Destination,
702 _In_reads_bytes_(Length) CONST VOID UNALIGNED *Source,
703 _In_ SIZE_T Length)
704 {
705 _SEH2_TRY
706 {
707 RtlCopyMemory(Destination, Source, Length);
708 }
709 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
710 {
711 _SEH2_YIELD(return _SEH2_GetExceptionCode());
712 }
713 _SEH2_END;
714
715 return STATUS_SUCCESS;
716 }
717
718 /* FIXME: code duplication with kernel32/client/time.c */
719 ULONG
720 NTAPI
721 RtlGetTickCount(VOID)
722 {
723 ULARGE_INTEGER TickCount;
724
725 #ifdef _WIN64
726 TickCount.QuadPart = *((volatile ULONG64*)&SharedUserData->TickCount);
727 #else
728 while (TRUE)
729 {
730 TickCount.HighPart = (ULONG)SharedUserData->TickCount.High1Time;
731 TickCount.LowPart = SharedUserData->TickCount.LowPart;
732
733 if (TickCount.HighPart == (ULONG)SharedUserData->TickCount.High2Time)
734 break;
735
736 YieldProcessor();
737 }
738 #endif
739
740 return (ULONG)((UInt32x32To64(TickCount.LowPart,
741 SharedUserData->TickCountMultiplier) >> 24) +
742 UInt32x32To64((TickCount.HighPart << 8) & 0xFFFFFFFF,
743 SharedUserData->TickCountMultiplier));
744 }
745
746 /* EOF */