1 // -*- C++ -*-
2
3 /*
4 The Hoard Multiprocessor Memory Allocator
5 www.hoard.org
6
7 Author: Emery Berger, http://www.emeryberger.org
8
9 Copyright (c) 1998-2019 Emery Berger
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
25 */
26
27 /*
28 * This file leverages compiler support for thread-local variables for
29 * access to thread-local heaps, when available. It also intercepts
30 * thread completions to flush these local heaps, returning any unused
31 * memory to the global Hoard heap. On Windows, this happens in
32 * DllMain. On Unix platforms, we interpose our own versions of
33 * pthread_create and pthread_exit.
34 */
35 #if defined(_WIN32)
36
37 #include <new>
38
39 #pragma warning(disable: 4447) // Disable weird warning about threading model.
40
41 // Windows TLS functions.
42
43 #include "VERSION.h"
44
45 #define versionMessage "Using the Hoard memory allocator (http://www.hoard.org), version " HOARD_VERSION_STRING "\n"
46
47 #include "hoardheap.h"
48 #include "hoardtlab.h"
49
50 using namespace Hoard;
51
52 #define USE_DECLSPEC_THREADLOCAL 0
53
54 #if USE_DECLSPEC_THREADLOCAL
55 __declspec(thread) TheCustomHeapType * threadLocalHeap = NULL;
56 #else
57 DWORD LocalTLABIndex;
58 #endif
59
60 extern HoardHeapType * getMainHoardHeap();
61
initializeCustomHeap()62 static TheCustomHeapType * initializeCustomHeap()
63 {
64 // Allocate a per-thread heap.
65 TheCustomHeapType * heap;
66 void * mh = getMainHoardHeap()->malloc(sizeof(TheCustomHeapType));
67 heap = new (mh) TheCustomHeapType (getMainHoardHeap());
68
69 // Store it in the appropriate thread-local area.
70 #if USE_DECLSPEC_THREADLOCAL
71 threadLocalHeap = heap;
72 #else
73 TlsSetValue (LocalTLABIndex, heap);
74 #endif
75
76 return heap;
77 }
78
isCustomHeapInitialized()79 bool isCustomHeapInitialized() {
80 #if USE_DECLSPEC_THREADLOCAL
81 return (threadLocalHeap != NULL);
82 #else
83 return (TlsGetValue(LocalTLABIndex) != NULL);
84 #endif
85 }
86
getCustomHeap()87 TheCustomHeapType * getCustomHeap() {
88 #if USE_DECLSPEC_THREADLOCAL
89 if (threadLocalHeap != NULL)
90 return threadLocalHeap;
91 initializeCustomHeap();
92 return threadLocalHeap;
93 #else
94 auto p = TlsGetValue(LocalTLABIndex);
95 if (p == NULL) {
96 initializeCustomHeap();
97 p = TlsGetValue(LocalTLABIndex);
98 }
99 return (TheCustomHeapType *) p;
100 #endif
101 }
102
103 extern "C" void InitializeWinWrapper();
104 extern "C" void FinalizeWinWrapper();
105
106
107 //
108 // Intercept thread creation and destruction to flush the TLABs.
109 //
110
111 extern "C" {
112
DllMain(HANDLE hinstDLL,DWORD fdwReason,LPVOID lpreserved)113 BOOL APIENTRY DllMain (HANDLE hinstDLL,
114 DWORD fdwReason,
115 LPVOID lpreserved)
116 {
117 static int np = HL::CPUInfo::computeNumProcessors();
118 switch (fdwReason) {
119
120 case DLL_PROCESS_ATTACH:
121 {
122 fprintf (stderr, versionMessage);
123 InitializeWinWrapper();
124 getCustomHeap();
125 }
126 break;
127
128 case DLL_THREAD_ATTACH:
129 if (np == 1) {
130 // We have exactly one processor - just assign the thread to
131 // heap 0.
132 getMainHoardHeap()->chooseZero();
133 } else {
134 getMainHoardHeap()->findUnusedHeap();
135 }
136 getCustomHeap();
137 break;
138
139 case DLL_THREAD_DETACH:
140 {
141 // Dump the memory from the TLAB.
142 getCustomHeap()->clear();
143
144 #if USE_DECLSPEC_THREADLOCAL
145 auto * heap = threadLocalHeap;
146 #else
147 auto * heap = (TheCustomHeapType *) TlsGetValue(LocalTLABIndex);
148 #endif
149
150 if (np != 1) {
151 // If we're on a multiprocessor box, relinquish the heap
152 // assigned to this thread.
153 getMainHoardHeap()->releaseHeap();
154 }
155
156 }
157 break;
158
159 case DLL_PROCESS_DETACH:
160 FinalizeWinWrapper();
161 break;
162
163 default:
164 return TRUE;
165 }
166
167 return TRUE;
168 }
169 }
170
171 #endif // _WIN32
172