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