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)
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: %ld dwStackSize: %ld lpStartAddress"
179 ": %p lpParameter: %lx, 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 // WARNING!!! THIS IS USING THE WIN32 FLAG BECAUSE REACTOS CONTINUES TO BE A POS!!! ///
264 Status
= RtlQueryInformationActivationContext(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX
,
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
,
575 PRTL_CRITICAL_SECTION LoaderLock
;
576 THREAD_BASIC_INFORMATION ThreadInfo
;
578 /* Check for invalid thread handle */
581 /* Fail if one was passed */
582 SetLastError(ERROR_INVALID_HANDLE
);
586 /* Get the loader lock */
587 LoaderLock
= NtCurrentPeb()->LoaderLock
;
591 Status
= NtQueryInformationThread(hThread
,
592 ThreadBasicInformation
,
596 if (!NT_SUCCESS(Status
))
598 /* Assert that we don't hold the loader lock */
599 ASSERT(NtCurrentTeb()->ClientId
.UniqueThread
!= ThreadInfo
.ClientId
.UniqueThread
);
600 ASSERT(NtCurrentTeb()->ClientId
.UniqueThread
!= LoaderLock
->OwningThread
);
604 /* Now terminate the thread */
605 Status
= NtTerminateThread(hThread
, dwExitCode
);
606 if (!NT_SUCCESS(Status
))
609 BaseSetLastNTError(Status
);
622 SuspendThread(IN HANDLE hThread
)
624 ULONG PreviousSuspendCount
;
627 Status
= NtSuspendThread(hThread
, &PreviousSuspendCount
);
628 if (!NT_SUCCESS(Status
))
630 BaseSetLastNTError(Status
);
634 return PreviousSuspendCount
;
642 SetThreadAffinityMask(IN HANDLE hThread
,
643 IN DWORD_PTR dwThreadAffinityMask
)
645 THREAD_BASIC_INFORMATION ThreadBasic
;
646 KAFFINITY AffinityMask
;
649 AffinityMask
= (KAFFINITY
)dwThreadAffinityMask
;
651 Status
= NtQueryInformationThread(hThread
,
652 ThreadBasicInformation
,
654 sizeof(THREAD_BASIC_INFORMATION
),
656 if (!NT_SUCCESS(Status
))
658 BaseSetLastNTError(Status
);
662 Status
= NtSetInformationThread(hThread
,
666 if (!NT_SUCCESS(Status
))
668 BaseSetLastNTError(Status
);
669 ThreadBasic
.AffinityMask
= 0;
672 return ThreadBasic
.AffinityMask
;
680 SetThreadPriority(IN HANDLE hThread
,
683 LONG Prio
= nPriority
;
686 /* Check if values forcing saturation should be used */
687 if (Prio
== THREAD_PRIORITY_TIME_CRITICAL
)
690 Prio
= (HIGH_PRIORITY
+ 1) / 2;
692 else if (Prio
== THREAD_PRIORITY_IDLE
)
695 Prio
= -((HIGH_PRIORITY
+ 1) / 2);
698 /* Set the Base Priority */
699 Status
= NtSetInformationThread(hThread
,
703 if (!NT_SUCCESS(Status
))
706 BaseSetLastNTError(Status
);
719 GetThreadPriority(IN HANDLE hThread
)
721 THREAD_BASIC_INFORMATION ThreadBasic
;
724 /* Query the Base Priority Increment */
725 Status
= NtQueryInformationThread(hThread
,
726 ThreadBasicInformation
,
728 sizeof(THREAD_BASIC_INFORMATION
),
730 if (!NT_SUCCESS(Status
))
733 BaseSetLastNTError(Status
);
734 return THREAD_PRIORITY_ERROR_RETURN
;
737 /* Do some conversions for saturation values */
738 if (ThreadBasic
.BasePriority
== ((HIGH_PRIORITY
+ 1) / 2))
740 /* Win32 calls this "time critical" */
741 ThreadBasic
.BasePriority
= THREAD_PRIORITY_TIME_CRITICAL
;
743 else if (ThreadBasic
.BasePriority
== -((HIGH_PRIORITY
+ 1) / 2))
745 /* Win32 calls this "idle" */
746 ThreadBasic
.BasePriority
= THREAD_PRIORITY_IDLE
;
749 /* Return the final result */
750 return ThreadBasic
.BasePriority
;
758 GetThreadPriorityBoost(IN HANDLE hThread
,
759 OUT PBOOL pDisablePriorityBoost
)
764 Status
= NtQueryInformationThread(hThread
,
769 if (!NT_SUCCESS(Status
))
771 BaseSetLastNTError(Status
);
775 *pDisablePriorityBoost
= PriorityBoost
;
784 SetThreadPriorityBoost(IN HANDLE hThread
,
785 IN BOOL bDisablePriorityBoost
)
790 PriorityBoost
= bDisablePriorityBoost
!= FALSE
;
792 Status
= NtSetInformationThread(hThread
,
796 if (!NT_SUCCESS(Status
))
798 BaseSetLastNTError(Status
);
810 GetThreadSelectorEntry(IN HANDLE hThread
,
812 OUT LPLDT_ENTRY lpSelectorEntry
)
815 DESCRIPTOR_TABLE_ENTRY DescriptionTableEntry
;
818 /* Set the selector and do the query */
819 DescriptionTableEntry
.Selector
= dwSelector
;
820 Status
= NtQueryInformationThread(hThread
,
821 ThreadDescriptorTableEntry
,
822 &DescriptionTableEntry
,
823 sizeof(DESCRIPTOR_TABLE_ENTRY
),
825 if (!NT_SUCCESS(Status
))
828 BaseSetLastNTError(Status
);
832 /* Success, return the selector */
833 *lpSelectorEntry
= DescriptionTableEntry
.Descriptor
;
836 DPRINT1("Calling GetThreadSelectorEntry!\n");
846 SetThreadIdealProcessor(IN HANDLE hThread
,
847 IN DWORD dwIdealProcessor
)
851 Status
= NtSetInformationThread(hThread
,
852 ThreadIdealProcessor
,
855 if (!NT_SUCCESS(Status
))
857 BaseSetLastNTError(Status
);
861 return (DWORD
)Status
;
869 GetProcessIdOfThread(IN HANDLE Thread
)
871 THREAD_BASIC_INFORMATION ThreadBasic
;
874 Status
= NtQueryInformationThread(Thread
,
875 ThreadBasicInformation
,
877 sizeof(THREAD_BASIC_INFORMATION
),
879 if (!NT_SUCCESS(Status
))
881 BaseSetLastNTError(Status
);
885 return HandleToUlong(ThreadBasic
.ClientId
.UniqueProcess
);
893 GetThreadId(IN HANDLE Thread
)
895 THREAD_BASIC_INFORMATION ThreadBasic
;
898 Status
= NtQueryInformationThread(Thread
,
899 ThreadBasicInformation
,
901 sizeof(THREAD_BASIC_INFORMATION
),
903 if (!NT_SUCCESS(Status
))
905 BaseSetLastNTError(Status
);
909 return HandleToUlong(ThreadBasic
.ClientId
.UniqueThread
);
917 SetThreadUILanguage(IN LANGID LangId
)
920 return NtCurrentTeb()->CurrentLocale
;
928 QueueUserAPC(IN PAPCFUNC pfnAPC
,
933 ACTIVATION_CONTEXT_BASIC_INFORMATION ActCtxInfo
;
935 /* Zero the activation context and query information on it */
936 RtlZeroMemory(&ActCtxInfo
, sizeof(ActCtxInfo
));
937 // WARNING!!! THIS IS USING THE WIN32 FLAG BECAUSE REACTOS CONTINUES TO BE A POS!!! ///
938 Status
= RtlQueryInformationActivationContext(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX
,
941 ActivationContextBasicInformation
,
945 if (!NT_SUCCESS(Status
))
947 /* Fail due to SxS */
948 DbgPrint("SXS: %s failing because RtlQueryInformationActivationContext()"
949 "returned status %08lx\n", __FUNCTION__
, Status
);
950 BaseSetLastNTError(Status
);
955 Status
= NtQueueApcThread(hThread
,
956 (PKNORMAL_ROUTINE
)BaseDispatchApc
,
959 (ActCtxInfo
.dwFlags
& 1) ?
960 INVALID_ACTIVATION_CONTEXT
: ActCtxInfo
.hActCtx
);
961 if (!NT_SUCCESS(Status
))
963 BaseSetLastNTError(Status
);
976 SetThreadStackGuarantee(IN OUT PULONG StackSizeInBytes
)
987 GetThreadIOPendingFlag(IN HANDLE hThread
,
988 OUT PBOOL lpIOIsPending
)
994 Status
= NtQueryInformationThread(hThread
,
999 if (NT_SUCCESS(Status
))
1001 /* Return the flag */
1002 *lpIOIsPending
= IoPending
? TRUE
: FALSE
;
1007 BaseSetLastNTError(Status
);
1016 QueueUserWorkItem(IN LPTHREAD_START_ROUTINE Function
,
1022 /* NOTE: Rtl needs to safely call the function using a trampoline */
1023 Status
= RtlQueueWorkItem((WORKERCALLBACKFUNC
)Function
, Context
, Flags
);
1024 if (!NT_SUCCESS(Status
))
1027 BaseSetLastNTError(Status
);
1046 /* Get the PEB and TEB, lock the PEB */
1047 Teb
= NtCurrentTeb();
1048 Peb
= Teb
->ProcessEnvironmentBlock
;
1049 RtlAcquirePebLock();
1051 /* Try to get regular TEB slot */
1052 Index
= RtlFindClearBitsAndSet(Peb
->TlsBitmap
, 1, 0);
1053 if (Index
!= 0xFFFFFFFF)
1055 /* Clear the value. */
1056 Teb
->TlsSlots
[Index
] = 0;
1057 RtlReleasePebLock();
1061 /* If it fails, try to find expansion TEB slot. */
1062 Index
= RtlFindClearBitsAndSet(Peb
->TlsExpansionBitmap
, 1, 0);
1063 if (Index
!= 0xFFFFFFFF)
1065 /* Is there no expansion slot yet? */
1066 if (!Teb
->TlsExpansionSlots
)
1068 /* Allocate an array */
1069 Teb
->TlsExpansionSlots
= RtlAllocateHeap(RtlGetProcessHeap(),
1071 TLS_EXPANSION_SLOTS
*
1075 /* Did we get an array? */
1076 if (!Teb
->TlsExpansionSlots
)
1079 RtlClearBits(Peb
->TlsExpansionBitmap
, Index
, 1);
1081 BaseSetLastNTError(STATUS_NO_MEMORY
);
1085 /* Clear the value. */
1086 Teb
->TlsExpansionSlots
[Index
] = 0;
1087 Index
+= TLS_MINIMUM_AVAILABLE
;
1093 BaseSetLastNTError(STATUS_NO_MEMORY
);
1096 /* Release the lock and return */
1097 RtlReleasePebLock();
1106 TlsFree(IN DWORD Index
)
1114 /* Acquire the PEB lock and grab the PEB */
1115 Peb
= NtCurrentPeb();
1116 RtlAcquirePebLock();
1118 /* Check if the index is too high */
1119 if (Index
>= TLS_MINIMUM_AVAILABLE
)
1121 /* Check if it can fit in the expansion slots */
1122 TlsIndex
= Index
- TLS_MINIMUM_AVAILABLE
;
1123 if (TlsIndex
>= TLS_EXPANSION_SLOTS
)
1126 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
1127 RtlReleasePebLock();
1132 /* Use the expansion bitmap */
1133 TlsBitmap
= Peb
->TlsExpansionBitmap
;
1139 /* Use the normal bitmap */
1140 TlsBitmap
= Peb
->TlsBitmap
;
1143 /* Check if the index was set */
1144 BitSet
= RtlAreBitsSet(TlsBitmap
, Index
, 1);
1147 /* Tell the kernel to free the TLS cells */
1148 Status
= NtSetInformationThread(NtCurrentThread(),
1152 if (!NT_SUCCESS(Status
))
1154 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
1155 RtlReleasePebLock();
1160 RtlClearBits(TlsBitmap
, Index
, 1);
1165 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
1166 RtlReleasePebLock();
1171 RtlReleasePebLock();
1180 TlsGetValue(IN DWORD Index
)
1184 /* Get the TEB and clear the last error */
1185 Teb
= NtCurrentTeb();
1186 Teb
->LastErrorValue
= 0;
1188 /* Check for simple TLS index */
1189 if (Index
< TLS_MINIMUM_AVAILABLE
)
1192 return Teb
->TlsSlots
[Index
];
1195 /* Check for valid index */
1196 if (Index
>= TLS_EXPANSION_SLOTS
+ TLS_MINIMUM_AVAILABLE
)
1199 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
1203 /* The expansion slots are allocated on demand, so check for it. */
1204 Teb
->LastErrorValue
= 0;
1205 if (!Teb
->TlsExpansionSlots
) return NULL
;
1207 /* Return the value from the expansion slots */
1208 return Teb
->TlsExpansionSlots
[Index
- TLS_MINIMUM_AVAILABLE
];
1216 TlsSetValue(IN DWORD Index
,
1220 PTEB Teb
= NtCurrentTeb();
1222 /* Check for simple TLS index */
1223 if (Index
< TLS_MINIMUM_AVAILABLE
)
1226 Teb
->TlsSlots
[Index
] = Value
;
1230 /* Check if this is an expansion slot */
1231 TlsIndex
= Index
- TLS_MINIMUM_AVAILABLE
;
1232 if (TlsIndex
>= TLS_EXPANSION_SLOTS
)
1235 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
1239 /* Do we not have expansion slots? */
1240 if (!Teb
->TlsExpansionSlots
)
1242 /* Get the PEB lock to see if we still need them */
1243 RtlAcquirePebLock();
1244 if (!Teb
->TlsExpansionSlots
)
1247 Teb
->TlsExpansionSlots
= RtlAllocateHeap(RtlGetProcessHeap(),
1249 TLS_EXPANSION_SLOTS
*
1251 if (!Teb
->TlsExpansionSlots
)
1254 RtlReleasePebLock();
1255 BaseSetLastNTError(STATUS_NO_MEMORY
);
1260 /* Release the lock */
1261 RtlReleasePebLock();
1264 /* Write the value */
1265 Teb
->TlsExpansionSlots
[TlsIndex
] = Value
;