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