2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: dll/win32/kernel32/client/thread.c
5 * PURPOSE: Thread functions
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Ariadne (ariadne@xs4all.nl)
11 /* INCLUDES *******************************************************************/
18 #define SXS_SUPPORT_FIXME
20 typedef NTSTATUS (NTAPI
*PCSR_CREATE_REMOTE_THREAD
)(IN HANDLE ThreadHandle
, IN PCLIENT_ID ClientId
);
24 BasepNotifyCsrOfThread(IN HANDLE ThreadHandle
,
25 IN PCLIENT_ID ClientId
);
27 /* FUNCTIONS ******************************************************************/
30 LONG
BaseThreadExceptionFilter(EXCEPTION_POINTERS
* ExceptionInfo
)
32 LONG ExceptionDisposition
= EXCEPTION_EXECUTE_HANDLER
;
33 LPTOP_LEVEL_EXCEPTION_FILTER RealFilter
;
34 RealFilter
= RtlDecodePointer(GlobalTopLevelExceptionFilter
);
36 if (RealFilter
!= NULL
)
40 ExceptionDisposition
= RealFilter(ExceptionInfo
);
42 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
44 ExceptionDisposition
= UnhandledExceptionFilter(ExceptionInfo
);
49 return ExceptionDisposition
;
55 BaseThreadStartup(IN LPTHREAD_START_ROUTINE lpStartAddress
,
56 IN LPVOID lpParameter
)
58 /* Attempt to call the Thread Start Address */
61 /* Legacy check which is still used today for Win32 threads */
62 if (NtCurrentTeb()->NtTib
.Version
== (30 << 8)) // OS/2 V3.0 ("Cruiser")
64 /* This registers the termination port with CSRSS */
65 if (!BaseRunningInServerProcess
) CsrNewThread();
68 /* Get the exit code from the Thread Start */
69 ExitThread((lpStartAddress
)((PVOID
)lpParameter
));
71 _SEH2_EXCEPT(BaseThreadExceptionFilter(_SEH2_GetExceptionInformation()))
73 /* Get the Exit code from the SEH Handler */
74 if (!BaseRunningInServerProcess
)
76 /* Kill the whole process, usually */
77 ExitProcess(_SEH2_GetExceptionCode());
81 /* If running inside CSRSS, kill just this thread */
82 ExitThread(_SEH2_GetExceptionCode());
90 BaseDispatchApc(IN PAPCFUNC ApcRoutine
,
92 IN PACTIVATION_CONTEXT ActivationContext
)
94 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActivationFrame
;
96 /* Setup the activation context */
97 ActivationFrame
.Size
= sizeof(ActivationFrame
);
98 ActivationFrame
.Format
= RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER
;
100 /* Check if caller wanted one */
101 if (ActivationContext
== INVALID_ACTIVATION_CONTEXT
)
103 /* Do the APC directly */
104 ApcRoutine((ULONG_PTR
)Data
);
108 /* Then activate it */
109 RtlActivateActivationContextUnsafeFast(&ActivationFrame
, ActivationContext
);
111 /* Call the routine under SEH */
114 ApcRoutine((ULONG_PTR
)Data
);
116 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
122 /* Now de-activate and release the activation context */
123 RtlDeactivateActivationContextUnsafeFast(&ActivationFrame
);
124 RtlReleaseActivationContext(ActivationContext
);
127 /* PUBLIC FUNCTIONS ***********************************************************/
134 CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes
,
135 IN DWORD dwStackSize
,
136 IN LPTHREAD_START_ROUTINE lpStartAddress
,
137 IN LPVOID lpParameter
,
138 IN DWORD dwCreationFlags
,
139 OUT LPDWORD lpThreadId
)
141 /* Act as if we're going to create a remote thread in ourselves */
142 return CreateRemoteThread(NtCurrentProcess(),
156 CreateRemoteThread(IN HANDLE hProcess
,
157 IN LPSECURITY_ATTRIBUTES lpThreadAttributes
,
158 IN DWORD dwStackSize
,
159 IN LPTHREAD_START_ROUTINE lpStartAddress
,
160 IN LPVOID lpParameter
,
161 IN DWORD dwCreationFlags
,
162 OUT LPDWORD lpThreadId
)
165 INITIAL_TEB InitialTeb
;
168 OBJECT_ATTRIBUTES LocalObjectAttributes
;
169 POBJECT_ATTRIBUTES ObjectAttributes
;
173 THREAD_BASIC_INFORMATION ThreadBasicInfo
;
174 PACTIVATION_CONTEXT_STACK ActivationContextStack
= NULL
;
175 ACTIVATION_CONTEXT_BASIC_INFORMATION ActCtxInfo
;
178 DPRINT("CreateRemoteThread: hProcess: %p dwStackSize: %lu lpStartAddress"
179 ": %p lpParameter: %p, dwCreationFlags: %lx\n", hProcess
,
180 dwStackSize
, lpStartAddress
, lpParameter
, dwCreationFlags
);
182 /* Clear the Context */
183 RtlZeroMemory(&Context
, sizeof(CONTEXT
));
186 ClientId
.UniqueProcess
= hProcess
;
188 /* Create the Stack */
189 Status
= BaseCreateStack(hProcess
,
191 dwCreationFlags
& STACK_SIZE_PARAM_IS_A_RESERVATION
?
194 if (!NT_SUCCESS(Status
))
196 BaseSetLastNTError(Status
);
200 /* Create Initial Context */
201 BaseInitializeContext(&Context
,
204 InitialTeb
.StackBase
,
207 /* initialize the attributes for the thread object */
208 ObjectAttributes
= BaseFormatObjectAttributes(&LocalObjectAttributes
,
212 /* Create the Kernel Thread Object */
213 Status
= NtCreateThread(&hThread
,
221 if (!NT_SUCCESS(Status
))
223 /* Fail the kernel create */
224 BaseFreeThreadStack(hProcess
, &InitialTeb
);
225 BaseSetLastNTError(Status
);
229 /* Are we in the same process? */
230 if (hProcess
== NtCurrentProcess())
233 Status
= NtQueryInformationThread(hThread
,
234 ThreadBasicInformation
,
236 sizeof(ThreadBasicInfo
),
238 if (!NT_SUCCESS(Status
))
241 ERROR_DBGBREAK("SXS: %s - Failing thread create because "
242 "NtQueryInformationThread() failed with status %08lx\n",
243 __FUNCTION__
, Status
);
247 /* Allocate the Activation Context Stack */
248 Status
= RtlAllocateActivationContextStack(&ActivationContextStack
);
249 if (!NT_SUCCESS(Status
))
252 ERROR_DBGBREAK("SXS: %s - Failing thread create because "
253 "RtlAllocateActivationContextStack() failed with status %08lx\n",
254 __FUNCTION__
, Status
);
259 Teb
= ThreadBasicInfo
.TebBaseAddress
;
260 Teb
->ActivationContextStackPointer
= ActivationContextStack
;
262 /* Query the Context */
263 Status
= RtlQueryInformationActivationContext(RTL_QUERY_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT
,
266 ActivationContextBasicInformation
,
270 if (!NT_SUCCESS(Status
))
273 ERROR_DBGBREAK("SXS: %s - Failing thread create because "
274 "RtlQueryInformationActivationContext() failed with status %08lx\n",
275 __FUNCTION__
, Status
);
277 /* Free the activation context stack */
278 // RtlFreeThreadActivationContextStack();
279 RtlFreeActivationContextStack(Teb
->ActivationContextStackPointer
);
284 /* Does it need to be activated? */
285 if ((ActCtxInfo
.hActCtx
) && !(ActCtxInfo
.dwFlags
& 1))
288 Status
= RtlActivateActivationContextEx(RTL_ACTIVATE_ACTIVATION_CONTEXT_EX_FLAG_RELEASE_ON_STACK_DEALLOCATION
,
292 if (!NT_SUCCESS(Status
))
295 ERROR_DBGBREAK("SXS: %s - Failing thread create because "
296 "RtlActivateActivationContextEx() failed with status %08lx\n",
297 __FUNCTION__
, Status
);
299 /* Free the activation context stack */
300 // RtlFreeThreadActivationContextStack();
301 RtlFreeActivationContextStack(Teb
->ActivationContextStackPointer
);
309 if (!BaseRunningInServerProcess
)
311 Status
= BasepNotifyCsrOfThread(hThread
, &ClientId
);
312 ASSERT(NT_SUCCESS(Status
));
316 if (hProcess
!= NtCurrentProcess())
318 PCSR_CREATE_REMOTE_THREAD CsrCreateRemoteThread
;
320 /* Get the direct CSRSRV export */
321 CsrCreateRemoteThread
= (PCSR_CREATE_REMOTE_THREAD
)
322 GetProcAddress(GetModuleHandleA("csrsrv"),
323 "CsrCreateRemoteThread");
324 if (CsrCreateRemoteThread
)
326 /* Call it instead of going through LPC */
327 Status
= CsrCreateRemoteThread(hThread
, &ClientId
);
328 ASSERT(NT_SUCCESS(Status
));
334 if (lpThreadId
) *lpThreadId
= HandleToUlong(ClientId
.UniqueThread
);
336 /* Resume it if asked */
337 if (!(dwCreationFlags
& CREATE_SUSPENDED
)) NtResumeThread(hThread
, &Dummy
);
339 /* Return handle to thread */
348 ExitThread(IN DWORD uExitCode
)
352 PRTL_CRITICAL_SECTION LoaderLock
;
354 /* Make sure loader lock isn't held */
355 LoaderLock
= NtCurrentPeb()->LoaderLock
;
356 if (LoaderLock
) ASSERT(NtCurrentTeb()->ClientId
.UniqueThread
!= LoaderLock
->OwningThread
);
359 * Terminate process if this is the last thread
360 * of the current process
362 Status
= NtQueryInformationThread(NtCurrentThread(),
367 if ((NT_SUCCESS(Status
)) && (LastThread
)) ExitProcess(uExitCode
);
369 /* Notify DLLs and TLS Callbacks of termination */
372 /* Tell the Kernel to free the Stack */
373 NtCurrentTeb()->FreeStackOnTermination
= TRUE
;
374 NtTerminateThread(NULL
, uExitCode
);
376 /* We should never reach this place */
377 ERROR_FATAL("It should not happen\n");
378 while (TRUE
); /* 'noreturn' function */
386 OpenThread(IN DWORD dwDesiredAccess
,
387 IN BOOL bInheritHandle
,
392 OBJECT_ATTRIBUTES ObjectAttributes
;
395 ClientId
.UniqueProcess
= 0;
396 ClientId
.UniqueThread
= ULongToHandle(dwThreadId
);
398 InitializeObjectAttributes(&ObjectAttributes
,
400 (bInheritHandle
? OBJ_INHERIT
: 0),
404 Status
= NtOpenThread(&ThreadHandle
,
408 if (!NT_SUCCESS(Status
))
410 BaseSetLastNTError(Status
);
423 return NtCurrentTeb();
433 return NtYieldExecution() != STATUS_NO_YIELD_PERFORMED
;
442 GetCurrentThreadId(VOID
)
444 return HandleToUlong(NtCurrentTeb()->ClientId
.UniqueThread
);
452 GetThreadTimes(IN HANDLE hThread
,
453 OUT LPFILETIME lpCreationTime
,
454 OUT LPFILETIME lpExitTime
,
455 OUT LPFILETIME lpKernelTime
,
456 OUT LPFILETIME lpUserTime
)
458 KERNEL_USER_TIMES KernelUserTimes
;
461 Status
= NtQueryInformationThread(hThread
,
464 sizeof(KERNEL_USER_TIMES
),
466 if (!NT_SUCCESS(Status
))
468 BaseSetLastNTError(Status
);
472 *lpCreationTime
= *(LPFILETIME
)&KernelUserTimes
.CreateTime
;
473 *lpExitTime
= *(LPFILETIME
)&KernelUserTimes
.ExitTime
;
474 *lpKernelTime
= *(LPFILETIME
)&KernelUserTimes
.KernelTime
;
475 *lpUserTime
= *(LPFILETIME
)&KernelUserTimes
.UserTime
;
484 GetThreadContext(IN HANDLE hThread
,
485 OUT LPCONTEXT lpContext
)
489 Status
= NtGetContextThread(hThread
, lpContext
);
490 if (!NT_SUCCESS(Status
))
492 BaseSetLastNTError(Status
);
504 SetThreadContext(IN HANDLE hThread
,
505 IN CONST CONTEXT
*lpContext
)
509 Status
= NtSetContextThread(hThread
, (PCONTEXT
)lpContext
);
510 if (!NT_SUCCESS(Status
))
512 BaseSetLastNTError(Status
);
524 GetExitCodeThread(IN HANDLE hThread
,
525 OUT LPDWORD lpExitCode
)
527 THREAD_BASIC_INFORMATION ThreadBasic
;
530 Status
= NtQueryInformationThread(hThread
,
531 ThreadBasicInformation
,
533 sizeof(THREAD_BASIC_INFORMATION
),
535 if (!NT_SUCCESS(Status
))
537 BaseSetLastNTError(Status
);
541 *lpExitCode
= ThreadBasic
.ExitStatus
;
550 ResumeThread(IN HANDLE hThread
)
552 ULONG PreviousResumeCount
;
555 Status
= NtResumeThread(hThread
, &PreviousResumeCount
);
556 if (!NT_SUCCESS(Status
))
558 BaseSetLastNTError(Status
);
562 return PreviousResumeCount
;
570 TerminateThread(IN HANDLE hThread
,
575 PRTL_CRITICAL_SECTION LoaderLock
;
576 THREAD_BASIC_INFORMATION ThreadInfo
;
579 /* Check for invalid thread handle */
582 /* Fail if one was passed */
583 SetLastError(ERROR_INVALID_HANDLE
);
588 /* Get the loader lock */
589 LoaderLock
= NtCurrentPeb()->LoaderLock
;
593 Status
= NtQueryInformationThread(hThread
,
594 ThreadBasicInformation
,
598 if (NT_SUCCESS(Status
))
600 /* If terminating the current thread, we must not hold the loader lock */
601 if (NtCurrentTeb()->ClientId
.UniqueThread
== ThreadInfo
.ClientId
.UniqueThread
)
602 ASSERT(NtCurrentTeb()->ClientId
.UniqueThread
!= LoaderLock
->OwningThread
);
607 /* Now terminate the thread */
608 Status
= NtTerminateThread(hThread
, dwExitCode
);
609 if (!NT_SUCCESS(Status
))
612 BaseSetLastNTError(Status
);
625 SuspendThread(IN HANDLE hThread
)
627 ULONG PreviousSuspendCount
;
630 Status
= NtSuspendThread(hThread
, &PreviousSuspendCount
);
631 if (!NT_SUCCESS(Status
))
633 BaseSetLastNTError(Status
);
637 return PreviousSuspendCount
;
645 SetThreadAffinityMask(IN HANDLE hThread
,
646 IN DWORD_PTR dwThreadAffinityMask
)
648 THREAD_BASIC_INFORMATION ThreadBasic
;
649 KAFFINITY AffinityMask
;
652 AffinityMask
= (KAFFINITY
)dwThreadAffinityMask
;
654 Status
= NtQueryInformationThread(hThread
,
655 ThreadBasicInformation
,
657 sizeof(THREAD_BASIC_INFORMATION
),
659 if (!NT_SUCCESS(Status
))
661 BaseSetLastNTError(Status
);
665 Status
= NtSetInformationThread(hThread
,
669 if (!NT_SUCCESS(Status
))
671 BaseSetLastNTError(Status
);
672 ThreadBasic
.AffinityMask
= 0;
675 return ThreadBasic
.AffinityMask
;
683 SetThreadPriority(IN HANDLE hThread
,
686 LONG Prio
= nPriority
;
689 /* Check if values forcing saturation should be used */
690 if (Prio
== THREAD_PRIORITY_TIME_CRITICAL
)
693 Prio
= (HIGH_PRIORITY
+ 1) / 2;
695 else if (Prio
== THREAD_PRIORITY_IDLE
)
698 Prio
= -((HIGH_PRIORITY
+ 1) / 2);
701 /* Set the Base Priority */
702 Status
= NtSetInformationThread(hThread
,
706 if (!NT_SUCCESS(Status
))
709 BaseSetLastNTError(Status
);
722 GetThreadPriority(IN HANDLE hThread
)
724 THREAD_BASIC_INFORMATION ThreadBasic
;
727 /* Query the Base Priority Increment */
728 Status
= NtQueryInformationThread(hThread
,
729 ThreadBasicInformation
,
731 sizeof(THREAD_BASIC_INFORMATION
),
733 if (!NT_SUCCESS(Status
))
736 BaseSetLastNTError(Status
);
737 return THREAD_PRIORITY_ERROR_RETURN
;
740 /* Do some conversions for saturation values */
741 if (ThreadBasic
.BasePriority
== ((HIGH_PRIORITY
+ 1) / 2))
743 /* Win32 calls this "time critical" */
744 ThreadBasic
.BasePriority
= THREAD_PRIORITY_TIME_CRITICAL
;
746 else if (ThreadBasic
.BasePriority
== -((HIGH_PRIORITY
+ 1) / 2))
748 /* Win32 calls this "idle" */
749 ThreadBasic
.BasePriority
= THREAD_PRIORITY_IDLE
;
752 /* Return the final result */
753 return ThreadBasic
.BasePriority
;
761 GetThreadPriorityBoost(IN HANDLE hThread
,
762 OUT PBOOL pDisablePriorityBoost
)
767 Status
= NtQueryInformationThread(hThread
,
772 if (!NT_SUCCESS(Status
))
774 BaseSetLastNTError(Status
);
778 *pDisablePriorityBoost
= PriorityBoost
;
787 SetThreadPriorityBoost(IN HANDLE hThread
,
788 IN BOOL bDisablePriorityBoost
)
793 PriorityBoost
= bDisablePriorityBoost
!= FALSE
;
795 Status
= NtSetInformationThread(hThread
,
799 if (!NT_SUCCESS(Status
))
801 BaseSetLastNTError(Status
);
813 GetThreadSelectorEntry(IN HANDLE hThread
,
815 OUT LPLDT_ENTRY lpSelectorEntry
)
818 DESCRIPTOR_TABLE_ENTRY DescriptionTableEntry
;
821 /* Set the selector and do the query */
822 DescriptionTableEntry
.Selector
= dwSelector
;
823 Status
= NtQueryInformationThread(hThread
,
824 ThreadDescriptorTableEntry
,
825 &DescriptionTableEntry
,
826 sizeof(DESCRIPTOR_TABLE_ENTRY
),
828 if (!NT_SUCCESS(Status
))
831 BaseSetLastNTError(Status
);
835 /* Success, return the selector */
836 *lpSelectorEntry
= DescriptionTableEntry
.Descriptor
;
839 DPRINT1("Calling GetThreadSelectorEntry!\n");
849 SetThreadIdealProcessor(IN HANDLE hThread
,
850 IN DWORD dwIdealProcessor
)
854 Status
= NtSetInformationThread(hThread
,
855 ThreadIdealProcessor
,
858 if (!NT_SUCCESS(Status
))
860 BaseSetLastNTError(Status
);
864 return (DWORD
)Status
;
872 GetProcessIdOfThread(IN HANDLE Thread
)
874 THREAD_BASIC_INFORMATION ThreadBasic
;
877 Status
= NtQueryInformationThread(Thread
,
878 ThreadBasicInformation
,
880 sizeof(THREAD_BASIC_INFORMATION
),
882 if (!NT_SUCCESS(Status
))
884 BaseSetLastNTError(Status
);
888 return HandleToUlong(ThreadBasic
.ClientId
.UniqueProcess
);
896 GetThreadId(IN HANDLE Thread
)
898 THREAD_BASIC_INFORMATION ThreadBasic
;
901 Status
= NtQueryInformationThread(Thread
,
902 ThreadBasicInformation
,
904 sizeof(THREAD_BASIC_INFORMATION
),
906 if (!NT_SUCCESS(Status
))
908 BaseSetLastNTError(Status
);
912 return HandleToUlong(ThreadBasic
.ClientId
.UniqueThread
);
920 SetThreadUILanguage(IN LANGID LangId
)
923 return (LANGID
)NtCurrentTeb()->CurrentLocale
;
931 QueueUserAPC(IN PAPCFUNC pfnAPC
,
936 ACTIVATION_CONTEXT_BASIC_INFORMATION ActCtxInfo
;
938 /* Zero the activation context and query information on it */
939 RtlZeroMemory(&ActCtxInfo
, sizeof(ActCtxInfo
));
940 Status
= RtlQueryInformationActivationContext(RTL_QUERY_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT
,
943 ActivationContextBasicInformation
,
947 if (!NT_SUCCESS(Status
))
949 /* Fail due to SxS */
950 DbgPrint("SXS: %s failing because RtlQueryInformationActivationContext()"
951 "returned status %08lx\n", __FUNCTION__
, Status
);
952 BaseSetLastNTError(Status
);
957 Status
= NtQueueApcThread(hThread
,
958 (PKNORMAL_ROUTINE
)BaseDispatchApc
,
961 (ActCtxInfo
.dwFlags
& 1) ?
962 INVALID_ACTIVATION_CONTEXT
: ActCtxInfo
.hActCtx
);
963 if (!NT_SUCCESS(Status
))
965 BaseSetLastNTError(Status
);
978 SetThreadStackGuarantee(IN OUT PULONG StackSizeInBytes
)
989 GetThreadIOPendingFlag(IN HANDLE hThread
,
990 OUT PBOOL lpIOIsPending
)
996 Status
= NtQueryInformationThread(hThread
,
1001 if (NT_SUCCESS(Status
))
1003 /* Return the flag */
1004 *lpIOIsPending
= IoPending
? TRUE
: FALSE
;
1009 BaseSetLastNTError(Status
);
1018 QueueUserWorkItem(IN LPTHREAD_START_ROUTINE Function
,
1024 /* NOTE: Rtl needs to safely call the function using a trampoline */
1025 Status
= RtlQueueWorkItem((WORKERCALLBACKFUNC
)Function
, Context
, Flags
);
1026 if (!NT_SUCCESS(Status
))
1029 BaseSetLastNTError(Status
);
1048 /* Get the PEB and TEB, lock the PEB */
1049 Teb
= NtCurrentTeb();
1050 Peb
= Teb
->ProcessEnvironmentBlock
;
1051 RtlAcquirePebLock();
1053 /* Try to get regular TEB slot */
1054 Index
= RtlFindClearBitsAndSet(Peb
->TlsBitmap
, 1, 0);
1055 if (Index
!= 0xFFFFFFFF)
1057 /* Clear the value. */
1058 Teb
->TlsSlots
[Index
] = 0;
1059 RtlReleasePebLock();
1063 /* If it fails, try to find expansion TEB slot. */
1064 Index
= RtlFindClearBitsAndSet(Peb
->TlsExpansionBitmap
, 1, 0);
1065 if (Index
!= 0xFFFFFFFF)
1067 /* Is there no expansion slot yet? */
1068 if (!Teb
->TlsExpansionSlots
)
1070 /* Allocate an array */
1071 Teb
->TlsExpansionSlots
= RtlAllocateHeap(RtlGetProcessHeap(),
1073 TLS_EXPANSION_SLOTS
*
1077 /* Did we get an array? */
1078 if (!Teb
->TlsExpansionSlots
)
1081 RtlClearBits(Peb
->TlsExpansionBitmap
, Index
, 1);
1083 BaseSetLastNTError(STATUS_NO_MEMORY
);
1087 /* Clear the value. */
1088 Teb
->TlsExpansionSlots
[Index
] = 0;
1089 Index
+= TLS_MINIMUM_AVAILABLE
;
1095 BaseSetLastNTError(STATUS_NO_MEMORY
);
1098 /* Release the lock and return */
1099 RtlReleasePebLock();
1108 TlsFree(IN DWORD Index
)
1116 /* Acquire the PEB lock and grab the PEB */
1117 Peb
= NtCurrentPeb();
1118 RtlAcquirePebLock();
1120 /* Check if the index is too high */
1121 if (Index
>= TLS_MINIMUM_AVAILABLE
)
1123 /* Check if it can fit in the expansion slots */
1124 TlsIndex
= Index
- TLS_MINIMUM_AVAILABLE
;
1125 if (TlsIndex
>= TLS_EXPANSION_SLOTS
)
1128 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
1129 RtlReleasePebLock();
1134 /* Use the expansion bitmap */
1135 TlsBitmap
= Peb
->TlsExpansionBitmap
;
1141 /* Use the normal bitmap */
1142 TlsBitmap
= Peb
->TlsBitmap
;
1145 /* Check if the index was set */
1146 BitSet
= RtlAreBitsSet(TlsBitmap
, Index
, 1);
1149 /* Tell the kernel to free the TLS cells */
1150 Status
= NtSetInformationThread(NtCurrentThread(),
1154 if (!NT_SUCCESS(Status
))
1156 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
1157 RtlReleasePebLock();
1162 RtlClearBits(TlsBitmap
, Index
, 1);
1167 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
1168 RtlReleasePebLock();
1173 RtlReleasePebLock();
1182 TlsGetValue(IN DWORD Index
)
1186 /* Get the TEB and clear the last error */
1187 Teb
= NtCurrentTeb();
1188 Teb
->LastErrorValue
= 0;
1190 /* Check for simple TLS index */
1191 if (Index
< TLS_MINIMUM_AVAILABLE
)
1194 return Teb
->TlsSlots
[Index
];
1197 /* Check for valid index */
1198 if (Index
>= TLS_EXPANSION_SLOTS
+ TLS_MINIMUM_AVAILABLE
)
1201 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
1205 /* The expansion slots are allocated on demand, so check for it. */
1206 Teb
->LastErrorValue
= 0;
1207 if (!Teb
->TlsExpansionSlots
) return NULL
;
1209 /* Return the value from the expansion slots */
1210 return Teb
->TlsExpansionSlots
[Index
- TLS_MINIMUM_AVAILABLE
];
1218 TlsSetValue(IN DWORD Index
,
1222 PTEB Teb
= NtCurrentTeb();
1224 /* Check for simple TLS index */
1225 if (Index
< TLS_MINIMUM_AVAILABLE
)
1228 Teb
->TlsSlots
[Index
] = Value
;
1232 /* Check if this is an expansion slot */
1233 TlsIndex
= Index
- TLS_MINIMUM_AVAILABLE
;
1234 if (TlsIndex
>= TLS_EXPANSION_SLOTS
)
1237 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
1241 /* Do we not have expansion slots? */
1242 if (!Teb
->TlsExpansionSlots
)
1244 /* Get the PEB lock to see if we still need them */
1245 RtlAcquirePebLock();
1246 if (!Teb
->TlsExpansionSlots
)
1249 Teb
->TlsExpansionSlots
= RtlAllocateHeap(RtlGetProcessHeap(),
1251 TLS_EXPANSION_SLOTS
*
1253 if (!Teb
->TlsExpansionSlots
)
1256 RtlReleasePebLock();
1257 BaseSetLastNTError(STATUS_NO_MEMORY
);
1262 /* Release the lock */
1263 RtlReleasePebLock();
1266 /* Write the value */
1267 Teb
->TlsExpansionSlots
[TlsIndex
] = Value
;