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