- Merge from trunk up to r45543
[reactos.git] / dll / win32 / kernel32 / thread / tls.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/thread/tls.c
6 * PURPOSE: Thread functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
8 * Tls functions are modified from WINE
9 * UPDATE HISTORY:
10 * Created 01/11/98
11 */
12
13 /* INCLUDES ******************************************************************/
14
15 #include <k32.h>
16 #define NDEBUG
17 #include <debug.h>
18
19 /* FUNCTIONS *****************************************************************/
20
21 /*
22 * @implemented
23 */
24 DWORD
25 WINAPI
26 TlsAlloc(VOID)
27 {
28 ULONG Index;
29
30 RtlAcquirePebLock();
31
32 /* Try to get regular TEB slot. */
33 Index = RtlFindClearBitsAndSet(NtCurrentPeb()->TlsBitmap, 1, 0);
34 if (Index == ~0U)
35 {
36 /* If it fails, try to find expansion TEB slot. */
37 Index = RtlFindClearBitsAndSet(NtCurrentPeb()->TlsExpansionBitmap, 1, 0);
38 if (Index != ~0U)
39 {
40 if (NtCurrentTeb()->TlsExpansionSlots == NULL)
41 {
42 NtCurrentTeb()->TlsExpansionSlots = HeapAlloc(GetProcessHeap(),
43 HEAP_ZERO_MEMORY,
44 TLS_EXPANSION_SLOTS *
45 sizeof(PVOID));
46 }
47
48 if (NtCurrentTeb()->TlsExpansionSlots == NULL)
49 {
50 RtlClearBits(NtCurrentPeb()->TlsExpansionBitmap, Index, 1);
51 Index = ~0;
52 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
53 }
54 else
55 {
56 /* Clear the value. */
57 NtCurrentTeb()->TlsExpansionSlots[Index] = 0;
58 Index += TLS_MINIMUM_AVAILABLE;
59 }
60 }
61 else
62 {
63 SetLastError(ERROR_NO_MORE_ITEMS);
64 }
65 }
66 else
67 {
68 /* Clear the value. */
69 NtCurrentTeb()->TlsSlots[Index] = 0;
70 }
71
72 RtlReleasePebLock();
73
74 return Index;
75 }
76
77 /*
78 * @implemented
79 */
80 BOOL
81 WINAPI
82 TlsFree(DWORD Index)
83 {
84 BOOL BitSet;
85
86 if (Index >= TLS_EXPANSION_SLOTS + TLS_MINIMUM_AVAILABLE)
87 {
88 SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
89 return FALSE;
90 }
91
92 RtlAcquirePebLock();
93
94 if (Index >= TLS_MINIMUM_AVAILABLE)
95 {
96 BitSet = RtlAreBitsSet(NtCurrentPeb()->TlsExpansionBitmap,
97 Index - TLS_MINIMUM_AVAILABLE,
98 1);
99
100 if (BitSet)
101 RtlClearBits(NtCurrentPeb()->TlsExpansionBitmap,
102 Index - TLS_MINIMUM_AVAILABLE,
103 1);
104 }
105 else
106 {
107 BitSet = RtlAreBitsSet(NtCurrentPeb()->TlsBitmap, Index, 1);
108 if (BitSet)
109 RtlClearBits(NtCurrentPeb()->TlsBitmap, Index, 1);
110 }
111
112 if (BitSet)
113 {
114 /* Clear the TLS cells (slots) in all threads of the current process. */
115 NtSetInformationThread(NtCurrentThread(),
116 ThreadZeroTlsCell,
117 &Index,
118 sizeof(DWORD));
119 }
120 else
121 {
122 SetLastError(ERROR_INVALID_PARAMETER);
123 }
124
125 RtlReleasePebLock();
126
127 return BitSet;
128 }
129
130 /*
131 * @implemented
132 */
133 LPVOID
134 WINAPI
135 TlsGetValue(DWORD Index)
136 {
137 if (Index >= TLS_EXPANSION_SLOTS + TLS_MINIMUM_AVAILABLE)
138 {
139 SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
140 return NULL;
141 }
142
143 SetLastError(NO_ERROR);
144
145 if (Index >= TLS_MINIMUM_AVAILABLE)
146 {
147 /* The expansion slots are allocated on demand, so check for it. */
148 if (NtCurrentTeb()->TlsExpansionSlots == NULL)
149 return NULL;
150 return NtCurrentTeb()->TlsExpansionSlots[Index - TLS_MINIMUM_AVAILABLE];
151 }
152 else
153 {
154 return NtCurrentTeb()->TlsSlots[Index];
155 }
156 }
157
158 /*
159 * @implemented
160 */
161 BOOL
162 WINAPI
163 TlsSetValue(DWORD Index,
164 LPVOID Value)
165 {
166 if (Index >= TLS_EXPANSION_SLOTS + TLS_MINIMUM_AVAILABLE)
167 {
168 SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
169 return FALSE;
170 }
171
172 if (Index >= TLS_MINIMUM_AVAILABLE)
173 {
174 if (NtCurrentTeb()->TlsExpansionSlots == NULL)
175 {
176 NtCurrentTeb()->TlsExpansionSlots = HeapAlloc(GetProcessHeap(),
177 HEAP_ZERO_MEMORY,
178 TLS_EXPANSION_SLOTS *
179 sizeof(PVOID));
180
181 if (NtCurrentTeb()->TlsExpansionSlots == NULL)
182 {
183 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
184 return FALSE;
185 }
186 }
187
188 NtCurrentTeb()->TlsExpansionSlots[Index - TLS_MINIMUM_AVAILABLE] = Value;
189 }
190 else
191 {
192 NtCurrentTeb()->TlsSlots[Index] = Value;
193 }
194
195 return TRUE;
196 }