1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/*++
6
7
8
9Module Name:
10
11 tls.cpp
12
13Abstract:
14
15 Implementation of Thread local storage functions.
16
17
18
19--*/
20
21#include "pal/thread.hpp"
22#include "procprivate.hpp"
23
24#include <pthread.h>
25
26#include "pal/dbgmsg.h"
27#include "pal/misc.h"
28#include "pal/virtual.h"
29#include "pal/process.h"
30#include "pal/init.h"
31#include "pal/malloc.hpp"
32#include "pal_endian.h"
33
34#include <stddef.h>
35using namespace CorUnix;
36
37SET_DEFAULT_DEBUG_CHANNEL(THREAD);
38
39// In safemath.h, Template SafeInt uses macro _ASSERTE, which need to use variable
40// defdbgchan defined by SET_DEFAULT_DEBUG_CHANNEL. Therefore, the include statement
41// should be placed after the SET_DEFAULT_DEBUG_CHANNEL(THREAD)
42#include <safemath.h>
43
44/* This tracks the slots that are used for TlsAlloc. Its size in bits
45 must be the same as TLS_SLOT_SIZE in pal/thread.h. Since this is
46 static, it is initialized to 0, which is what we want. */
47static unsigned __int64 sTlsSlotFields;
48
49/*++
50Function:
51 TlsAlloc
52
53See MSDN doc.
54--*/
55DWORD
56PALAPI
57TlsAlloc(
58 VOID)
59{
60 DWORD dwIndex;
61 unsigned int i;
62
63 PERF_ENTRY(TlsAlloc);
64 ENTRY("TlsAlloc()\n");
65
66 /* Yes, this could be ever so slightly improved. It's not
67 likely to be called enough to matter, though, so we won't
68 optimize here until or unless we need to. */
69
70 PROCProcessLock();
71
72 for(i = 0; i < sizeof(sTlsSlotFields) * 8; i++)
73 {
74 if ((sTlsSlotFields & ((unsigned __int64) 1 << i)) == 0)
75 {
76 sTlsSlotFields |= ((unsigned __int64) 1 << i);
77 break;
78 }
79 }
80 if (i == sizeof(sTlsSlotFields) * 8)
81 {
82 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
83 dwIndex = TLS_OUT_OF_INDEXES;
84 }
85 else
86 {
87 dwIndex = i;
88 }
89
90 PROCProcessUnlock();
91
92 LOGEXIT("TlsAlloc returns DWORD %u\n", dwIndex);
93 PERF_EXIT(TlsAlloc);
94 return dwIndex;
95}
96
97
98/*++
99Function:
100 TlsGetValue
101
102See MSDN doc.
103--*/
104LPVOID
105PALAPI
106TlsGetValue(
107 IN DWORD dwTlsIndex)
108{
109 CPalThread *pThread;
110
111 PERF_ENTRY(TlsGetValue);
112 ENTRY("TlsGetValue()\n");
113
114 if (dwTlsIndex == (DWORD) -1 || dwTlsIndex >= TLS_SLOT_SIZE)
115 {
116 SetLastError(ERROR_INVALID_PARAMETER);
117 return 0;
118 }
119
120 pThread = InternalGetCurrentThread();
121
122 /* From MSDN : "The TlsGetValue function calls SetLastError to clear a
123 thread's last error when it succeeds." */
124 pThread->SetLastError(NO_ERROR);
125
126 LOGEXIT("TlsGetValue \n" );
127 PERF_EXIT(TlsGetValue);
128
129 return pThread->tlsInfo.tlsSlots[dwTlsIndex];
130}
131
132
133/*++
134Function:
135 TlsSetValue
136
137See MSDN doc.
138--*/
139BOOL
140PALAPI
141TlsSetValue(
142 IN DWORD dwTlsIndex,
143 IN LPVOID lpTlsValue)
144{
145 CPalThread *pThread;
146 BOOL bRet = FALSE;
147 PERF_ENTRY(TlsSetValue);
148 ENTRY("TlsSetValue(dwTlsIndex=%u, lpTlsValue=%p)\n", dwTlsIndex, lpTlsValue);
149
150 if (dwTlsIndex == (DWORD) -1 || dwTlsIndex >= TLS_SLOT_SIZE)
151 {
152 SetLastError(ERROR_INVALID_PARAMETER);
153 goto EXIT;
154 }
155
156 pThread = InternalGetCurrentThread();
157 pThread->tlsInfo.tlsSlots[dwTlsIndex] = lpTlsValue;
158 bRet = TRUE;
159
160EXIT:
161 LOGEXIT("TlsSetValue returns BOOL %d\n", bRet);
162 PERF_EXIT(TlsSetValue);
163 return bRet;
164}
165
166
167/*++
168Function:
169 TlsFree
170
171See MSDN doc.
172--*/
173BOOL
174PALAPI
175TlsFree(
176 IN DWORD dwTlsIndex)
177{
178 CPalThread *pThread;
179
180 PERF_ENTRY(TlsFree);
181 ENTRY("TlsFree(dwTlsIndex=%u)\n", dwTlsIndex);
182
183
184 if (dwTlsIndex == (DWORD) -1 || dwTlsIndex >= TLS_SLOT_SIZE)
185 {
186 SetLastError(ERROR_INVALID_PARAMETER);
187 LOGEXIT("TlsFree returns BOOL FALSE\n");
188 PERF_EXIT(TlsFree);
189 return FALSE;
190 }
191
192 PROCProcessLock();
193
194 /* Reset all threads' values to zero for this index. */
195 for(pThread = pGThreadList;
196 pThread != NULL; pThread = pThread->GetNext())
197 {
198 pThread->tlsInfo.tlsSlots[dwTlsIndex] = 0;
199 }
200 sTlsSlotFields &= ~((unsigned __int64) 1 << dwTlsIndex);
201
202 PROCProcessUnlock();
203
204 LOGEXIT("TlsFree returns BOOL TRUE\n");
205 PERF_EXIT(TlsFree);
206 return TRUE;
207}
208
209PAL_ERROR
210CThreadTLSInfo::InitializePostCreate(
211 CPalThread *pThread,
212 SIZE_T threadId,
213 DWORD dwLwpId
214 )
215{
216 PAL_ERROR palError = NO_ERROR;
217
218 if (pthread_setspecific(thObjKey, reinterpret_cast<void*>(pThread)))
219 {
220 ASSERT("Unable to set the thread object key's value\n");
221 palError = ERROR_INTERNAL_ERROR;
222 }
223
224 return palError;
225}
226
227