0025396: Crash occurs when using TBB allocator on an Intel architecture not supportin...
[occt.git] / src / Standard / Standard.cxx
CommitLineData
b311480e 1// Created on: 2005-03-15
2// Created by: Peter KURNEV
3// Copyright (c) 1998-1999 Matra Datavision
973c2be1 4// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 5//
973c2be1 6// This file is part of Open CASCADE Technology software library.
b311480e 7//
d5f74e42 8// This library is free software; you can redistribute it and/or modify it under
9// the terms of the GNU Lesser General Public License version 2.1 as published
973c2be1 10// by the Free Software Foundation, with special exception defined in the file
11// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12// distribution for complete text of the license and disclaimer of any warranty.
b311480e 13//
973c2be1 14// Alternatively, this file may be used under the terms of Open CASCADE
15// commercial license or contractual agreement.
7fd59977 16
17#include <Standard.ixx>
18
19#include <stdlib.h>
20
21#include <Standard_MMgrOpt.hxx>
22#include <Standard_MMgrRaw.hxx>
23#include <Standard_MMgrTBBalloc.hxx>
24
af09dbff 25#if(defined(_WIN32) || defined(__WIN32__))
91322f44 26 #include <windows.h>
27 #include <malloc.h>
28 #include <locale.h>
af09dbff 29#endif
30
0304f711 31#if defined(_MSC_VER) || defined(__ANDROID__)
acc62560 32 #include <malloc.h>
33#elif (defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 1)
34 #include <mm_malloc.h>
35#else
36 extern "C" int posix_memalign (void** thePtr, size_t theAlign, size_t theSize);
37#endif
38
a0d8a9fc
RL
39#ifndef OCCT_MMGT_OPT_DEFAULT
40#define OCCT_MMGT_OPT_DEFAULT 0
41#endif
42
7fd59977 43//=======================================================================
44//class : Standard_MMgrFactory
45//purpose : Container for pointer to memory manager;
46// used to construct appropriate memory manager according
47// to environment settings, and to ensure destruction upon exit
48//=======================================================================
49
50class Standard_MMgrFactory {
51 public:
52 Standard_MMgrFactory();
53 ~Standard_MMgrFactory();
54 public:
55 Standard_MMgrRoot* myFMMgr;
56};
57
58//=======================================================================
59//function : Standard_MMgrFactory
60//purpose : Check environment variables and create appropriate memory manager
61//=======================================================================
62
af09dbff 63Standard_MMgrFactory::Standard_MMgrFactory()
64: myFMMgr (NULL)
7fd59977 65{
91322f44 66/*#if defined(_MSC_VER) && (_MSC_VER > 1400)
67 // Turn ON thread-safe C locale globally to avoid side effects by setlocale() calls between threads.
68 // After this call all following _configthreadlocale() will be ignored assuming
69 // Notice that this is MSVCRT feature - on POSIX systems xlocale API (uselocale instead of setlocale)
70 // should be used explicitly to ensure thread-safety!
71
72 // This is not well documented call because _ENABLE_PER_THREAD_LOCALE_GLOBAL flag is defined but not implemented for some reason.
73 // -1 will set global locale flag to force _ENABLE_PER_THREAD_LOCALE_GLOBAL + _ENABLE_PER_THREAD_LOCALE_NEW behaviour
74 // although there NO way to turn it off again and following calls will have no effect (locale will be changed only for current thread).
75 _configthreadlocale (-1);
76#endif*/
77
af09dbff 78 char* aVar;
302f96fb 79 aVar = getenv ("MMGT_OPT");
80 Standard_Integer anAllocId = (aVar ? atoi (aVar): OCCT_MMGT_OPT_DEFAULT);
75827e76 81
82#if defined(_WIN32) && !defined(_WIN64)
83 static const DWORD _SSE2_FEATURE_BIT(0x04000000);
84 if ( anAllocId == 2 )
85 {
86 // CR25396: Check if SSE2 instructions are supported, if not then use MMgrRaw
87 // instead of MMgrTBBalloc. It is to avoid runtime crash when running on a
88 // CPU that supports SSE but does not support SSE2 (some modifications of
89 // AMD Sempron).
90 DWORD volatile dwFeature;
91 _asm
92 {
93 push eax
94 push ebx
95 push ecx
96 push edx
97
98 // get the CPU feature bits
99 mov eax, 1
100 cpuid
101 mov dwFeature, edx
102
103 pop edx
104 pop ecx
105 pop ebx
106 pop eax
107 }
108 if ((dwFeature & _SSE2_FEATURE_BIT) == 0)
109 anAllocId = 0;
110 }
111#endif
112
302f96fb 113 aVar = getenv ("MMGT_CLEAR");
114 Standard_Boolean toClear = (aVar ? (atoi (aVar) != 0) : Standard_True);
af09dbff 115
af09dbff 116 // on Windows (actual for XP and 2000) activate low fragmentation heap
117 // for CRT heap in order to get best performance.
118 // Environment variable MMGT_LFH can be used to switch off this action (if set to 0)
119#if defined(_MSC_VER)
120 aVar = getenv ("MMGT_LFH");
121 if ( aVar == NULL || atoi (aVar) != 0 )
122 {
123 ULONG aHeapInfo = 2;
124 HANDLE aCRTHeap = (HANDLE)_get_heap_handle();
125 HeapSetInformation (aCRTHeap, HeapCompatibilityInformation, &aHeapInfo, sizeof(aHeapInfo));
7fd59977 126 }
af09dbff 127#endif
128
af09dbff 129 switch (anAllocId)
130 {
131 case 1: // OCCT optimized memory allocator
132 {
302f96fb 133 aVar = getenv ("MMGT_MMAP");
134 Standard_Boolean bMMap = (aVar ? (atoi (aVar) != 0) : Standard_True);
135 aVar = getenv ("MMGT_CELLSIZE");
136 Standard_Integer aCellSize = (aVar ? atoi (aVar) : 200);
137 aVar = getenv ("MMGT_NBPAGES");
138 Standard_Integer aNbPages = (aVar ? atoi (aVar) : 1000);
139 aVar = getenv ("MMGT_THRESHOLD");
140 Standard_Integer aThreshold = (aVar ? atoi (aVar) : 40000);
bd0c22ce 141 myFMMgr = new Standard_MMgrOpt (toClear, bMMap, aCellSize, aNbPages, aThreshold);
af09dbff 142 break;
143 }
144 case 2: // TBB memory allocator
145 myFMMgr = new Standard_MMgrTBBalloc (toClear);
146 break;
147 case 0:
148 default: // system default memory allocator
149 myFMMgr = new Standard_MMgrRaw (toClear);
150 }
7fd59977 151}
152
153//=======================================================================
154//function : ~Standard_MMgrFactory
155//purpose :
156//=======================================================================
157
158Standard_MMgrFactory::~Standard_MMgrFactory()
159{
207e57e4 160 if ( myFMMgr ) {
7fd59977 161 myFMMgr->Purge(Standard_True);
162// delete myFMMgr;
163// myFMMgr = 0;
164 }
165}
166
167//=======================================================================
168// function: GetMMgr
169//
170// This static function has a purpose to wrap static holder for memory
171// manager instance.
172//
173// Wrapping holder inside a function is needed to ensure that it will
174// be initialized not later than the first call to memory manager (that
175// would be impossible to guarantee if holder was static variable on
176// global or file scope, because memory manager may be called from
177// constructors of other static objects).
178//
179// Note that at the same time we could not guarantee that the holder
180// object is destroyed after last call to memory manager, since that
181// last call may be from static Handle() object which has been initialized
182// dynamically during program execution rather than in its constructor.
183//
184// Therefore holder currently does not call destructor of the memory manager
185// but only its method Purge() with Standard_True.
186//
187// To free the memory completely, we probably could use compiler-specific
188// pragmas (such as '#pragma fini' on SUN Solaris and '#pragma init_seg' on
189// WNT MSVC++) to put destructing function in code segment that is called
190// after destructors of other (even static) objects. However, this is not
191// done by the moment since it is compiler-dependent and there is no guarantee
192// thatsome other object calling memory manager is not placed also in that segment...
193//
194// Note that C runtime function atexit() could not help in this problem
195// since its behaviour is the same as for destructors of static objects
196// (see ISO 14882:1998 "Programming languages -- C++" 3.6.3)
197//
198// The correct approach to deal with the problem would be to have memory manager
199// to properly control its memory allocation and caching free blocks so
200// as to release all memory as soon as it is returned to it, and probably
201// even delete itself if all memory it manages has been released and
202// last call to method Purge() was with True.
203//
204// Note that one possible method to control memory allocations could
205// be counting calls to Allocate() and Free()...
206//
207//=======================================================================
208
209static Standard_MMgrRoot* GetMMgr()
210{
211 static Standard_MMgrFactory aFactory;
212 return aFactory.myFMMgr;
213}
214
215//=======================================================================
216//function : Allocate
217//purpose :
218//=======================================================================
219
220Standard_Address Standard::Allocate(const Standard_Size size)
221{
222 return GetMMgr()->Allocate(size);
223}
224
225//=======================================================================
acc62560 226//function : Free
7fd59977 227//purpose :
228//=======================================================================
229
547702a1 230void Standard::Free (Standard_Address theStorage)
7fd59977 231{
547702a1 232 GetMMgr()->Free(theStorage);
7fd59977 233}
234
235//=======================================================================
236//function : Reallocate
237//purpose :
238//=======================================================================
239
547702a1 240Standard_Address Standard::Reallocate (Standard_Address theStorage,
241 const Standard_Size theSize)
7fd59977 242{
547702a1 243 return GetMMgr()->Reallocate (theStorage, theSize);
7fd59977 244}
245
246//=======================================================================
247//function : Purge
248//purpose :
249//=======================================================================
250
251Standard_Integer Standard::Purge()
252{
253 return GetMMgr()->Purge();
254}
acc62560 255
256//=======================================================================
257//function : AllocateAligned
258//purpose :
259//=======================================================================
260
261Standard_Address Standard::AllocateAligned (const Standard_Size theSize,
262 const Standard_Size theAlign)
263{
264#if defined(_MSC_VER)
265 return _aligned_malloc (theSize, theAlign);
0304f711 266#elif defined(__ANDROID__)
267 return memalign (theAlign, theSize);
acc62560 268#elif (defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 1)
0304f711 269 return _mm_malloc (theSize, theAlign);
acc62560 270#else
271 void* aPtr;
272 if (posix_memalign (&aPtr, theAlign, theSize))
273 {
274 return NULL;
275 }
276 return aPtr;
277#endif
278}
279
280//=======================================================================
281//function : FreeAligned
282//purpose :
283//=======================================================================
284
285void Standard::FreeAligned (Standard_Address thePtrAligned)
286{
287#if defined(_MSC_VER)
288 _aligned_free (thePtrAligned);
0304f711 289#elif defined(__ANDROID__)
290 free (thePtrAligned);
acc62560 291#elif (defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 1)
292 _mm_free (thePtrAligned);
293#else
294 free (thePtrAligned);
295#endif
296}