1/* $Id: CoinAlloc.cpp 1373 2011-01-03 23:57:44Z lou $ */
2// Copyright (C) 2007, International Business Machines
3// Corporation and others. All Rights Reserved.
4// This code is licensed under the terms of the Eclipse Public License (EPL).
5
6#include <cassert>
7#include <cstdlib>
8#include <new>
9#include "CoinAlloc.hpp"
10
11#if (COINUTILS_MEMPOOL_MAXPOOLED >= 0)
12
13//=============================================================================
14
15CoinMempool::CoinMempool(size_t entry) :
16#if (COIN_MEMPOOL_SAVE_BLOCKHEADS==1)
17 block_heads_(NULL),
18 block_num_(0),
19 max_block_num_(0),
20#endif
21 last_block_size_(0),
22 first_free_(NULL),
23 entry_size_(entry)
24{
25#if defined(COINUTILS_PTHREADS) && (COINUTILS_PTHREAD == 1)
26 pthread_mutex_init(&mutex_, NULL);
27#endif
28 assert((entry_size_/COINUTILS_MEMPOOL_ALIGNMENT)*COINUTILS_MEMPOOL_ALIGNMENT
29 == entry_size_);
30}
31
32//=============================================================================
33
34CoinMempool::~CoinMempool()
35{
36#if (COIN_MEMPOOL_SAVE_BLOCKHEADS==1)
37 for (size_t i = 0; i < block_num_; ++i) {
38 free(block_heads_[i]);
39 }
40#endif
41#if defined(COINUTILS_PTHREADS) && (COINUTILS_PTHREAD == 1)
42 pthread_mutex_destroy(&mutex_);
43#endif
44}
45
46//==============================================================================
47
48char*
49CoinMempool::alloc()
50{
51 lock_mutex();
52 if (first_free_ == NULL) {
53 unlock_mutex();
54 char* block = allocate_new_block();
55 lock_mutex();
56#if (COIN_MEMPOOL_SAVE_BLOCKHEADS==1)
57 // see if we can record another block head. If not, then resize
58 // block_heads
59 if (max_block_num_ == block_num_) {
60 max_block_num_ = 2 * block_num_ + 10;
61 char** old_block_heads = block_heads_;
62 block_heads_ = (char**)malloc(max_block_num_ * sizeof(char*));
63 CoinMemcpyN( old_block_heads,block_num_,block_heads_);
64 free(old_block_heads);
65 }
66 // save the new block
67 block_heads_[block_num_++] = block;
68#endif
69 // link in the new block
70 *(char**)(block+((last_block_size_-1)*entry_size_)) = first_free_;
71 first_free_ = block;
72 }
73 char* p = first_free_;
74 first_free_ = *(char**)p;
75 unlock_mutex();
76 return p;
77}
78
79//=============================================================================
80
81char*
82CoinMempool::allocate_new_block()
83{
84 last_block_size_ = static_cast<int>(1.5 * last_block_size_ + 32);
85 char* block = static_cast<char*>(std::malloc(last_block_size_*entry_size_));
86 // link the entries in the new block together
87 for (int i = last_block_size_-2; i >= 0; --i) {
88 *(char**)(block+(i*entry_size_)) = block+((i+1)*entry_size_);
89 }
90 // terminate the linked list with a null pointer
91 *(char**)(block+((last_block_size_-1)*entry_size_)) = NULL;
92 return block;
93}
94
95//#############################################################################
96
97CoinAlloc CoinAllocator;
98
99CoinAlloc::CoinAlloc() :
100 pool_(NULL),
101 maxpooled_(COINUTILS_MEMPOOL_MAXPOOLED)
102{
103 const char* maxpooled = std::getenv("COINUTILS_MEMPOOL_MAXPOOLED");
104 if (maxpooled) {
105 maxpooled_ = std::atoi(maxpooled);
106 }
107 const size_t poolnum = maxpooled_ / COINUTILS_MEMPOOL_ALIGNMENT;
108 maxpooled_ = poolnum * COINUTILS_MEMPOOL_ALIGNMENT;
109 if (maxpooled_ > 0) {
110 pool_ = (CoinMempool*)malloc(sizeof(CoinMempool)*poolnum);
111 for (int i = poolnum-1; i >= 0; --i) {
112 new (&pool_[i]) CoinMempool(i*COINUTILS_MEMPOOL_ALIGNMENT);
113 }
114 }
115}
116
117//#############################################################################
118
119#if defined(COINUTILS_MEMPOOL_OVERRIDE_NEW) && (COINUTILS_MEMPOOL_OVERRIDE_NEW == 1)
120void* operator new(std::size_t sz) throw (std::bad_alloc)
121{
122 return CoinAllocator.alloc(sz);
123}
124
125void* operator new[](std::size_t sz) throw (std::bad_alloc)
126{
127 return CoinAllocator.alloc(sz);
128}
129
130void operator delete(void* p) throw()
131{
132 CoinAllocator.dealloc(p);
133}
134
135void operator delete[](void* p) throw()
136{
137 CoinAllocator.dealloc(p);
138}
139
140void* operator new(std::size_t sz, const std::nothrow_t&) throw()
141{
142 void *p = NULL;
143 try {
144 p = CoinAllocator.alloc(sz);
145 }
146 catch (std::bad_alloc &ba) {
147 return NULL;
148 }
149 return p;
150}
151
152void* operator new[](std::size_t sz, const std::nothrow_t&) throw()
153{
154 void *p = NULL;
155 try {
156 p = CoinAllocator.alloc(sz);
157 }
158 catch (std::bad_alloc &ba) {
159 return NULL;
160 }
161 return p;
162}
163
164void operator delete(void* p, const std::nothrow_t&) throw()
165{
166 CoinAllocator.dealloc(p);
167}
168
169void operator delete[](void* p, const std::nothrow_t&) throw()
170{
171 CoinAllocator.dealloc(p);
172}
173
174#endif
175
176#endif /*(COINUTILS_MEMPOOL_MAXPOOLED >= 0)*/
177