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