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