VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/nocrt-per-thread-2.cpp@ 96108

Last change on this file since 96108 was 96084, checked in by vboxsync, 2 years ago

IPRT/nocrt: doxygen fix. bugref:10261

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.9 KB
Line 
1/* $Id: nocrt-per-thread-2.cpp 96084 2022-08-06 02:07:33Z vboxsync $ */
2/** @file
3 * IPRT - No-Crt - Per Thread Data, Managment code
4 */
5
6/*
7 * Copyright (C) 2006-2022 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* Defined Constants And Macros *
30*********************************************************************************************************************************/
31#include "internal/nocrt.h"
32#include <iprt/asm.h>
33#include <iprt/critsect.h>
34#include <iprt/errcore.h>
35#include <iprt/mem.h>
36#include <iprt/once.h>
37#include <iprt/thread.h>
38
39
40/*********************************************************************************************************************************
41* Global Variables *
42*********************************************************************************************************************************/
43/** Init/term once state. */
44static RTONCE g_NoCrtPerThreadOnce = RTONCE_INITIALIZER;
45
46/** List of heap allocations (PRTNOCRTTHREADDATA). */
47static RTLISTANCHOR g_NoCrtPerThreadHeapList;
48/** Critical section protecting g_NoCrtPerThreadHeapList. */
49static RTCRITSECT g_NoCrtPerThreadCritSect;
50
51/** Allocation bitmap for g_aNoCrtPerThreadStatic.
52 *
53 * In debug builds we only have one slot here, so we have a better chance of
54 * testing the heap code path. */
55#ifdef DEBUG
56static uint32_t volatile g_fNoCrtPerThreadStaticAlloc = UINT32_C(0xffffefff);
57#else
58static uint32_t volatile g_fNoCrtPerThreadStaticAlloc = 0;
59#endif
60/* Static allocations to avoid the heap and associate slowness. */
61static RTNOCRTTHREADDATA g_aNoCrtPerThreadStatic[32];
62
63
64/**
65 * @callback_method_impl{FNRTTLSDTOR}
66 */
67static DECLCALLBACK(void) rtNoCrtPerThreadDtor(void *pvValue)
68{
69 PRTNOCRTTHREADDATA pNoCrtData = (PRTNOCRTTHREADDATA)pvValue;
70 if (pNoCrtData->enmAllocType == RTNOCRTTHREADDATA::kAllocType_Heap)
71 {
72 AssertReturnVoid(RTOnceWasInitialized(&g_NoCrtPerThreadOnce));
73
74 RTCritSectEnter(&g_NoCrtPerThreadCritSect); /* timeout? */
75
76 RTListNodeRemove(&pNoCrtData->ListEntry);
77 pNoCrtData->enmAllocType = RTNOCRTTHREADDATA::kAllocType_End;
78
79 RTCritSectLeave(&g_NoCrtPerThreadCritSect);
80
81 RTMemFree(pNoCrtData);
82 }
83 else if (pNoCrtData->enmAllocType == RTNOCRTTHREADDATA::kAllocType_Static)
84 {
85 size_t iSlot = (size_t)(pNoCrtData - &g_aNoCrtPerThreadStatic[0]);
86 AssertReturnVoid(iSlot < RT_ELEMENTS(g_aNoCrtPerThreadStatic));
87
88 pNoCrtData->enmAllocType = RTNOCRTTHREADDATA::kAllocType_Invalid;
89 ASMAtomicAndU32(&g_fNoCrtPerThreadStaticAlloc, ~(uint32_t)iSlot);
90 }
91}
92
93
94/**
95 * @callback_method_impl{FNRTONCE}
96 */
97static DECLCALLBACK(int32_t) rtNoCrtPerThreadInit(void *pvUser)
98{
99 RTListInit(&g_NoCrtPerThreadHeapList);
100
101 RTTLS iTls = NIL_RTTLS;
102 int rc = RTTlsAllocEx(&iTls, rtNoCrtPerThreadDtor);
103 if (iTls != NIL_RTTLS)
104 {
105 rc = RTCritSectInit(&g_NoCrtPerThreadCritSect);
106 if (RT_SUCCESS(rc))
107 {
108 g_iTlsRtNoCrtPerThread = iTls;
109 return VINF_SUCCESS;
110 }
111 RTTlsFree(iTls);
112 }
113 RT_NOREF(pvUser);
114 return rc;
115}
116
117
118/**
119 * @callback_method_impl{FNRTONCECLEANUP}
120 */
121static DECLCALLBACK(void) rtNoCrtPerThreadCleanup(void *pvUser, bool fLazyCleanUpOk)
122{
123 RT_NOREF(pvUser);
124 if (fLazyCleanUpOk)
125 return;
126
127 /*
128 * First destroy the TLS entry.
129 */
130 RTTLS iTls = g_iTlsRtNoCrtPerThread;
131 g_iTlsRtNoCrtPerThread = NIL_RTTLS;
132 int rc = RTTlsFree(iTls);
133 AssertRC(rc);
134
135 /*
136 * Then destroy the critical section and free all entries in the list.
137 */
138 RTCritSectDelete(&g_NoCrtPerThreadCritSect);
139
140 PRTNOCRTTHREADDATA pNoCrtData;
141 while ((pNoCrtData = RTListRemoveFirst(&g_NoCrtPerThreadHeapList, RTNOCRTTHREADDATA, ListEntry)) != NULL)
142 {
143 AssertContinue(pNoCrtData->enmAllocType == RTNOCRTTHREADDATA::kAllocType_Heap);
144 pNoCrtData->enmAllocType = RTNOCRTTHREADDATA::kAllocType_End;
145 RTMemFree(pNoCrtData);
146 }
147}
148
149PRTNOCRTTHREADDATA rtNoCrtThreadDataGet(void)
150{
151 int rc = RTOnceEx(&g_NoCrtPerThreadOnce, rtNoCrtPerThreadInit, rtNoCrtPerThreadCleanup, NULL);
152 if (RT_SUCCESS(rc))
153 {
154 /*
155 * We typically have an entry already.
156 */
157 PRTNOCRTTHREADDATA pNoCrtData = (PRTNOCRTTHREADDATA)RTTlsGet(g_iTlsRtNoCrtPerThread);
158 if (pNoCrtData)
159 {
160 AssertReturn( pNoCrtData->enmAllocType > RTNOCRTTHREADDATA::kAllocType_Invalid
161 && pNoCrtData->enmAllocType < RTNOCRTTHREADDATA::kAllocType_End,
162 NULL);
163 return pNoCrtData;
164 }
165
166 /*
167 * Okay, allocate a new entry first using some of the statically allocated
168 * ones then falling back on heap allocations.
169 */
170 for (;;)
171 {
172 uint32_t const fAlloc = ASMAtomicUoReadU32(&g_fNoCrtPerThreadStaticAlloc);
173 uint32_t iSlot = ASMBitFirstSetU32(~fAlloc);
174 if (iSlot != 0)
175 iSlot--;
176 else
177 break;
178 if (ASMAtomicCmpXchgU32(&g_fNoCrtPerThreadStaticAlloc, fAlloc | RT_BIT_32(iSlot), fAlloc))
179 {
180 pNoCrtData = &g_aNoCrtPerThreadStatic[iSlot];
181
182 /* Init the entry in case it's being re-used: */
183 Assert(pNoCrtData->enmAllocType == RTNOCRTTHREADDATA::kAllocType_Invalid);
184 rc = RTTlsSet(g_iTlsRtNoCrtPerThread, pNoCrtData);
185 AssertRC(rc);
186 if (RT_SUCCESS(rc))
187 {
188 pNoCrtData->enmAllocType = RTNOCRTTHREADDATA::kAllocType_Static;
189 RTListInit(&pNoCrtData->ListEntry);
190 pNoCrtData->iErrno = 0;
191 pNoCrtData->pszStrToken = NULL;
192 return pNoCrtData;
193 }
194
195 ASMAtomicOrU32(&g_fNoCrtPerThreadStaticAlloc, RT_BIT_32(iSlot));
196 return NULL;
197 }
198 ASMNopPause();
199 }
200
201 /*
202 * Heap.
203 */
204 pNoCrtData = (PRTNOCRTTHREADDATA)RTMemAllocZ(sizeof(*pNoCrtData));
205 if (pNoCrtData)
206 {
207 pNoCrtData->enmAllocType = RTNOCRTTHREADDATA::kAllocType_Heap;
208
209 RTCritSectEnter(&g_NoCrtPerThreadCritSect);
210 RTListAppend(&g_NoCrtPerThreadHeapList, &pNoCrtData->ListEntry);
211 RTCritSectLeave(&g_NoCrtPerThreadCritSect);
212
213 rc = RTTlsSet(g_iTlsRtNoCrtPerThread, pNoCrtData);
214 AssertRC(rc);
215 if (RT_SUCCESS(rc))
216 return pNoCrtData;
217
218 RTCritSectEnter(&g_NoCrtPerThreadCritSect);
219 RTListNodeRemove(&pNoCrtData->ListEntry);
220 RTCritSectLeave(&g_NoCrtPerThreadCritSect);
221
222 pNoCrtData->enmAllocType = RTNOCRTTHREADDATA::kAllocType_End;
223 RTMemFree(pNoCrtData);
224 }
225 }
226 return NULL;
227}
228
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