| 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 | |
| 9 | Module Name: |
| 10 | |
| 11 | tls.cpp |
| 12 | |
| 13 | Abstract: |
| 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> |
| 35 | using namespace CorUnix; |
| 36 | |
| 37 | SET_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. */ |
| 47 | static unsigned __int64 sTlsSlotFields; |
| 48 | |
| 49 | /*++ |
| 50 | Function: |
| 51 | TlsAlloc |
| 52 | |
| 53 | See MSDN doc. |
| 54 | --*/ |
| 55 | DWORD |
| 56 | PALAPI |
| 57 | TlsAlloc( |
| 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 | /*++ |
| 99 | Function: |
| 100 | TlsGetValue |
| 101 | |
| 102 | See MSDN doc. |
| 103 | --*/ |
| 104 | LPVOID |
| 105 | PALAPI |
| 106 | TlsGetValue( |
| 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 | /*++ |
| 134 | Function: |
| 135 | TlsSetValue |
| 136 | |
| 137 | See MSDN doc. |
| 138 | --*/ |
| 139 | BOOL |
| 140 | PALAPI |
| 141 | TlsSetValue( |
| 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 | |
| 160 | EXIT: |
| 161 | LOGEXIT("TlsSetValue returns BOOL %d\n" , bRet); |
| 162 | PERF_EXIT(TlsSetValue); |
| 163 | return bRet; |
| 164 | } |
| 165 | |
| 166 | |
| 167 | /*++ |
| 168 | Function: |
| 169 | TlsFree |
| 170 | |
| 171 | See MSDN doc. |
| 172 | --*/ |
| 173 | BOOL |
| 174 | PALAPI |
| 175 | TlsFree( |
| 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 | |
| 209 | PAL_ERROR |
| 210 | CThreadTLSInfo::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 | |