CVM Class Library  8.1
This C++ class library encapsulates concepts of vector and different matrices including square, band, symmetric and hermitian ones in Euclidean space of real and complex numbers.
 All Classes Files Functions Variables Typedefs Friends Macros Pages
globals.cpp
Go to the documentation of this file.
1 // CVM Class Library
2 // http://cvmlib.com
3 //
4 // Copyright Sergei Nikolaev 1992-2014
5 // Distributed under the Boost Software License, Version 1.0.
6 // (See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8 
9 #include "cvm.h"
10 #include "cfun.h"
11 
12 #include <stdio.h>
13 #include <ctype.h>
14 
15 extern "C" {
16  void __stdcall XERBLA (const char* szSubName,
17  #ifdef CVM_PASS_STRING_LENGTH_TO_FTN_SUBROUTINES
18  const tint,
19  #endif
20  const tint* pnParam) throw (cvm::cvmexception)
21  {
22  throw cvm::cvmexception (CVM_WRONGMKLARG2, *pnParam, szSubName);
23  }
24 }
25 
26 
27 #if !defined (CVM_STATIC) && (defined (_MSC_VER) || defined (__WATCOMC__))
28 # ifdef _MANAGED
29 # pragma managed(push, off)
30 # endif
31 
32 BOOL APIENTRY DllMain (HANDLE /*hModule*/,
33  DWORD ul_reason_for_call,
34  LPVOID /*lpReserved*/)
35 {
36  switch (ul_reason_for_call)
37  {
38  case DLL_PROCESS_ATTACH:
39  case DLL_THREAD_ATTACH:
40  case DLL_THREAD_DETACH:
41  case DLL_PROCESS_DETACH:
42  break;
43  }
44  return TRUE;
45 }
46 
47 # ifdef _MANAGED
48 # pragma managed(pop)
49 # endif
50 #endif
51 
53 
54 #if !defined (CVM_STD_MUTEX)
55 
57 CriticalSection::CriticalSection()
58 #if defined (CVM_MT)
59  : mbOK (false),
60 #endif
61 #if defined (WIN32) || defined (_WIN32)
62 #if defined (CVM_USE_CRITICAL_SECTION_NOT_MUTEX)
63  mCriticalSection()
64 #else
65  mMutex(0)
66 #endif
67 #else // POSIX Threads library assumed
68  mMutex(), mMutexAttr()
69 #endif
70 {
71 #if defined (CVM_MT)
72 #if defined (WIN32) || defined (_WIN32)
73 # if defined (CVM_USE_CRITICAL_SECTION_NOT_MUTEX)
74  if (!::InitializeCriticalSectionAndSpinCount (&mCriticalSection, 0x80000400))
75  {
76  ::InitializeCriticalSection (&mCriticalSection);
77  }
78  mbOK = true;
79 # else
80  mMutex = ::CreateMutex (nullptr, FALSE, nullptr);
81  mbOK = mMutex != nullptr;
82 # endif
83 #else
84  if (pthread_mutexattr_init (&mMutexAttr) == 0 &&
85  pthread_mutexattr_setpshared (&mMutexAttr, PTHREAD_PROCESS_PRIVATE) == 0 &&
86  pthread_mutex_init (&mMutex, &mMutexAttr) == 0)
87  {
88  mbOK = true;
89  }
90 #endif
91 #endif
92 }
93 
94 CriticalSection::~CriticalSection()
95 {
96 #if defined (CVM_MT)
97 #if defined (WIN32) || defined (_WIN32)
98  if (mbOK)
99  {
100 # if defined (CVM_USE_CRITICAL_SECTION_NOT_MUTEX)
101  ::DeleteCriticalSection (&mCriticalSection);
102 # else
103  ::CloseHandle(mMutex);
104 # endif
105  }
106 #else
107  pthread_mutexattr_destroy (&mMutexAttr);
108  pthread_mutex_destroy (&mMutex);
109 #endif
110 #endif
111 }
112 
113 void CriticalSection::enter()
114 #if defined (CVM_MT)
115 throw (cvmexception)
116 #endif
117 {
118 #if defined (CVM_MT)
119 #if defined (WIN32) || defined (_WIN32)
120  if (!mbOK)
121  {
123  }
124 # if defined (CVM_USE_CRITICAL_SECTION_NOT_MUTEX)
125  ::EnterCriticalSection (&mCriticalSection);
126 # else
127  ::WaitForSingleObject (mMutex, INFINITE);
128 # endif
129 #else
130  if (!mbOK || pthread_mutex_lock (&mMutex) != 0)
131  {
133  }
134 #endif
135 #endif
136 }
137 
138 void CriticalSection::leave()
139 #if defined (CVM_MT)
140 throw (cvmexception)
141 #endif
142 {
143 #if defined (CVM_MT)
144 #if defined (WIN32) || defined (_WIN32)
145  if (!mbOK)
146  {
148  }
149 # if defined (CVM_USE_CRITICAL_SECTION_NOT_MUTEX)
150  ::LeaveCriticalSection (&mCriticalSection);
151 # else
152  ::ReleaseMutex(mMutex);
153 # endif
154 #else
155  if (!mbOK || pthread_mutex_unlock (&mMutex) != 0)
156  {
158  }
159 #endif
160 #endif
161 }
163 
164 #endif
165 
166 
167 // 5.5.2 - moved out of cvm.h
168 cvmexception::cvmexception (int nCause, ...)
169  : mnCause (nCause)
170 {
171  va_list argList;
172  va_start (argList, nCause);
173 #if defined (CVM_VSNPRINTF_S_DEFINED)
174  const tint nLength = CVM_VSNPRINTF (mszMsg, sizeof(mszMsg), sizeof(mszMsg) - 1, _get_message(mnCause), argList);
175 #else
176  const tint nLength = CVM_VSNPRINTF (mszMsg, sizeof(mszMsg) - 1, _get_message(mnCause), argList);
177 #endif
178  va_end (argList);
179  if (nLength >= (int) sizeof(mszMsg))
180  {
181  mszMsg[sizeof(mszMsg) - 1] = '\0';
182  }
183 }
184 
186  : std::exception(e), mnCause (e.mnCause)
187 {
188 #if defined (CVM_STRCPY_S_DEFINED)
189  strcpy_s (mszMsg, sizeof(mszMsg), e.mszMsg);
190 #else
191  strcpy (mszMsg, e.mszMsg);
192 #endif
193 }
194 
195 
196 #if defined (CVM_USE_POOL_MANAGER)
197 
198 MemoryPool gPool;
199 CriticalSection gCS;
200 
201 CVM_API tbyte* _cvmMalloc (size_t nBytes) throw (cvmexception)
202 {
203  Lock l(gCS);
204  return gPool.Malloc (nBytes);
205 }
206 
207 CVM_API tbyte* _cvmAddRef (const tbyte* pD)
208 {
209  Lock l(gCS);
210  return gPool.AddRef (pD);
211 }
212 
213 CVM_API tint _cvmFree (tbyte*& pD)
214 {
215  Lock l(gCS);
216  return gPool.Free (pD);
217 }
218 
219 
220 #define CVM_PAGE_SIZE (0x1000)
221 #define CVM_HEAP_SIZE ((tint) 0x40000000)
222 
223 size_t _up_value (size_t n) // the least power of 2 multiplied by 2
224 {
225  if (n < CVM_PAGE_SIZE) // let small objects be in one page
226  {
227  n = CVM_PAGE_SIZE;
228  }
229  else //if (n < CVM_HEAP_SIZE)
230  {
231  tint i = 0;
232  while (n >> i) ++i;
233  if (i && (n & ((1 << (i - 1)) - 1))) ++i; // obey warning C4554 :)
234  n = 1 << i;
235  }
236  return n;
237 }
238 
239 MemoryPool::MemoryPool()
240 {
241 }
242 
243 MemoryPool::~MemoryPool()
244 {
245  Clear();
246 }
247 
248 #ifdef __BORLANDC__
249 # pragma warn -8091
250 #endif
251 
252 void MemoryPool::Clear()
253 {
254  std::for_each (mOutBlocks.rbegin(), mOutBlocks.rend(), MemoryPool::DeletePtr());
255  mOutBlocks.clear();
256 }
257 
258 #ifdef __BORLANDC__
259 # pragma warn +8091
260 #endif
261 
262 #if !defined (CVM_ALLOCATOR)
263 # define CVM_ALLOCATOR std::allocator
264 #endif
265 
266 template <class T>
267 inline CVM_ALLOCATOR<T>& AllocatorInstance()
268 {
269  static CVM_ALLOCATOR<T> _A;
270  return _A;
271 }
272 
273 tbyte* MemoryPool::Malloc (size_t nBytes) throw (cvmexception)
274 {
275  if (nBytes >= CVM_HEAP_SIZE) throw cvmexception (CVM_WRONGSIZE, nBytes);
276  if (nBytes == 0) return nullptr;
277 
278  tbyte* pB = mMemoryBlocks.GetFreeBlock (nBytes);
279 
280  if (pB == nullptr) // There is no suitable memory block. Let's create a new one.
281  {
282  const size_t nUpBytes = _up_value (nBytes);
283  const size_t nRest = nUpBytes - nBytes;
284  try
285  {
286  pB = AllocatorInstance<tbyte>().allocate(nUpBytes, nullptr);
287  }
288  catch (const std::bad_alloc&)
289  {
290  }
291  if (pB == nullptr)
292  {
293  throw (cvmexception (CVM_OUTOFMEMORY, nBytes));
294  }
295 
296  mOutBlocks.push_back (pB);
297  mMemoryBlocks.AddPair (pB, nBytes, nRest);
298  }
299  return pB;
300 }
301 
302 tbyte* MemoryPool::AddRef (const tbyte* pD)
303 {
304  return mMemoryBlocks.AddRef (pD);
305 }
306 
307 tint MemoryPool::Free (tbyte*& pToFree) throw (cvmexception)
308 {
309  tint nRefCounter = mMemoryBlocks.FreeBlock (pToFree);
310  if (!nRefCounter)
311  {
312  pToFree = nullptr;
313  }
314  return nRefCounter;
315 }
316 
317 
318 void MemoryBlocks::AddBlock (tbyte* pBlock, size_t nBytes, bool bOccupied)
319 {
320  if (!bOccupied) // Add freed block
321  {
322  itr_FreeIt j;
323  itr_Blocks i = mBlocks.upper_bound (pBlock);
324  itr_Blocks i_next = i;
325  // Is there upper neighboring memory block?
326  if (i != mBlocks.end())
327  {
328  tbyte* pUpperBlock = (*i).first;
329  j = mFreeIt.find (pUpperBlock);
330  if (j != mFreeIt.end() && pBlock + nBytes == pUpperBlock) // Yes. It's free and will be concatenated
331  {
332  nBytes += (*i).second.mnSize;
333  ++i_next;
334  mBlocks.erase (i);
335  i = i_next;
336  mFreeBs.erase ((*j).second);
337  mFreeIt.erase (j);
338  }
339  }
340  // Is there lower neighboring memory block?
341  if (i != mBlocks.begin() && mBlocks.size() > 0)
342  {
343  --i;
344  tbyte* pLowerBlock = (*i).first;
345  const size_t nLowerBytes = (*i).second.mnSize;
346  j = mFreeIt.find (pLowerBlock);
347  if (j != mFreeIt.end() && pLowerBlock + nLowerBytes == pBlock) // Yes. It's free and will be concatenated
348  {
349  pBlock = pLowerBlock;
350  nBytes += nLowerBytes;
351  mBlocks.erase (i);
352  mFreeBs.erase ((*j).second);
353  mFreeIt.erase (j);
354  }
355  }
356  mFreeIt[pBlock] = mFreeBs.insert (std::pair<tint, tbyte*>(nBytes, pBlock));
357  }
358 
359  mBlocks.insert (std::pair<tbyte*, BlockProperty>(pBlock, BlockProperty(nBytes, 1)));
360 }
361 
362 tint MemoryBlocks::FreeBlock (tbyte* pBlock)
363 {
364  tint nRefCounter = 0;
365  itr_Blocks i = mBlocks.find (pBlock);
366 
367  if (i != mBlocks.end())
368  {
369  if (mFreeIt.find (pBlock) == mFreeIt.end())
370  {
371  nRefCounter = -- (*i).second.mnRefCount;
372  if (nRefCounter <= 0)
373  {
374  const tint nBytes = (*i).second.mnSize;
375  mBlocks.erase (i);
376  AddBlock (pBlock, nBytes, false); // return free block to the pool
377  }
378  }
379 #ifdef CVM_DEBUG
380  else
381  {
382  assert (mFreeIt.find (pBlock) == mFreeIt.end());
383  }
384 #endif
385  }
386  else
387  {
388  nRefCounter = -1; // foreign array.
389  }
390 
391  return nRefCounter;
392 }
393 
394 tbyte* MemoryBlocks::GetFreeBlock (size_t nBytes)
395 {
396  tbyte* pBlock = nullptr;
397  if (mFreeBs.size() > 0)
398  {
399  // Is there a suitable memory block?
400  itr_FreeBs i = mFreeBs.lower_bound (nBytes);
401 
402  // Yes. Let's use it.
403  if (i != mFreeBs.end())
404  {
405  const size_t nRest = (*i).first - nBytes;
406  pBlock = (*i).second;
407 
408  mFreeBs.erase (i);
409  if (mFreeIt.size() > 0 && mFreeIt.find(pBlock) != mFreeIt.end())
410  {
411  mFreeIt.erase (pBlock);
412  }
413  if (mBlocks.size() > 0 && mBlocks.find(pBlock) != mBlocks.end())
414  {
415  mBlocks.erase (pBlock);
416  }
417 
418  AddPair (pBlock, nBytes, nRest);
419  }
420  }
421  return pBlock;
422 }
423 
424 tbyte* MemoryBlocks::AddRef (const tbyte* pcBlock)
425 {
426  tbyte* pBlock = const_cast<tbyte*>(pcBlock);
427  itr_Blocks i = mBlocks.find (pBlock);
428  if (i != mBlocks.end())
429  {
430  ++ (*i).second.mnRefCount;
431  }
432  else
433  {
434  // This is a foreign array. Leave it alone.
435  }
436  return pBlock;
437 }
438 
439 
440 #ifdef CVM_DEBUG
441 void MemoryBlocks::Assert (const void* pvBlock, size_t nBytes)
442 {
443  tbyte* pBlock = (tbyte*) const_cast<void*>(pvBlock);
444  itr_Blocks i = mBlocks.find (pBlock);
445  if (i != mBlocks.end())
446  {
447  const size_t nSize = (*i).second.mnSize;
448  assert (nSize >= nBytes);
449  }
450  else
451  {
452  tbyte* pB;
453  size_t nB;
454  itr_Blocks end = mBlocks.end();
455  for (i = mBlocks.begin(); i != end; ++i)
456  {
457  pB = (*i).first;
458  nB = (*i).second.mnSize;
459  if (pBlock >= pB && pBlock < pB + nB)
460  {
461  tbyte* pBase = pB + nB;
462  tbyte* pTest = pBlock + nBytes;
463  assert (pTest <= pBase);
464  }
465  }
466  }
467 }
468 #endif
469 
470 void MemoryBlocks::AddPair (tbyte* pBlock, size_t nBytes, size_t nRest)
471 {
472  AddBlock (pBlock, nBytes, true); // occupied block...
473  if (nRest > 0)
474  {
475  AddBlock (pBlock + nBytes, nRest, false); // ...and the rest free block
476  }
477 }
478 
479 #endif // !CVM_USE_POOL_MANAGER
480 
481 #if defined (CVM_USE_POOL_MANAGER) && defined (CVM_DEBUG)
482 CVM_API void _cvm_assert (const void* pvBlock, size_t nBytes)
483 {
484  Lock l(gCS);
485  gPool.Assert (pvBlock, nBytes);
486 }
487 #else
488 CVM_API void _cvm_assert (const void*, size_t)
489 {
490 }
491 #endif // CVM_USE_POOL_MANAGER && CVM_DEBUG
492 
493 CVM_API void cvmExit()
494 {
495 #ifdef CVM_USE_POOL_MANAGER
496  gPool.Clear();
497 #endif
498 }
499 
501