Sync to trunk head (r42241)
[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 WINAPI
655 GetThreadSelectorEntry(IN HANDLE hThread,
656 IN DWORD dwSelector,
657 OUT LPLDT_ENTRY lpSelectorEntry)
658 {
659 #ifdef _M_IX86
660 DESCRIPTOR_TABLE_ENTRY DescriptionTableEntry;
661 NTSTATUS Status;
662
663 DescriptionTableEntry.Selector = dwSelector;
664 Status = NtQueryInformationThread(hThread,
665 ThreadDescriptorTableEntry,
666 &DescriptionTableEntry,
667 sizeof(DESCRIPTOR_TABLE_ENTRY),
668 NULL);
669 if(!NT_SUCCESS(Status))
670 {
671 SetLastErrorByStatus(Status);
672 return FALSE;
673 }
674
675 *lpSelectorEntry = DescriptionTableEntry.Descriptor;
676 return TRUE;
677 #else
678 DPRINT1("Calling GetThreadSelectorEntry!\n");
679 return FALSE;
680 #endif
681 }
682
683 /*
684 * @implemented
685 */
686 DWORD
687 WINAPI
688 SetThreadIdealProcessor(HANDLE hThread,
689 DWORD dwIdealProcessor)
690 {
691 NTSTATUS Status;
692
693 Status = NtSetInformationThread(hThread,
694 ThreadIdealProcessor,
695 &dwIdealProcessor,
696 sizeof(ULONG));
697 if (!NT_SUCCESS(Status))
698 {
699 SetLastErrorByStatus(Status);
700 return -1;
701 }
702
703 return (DWORD)Status;
704 }
705
706 /*
707 * @implemented
708 */
709 DWORD WINAPI
710 GetProcessIdOfThread(HANDLE Thread)
711 {
712 THREAD_BASIC_INFORMATION ThreadBasic;
713 NTSTATUS Status;
714
715 Status = NtQueryInformationThread(Thread,
716 ThreadBasicInformation,
717 &ThreadBasic,
718 sizeof(THREAD_BASIC_INFORMATION),
719 NULL);
720 if(!NT_SUCCESS(Status))
721 {
722 SetLastErrorByStatus(Status);
723 return 0;
724 }
725
726 return (DWORD)ThreadBasic.ClientId.UniqueProcess;
727 }
728
729 /*
730 * @implemented
731 */
732 DWORD WINAPI
733 GetThreadId(HANDLE Thread)
734 {
735 THREAD_BASIC_INFORMATION ThreadBasic;
736 NTSTATUS Status;
737
738 Status = NtQueryInformationThread(Thread,
739 ThreadBasicInformation,
740 &ThreadBasic,
741 sizeof(THREAD_BASIC_INFORMATION),
742 NULL);
743 if(!NT_SUCCESS(Status))
744 {
745 SetLastErrorByStatus(Status);
746 return 0;
747 }
748
749 return (DWORD)ThreadBasic.ClientId.UniqueThread;
750 }
751
752 /*
753 * @unimplemented
754 */
755 LANGID WINAPI
756 SetThreadUILanguage(LANGID LangId)
757 {
758 DPRINT1("SetThreadUILanguage(0x%4x) unimplemented!\n", LangId);
759 return LangId;
760 }
761
762 static void CALLBACK
763 IntCallUserApc(PVOID Function, PVOID dwData, PVOID Argument3)
764 {
765 PAPCFUNC pfnAPC = (PAPCFUNC)Function;
766 pfnAPC((ULONG_PTR)dwData);
767 }
768
769 /*
770 * @implemented
771 */
772 DWORD WINAPI
773 QueueUserAPC(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData)
774 {
775 NTSTATUS Status;
776
777 Status = NtQueueApcThread(hThread, IntCallUserApc, pfnAPC,
778 (PVOID)dwData, NULL);
779 if (!NT_SUCCESS(Status))
780 {
781 SetLastErrorByStatus(Status);
782 return 0;
783 }
784
785 return 1;
786 }
787
788 /*
789 * @implemented
790 */
791 BOOL WINAPI
792 GetThreadIOPendingFlag(HANDLE hThread,
793 PBOOL lpIOIsPending)
794 {
795 ULONG IoPending;
796 NTSTATUS Status;
797
798 if(lpIOIsPending == NULL)
799 {
800 SetLastError(ERROR_INVALID_PARAMETER);
801 return FALSE;
802 }
803
804 Status = NtQueryInformationThread(hThread,
805 ThreadIsIoPending,
806 (PVOID)&IoPending,
807 sizeof(IoPending),
808 NULL);
809 if(NT_SUCCESS(Status))
810 {
811 *lpIOIsPending = ((IoPending != 0) ? TRUE : FALSE);
812 return TRUE;
813 }
814
815 SetLastErrorByStatus(Status);
816 return FALSE;
817 }
818
819
820 /*
821 * @implemented
822 */
823 VOID WINAPI
824 Sleep(DWORD dwMilliseconds)
825 {
826 SleepEx(dwMilliseconds, FALSE);
827 return;
828 }
829
830
831 /*
832 * @implemented
833 */
834 DWORD WINAPI
835 SleepEx(DWORD dwMilliseconds,
836 BOOL bAlertable)
837 {
838 LARGE_INTEGER Interval;
839 NTSTATUS errCode;
840
841 if (dwMilliseconds != INFINITE)
842 {
843 /*
844 * System time units are 100 nanoseconds (a nanosecond is a billionth of
845 * a second).
846 */
847 Interval.QuadPart = -((LONGLONG)dwMilliseconds * 10000);
848 }
849 else
850 {
851 /* Approximately 292000 years hence */
852 Interval.QuadPart = -0x7FFFFFFFFFFFFFFFLL;
853 }
854
855 dowait:
856 errCode = NtDelayExecution ((BOOLEAN)bAlertable, &Interval);
857 if ((bAlertable) && (errCode == STATUS_ALERTED)) goto dowait;
858 return (errCode == STATUS_USER_APC) ? WAIT_IO_COMPLETION : 0;
859 }
860
861
862 typedef struct _QUEUE_USER_WORKITEM_CONTEXT
863 {
864 LPTHREAD_START_ROUTINE Function;
865 PVOID Context;
866 } QUEUE_USER_WORKITEM_CONTEXT, *PQUEUE_USER_WORKITEM_CONTEXT;
867
868 static VOID
869 NTAPI
870 InternalWorkItemTrampoline(PVOID Context)
871 {
872 QUEUE_USER_WORKITEM_CONTEXT Info;
873
874 ASSERT(Context);
875
876 /* Save the context to the stack */
877 Info = *(volatile QUEUE_USER_WORKITEM_CONTEXT *)Context;
878
879 /* Free the context before calling the callback. This avoids
880 a memory leak in case the thread dies... */
881 RtlFreeHeap(RtlGetProcessHeap(),
882 0,
883 Context);
884
885 /* Call the real callback */
886 Info.Function(Info.Context);
887 }
888
889
890 /*
891 * @implemented
892 */
893 BOOL
894 WINAPI
895 QueueUserWorkItem(
896 LPTHREAD_START_ROUTINE Function,
897 PVOID Context,
898 ULONG Flags
899 )
900 {
901 PQUEUE_USER_WORKITEM_CONTEXT WorkItemContext;
902 NTSTATUS Status;
903
904 /* Save the context for the trampoline function */
905 WorkItemContext = RtlAllocateHeap(RtlGetProcessHeap(),
906 0,
907 sizeof(*WorkItemContext));
908 if (WorkItemContext == NULL)
909 {
910 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
911 return FALSE;
912 }
913
914 WorkItemContext->Function = Function;
915 WorkItemContext->Context = Context;
916
917 /* NOTE: Don't use Function directly since the callback signature
918 differs. This might cause problems on certain platforms... */
919 Status = RtlQueueWorkItem(InternalWorkItemTrampoline,
920 WorkItemContext,
921 Flags);
922 if (!NT_SUCCESS(Status))
923 {
924 /* Free the allocated context in case of failure */
925 RtlFreeHeap(RtlGetProcessHeap(),
926 0,
927 WorkItemContext);
928
929 SetLastErrorByStatus(Status);
930 return FALSE;
931 }
932
933 return TRUE;
934 }
935
936
937 /*
938 * @implemented
939 */
940 BOOL
941 WINAPI
942 RegisterWaitForSingleObject(
943 PHANDLE phNewWaitObject,
944 HANDLE hObject,
945 WAITORTIMERCALLBACK Callback,
946 PVOID Context,
947 ULONG dwMilliseconds,
948 ULONG dwFlags
949 )
950 {
951 NTSTATUS Status = RtlRegisterWait(phNewWaitObject,
952 hObject,
953 Callback,
954 Context,
955 dwMilliseconds,
956 dwFlags);
957
958 if (!NT_SUCCESS(Status))
959 {
960 SetLastErrorByStatus(Status);
961 return FALSE;
962 }
963 return TRUE;
964 }
965
966
967 /*
968 * @implemented
969 */
970 HANDLE
971 WINAPI
972 RegisterWaitForSingleObjectEx(
973 HANDLE hObject,
974 WAITORTIMERCALLBACK Callback,
975 PVOID Context,
976 ULONG dwMilliseconds,
977 ULONG dwFlags
978 )
979 {
980 NTSTATUS Status;
981 HANDLE hNewWaitObject;
982
983 Status = RtlRegisterWait(&hNewWaitObject,
984 hObject,
985 Callback,
986 Context,
987 dwMilliseconds,
988 dwFlags);
989
990 if (!NT_SUCCESS(Status))
991 {
992 SetLastErrorByStatus(Status);
993 return NULL;
994 }
995
996 return hNewWaitObject;
997 }
998
999
1000 /*
1001 * @implemented
1002 */
1003 BOOL
1004 WINAPI
1005 UnregisterWait(
1006 HANDLE WaitHandle
1007 )
1008 {
1009 NTSTATUS Status = RtlDeregisterWaitEx(WaitHandle, NULL);
1010
1011 if (!NT_SUCCESS(Status))
1012 {
1013 SetLastErrorByStatus(Status);
1014 return FALSE;
1015 }
1016
1017 return TRUE;
1018 }
1019
1020
1021 /*
1022 * @implemented
1023 */
1024 BOOL
1025 WINAPI
1026 UnregisterWaitEx(
1027 HANDLE WaitHandle,
1028 HANDLE CompletionEvent
1029 )
1030 {
1031 NTSTATUS Status = RtlDeregisterWaitEx(WaitHandle, CompletionEvent);
1032
1033 if (!NT_SUCCESS(Status))
1034 {
1035 SetLastErrorByStatus(Status);
1036 return FALSE;
1037 }
1038
1039 return TRUE;
1040 }
1041
1042 /* EOF */