VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/win/tls-win.cpp@ 86412

Last change on this file since 86412 was 83124, checked in by vboxsync, 5 years ago

IPRT: Merged the two tls files, with the sideeffect that destructors only works for IPRT threads in non-dll setups.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 6.8 KB
Line 
1/* $Id: tls-win.cpp 83124 2020-02-20 17:23:23Z vboxsync $ */
2/** @file
3 * IPRT - Thread Local Storage (TLS), Win32.
4 */
5
6/*
7 * Copyright (C) 2008-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP RTLOGGROUP_THREAD
32#include <iprt/win/windows.h>
33
34#include <iprt/thread.h>
35#include <iprt/assert.h>
36#include <iprt/critsect.h>
37#include <iprt/errcore.h>
38#include <iprt/log.h>
39#include <iprt/mem.h>
40#include <iprt/once.h>
41#include "internal/thread.h"
42
43
44/*********************************************************************************************************************************
45* Structures and Typedefs *
46*********************************************************************************************************************************/
47typedef struct RTTLSWINDTOR
48{
49 RTLISTNODE ListEntry;
50 DWORD iTls;
51 PFNRTTLSDTOR pfnDestructor;
52} RTTLSWINDTOR;
53typedef RTTLSWINDTOR *PRTTLSWINDTOR;
54
55
56/*********************************************************************************************************************************
57* Global Variables *
58*********************************************************************************************************************************/
59/** Init once for the list and critical section. */
60static RTONCE g_Once = RTONCE_INITIALIZER;
61/** Critical section protecting the TLS destructor list. */
62static RTCRITSECTRW g_CritSect;
63/** List of TLS destrictors (RTTLSWINDTOR). */
64static RTLISTANCHOR g_TlsDtorHead;
65/** Number of desturctors in the list (helps putting of initialization). */
66static uint32_t volatile g_cTlsDtors = 0;
67
68
69/**
70 * @callback_method_impl{FNRTONCE}
71 */
72static DECLCALLBACK(int32_t) rtTlsWinInitLock(void *pvUser)
73{
74 RT_NOREF(pvUser);
75 RTListInit(&g_TlsDtorHead);
76 return RTCritSectRwInit(&g_CritSect);
77}
78
79
80RTR3DECL(RTTLS) RTTlsAlloc(void)
81{
82 AssertCompile(sizeof(RTTLS) >= sizeof(DWORD));
83 DWORD iTls = TlsAlloc();
84 return iTls != TLS_OUT_OF_INDEXES ? (RTTLS)iTls : NIL_RTTLS;
85}
86
87
88RTR3DECL(int) RTTlsAllocEx(PRTTLS piTls, PFNRTTLSDTOR pfnDestructor)
89{
90 int rc;
91 if (!pfnDestructor)
92 {
93 DWORD iTls = TlsAlloc();
94 if (iTls != TLS_OUT_OF_INDEXES)
95 {
96 Assert((RTTLS)iTls != NIL_RTTLS);
97 *piTls = (RTTLS)iTls;
98 Assert((DWORD)*piTls == iTls);
99 rc = VINF_SUCCESS;
100 }
101 else
102 rc = VERR_NO_MEMORY;
103 }
104 else
105 {
106 rc = RTOnce(&g_Once, rtTlsWinInitLock, NULL);
107 if (RT_SUCCESS(rc))
108 {
109 PRTTLSWINDTOR pDtor = (PRTTLSWINDTOR)RTMemAlloc(sizeof(*pDtor));
110 if (pDtor)
111 {
112 DWORD iTls = TlsAlloc();
113 if (iTls != TLS_OUT_OF_INDEXES)
114 {
115 Assert((RTTLS)iTls != NIL_RTTLS);
116 *piTls = (RTTLS)iTls;
117 Assert((DWORD)*piTls == iTls);
118
119 /*
120 * Add the destructor to the list. We keep it sorted.
121 */
122 pDtor->iTls = iTls;
123 pDtor->pfnDestructor = pfnDestructor;
124 RTCritSectRwEnterExcl(&g_CritSect);
125 RTListAppend(&g_TlsDtorHead, &pDtor->ListEntry);
126 ASMAtomicIncU32(&g_cTlsDtors);
127 RTCritSectRwLeaveExcl(&g_CritSect);
128
129 rc = VINF_SUCCESS;
130 }
131 else
132 rc = VERR_NO_MEMORY;
133 }
134 else
135 rc = VERR_NO_MEMORY;
136 }
137 }
138 return rc;
139}
140
141
142RTR3DECL(int) RTTlsFree(RTTLS iTls)
143{
144 if (iTls == NIL_RTTLS)
145 return VINF_SUCCESS;
146 if (TlsFree((DWORD)iTls))
147 {
148 if (ASMAtomicReadU32(&g_cTlsDtors) > 0)
149 {
150 RTCritSectRwEnterExcl(&g_CritSect);
151 PRTTLSWINDTOR pDtor;
152 RTListForEach(&g_TlsDtorHead, pDtor, RTTLSWINDTOR, ListEntry)
153 {
154 if (pDtor->iTls == (DWORD)iTls)
155 {
156 RTListNodeRemove(&pDtor->ListEntry);
157 ASMAtomicDecU32(&g_cTlsDtors);
158 RTMemFree(pDtor);
159 break;
160 }
161 }
162 RTCritSectRwLeaveExcl(&g_CritSect);
163 }
164 return VINF_SUCCESS;
165 }
166 return RTErrConvertFromWin32(GetLastError());
167}
168
169
170RTR3DECL(void *) RTTlsGet(RTTLS iTls)
171{
172 return TlsGetValue((DWORD)iTls);
173}
174
175
176RTR3DECL(int) RTTlsGetEx(RTTLS iTls, void **ppvValue)
177{
178 void *pv = TlsGetValue((DWORD)iTls);
179 if (pv)
180 {
181 *ppvValue = pv;
182 return VINF_SUCCESS;
183 }
184
185 /* TlsGetValue always updates last error */
186 *ppvValue = NULL;
187 return RTErrConvertFromWin32(GetLastError());
188}
189
190
191RTR3DECL(int) RTTlsSet(RTTLS iTls, void *pvValue)
192{
193 if (TlsSetValue((DWORD)iTls, pvValue))
194 return VINF_SUCCESS;
195 return RTErrConvertFromWin32(GetLastError());
196}
197
198
199/**
200 * Called by dllmain-win.cpp when a thread detaches.
201 */
202DECLHIDDEN(void) rtThreadWinTlsDestruction(void)
203{
204 if (ASMAtomicReadU32(&g_cTlsDtors) > 0)
205 {
206 RTCritSectRwEnterShared(&g_CritSect);
207 PRTTLSWINDTOR pDtor;
208 RTListForEach(&g_TlsDtorHead, pDtor, RTTLSWINDTOR, ListEntry)
209 {
210 void *pvValue = TlsGetValue(pDtor->iTls);
211 if (pvValue != NULL)
212 {
213 pDtor->pfnDestructor(pvValue);
214 TlsSetValue(pDtor->iTls, NULL);
215 }
216 }
217 RTCritSectRwLeaveShared(&g_CritSect);
218 }
219}
220
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette