summaryrefslogtreecommitdiff
path: root/src/pal/src/thread/tls.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/pal/src/thread/tls.cpp')
-rw-r--r--src/pal/src/thread/tls.cpp226
1 files changed, 226 insertions, 0 deletions
diff --git a/src/pal/src/thread/tls.cpp b/src/pal/src/thread/tls.cpp
new file mode 100644
index 0000000000..ef6d02f00a
--- /dev/null
+++ b/src/pal/src/thread/tls.cpp
@@ -0,0 +1,226 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ tls.cpp
+
+Abstract:
+
+ Implementation of Thread local storage functions.
+
+
+
+--*/
+
+#include "pal/thread.hpp"
+#include "procprivate.hpp"
+
+#include <pthread.h>
+
+#include "pal/dbgmsg.h"
+#include "pal/misc.h"
+#include "pal/virtual.h"
+#include "pal/process.h"
+#include "pal/init.h"
+#include "pal/malloc.hpp"
+#include "pal_endian.h"
+
+#include <stddef.h>
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(THREAD);
+
+// In safemath.h, Template SafeInt uses macro _ASSERTE, which need to use variable
+// defdbgchan defined by SET_DEFAULT_DEBUG_CHANNEL. Therefore, the include statement
+// should be placed after the SET_DEFAULT_DEBUG_CHANNEL(THREAD)
+#include <safemath.h>
+
+/* This tracks the slots that are used for TlsAlloc. Its size in bits
+ must be the same as TLS_SLOT_SIZE in pal/thread.h. Since this is
+ static, it is initialized to 0, which is what we want. */
+static unsigned __int64 sTlsSlotFields;
+
+/*++
+Function:
+ TlsAlloc
+
+See MSDN doc.
+--*/
+DWORD
+PALAPI
+TlsAlloc(
+ VOID)
+{
+ DWORD dwIndex;
+ unsigned int i;
+
+ PERF_ENTRY(TlsAlloc);
+ ENTRY("TlsAlloc()\n");
+
+ /* Yes, this could be ever so slightly improved. It's not
+ likely to be called enough to matter, though, so we won't
+ optimize here until or unless we need to. */
+
+ PROCProcessLock();
+
+ for(i = 0; i < sizeof(sTlsSlotFields) * 8; i++)
+ {
+ if ((sTlsSlotFields & ((unsigned __int64) 1 << i)) == 0)
+ {
+ sTlsSlotFields |= ((unsigned __int64) 1 << i);
+ break;
+ }
+ }
+ if (i == sizeof(sTlsSlotFields) * 8)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ dwIndex = TLS_OUT_OF_INDEXES;
+ }
+ else
+ {
+ dwIndex = i;
+ }
+
+ PROCProcessUnlock();
+
+ LOGEXIT("TlsAlloc returns DWORD %u\n", dwIndex);
+ PERF_EXIT(TlsAlloc);
+ return dwIndex;
+}
+
+
+/*++
+Function:
+ TlsGetValue
+
+See MSDN doc.
+--*/
+LPVOID
+PALAPI
+TlsGetValue(
+ IN DWORD dwTlsIndex)
+{
+ CPalThread *pThread;
+
+ PERF_ENTRY(TlsGetValue);
+ ENTRY("TlsGetValue()\n");
+
+ if (dwTlsIndex == (DWORD) -1 || dwTlsIndex >= TLS_SLOT_SIZE)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+
+ pThread = InternalGetCurrentThread();
+
+ /* From MSDN : "The TlsGetValue function calls SetLastError to clear a
+ thread's last error when it succeeds." */
+ pThread->SetLastError(NO_ERROR);
+
+ LOGEXIT("TlsGetValue \n" );
+ PERF_EXIT(TlsGetValue);
+
+ return pThread->tlsInfo.tlsSlots[dwTlsIndex];
+}
+
+
+/*++
+Function:
+ TlsSetValue
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+TlsSetValue(
+ IN DWORD dwTlsIndex,
+ IN LPVOID lpTlsValue)
+{
+ CPalThread *pThread;
+ BOOL bRet = FALSE;
+ PERF_ENTRY(TlsSetValue);
+ ENTRY("TlsSetValue(dwTlsIndex=%u, lpTlsValue=%p)\n", dwTlsIndex, lpTlsValue);
+
+ if (dwTlsIndex == (DWORD) -1 || dwTlsIndex >= TLS_SLOT_SIZE)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto EXIT;
+ }
+
+ pThread = InternalGetCurrentThread();
+ pThread->tlsInfo.tlsSlots[dwTlsIndex] = lpTlsValue;
+ bRet = TRUE;
+
+EXIT:
+ LOGEXIT("TlsSetValue returns BOOL %d\n", bRet);
+ PERF_EXIT(TlsSetValue);
+ return bRet;
+}
+
+
+/*++
+Function:
+ TlsFree
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+TlsFree(
+ IN DWORD dwTlsIndex)
+{
+ CPalThread *pThread;
+
+ PERF_ENTRY(TlsFree);
+ ENTRY("TlsFree(dwTlsIndex=%u)\n", dwTlsIndex);
+
+
+ if (dwTlsIndex == (DWORD) -1 || dwTlsIndex >= TLS_SLOT_SIZE)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ LOGEXIT("TlsFree returns BOOL FALSE\n");
+ PERF_EXIT(TlsFree);
+ return FALSE;
+ }
+
+ PROCProcessLock();
+
+ /* Reset all threads' values to zero for this index. */
+ for(pThread = pGThreadList;
+ pThread != NULL; pThread = pThread->GetNext())
+ {
+ pThread->tlsInfo.tlsSlots[dwTlsIndex] = 0;
+ }
+ sTlsSlotFields &= ~((unsigned __int64) 1 << dwTlsIndex);
+
+ PROCProcessUnlock();
+
+ LOGEXIT("TlsFree returns BOOL TRUE\n");
+ PERF_EXIT(TlsFree);
+ return TRUE;
+}
+
+PAL_ERROR
+CThreadTLSInfo::InitializePostCreate(
+ CPalThread *pThread,
+ SIZE_T threadId,
+ DWORD dwLwpId
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+
+ if (pthread_setspecific(thObjKey, reinterpret_cast<void*>(pThread)))
+ {
+ ASSERT("Unable to set the thread object key's value\n");
+ palError = ERROR_INTERNAL_ERROR;
+ }
+
+ return palError;
+}
+