- Allow TLS usage for 1088 TLS slots, fixes part of Bug 191. Patch by Filip Navara...
[reactos.git] / reactos / lib / 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
17 #define NDEBUG
18 #include "../include/debug.h"
19
20 #define TLS_EXPANSION_SLOTS (8 * sizeof(((PPEB)NULL)->TlsExpansionBitmapBits))
21
22 /* FUNCTIONS *****************************************************************/
23
24 /*
25 * @implemented
26 */
27 DWORD STDCALL
28 TlsAlloc(VOID)
29 {
30 ULONG Index;
31
32 RtlAcquirePebLock();
33
34 /* Try to get regular TEB slot. */
35 Index = RtlFindClearBitsAndSet(NtCurrentPeb()->TlsBitmap, 1, 0);
36 if (Index == ~0)
37 {
38 /* If it fails, try to find expansion TEB slot. */
39 Index = RtlFindClearBitsAndSet(NtCurrentPeb()->TlsExpansionBitmap, 1, 0);
40 if (Index != ~0)
41 {
42 if (NtCurrentTeb()->TlsExpansionSlots == NULL)
43 {
44 NtCurrentTeb()->TlsExpansionSlots = HeapAlloc(
45 GetProcessHeap(), HEAP_ZERO_MEMORY,
46 TLS_EXPANSION_SLOTS * sizeof(PVOID));
47 }
48
49 if (NtCurrentTeb()->TlsExpansionSlots == NULL)
50 {
51 RtlClearBits(NtCurrentPeb()->TlsExpansionBitmap, Index, 1);
52 Index = ~0;
53 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
54 }
55 else
56 {
57 /* Clear the value. */
58 NtCurrentTeb()->TlsExpansionSlots[Index] = 0;
59 Index += TLS_MINIMUM_AVAILABLE;
60 }
61 }
62 else
63 {
64 SetLastError(ERROR_NO_MORE_ITEMS);
65 }
66 }
67 else
68 {
69 /* Clear the value. */
70 NtCurrentTeb()->TlsSlots[Index] = 0;
71 }
72
73 RtlReleasePebLock();
74
75 return Index;
76 }
77
78
79 /*
80 * @implemented
81 */
82 BOOL STDCALL
83 TlsFree(DWORD Index)
84 {
85 BOOL BitSet;
86
87 if (Index >= TLS_EXPANSION_SLOTS + TLS_MINIMUM_AVAILABLE)
88 {
89 SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
90 return FALSE;
91 }
92
93 RtlAcquirePebLock();
94
95 if (Index >= TLS_MINIMUM_AVAILABLE)
96 {
97 BitSet = RtlAreBitsSet(NtCurrentPeb()->TlsExpansionBitmap,
98 Index - TLS_MINIMUM_AVAILABLE, 1);
99 if (BitSet)
100 RtlClearBits(NtCurrentPeb()->TlsExpansionBitmap,
101 Index - TLS_MINIMUM_AVAILABLE, 1);
102 }
103 else
104 {
105 BitSet = RtlAreBitsSet(NtCurrentPeb()->TlsBitmap, Index, 1);
106 if (BitSet)
107 RtlClearBits(NtCurrentPeb()->TlsBitmap, Index, 1);
108 }
109
110 if (BitSet)
111 {
112 /* Clear the TLS cells (slots) in all threads of the current process. */
113 NtSetInformationThread(NtCurrentThread(), ThreadZeroTlsCell,
114 &Index, sizeof(DWORD));
115 }
116 else
117 {
118 SetLastError(ERROR_INVALID_PARAMETER);
119 }
120
121 RtlReleasePebLock();
122
123 return BitSet;
124 }
125
126
127 /*
128 * @implemented
129 */
130 LPVOID STDCALL
131 TlsGetValue(DWORD Index)
132 {
133 if (Index >= TLS_EXPANSION_SLOTS + TLS_MINIMUM_AVAILABLE)
134 {
135 SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
136 return NULL;
137 }
138
139 SetLastError(NO_ERROR);
140
141 if (Index >= TLS_MINIMUM_AVAILABLE)
142 {
143 /* The expansion slots are allocated on demand, so check for it. */
144 if (NtCurrentTeb()->TlsExpansionSlots == NULL)
145 return NULL;
146 return NtCurrentTeb()->TlsExpansionSlots[Index - TLS_MINIMUM_AVAILABLE];
147 }
148 else
149 {
150 return NtCurrentTeb()->TlsSlots[Index];
151 }
152 }
153
154
155 /*
156 * @implemented
157 */
158 BOOL STDCALL
159 TlsSetValue(DWORD Index, LPVOID Value)
160 {
161 if (Index >= TLS_EXPANSION_SLOTS + TLS_MINIMUM_AVAILABLE)
162 {
163 SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
164 return FALSE;
165 }
166
167 if (Index >= TLS_MINIMUM_AVAILABLE)
168 {
169 if (NtCurrentTeb()->TlsExpansionSlots == NULL)
170 {
171 NtCurrentTeb()->TlsExpansionSlots = HeapAlloc(
172 GetProcessHeap(), HEAP_ZERO_MEMORY,
173 TLS_EXPANSION_SLOTS * sizeof(PVOID));
174
175 if (NtCurrentTeb()->TlsExpansionSlots == NULL)
176 {
177 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
178 return FALSE;
179 }
180 }
181
182 NtCurrentTeb()->TlsExpansionSlots[Index - TLS_MINIMUM_AVAILABLE] = Value;
183 }
184 else
185 {
186 NtCurrentTeb()->TlsSlots[Index] = Value;
187 }
188
189 return TRUE;
190 }
191
192 /* EOF */