Merge from amd64-branch:
[reactos.git] / reactos / dll / win32 / kernel32 / thread / thread.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/kernel32/thread/thread.c
5 * PURPOSE: Thread functions
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Ariadne ( ariadne@xs4all.nl)
8 *
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <k32.h>
14
15 #define NDEBUG
16 #include <debug.h>
17
18 /* FIXME: NDK */
19 #define HIGH_PRIORITY 31
20 #define SXS_SUPPORT_FIXME
21
22 /* FUNCTIONS *****************************************************************/
23 static
24 LONG BaseThreadExceptionFilter(EXCEPTION_POINTERS * ExceptionInfo)
25 {
26 LONG ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER;
27
28 if (GlobalTopLevelExceptionFilter != NULL)
29 {
30 _SEH2_TRY
31 {
32 ExceptionDisposition = GlobalTopLevelExceptionFilter(ExceptionInfo);
33 }
34 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
35 {
36 ExceptionDisposition = UnhandledExceptionFilter(ExceptionInfo);
37 }
38 _SEH2_END;
39 }
40
41 return ExceptionDisposition;
42 }
43
44 __declspec(noreturn)
45 VOID
46 WINAPI
47 BaseThreadStartup(LPTHREAD_START_ROUTINE lpStartAddress,
48 LPVOID lpParameter)
49 {
50 volatile UINT uExitCode = 0;
51
52 /* Attempt to call the Thread Start Address */
53 _SEH2_TRY
54 {
55 /* Get the exit code from the Thread Start */
56 uExitCode = (lpStartAddress)((PVOID)lpParameter);
57 }
58 _SEH2_EXCEPT(BaseThreadExceptionFilter(_SEH2_GetExceptionInformation()))
59 {
60 /* Get the Exit code from the SEH Handler */
61 uExitCode = _SEH2_GetExceptionCode();
62 } _SEH2_END;
63
64 /* Exit the Thread */
65 ExitThread(uExitCode);
66 }
67
68 /*
69 * @implemented
70 */
71 HANDLE
72 WINAPI
73 CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,
74 DWORD dwStackSize,
75 LPTHREAD_START_ROUTINE lpStartAddress,
76 LPVOID lpParameter,
77 DWORD dwCreationFlags,
78 LPDWORD lpThreadId)
79 {
80 /* Act as if we're going to create a remote thread in ourselves */
81 return CreateRemoteThread(NtCurrentProcess(),
82 lpThreadAttributes,
83 dwStackSize,
84 lpStartAddress,
85 lpParameter,
86 dwCreationFlags,
87 lpThreadId);
88 }
89
90 /*
91 * @implemented
92 */
93 HANDLE
94 WINAPI
95 CreateRemoteThread(HANDLE hProcess,
96 LPSECURITY_ATTRIBUTES lpThreadAttributes,
97 DWORD dwStackSize,
98 LPTHREAD_START_ROUTINE lpStartAddress,
99 LPVOID lpParameter,
100 DWORD dwCreationFlags,
101 LPDWORD lpThreadId)
102 {
103 NTSTATUS Status;
104 INITIAL_TEB InitialTeb;
105 CONTEXT Context;
106 CLIENT_ID ClientId;
107 OBJECT_ATTRIBUTES LocalObjectAttributes;
108 POBJECT_ATTRIBUTES ObjectAttributes;
109 HANDLE hThread;
110 ULONG Dummy;
111
112 DPRINT("CreateRemoteThread: hProcess: %ld dwStackSize: %ld lpStartAddress"
113 ": %p lpParameter: %lx, dwCreationFlags: %lx\n", hProcess,
114 dwStackSize, lpStartAddress, lpParameter, dwCreationFlags);
115
116 /* Clear the Context */
117 RtlZeroMemory(&Context, sizeof(CONTEXT));
118
119 /* Write PID */
120 ClientId.UniqueProcess = hProcess;
121
122 /* Create the Stack */
123 Status = BasepCreateStack(hProcess,
124 dwStackSize,
125 dwCreationFlags & STACK_SIZE_PARAM_IS_A_RESERVATION ?
126 dwStackSize : 0,
127 &InitialTeb);
128 if(!NT_SUCCESS(Status))
129 {
130 SetLastErrorByStatus(Status);
131 return NULL;
132 }
133
134 /* Create Initial Context */
135 BasepInitializeContext(&Context,
136 lpParameter,
137 lpStartAddress,
138 InitialTeb.StackBase,
139 1);
140
141 /* initialize the attributes for the thread object */
142 ObjectAttributes = BasepConvertObjectAttributes(&LocalObjectAttributes,
143 lpThreadAttributes,
144 NULL);
145
146 /* Create the Kernel Thread Object */
147 Status = NtCreateThread(&hThread,
148 THREAD_ALL_ACCESS,
149 ObjectAttributes,
150 hProcess,
151 &ClientId,
152 &Context,
153 &InitialTeb,
154 TRUE);
155 if(!NT_SUCCESS(Status))
156 {
157 BasepFreeStack(hProcess, &InitialTeb);
158 SetLastErrorByStatus(Status);
159 return NULL;
160 }
161
162 /* Are we in the same process? */
163 if (hProcess == NtCurrentProcess())
164 {
165 PTEB Teb;
166 PVOID ActivationContextStack;
167 THREAD_BASIC_INFORMATION ThreadBasicInfo;
168 #ifndef SXS_SUPPORT_FIXME
169 ACTIVATION_CONTEXT_BASIC_INFORMATION ActivationCtxInfo;
170 ULONG_PTR Cookie;
171 #endif
172 ULONG retLen;
173
174 /* Get the TEB */
175 Status = NtQueryInformationThread(hThread,
176 ThreadBasicInformation,
177 &ThreadBasicInfo,
178 sizeof(ThreadBasicInfo),
179 &retLen);
180 if (NT_SUCCESS(Status))
181 {
182 /* Allocate the Activation Context Stack */
183 Status = RtlAllocateActivationContextStack(&ActivationContextStack);
184 }
185
186 if (NT_SUCCESS(Status))
187 {
188 Teb = ThreadBasicInfo.TebBaseAddress;
189
190 /* Save it */
191 Teb->ActivationContextStackPointer = ActivationContextStack;
192 #ifndef SXS_SUPPORT_FIXME
193 /* Query the Context */
194 Status = RtlQueryInformationActivationContext(1,
195 0,
196 NULL,
197 ActivationContextBasicInformation,
198 &ActivationCtxInfo,
199 sizeof(ActivationCtxInfo),
200 &retLen);
201 if (NT_SUCCESS(Status))
202 {
203 /* Does it need to be activated? */
204 if (!ActivationCtxInfo.hActCtx)
205 {
206 /* Activate it */
207 Status = RtlActivateActivationContext(1,
208 ActivationCtxInfo.hActCtx,
209 &Cookie);
210 if (!NT_SUCCESS(Status))
211 DPRINT1("RtlActivateActivationContext failed %x\n", Status);
212 }
213 }
214 else
215 DPRINT1("RtlQueryInformationActivationContext failed %x\n", Status);
216 #endif
217 }
218 else
219 DPRINT1("RtlAllocateActivationContextStack failed %x\n", Status);
220 }
221
222 /* FIXME: Notify CSR */
223
224 /* Success */
225 if(lpThreadId) *lpThreadId = (DWORD)ClientId.UniqueThread;
226
227 /* Resume it if asked */
228 if (!(dwCreationFlags & CREATE_SUSPENDED))
229 {
230 NtResumeThread(hThread, &Dummy);
231 }
232
233 /* Return handle to thread */
234 return hThread;
235 }
236
237 /*
238 * @implemented
239 */
240 VOID
241 WINAPI
242 ExitThread(DWORD uExitCode)
243 {
244 NTSTATUS Status;
245 ULONG LastThread;
246
247 /*
248 * Terminate process if this is the last thread
249 * of the current process
250 */
251 Status = NtQueryInformationThread(NtCurrentThread(),
252 ThreadAmILastThread,
253 &LastThread,
254 sizeof(LastThread),
255 NULL);
256 if (NT_SUCCESS(Status) && LastThread)
257 {
258 /* Exit the Process */
259 ExitProcess(uExitCode);
260 }
261
262 /* Notify DLLs and TLS Callbacks of termination */
263 LdrShutdownThread();
264
265 /* Tell the Kernel to free the Stack */
266 NtCurrentTeb()->FreeStackOnTermination = TRUE;
267 NtTerminateThread(NULL, uExitCode);
268
269 /* We should never reach this place */
270 DPRINT1("It should not happen\n");
271 while (TRUE) ;
272 }
273
274 /*
275 * @implemented
276 */
277 HANDLE
278 WINAPI
279 OpenThread(DWORD dwDesiredAccess,
280 BOOL bInheritHandle,
281 DWORD dwThreadId)
282 {
283 NTSTATUS Status;
284 HANDLE ThreadHandle;
285 OBJECT_ATTRIBUTES ObjectAttributes;
286 CLIENT_ID ClientId ;
287
288 ClientId.UniqueProcess = 0;
289 ClientId.UniqueThread = ULongToHandle(dwThreadId);
290
291 InitializeObjectAttributes(&ObjectAttributes,
292 NULL,
293 (bInheritHandle ? OBJ_INHERIT : 0),
294 NULL,
295 NULL);
296
297 Status = NtOpenThread(&ThreadHandle,
298 dwDesiredAccess,
299 &ObjectAttributes,
300 &ClientId);
301 if (!NT_SUCCESS(Status))
302 {
303 SetLastErrorByStatus(Status);
304 return NULL;
305 }
306
307 return ThreadHandle;
308 }
309
310 /*
311 * @implemented
312 */
313 PTEB
314 GetTeb(VOID)
315 {
316 return NtCurrentTeb();
317 }
318
319 /*
320 * @implemented
321 */
322 BOOL
323 WINAPI
324 SwitchToThread(VOID)
325 {
326 return NtYieldExecution() != STATUS_NO_YIELD_PERFORMED;
327 }
328
329
330 /*
331 * @implemented
332 */
333 DWORD
334 WINAPI
335 GetCurrentThreadId(VOID)
336 {
337 return (DWORD)(NtCurrentTeb()->ClientId).UniqueThread;
338 }
339
340 /*
341 * @implemented
342 */
343 BOOL
344 NTAPI
345 GetThreadTimes(HANDLE hThread,
346 LPFILETIME lpCreationTime,
347 LPFILETIME lpExitTime,
348 LPFILETIME lpKernelTime,
349 LPFILETIME lpUserTime)
350 {
351 KERNEL_USER_TIMES KernelUserTimes;
352 NTSTATUS Status;
353
354 Status = NtQueryInformationThread(hThread,
355 ThreadTimes,
356 &KernelUserTimes,
357 sizeof(KERNEL_USER_TIMES),
358 NULL);
359 if (!NT_SUCCESS(Status))
360 {
361 SetLastErrorByStatus(Status);
362 return(FALSE);
363 }
364
365 *lpCreationTime = *(LPFILETIME)&KernelUserTimes.CreateTime;
366 *lpExitTime = *(LPFILETIME)&KernelUserTimes.ExitTime;
367 *lpKernelTime = *(LPFILETIME)&KernelUserTimes.KernelTime;
368 *lpUserTime = *(LPFILETIME)&KernelUserTimes.UserTime;
369 return TRUE;
370 }
371
372 /*
373 * @implemented
374 */
375 BOOL
376 WINAPI
377 GetThreadContext(HANDLE hThread,
378 LPCONTEXT lpContext)
379 {
380 NTSTATUS Status;
381
382 Status = NtGetContextThread(hThread, lpContext);
383 if (!NT_SUCCESS(Status))
384 {
385 SetLastErrorByStatus(Status);
386 return FALSE;
387 }
388
389 return TRUE;
390 }
391
392 /*
393 * @implemented
394 */
395 BOOL
396 WINAPI
397 SetThreadContext(HANDLE hThread,
398 CONST CONTEXT *lpContext)
399 {
400 NTSTATUS Status;
401
402 Status = NtSetContextThread(hThread, (PCONTEXT)lpContext);
403 if (!NT_SUCCESS(Status))
404 {
405 SetLastErrorByStatus(Status);
406 return FALSE;
407 }
408
409 return TRUE;
410 }
411
412 /*
413 * @implemented
414 */
415 BOOL
416 WINAPI
417 GetExitCodeThread(HANDLE hThread,
418 LPDWORD lpExitCode)
419 {
420 THREAD_BASIC_INFORMATION ThreadBasic;
421 NTSTATUS Status;
422
423 Status = NtQueryInformationThread(hThread,
424 ThreadBasicInformation,
425 &ThreadBasic,
426 sizeof(THREAD_BASIC_INFORMATION),
427 NULL);
428 if (!NT_SUCCESS(Status))
429 {
430 SetLastErrorByStatus(Status);
431 return(FALSE);
432 }
433
434 *lpExitCode = ThreadBasic.ExitStatus;
435 return TRUE;
436 }
437
438 /*
439 * @implemented
440 */
441 DWORD
442 WINAPI
443 ResumeThread(HANDLE hThread)
444 {
445 ULONG PreviousResumeCount;
446 NTSTATUS Status;
447
448 Status = NtResumeThread(hThread, &PreviousResumeCount);
449 if (!NT_SUCCESS(Status))
450 {
451 SetLastErrorByStatus(Status);
452 return -1;
453 }
454
455 return PreviousResumeCount;
456 }
457
458 /*
459 * @implemented
460 */
461 BOOL
462 WINAPI
463 TerminateThread(HANDLE hThread,
464 DWORD dwExitCode)
465 {
466 NTSTATUS Status;
467
468 if (!hThread)
469 {
470 SetLastError(ERROR_INVALID_HANDLE);
471 return FALSE;
472 }
473
474 Status = NtTerminateThread(hThread, dwExitCode);
475 if (!NT_SUCCESS(Status))
476 {
477 SetLastErrorByStatus(Status);
478 return FALSE;
479 }
480
481 return TRUE;
482 }
483
484 /*
485 * @implemented
486 */
487 DWORD
488 WINAPI
489 SuspendThread(HANDLE hThread)
490 {
491 ULONG PreviousSuspendCount;
492 NTSTATUS Status;
493
494 Status = NtSuspendThread(hThread, &PreviousSuspendCount);
495 if (!NT_SUCCESS(Status))
496 {
497 SetLastErrorByStatus(Status);
498 return -1;
499 }
500
501 return PreviousSuspendCount;
502 }
503
504 /*
505 * @implemented
506 */
507 DWORD_PTR
508 WINAPI
509 SetThreadAffinityMask(HANDLE hThread,
510 DWORD_PTR dwThreadAffinityMask)
511 {
512 THREAD_BASIC_INFORMATION ThreadBasic;
513 KAFFINITY AffinityMask;
514 NTSTATUS Status;
515
516 AffinityMask = (KAFFINITY)dwThreadAffinityMask;
517
518 Status = NtQueryInformationThread(hThread,
519 ThreadBasicInformation,
520 &ThreadBasic,
521 sizeof(THREAD_BASIC_INFORMATION),
522 NULL);
523 if (!NT_SUCCESS(Status))
524 {
525 SetLastErrorByStatus(Status);
526 return 0;
527 }
528
529 Status = NtSetInformationThread(hThread,
530 ThreadAffinityMask,
531 &AffinityMask,
532 sizeof(KAFFINITY));
533 if (!NT_SUCCESS(Status))
534 {
535 SetLastErrorByStatus(Status);
536 ThreadBasic.AffinityMask = 0;
537 }
538
539 return ThreadBasic.AffinityMask;
540 }
541
542 /*
543 * @implemented
544 */
545 BOOL
546 WINAPI
547 SetThreadPriority(HANDLE hThread,
548 int nPriority)
549 {
550 LONG Prio = nPriority;
551 NTSTATUS Status;
552
553 /* Check if values forcing saturation should be used */
554 if (Prio == THREAD_PRIORITY_TIME_CRITICAL)
555 {
556 Prio = (HIGH_PRIORITY + 1) / 2;
557 }
558 else if (Prio == THREAD_PRIORITY_IDLE)
559 {
560 Prio = -((HIGH_PRIORITY + 1) / 2);
561 }
562
563 /* Set the Base Priority */
564 Status = NtSetInformationThread(hThread,
565 ThreadBasePriority,
566 &Prio,
567 sizeof(LONG));
568 if (!NT_SUCCESS(Status))
569 {
570 /* Failure */
571 SetLastErrorByStatus(Status);
572 return FALSE;
573 }
574
575 /* Return */
576 return TRUE;
577 }
578
579 /*
580 * @implemented
581 */
582 int
583 WINAPI
584 GetThreadPriority(HANDLE hThread)
585 {
586 THREAD_BASIC_INFORMATION ThreadBasic;
587 NTSTATUS Status;
588
589 /* Query the Base Priority Increment */
590 Status = NtQueryInformationThread(hThread,
591 ThreadBasicInformation,
592 &ThreadBasic,
593 sizeof(THREAD_BASIC_INFORMATION),
594 NULL);
595 if (!NT_SUCCESS(Status))
596 {
597 /* Failure */
598 SetLastErrorByStatus(Status);
599 return THREAD_PRIORITY_ERROR_RETURN;
600 }
601
602 /* Do some conversions for out of boundary values */
603 if (ThreadBasic.BasePriority > THREAD_BASE_PRIORITY_MAX)
604 {
605 ThreadBasic.BasePriority = THREAD_PRIORITY_TIME_CRITICAL;
606 }
607 else if (ThreadBasic.BasePriority < THREAD_BASE_PRIORITY_MIN)
608 {
609 ThreadBasic.BasePriority = THREAD_PRIORITY_IDLE;
610 }
611
612 /* Return the final result */
613 return ThreadBasic.BasePriority;
614 }
615
616 /*
617 * @implemented
618 */
619 BOOL
620 WINAPI
621 GetThreadPriorityBoost(IN HANDLE hThread,
622 OUT PBOOL pDisablePriorityBoost)
623 {
624 ULONG PriorityBoost;
625 NTSTATUS Status;
626
627 Status = NtQueryInformationThread(hThread,
628 ThreadPriorityBoost,
629 &PriorityBoost,
630 sizeof(ULONG),
631 NULL);
632 if (!NT_SUCCESS(Status))
633 {
634 SetLastErrorByStatus(Status);
635 return FALSE;
636 }
637
638 *pDisablePriorityBoost = PriorityBoost;
639 return TRUE;
640 }
641
642 /*
643 * @implemented
644 */
645 BOOL
646 NTAPI
647 SetThreadPriorityBoost(IN HANDLE hThread,
648 IN BOOL bDisablePriorityBoost)
649 {
650 ULONG PriorityBoost;
651 NTSTATUS Status;
652
653 PriorityBoost = (ULONG)bDisablePriorityBoost;
654
655 Status = NtSetInformationThread(hThread,
656 ThreadPriorityBoost,
657 &PriorityBoost,
658 sizeof(ULONG));
659 if (!NT_SUCCESS(Status))
660 {
661 SetLastErrorByStatus(Status);
662 return FALSE;
663 }
664
665 return TRUE;
666 }
667
668 /*
669 * @implemented
670 */
671 BOOL
672 WINAPI
673 GetThreadSelectorEntry(IN HANDLE hThread,
674 IN DWORD dwSelector,
675 OUT LPLDT_ENTRY lpSelectorEntry)
676 {
677 DESCRIPTOR_TABLE_ENTRY DescriptionTableEntry;
678 NTSTATUS Status;
679
680 /* Set the selector and do the query */
681 DescriptionTableEntry.Selector = dwSelector;
682 Status = NtQueryInformationThread(hThread,
683 ThreadDescriptorTableEntry,
684 &DescriptionTableEntry,
685 sizeof(DESCRIPTOR_TABLE_ENTRY),
686 NULL);
687 if (!NT_SUCCESS(Status))
688 {
689 /* Fail */
690 SetLastErrorByStatus(Status);
691 return FALSE;
692 }
693
694 /* Success, return the selector */
695 *lpSelectorEntry = DescriptionTableEntry.Descriptor;
696 return TRUE;
697 }
698
699 /*
700 * @implemented
701 */
702 DWORD
703 WINAPI
704 SetThreadIdealProcessor(HANDLE hThread,
705 DWORD dwIdealProcessor)
706 {
707 NTSTATUS Status;
708
709 Status = NtSetInformationThread(hThread,
710 ThreadIdealProcessor,
711 &dwIdealProcessor,
712 sizeof(ULONG));
713 if (!NT_SUCCESS(Status))
714 {
715 SetLastErrorByStatus(Status);
716 return -1;
717 }
718
719 return (DWORD)Status;
720 }
721
722 /*
723 * @implemented
724 */
725 DWORD WINAPI
726 GetProcessIdOfThread(HANDLE Thread)
727 {
728 THREAD_BASIC_INFORMATION ThreadBasic;
729 NTSTATUS Status;
730
731 Status = NtQueryInformationThread(Thread,
732 ThreadBasicInformation,
733 &ThreadBasic,
734 sizeof(THREAD_BASIC_INFORMATION),
735 NULL);
736 if(!NT_SUCCESS(Status))
737 {
738 SetLastErrorByStatus(Status);
739 return 0;
740 }
741
742 return (DWORD)ThreadBasic.ClientId.UniqueProcess;
743 }
744
745 /*
746 * @implemented
747 */
748 DWORD WINAPI
749 GetThreadId(HANDLE Thread)
750 {
751 THREAD_BASIC_INFORMATION ThreadBasic;
752 NTSTATUS Status;
753
754 Status = NtQueryInformationThread(Thread,
755 ThreadBasicInformation,
756 &ThreadBasic,
757 sizeof(THREAD_BASIC_INFORMATION),
758 NULL);
759 if(!NT_SUCCESS(Status))
760 {
761 SetLastErrorByStatus(Status);
762 return 0;
763 }
764
765 return (DWORD)ThreadBasic.ClientId.UniqueThread;
766 }
767
768 /*
769 * @unimplemented
770 */
771 LANGID WINAPI
772 SetThreadUILanguage(LANGID LangId)
773 {
774 DPRINT1("SetThreadUILanguage(0x%4x) unimplemented!\n", LangId);
775 return LangId;
776 }
777
778 static void CALLBACK
779 IntCallUserApc(PVOID Function, PVOID dwData, PVOID Argument3)
780 {
781 PAPCFUNC pfnAPC = (PAPCFUNC)Function;
782 pfnAPC((ULONG_PTR)dwData);
783 }
784
785 /*
786 * @implemented
787 */
788 DWORD WINAPI
789 QueueUserAPC(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData)
790 {
791 NTSTATUS Status;
792
793 Status = NtQueueApcThread(hThread, IntCallUserApc, pfnAPC,
794 (PVOID)dwData, NULL);
795 if (!NT_SUCCESS(Status))
796 {
797 SetLastErrorByStatus(Status);
798 return 0;
799 }
800
801 return 1;
802 }
803
804 /*
805 * @implemented
806 */
807 BOOL WINAPI
808 GetThreadIOPendingFlag(HANDLE hThread,
809 PBOOL lpIOIsPending)
810 {
811 ULONG IoPending;
812 NTSTATUS Status;
813
814 if(lpIOIsPending == NULL)
815 {
816 SetLastError(ERROR_INVALID_PARAMETER);
817 return FALSE;
818 }
819
820 Status = NtQueryInformationThread(hThread,
821 ThreadIsIoPending,
822 (PVOID)&IoPending,
823 sizeof(IoPending),
824 NULL);
825 if(NT_SUCCESS(Status))
826 {
827 *lpIOIsPending = ((IoPending != 0) ? TRUE : FALSE);
828 return TRUE;
829 }
830
831 SetLastErrorByStatus(Status);
832 return FALSE;
833 }
834
835
836 /*
837 * @implemented
838 */
839 VOID WINAPI
840 Sleep(DWORD dwMilliseconds)
841 {
842 SleepEx(dwMilliseconds, FALSE);
843 return;
844 }
845
846
847 /*
848 * @implemented
849 */
850 DWORD WINAPI
851 SleepEx(DWORD dwMilliseconds,
852 BOOL bAlertable)
853 {
854 LARGE_INTEGER Interval;
855 NTSTATUS errCode;
856
857 if (dwMilliseconds != INFINITE)
858 {
859 /*
860 * System time units are 100 nanoseconds (a nanosecond is a billionth of
861 * a second).
862 */
863 Interval.QuadPart = -((LONGLONG)dwMilliseconds * 10000);
864 }
865 else
866 {
867 /* Approximately 292000 years hence */
868 Interval.QuadPart = -0x7FFFFFFFFFFFFFFFLL;
869 }
870
871 dowait:
872 errCode = NtDelayExecution ((BOOLEAN)bAlertable, &Interval);
873 if ((bAlertable) && (errCode == STATUS_ALERTED)) goto dowait;
874 return (errCode == STATUS_USER_APC) ? WAIT_IO_COMPLETION : 0;
875 }
876
877
878 typedef struct _QUEUE_USER_WORKITEM_CONTEXT
879 {
880 LPTHREAD_START_ROUTINE Function;
881 PVOID Context;
882 } QUEUE_USER_WORKITEM_CONTEXT, *PQUEUE_USER_WORKITEM_CONTEXT;
883
884 static VOID
885 NTAPI
886 InternalWorkItemTrampoline(PVOID Context)
887 {
888 QUEUE_USER_WORKITEM_CONTEXT Info;
889
890 ASSERT(Context);
891
892 /* Save the context to the stack */
893 Info = *(volatile QUEUE_USER_WORKITEM_CONTEXT *)Context;
894
895 /* Free the context before calling the callback. This avoids
896 a memory leak in case the thread dies... */
897 RtlFreeHeap(RtlGetProcessHeap(),
898 0,
899 Context);
900
901 /* Call the real callback */
902 Info.Function(Info.Context);
903 }
904
905
906 /*
907 * @implemented
908 */
909 BOOL
910 WINAPI
911 QueueUserWorkItem(
912 LPTHREAD_START_ROUTINE Function,
913 PVOID Context,
914 ULONG Flags
915 )
916 {
917 PQUEUE_USER_WORKITEM_CONTEXT WorkItemContext;
918 NTSTATUS Status;
919
920 /* Save the context for the trampoline function */
921 WorkItemContext = RtlAllocateHeap(RtlGetProcessHeap(),
922 0,
923 sizeof(*WorkItemContext));
924 if (WorkItemContext == NULL)
925 {
926 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
927 return FALSE;
928 }
929
930 WorkItemContext->Function = Function;
931 WorkItemContext->Context = Context;
932
933 /* NOTE: Don't use Function directly since the callback signature
934 differs. This might cause problems on certain platforms... */
935 Status = RtlQueueWorkItem(InternalWorkItemTrampoline,
936 WorkItemContext,
937 Flags);
938 if (!NT_SUCCESS(Status))
939 {
940 /* Free the allocated context in case of failure */
941 RtlFreeHeap(RtlGetProcessHeap(),
942 0,
943 WorkItemContext);
944
945 SetLastErrorByStatus(Status);
946 return FALSE;
947 }
948
949 return TRUE;
950 }
951
952
953 /*
954 * @implemented
955 */
956 BOOL
957 WINAPI
958 RegisterWaitForSingleObject(
959 PHANDLE phNewWaitObject,
960 HANDLE hObject,
961 WAITORTIMERCALLBACK Callback,
962 PVOID Context,
963 ULONG dwMilliseconds,
964 ULONG dwFlags
965 )
966 {
967 NTSTATUS Status = RtlRegisterWait(phNewWaitObject,
968 hObject,
969 Callback,
970 Context,
971 dwMilliseconds,
972 dwFlags);
973
974 if (!NT_SUCCESS(Status))
975 {
976 SetLastErrorByStatus(Status);
977 return FALSE;
978 }
979 return TRUE;
980 }
981
982
983 /*
984 * @implemented
985 */
986 HANDLE
987 WINAPI
988 RegisterWaitForSingleObjectEx(
989 HANDLE hObject,
990 WAITORTIMERCALLBACK Callback,
991 PVOID Context,
992 ULONG dwMilliseconds,
993 ULONG dwFlags
994 )
995 {
996 NTSTATUS Status;
997 HANDLE hNewWaitObject;
998
999 Status = RtlRegisterWait(&hNewWaitObject,
1000 hObject,
1001 Callback,
1002 Context,
1003 dwMilliseconds,
1004 dwFlags);
1005
1006 if (!NT_SUCCESS(Status))
1007 {
1008 SetLastErrorByStatus(Status);
1009 return NULL;
1010 }
1011
1012 return hNewWaitObject;
1013 }
1014
1015
1016 /*
1017 * @implemented
1018 */
1019 BOOL
1020 WINAPI
1021 UnregisterWait(
1022 HANDLE WaitHandle
1023 )
1024 {
1025 NTSTATUS Status = RtlDeregisterWaitEx(WaitHandle, NULL);
1026
1027 if (!NT_SUCCESS(Status))
1028 {
1029 SetLastErrorByStatus(Status);
1030 return FALSE;
1031 }
1032
1033 return TRUE;
1034 }
1035
1036
1037 /*
1038 * @implemented
1039 */
1040 BOOL
1041 WINAPI
1042 UnregisterWaitEx(
1043 HANDLE WaitHandle,
1044 HANDLE CompletionEvent
1045 )
1046 {
1047 NTSTATUS Status = RtlDeregisterWaitEx(WaitHandle, CompletionEvent);
1048
1049 if (!NT_SUCCESS(Status))
1050 {
1051 SetLastErrorByStatus(Status);
1052 return FALSE;
1053 }
1054
1055 return TRUE;
1056 }
1057
1058 /* EOF */