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