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 | |
15 | CoinMempool::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 | |
34 | CoinMempool::~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 | |
48 | char* |
49 | CoinMempool::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 | |
81 | char* |
82 | CoinMempool::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 | |
97 | CoinAlloc CoinAllocator; |
98 | |
99 | CoinAlloc::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) |
120 | void* operator new(std::size_t sz) throw (std::bad_alloc) |
121 | { |
122 | return CoinAllocator.alloc(sz); |
123 | } |
124 | |
125 | void* operator new[](std::size_t sz) throw (std::bad_alloc) |
126 | { |
127 | return CoinAllocator.alloc(sz); |
128 | } |
129 | |
130 | void operator delete(void* p) throw() |
131 | { |
132 | CoinAllocator.dealloc(p); |
133 | } |
134 | |
135 | void operator delete[](void* p) throw() |
136 | { |
137 | CoinAllocator.dealloc(p); |
138 | } |
139 | |
140 | void* 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 | |
152 | void* 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 | |
164 | void operator delete(void* p, const std::nothrow_t&) throw() |
165 | { |
166 | CoinAllocator.dealloc(p); |
167 | } |
168 | |
169 | void 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 | |