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 ***********************************************************/
135 CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes
,
136 IN DWORD dwStackSize
,
137 IN LPTHREAD_START_ROUTINE lpStartAddress
,
138 IN LPVOID lpParameter
,
139 IN DWORD dwCreationFlags
,
140 OUT LPDWORD lpThreadId
)
142 /* Act as if we're going to create a remote thread in ourselves */
143 return CreateRemoteThread(NtCurrentProcess(),
157 CreateRemoteThread(IN HANDLE hProcess
,
158 IN LPSECURITY_ATTRIBUTES lpThreadAttributes
,
159 IN DWORD dwStackSize
,
160 IN LPTHREAD_START_ROUTINE lpStartAddress
,
161 IN LPVOID lpParameter
,
162 IN DWORD dwCreationFlags
,
163 OUT LPDWORD lpThreadId
)
166 INITIAL_TEB InitialTeb
;
169 OBJECT_ATTRIBUTES LocalObjectAttributes
;
170 POBJECT_ATTRIBUTES ObjectAttributes
;
174 THREAD_BASIC_INFORMATION ThreadBasicInfo
;
175 PACTIVATION_CONTEXT_STACK ActivationContextStack
= NULL
;
176 ACTIVATION_CONTEXT_BASIC_INFORMATION ActCtxInfo
;
179 DPRINT("CreateRemoteThread: hProcess: %p dwStackSize: %lu lpStartAddress"
180 ": %p lpParameter: %p, dwCreationFlags: %lx\n", hProcess
,
181 dwStackSize
, lpStartAddress
, lpParameter
, dwCreationFlags
);
183 /* Clear the Context */
184 RtlZeroMemory(&Context
, sizeof(CONTEXT
));
187 ClientId
.UniqueProcess
= hProcess
;
189 /* Create the Stack */
190 Status
= BaseCreateStack(hProcess
,
192 dwCreationFlags
& STACK_SIZE_PARAM_IS_A_RESERVATION
?
195 if (!NT_SUCCESS(Status
))
197 BaseSetLastNTError(Status
);
201 /* Create Initial Context */
202 BaseInitializeContext(&Context
,
205 InitialTeb
.StackBase
,
208 /* initialize the attributes for the thread object */
209 ObjectAttributes
= BaseFormatObjectAttributes(&LocalObjectAttributes
,
213 /* Create the Kernel Thread Object */
214 Status
= NtCreateThread(&hThread
,
222 if (!NT_SUCCESS(Status
))
224 /* Fail the kernel create */
225 BaseFreeThreadStack(hProcess
, &InitialTeb
);
226 BaseSetLastNTError(Status
);
230 /* Are we in the same process? */
231 if (hProcess
== NtCurrentProcess())
234 Status
= NtQueryInformationThread(hThread
,
235 ThreadBasicInformation
,
237 sizeof(ThreadBasicInfo
),
239 if (!NT_SUCCESS(Status
))
242 ERROR_DBGBREAK("SXS: %s - Failing thread create because "
243 "NtQueryInformationThread() failed with status %08lx\n",
244 __FUNCTION__
, Status
);
248 /* Allocate the Activation Context Stack */
249 Status
= RtlAllocateActivationContextStack(&ActivationContextStack
);
250 if (!NT_SUCCESS(Status
))
253 ERROR_DBGBREAK("SXS: %s - Failing thread create because "
254 "RtlAllocateActivationContextStack() failed with status %08lx\n",
255 __FUNCTION__
, Status
);
260 Teb
= ThreadBasicInfo
.TebBaseAddress
;
261 Teb
->ActivationContextStackPointer
= ActivationContextStack
;
263 /* Query the Context */
264 Status
= RtlQueryInformationActivationContext(RTL_QUERY_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT
,
267 ActivationContextBasicInformation
,
271 if (!NT_SUCCESS(Status
))
274 ERROR_DBGBREAK("SXS: %s - Failing thread create because "
275 "RtlQueryInformationActivationContext() failed with status %08lx\n",
276 __FUNCTION__
, Status
);
278 /* Free the activation context stack */
279 // RtlFreeThreadActivationContextStack();
280 RtlFreeActivationContextStack(Teb
->ActivationContextStackPointer
);
285 /* Does it need to be activated? */
286 if ((ActCtxInfo
.hActCtx
) && !(ActCtxInfo
.dwFlags
& 1))
289 Status
= RtlActivateActivationContextEx(RTL_ACTIVATE_ACTIVATION_CONTEXT_EX_FLAG_RELEASE_ON_STACK_DEALLOCATION
,
293 if (!NT_SUCCESS(Status
))
296 ERROR_DBGBREAK("SXS: %s - Failing thread create because "
297 "RtlActivateActivationContextEx() failed with status %08lx\n",
298 __FUNCTION__
, Status
);
300 /* Free the activation context stack */
301 // RtlFreeThreadActivationContextStack();
302 RtlFreeActivationContextStack(Teb
->ActivationContextStackPointer
);
310 if (!BaseRunningInServerProcess
)
312 Status
= BasepNotifyCsrOfThread(hThread
, &ClientId
);
313 ASSERT(NT_SUCCESS(Status
));
317 if (hProcess
!= NtCurrentProcess())
319 PCSR_CREATE_REMOTE_THREAD CsrCreateRemoteThread
;
321 /* Get the direct CSRSRV export */
322 CsrCreateRemoteThread
= (PCSR_CREATE_REMOTE_THREAD
)
323 GetProcAddress(GetModuleHandleA("csrsrv"),
324 "CsrCreateRemoteThread");
325 if (CsrCreateRemoteThread
)
327 /* Call it instead of going through LPC */
328 Status
= CsrCreateRemoteThread(hThread
, &ClientId
);
329 ASSERT(NT_SUCCESS(Status
));
335 if (lpThreadId
) *lpThreadId
= HandleToUlong(ClientId
.UniqueThread
);
337 /* Resume it if asked */
338 if (!(dwCreationFlags
& CREATE_SUSPENDED
)) NtResumeThread(hThread
, &Dummy
);
340 /* Return handle to thread */
349 ExitThread(IN DWORD uExitCode
)
353 PRTL_CRITICAL_SECTION LoaderLock
;
355 /* Make sure loader lock isn't held */
356 LoaderLock
= NtCurrentPeb()->LoaderLock
;
357 if (LoaderLock
) ASSERT(NtCurrentTeb()->ClientId
.UniqueThread
!= LoaderLock
->OwningThread
);
360 * Terminate process if this is the last thread
361 * of the current process
363 Status
= NtQueryInformationThread(NtCurrentThread(),
368 if ((NT_SUCCESS(Status
)) && (LastThread
)) ExitProcess(uExitCode
);
370 /* Notify DLLs and TLS Callbacks of termination */
373 /* Tell the Kernel to free the Stack */
374 NtCurrentTeb()->FreeStackOnTermination
= TRUE
;
375 NtTerminateThread(NULL
, uExitCode
);
377 /* We should never reach this place */
378 ERROR_FATAL("It should not happen\n");
379 while (TRUE
); /* 'noreturn' function */
387 OpenThread(IN DWORD dwDesiredAccess
,
388 IN BOOL bInheritHandle
,
393 OBJECT_ATTRIBUTES ObjectAttributes
;
396 ClientId
.UniqueProcess
= 0;
397 ClientId
.UniqueThread
= ULongToHandle(dwThreadId
);
399 InitializeObjectAttributes(&ObjectAttributes
,
401 (bInheritHandle
? OBJ_INHERIT
: 0),
405 Status
= NtOpenThread(&ThreadHandle
,
409 if (!NT_SUCCESS(Status
))
411 BaseSetLastNTError(Status
);
424 return NtCurrentTeb();
434 return NtYieldExecution() != STATUS_NO_YIELD_PERFORMED
;
443 GetCurrentThreadId(VOID
)
445 return HandleToUlong(NtCurrentTeb()->ClientId
.UniqueThread
);
453 GetThreadTimes(IN HANDLE hThread
,
454 OUT LPFILETIME lpCreationTime
,
455 OUT LPFILETIME lpExitTime
,
456 OUT LPFILETIME lpKernelTime
,
457 OUT LPFILETIME lpUserTime
)
459 KERNEL_USER_TIMES KernelUserTimes
;
462 Status
= NtQueryInformationThread(hThread
,
465 sizeof(KERNEL_USER_TIMES
),
467 if (!NT_SUCCESS(Status
))
469 BaseSetLastNTError(Status
);
473 *lpCreationTime
= *(LPFILETIME
)&KernelUserTimes
.CreateTime
;
474 *lpExitTime
= *(LPFILETIME
)&KernelUserTimes
.ExitTime
;
475 *lpKernelTime
= *(LPFILETIME
)&KernelUserTimes
.KernelTime
;
476 *lpUserTime
= *(LPFILETIME
)&KernelUserTimes
.UserTime
;
485 GetThreadContext(IN HANDLE hThread
,
486 OUT LPCONTEXT lpContext
)
490 Status
= NtGetContextThread(hThread
, lpContext
);
491 if (!NT_SUCCESS(Status
))
493 BaseSetLastNTError(Status
);
505 SetThreadContext(IN HANDLE hThread
,
506 IN CONST CONTEXT
*lpContext
)
510 Status
= NtSetContextThread(hThread
, (PCONTEXT
)lpContext
);
511 if (!NT_SUCCESS(Status
))
513 BaseSetLastNTError(Status
);
525 GetExitCodeThread(IN HANDLE hThread
,
526 OUT LPDWORD lpExitCode
)
528 THREAD_BASIC_INFORMATION ThreadBasic
;
531 Status
= NtQueryInformationThread(hThread
,
532 ThreadBasicInformation
,
534 sizeof(THREAD_BASIC_INFORMATION
),
536 if (!NT_SUCCESS(Status
))
538 BaseSetLastNTError(Status
);
542 *lpExitCode
= ThreadBasic
.ExitStatus
;
551 ResumeThread(IN HANDLE hThread
)
553 ULONG PreviousResumeCount
;
556 Status
= NtResumeThread(hThread
, &PreviousResumeCount
);
557 if (!NT_SUCCESS(Status
))
559 BaseSetLastNTError(Status
);
563 return PreviousResumeCount
;
571 TerminateThread(IN HANDLE hThread
,
576 PRTL_CRITICAL_SECTION LoaderLock
;
577 THREAD_BASIC_INFORMATION ThreadInfo
;
580 /* Check for invalid thread handle */
583 /* Fail if one was passed */
584 SetLastError(ERROR_INVALID_HANDLE
);
589 /* Get the loader lock */
590 LoaderLock
= NtCurrentPeb()->LoaderLock
;
594 Status
= NtQueryInformationThread(hThread
,
595 ThreadBasicInformation
,
599 if (NT_SUCCESS(Status
))
601 /* If terminating the current thread, we must not hold the loader lock */
602 if (NtCurrentTeb()->ClientId
.UniqueThread
== ThreadInfo
.ClientId
.UniqueThread
)
603 ASSERT(NtCurrentTeb()->ClientId
.UniqueThread
!= LoaderLock
->OwningThread
);
608 /* Now terminate the thread */
609 Status
= NtTerminateThread(hThread
, dwExitCode
);
610 if (!NT_SUCCESS(Status
))
613 BaseSetLastNTError(Status
);
626 SuspendThread(IN HANDLE hThread
)
628 ULONG PreviousSuspendCount
;
631 Status
= NtSuspendThread(hThread
, &PreviousSuspendCount
);
632 if (!NT_SUCCESS(Status
))
634 BaseSetLastNTError(Status
);
638 return PreviousSuspendCount
;
646 SetThreadAffinityMask(IN HANDLE hThread
,
647 IN DWORD_PTR dwThreadAffinityMask
)
649 THREAD_BASIC_INFORMATION ThreadBasic
;
650 KAFFINITY AffinityMask
;
653 AffinityMask
= (KAFFINITY
)dwThreadAffinityMask
;
655 Status
= NtQueryInformationThread(hThread
,
656 ThreadBasicInformation
,
658 sizeof(THREAD_BASIC_INFORMATION
),
660 if (!NT_SUCCESS(Status
))
662 BaseSetLastNTError(Status
);
666 Status
= NtSetInformationThread(hThread
,
670 if (!NT_SUCCESS(Status
))
672 BaseSetLastNTError(Status
);
673 ThreadBasic
.AffinityMask
= 0;
676 return ThreadBasic
.AffinityMask
;
684 SetThreadPriority(IN HANDLE hThread
,
687 LONG Prio
= nPriority
;
690 /* Check if values forcing saturation should be used */
691 if (Prio
== THREAD_PRIORITY_TIME_CRITICAL
)
694 Prio
= (HIGH_PRIORITY
+ 1) / 2;
696 else if (Prio
== THREAD_PRIORITY_IDLE
)
699 Prio
= -((HIGH_PRIORITY
+ 1) / 2);
702 /* Set the Base Priority */
703 Status
= NtSetInformationThread(hThread
,
707 if (!NT_SUCCESS(Status
))
710 BaseSetLastNTError(Status
);
723 GetThreadPriority(IN HANDLE hThread
)
725 THREAD_BASIC_INFORMATION ThreadBasic
;
728 /* Query the Base Priority Increment */
729 Status
= NtQueryInformationThread(hThread
,
730 ThreadBasicInformation
,
732 sizeof(THREAD_BASIC_INFORMATION
),
734 if (!NT_SUCCESS(Status
))
737 BaseSetLastNTError(Status
);
738 return THREAD_PRIORITY_ERROR_RETURN
;
741 /* Do some conversions for saturation values */
742 if (ThreadBasic
.BasePriority
== ((HIGH_PRIORITY
+ 1) / 2))
744 /* Win32 calls this "time critical" */
745 ThreadBasic
.BasePriority
= THREAD_PRIORITY_TIME_CRITICAL
;
747 else if (ThreadBasic
.BasePriority
== -((HIGH_PRIORITY
+ 1) / 2))
749 /* Win32 calls this "idle" */
750 ThreadBasic
.BasePriority
= THREAD_PRIORITY_IDLE
;
753 /* Return the final result */
754 return ThreadBasic
.BasePriority
;
762 GetThreadPriorityBoost(IN HANDLE hThread
,
763 OUT PBOOL pDisablePriorityBoost
)
768 Status
= NtQueryInformationThread(hThread
,
773 if (!NT_SUCCESS(Status
))
775 BaseSetLastNTError(Status
);
779 *pDisablePriorityBoost
= PriorityBoost
;
788 SetThreadPriorityBoost(IN HANDLE hThread
,
789 IN BOOL bDisablePriorityBoost
)
794 PriorityBoost
= bDisablePriorityBoost
!= FALSE
;
796 Status
= NtSetInformationThread(hThread
,
800 if (!NT_SUCCESS(Status
))
802 BaseSetLastNTError(Status
);
814 GetThreadSelectorEntry(IN HANDLE hThread
,
816 OUT LPLDT_ENTRY lpSelectorEntry
)
819 DESCRIPTOR_TABLE_ENTRY DescriptionTableEntry
;
822 /* Set the selector and do the query */
823 DescriptionTableEntry
.Selector
= dwSelector
;
824 Status
= NtQueryInformationThread(hThread
,
825 ThreadDescriptorTableEntry
,
826 &DescriptionTableEntry
,
827 sizeof(DESCRIPTOR_TABLE_ENTRY
),
829 if (!NT_SUCCESS(Status
))
832 BaseSetLastNTError(Status
);
836 /* Success, return the selector */
837 *lpSelectorEntry
= DescriptionTableEntry
.Descriptor
;
840 DPRINT1("Calling GetThreadSelectorEntry!\n");
850 SetThreadIdealProcessor(IN HANDLE hThread
,
851 IN DWORD dwIdealProcessor
)
855 Status
= NtSetInformationThread(hThread
,
856 ThreadIdealProcessor
,
859 if (!NT_SUCCESS(Status
))
861 BaseSetLastNTError(Status
);
865 return (DWORD
)Status
;
873 GetProcessIdOfThread(IN HANDLE Thread
)
875 THREAD_BASIC_INFORMATION ThreadBasic
;
878 Status
= NtQueryInformationThread(Thread
,
879 ThreadBasicInformation
,
881 sizeof(THREAD_BASIC_INFORMATION
),
883 if (!NT_SUCCESS(Status
))
885 BaseSetLastNTError(Status
);
889 return HandleToUlong(ThreadBasic
.ClientId
.UniqueProcess
);
897 GetThreadId(IN HANDLE Thread
)
899 THREAD_BASIC_INFORMATION ThreadBasic
;
902 Status
= NtQueryInformationThread(Thread
,
903 ThreadBasicInformation
,
905 sizeof(THREAD_BASIC_INFORMATION
),
907 if (!NT_SUCCESS(Status
))
909 BaseSetLastNTError(Status
);
913 return HandleToUlong(ThreadBasic
.ClientId
.UniqueThread
);
921 SetThreadUILanguage(IN LANGID LangId
)
924 return (LANGID
)NtCurrentTeb()->CurrentLocale
;
932 QueueUserAPC(IN PAPCFUNC pfnAPC
,
937 ACTIVATION_CONTEXT_BASIC_INFORMATION ActCtxInfo
;
939 /* Zero the activation context and query information on it */
940 RtlZeroMemory(&ActCtxInfo
, sizeof(ActCtxInfo
));
941 Status
= RtlQueryInformationActivationContext(RTL_QUERY_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT
,
944 ActivationContextBasicInformation
,
948 if (!NT_SUCCESS(Status
))
950 /* Fail due to SxS */
951 DbgPrint("SXS: %s failing because RtlQueryInformationActivationContext()"
952 "returned status %08lx\n", __FUNCTION__
, Status
);
953 BaseSetLastNTError(Status
);
958 Status
= NtQueueApcThread(hThread
,
959 (PKNORMAL_ROUTINE
)BaseDispatchApc
,
962 (ActCtxInfo
.dwFlags
& 1) ?
963 INVALID_ACTIVATION_CONTEXT
: ActCtxInfo
.hActCtx
);
964 if (!NT_SUCCESS(Status
))
966 BaseSetLastNTError(Status
);
979 SetThreadStackGuarantee(IN OUT PULONG StackSizeInBytes
)
990 GetThreadIOPendingFlag(IN HANDLE hThread
,
991 OUT PBOOL lpIOIsPending
)
997 Status
= NtQueryInformationThread(hThread
,
1002 if (NT_SUCCESS(Status
))
1004 /* Return the flag */
1005 *lpIOIsPending
= IoPending
? TRUE
: FALSE
;
1010 BaseSetLastNTError(Status
);
1019 QueueUserWorkItem(IN LPTHREAD_START_ROUTINE Function
,
1025 /* NOTE: Rtl needs to safely call the function using a trampoline */
1026 Status
= RtlQueueWorkItem((WORKERCALLBACKFUNC
)Function
, Context
, Flags
);
1027 if (!NT_SUCCESS(Status
))
1030 BaseSetLastNTError(Status
);
1049 /* Get the PEB and TEB, lock the PEB */
1050 Teb
= NtCurrentTeb();
1051 Peb
= Teb
->ProcessEnvironmentBlock
;
1052 RtlAcquirePebLock();
1054 /* Try to get regular TEB slot */
1055 Index
= RtlFindClearBitsAndSet(Peb
->TlsBitmap
, 1, 0);
1056 if (Index
!= 0xFFFFFFFF)
1058 /* Clear the value. */
1059 Teb
->TlsSlots
[Index
] = 0;
1060 RtlReleasePebLock();
1064 /* If it fails, try to find expansion TEB slot. */
1065 Index
= RtlFindClearBitsAndSet(Peb
->TlsExpansionBitmap
, 1, 0);
1066 if (Index
!= 0xFFFFFFFF)
1068 /* Is there no expansion slot yet? */
1069 if (!Teb
->TlsExpansionSlots
)
1071 /* Allocate an array */
1072 Teb
->TlsExpansionSlots
= RtlAllocateHeap(RtlGetProcessHeap(),
1074 TLS_EXPANSION_SLOTS
*
1078 /* Did we get an array? */
1079 if (!Teb
->TlsExpansionSlots
)
1082 RtlClearBits(Peb
->TlsExpansionBitmap
, Index
, 1);
1084 BaseSetLastNTError(STATUS_NO_MEMORY
);
1088 /* Clear the value. */
1089 Teb
->TlsExpansionSlots
[Index
] = 0;
1090 Index
+= TLS_MINIMUM_AVAILABLE
;
1096 BaseSetLastNTError(STATUS_NO_MEMORY
);
1099 /* Release the lock and return */
1100 RtlReleasePebLock();
1109 TlsFree(IN DWORD Index
)
1117 /* Acquire the PEB lock and grab the PEB */
1118 Peb
= NtCurrentPeb();
1119 RtlAcquirePebLock();
1121 /* Check if the index is too high */
1122 if (Index
>= TLS_MINIMUM_AVAILABLE
)
1124 /* Check if it can fit in the expansion slots */
1125 TlsIndex
= Index
- TLS_MINIMUM_AVAILABLE
;
1126 if (TlsIndex
>= TLS_EXPANSION_SLOTS
)
1129 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
1130 RtlReleasePebLock();
1135 /* Use the expansion bitmap */
1136 TlsBitmap
= Peb
->TlsExpansionBitmap
;
1142 /* Use the normal bitmap */
1143 TlsBitmap
= Peb
->TlsBitmap
;
1146 /* Check if the index was set */
1147 BitSet
= RtlAreBitsSet(TlsBitmap
, Index
, 1);
1150 /* Tell the kernel to free the TLS cells */
1151 Status
= NtSetInformationThread(NtCurrentThread(),
1155 if (!NT_SUCCESS(Status
))
1157 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
1158 RtlReleasePebLock();
1163 RtlClearBits(TlsBitmap
, Index
, 1);
1168 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
1169 RtlReleasePebLock();
1174 RtlReleasePebLock();
1183 TlsGetValue(IN DWORD Index
)
1187 /* Get the TEB and clear the last error */
1188 Teb
= NtCurrentTeb();
1189 Teb
->LastErrorValue
= 0;
1191 /* Check for simple TLS index */
1192 if (Index
< TLS_MINIMUM_AVAILABLE
)
1195 return Teb
->TlsSlots
[Index
];
1198 /* Check for valid index */
1199 if (Index
>= TLS_EXPANSION_SLOTS
+ TLS_MINIMUM_AVAILABLE
)
1202 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
1206 /* The expansion slots are allocated on demand, so check for it. */
1207 Teb
->LastErrorValue
= 0;
1208 if (!Teb
->TlsExpansionSlots
) return NULL
;
1210 /* Return the value from the expansion slots */
1211 return Teb
->TlsExpansionSlots
[Index
- TLS_MINIMUM_AVAILABLE
];
1219 TlsSetValue(IN DWORD Index
,
1223 PTEB Teb
= NtCurrentTeb();
1225 /* Check for simple TLS index */
1226 if (Index
< TLS_MINIMUM_AVAILABLE
)
1229 Teb
->TlsSlots
[Index
] = Value
;
1233 /* Check if this is an expansion slot */
1234 TlsIndex
= Index
- TLS_MINIMUM_AVAILABLE
;
1235 if (TlsIndex
>= TLS_EXPANSION_SLOTS
)
1238 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
1242 /* Do we not have expansion slots? */
1243 if (!Teb
->TlsExpansionSlots
)
1245 /* Get the PEB lock to see if we still need them */
1246 RtlAcquirePebLock();
1247 if (!Teb
->TlsExpansionSlots
)
1250 Teb
->TlsExpansionSlots
= RtlAllocateHeap(RtlGetProcessHeap(),
1252 TLS_EXPANSION_SLOTS
*
1254 if (!Teb
->TlsExpansionSlots
)
1257 RtlReleasePebLock();
1258 BaseSetLastNTError(STATUS_NO_MEMORY
);
1263 /* Release the lock */
1264 RtlReleasePebLock();
1267 /* Write the value */
1268 Teb
->TlsExpansionSlots
[TlsIndex
] = Value
;