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