Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5134 serge 1
// MT-optimized allocator -*- C++ -*-
2
 
3
// Copyright (C) 2003-2013 Free Software Foundation, Inc.
4
//
5
// This file is part of the GNU ISO C++ Library.  This library is free
6
// software; you can redistribute it and/or modify it under the
7
// terms of the GNU General Public License as published by the
8
// Free Software Foundation; either version 3, or (at your option)
9
// any later version.
10
 
11
// This library is distributed in the hope that it will be useful,
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
// GNU General Public License for more details.
15
 
16
// Under Section 7 of GPL version 3, you are granted additional
17
// permissions described in the GCC Runtime Library Exception, version
18
// 3.1, as published by the Free Software Foundation.
19
 
20
// You should have received a copy of the GNU General Public License and
21
// a copy of the GCC Runtime Library Exception along with this program;
22
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23
// .
24
 
25
/** @file ext/mt_allocator.h
26
 *  This file is a GNU extension to the Standard C++ Library.
27
 */
28
 
29
#ifndef _MT_ALLOCATOR_H
30
#define _MT_ALLOCATOR_H 1
31
 
32
#include 
33
#include 
34
#include 
35
#include 
36
#include 
37
#if __cplusplus >= 201103L
38
#include 
39
#endif
40
 
41
namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
42
{
43
_GLIBCXX_BEGIN_NAMESPACE_VERSION
44
 
45
  using std::size_t;
46
  using std::ptrdiff_t;
47
 
48
  typedef void (*__destroy_handler)(void*);
49
 
50
  /// Base class for pool object.
51
  struct __pool_base
52
  {
53
    // Using short int as type for the binmap implies we are never
54
    // caching blocks larger than 32768 with this allocator.
55
    typedef unsigned short int _Binmap_type;
56
 
57
    // Variables used to configure the behavior of the allocator,
58
    // assigned and explained in detail below.
59
    struct _Tune
60
     {
61
      // Compile time constants for the default _Tune values.
62
      enum { _S_align = 8 };
63
      enum { _S_max_bytes = 128 };
64
      enum { _S_min_bin = 8 };
65
      enum { _S_chunk_size = 4096 - 4 * sizeof(void*) };
66
      enum { _S_max_threads = 4096 };
67
      enum { _S_freelist_headroom = 10 };
68
 
69
      // Alignment needed.
70
      // NB: In any case must be >= sizeof(_Block_record), that
71
      // is 4 on 32 bit machines and 8 on 64 bit machines.
72
      size_t	_M_align;
73
 
74
      // Allocation requests (after round-up to power of 2) below
75
      // this value will be handled by the allocator. A raw new/
76
      // call will be used for requests larger than this value.
77
      // NB: Must be much smaller than _M_chunk_size and in any
78
      // case <= 32768.
79
      size_t	_M_max_bytes;
80
 
81
      // Size in bytes of the smallest bin.
82
      // NB: Must be a power of 2 and >= _M_align (and of course
83
      // much smaller than _M_max_bytes).
84
      size_t	_M_min_bin;
85
 
86
      // In order to avoid fragmenting and minimize the number of
87
      // new() calls we always request new memory using this
88
      // value. Based on previous discussions on the libstdc++
89
      // mailing list we have chosen the value below.
90
      // See http://gcc.gnu.org/ml/libstdc++/2001-07/msg00077.html
91
      // NB: At least one order of magnitude > _M_max_bytes.
92
      size_t	_M_chunk_size;
93
 
94
      // The maximum number of supported threads. For
95
      // single-threaded operation, use one. Maximum values will
96
      // vary depending on details of the underlying system. (For
97
      // instance, Linux 2.4.18 reports 4070 in
98
      // /proc/sys/kernel/threads-max, while Linux 2.6.6 reports
99
      // 65534)
100
      size_t 	_M_max_threads;
101
 
102
      // Each time a deallocation occurs in a threaded application
103
      // we make sure that there are no more than
104
      // _M_freelist_headroom % of used memory on the freelist. If
105
      // the number of additional records is more than
106
      // _M_freelist_headroom % of the freelist, we move these
107
      // records back to the global pool.
108
      size_t 	_M_freelist_headroom;
109
 
110
      // Set to true forces all allocations to use new().
111
      bool 	_M_force_new;
112
 
113
      explicit
114
      _Tune()
115
      : _M_align(_S_align), _M_max_bytes(_S_max_bytes), _M_min_bin(_S_min_bin),
116
      _M_chunk_size(_S_chunk_size), _M_max_threads(_S_max_threads),
117
      _M_freelist_headroom(_S_freelist_headroom),
118
      _M_force_new(std::getenv("GLIBCXX_FORCE_NEW") ? true : false)
119
      { }
120
 
121
      explicit
122
      _Tune(size_t __align, size_t __maxb, size_t __minbin, size_t __chunk,
123
	    size_t __maxthreads, size_t __headroom, bool __force)
124
      : _M_align(__align), _M_max_bytes(__maxb), _M_min_bin(__minbin),
125
      _M_chunk_size(__chunk), _M_max_threads(__maxthreads),
126
      _M_freelist_headroom(__headroom), _M_force_new(__force)
127
      { }
128
    };
129
 
130
    struct _Block_address
131
    {
132
      void* 			_M_initial;
133
      _Block_address* 		_M_next;
134
    };
135
 
136
    const _Tune&
137
    _M_get_options() const
138
    { return _M_options; }
139
 
140
    void
141
    _M_set_options(_Tune __t)
142
    {
143
      if (!_M_init)
144
	_M_options = __t;
145
    }
146
 
147
    bool
148
    _M_check_threshold(size_t __bytes)
149
    { return __bytes > _M_options._M_max_bytes || _M_options._M_force_new; }
150
 
151
    size_t
152
    _M_get_binmap(size_t __bytes)
153
    { return _M_binmap[__bytes]; }
154
 
155
    size_t
156
    _M_get_align()
157
    { return _M_options._M_align; }
158
 
159
    explicit
160
    __pool_base()
161
    : _M_options(_Tune()), _M_binmap(0), _M_init(false) { }
162
 
163
    explicit
164
    __pool_base(const _Tune& __options)
165
    : _M_options(__options), _M_binmap(0), _M_init(false) { }
166
 
167
  private:
168
    explicit
169
    __pool_base(const __pool_base&);
170
 
171
    __pool_base&
172
    operator=(const __pool_base&);
173
 
174
  protected:
175
    // Configuration options.
176
    _Tune 	       		_M_options;
177
 
178
    _Binmap_type* 		_M_binmap;
179
 
180
    // Configuration of the pool object via _M_options can happen
181
    // after construction but before initialization. After
182
    // initialization is complete, this variable is set to true.
183
    bool 			_M_init;
184
  };
185
 
186
 
187
  /**
188
   *  @brief  Data describing the underlying memory pool, parameterized on
189
   *  threading support.
190
   */
191
  template
192
    class __pool;
193
 
194
  /// Specialization for single thread.
195
  template<>
196
    class __pool : public __pool_base
197
    {
198
    public:
199
      union _Block_record
200
      {
201
	// Points to the block_record of the next free block.
202
	_Block_record* 			_M_next;
203
      };
204
 
205
      struct _Bin_record
206
      {
207
	// An "array" of pointers to the first free block.
208
	_Block_record**			_M_first;
209
 
210
	// A list of the initial addresses of all allocated blocks.
211
	_Block_address*		     	_M_address;
212
      };
213
 
214
      void
215
      _M_initialize_once()
216
      {
217
	if (__builtin_expect(_M_init == false, false))
218
	  _M_initialize();
219
      }
220
 
221
      void
222
      _M_destroy() throw();
223
 
224
      char*
225
      _M_reserve_block(size_t __bytes, const size_t __thread_id);
226
 
227
      void
228
      _M_reclaim_block(char* __p, size_t __bytes) throw ();
229
 
230
      size_t
231
      _M_get_thread_id() { return 0; }
232
 
233
      const _Bin_record&
234
      _M_get_bin(size_t __which)
235
      { return _M_bin[__which]; }
236
 
237
      void
238
      _M_adjust_freelist(const _Bin_record&, _Block_record*, size_t)
239
      { }
240
 
241
      explicit __pool()
242
      : _M_bin(0), _M_bin_size(1) { }
243
 
244
      explicit __pool(const __pool_base::_Tune& __tune)
245
      : __pool_base(__tune), _M_bin(0), _M_bin_size(1) { }
246
 
247
    private:
248
      // An "array" of bin_records each of which represents a specific
249
      // power of 2 size. Memory to this "array" is allocated in
250
      // _M_initialize().
251
      _Bin_record*		 _M_bin;
252
 
253
      // Actual value calculated in _M_initialize().
254
      size_t 	       	     	_M_bin_size;
255
 
256
      void
257
      _M_initialize();
258
  };
259
 
260
#ifdef __GTHREADS
261
  /// Specialization for thread enabled, via gthreads.h.
262
  template<>
263
    class __pool : public __pool_base
264
    {
265
    public:
266
      // Each requesting thread is assigned an id ranging from 1 to
267
      // _S_max_threads. Thread id 0 is used as a global memory pool.
268
      // In order to get constant performance on the thread assignment
269
      // routine, we keep a list of free ids. When a thread first
270
      // requests memory we remove the first record in this list and
271
      // stores the address in a __gthread_key. When initializing the
272
      // __gthread_key we specify a destructor. When this destructor
273
      // (i.e. the thread dies) is called, we return the thread id to
274
      // the front of this list.
275
      struct _Thread_record
276
      {
277
	// Points to next free thread id record. NULL if last record in list.
278
	_Thread_record*			_M_next;
279
 
280
	// Thread id ranging from 1 to _S_max_threads.
281
	size_t                          _M_id;
282
      };
283
 
284
      union _Block_record
285
      {
286
	// Points to the block_record of the next free block.
287
	_Block_record*			_M_next;
288
 
289
	// The thread id of the thread which has requested this block.
290
	size_t                          _M_thread_id;
291
      };
292
 
293
      struct _Bin_record
294
      {
295
	// An "array" of pointers to the first free block for each
296
	// thread id. Memory to this "array" is allocated in
297
	// _S_initialize() for _S_max_threads + global pool 0.
298
	_Block_record**			_M_first;
299
 
300
	// A list of the initial addresses of all allocated blocks.
301
	_Block_address*		     	_M_address;
302
 
303
	// An "array" of counters used to keep track of the amount of
304
	// blocks that are on the freelist/used for each thread id.
305
	// - Note that the second part of the allocated _M_used "array"
306
	//   actually hosts (atomic) counters of reclaimed blocks:  in
307
	//   _M_reserve_block and in _M_reclaim_block those numbers are
308
	//   subtracted from the first ones to obtain the actual size
309
	//   of the "working set" of the given thread.
310
	// - Memory to these "arrays" is allocated in _S_initialize()
311
	//   for _S_max_threads + global pool 0.
312
	size_t*				_M_free;
313
	size_t*			        _M_used;
314
 
315
	// Each bin has its own mutex which is used to ensure data
316
	// integrity while changing "ownership" on a block.  The mutex
317
	// is initialized in _S_initialize().
318
	__gthread_mutex_t*              _M_mutex;
319
      };
320
 
321
      // XXX GLIBCXX_ABI Deprecated
322
      void
323
      _M_initialize(__destroy_handler);
324
 
325
      void
326
      _M_initialize_once()
327
      {
328
	if (__builtin_expect(_M_init == false, false))
329
	  _M_initialize();
330
      }
331
 
332
      void
333
      _M_destroy() throw();
334
 
335
      char*
336
      _M_reserve_block(size_t __bytes, const size_t __thread_id);
337
 
338
      void
339
      _M_reclaim_block(char* __p, size_t __bytes) throw ();
340
 
341
      const _Bin_record&
342
      _M_get_bin(size_t __which)
343
      { return _M_bin[__which]; }
344
 
345
      void
346
      _M_adjust_freelist(const _Bin_record& __bin, _Block_record* __block,
347
			 size_t __thread_id)
348
      {
349
	if (__gthread_active_p())
350
	  {
351
	    __block->_M_thread_id = __thread_id;
352
	    --__bin._M_free[__thread_id];
353
	    ++__bin._M_used[__thread_id];
354
	  }
355
      }
356
 
357
      // XXX GLIBCXX_ABI Deprecated
358
      _GLIBCXX_CONST void
359
      _M_destroy_thread_key(void*) throw ();
360
 
361
      size_t
362
      _M_get_thread_id();
363
 
364
      explicit __pool()
365
      : _M_bin(0), _M_bin_size(1), _M_thread_freelist(0)
366
      { }
367
 
368
      explicit __pool(const __pool_base::_Tune& __tune)
369
      : __pool_base(__tune), _M_bin(0), _M_bin_size(1),
370
	_M_thread_freelist(0)
371
      { }
372
 
373
    private:
374
      // An "array" of bin_records each of which represents a specific
375
      // power of 2 size. Memory to this "array" is allocated in
376
      // _M_initialize().
377
      _Bin_record*		_M_bin;
378
 
379
      // Actual value calculated in _M_initialize().
380
      size_t 	       	     	_M_bin_size;
381
 
382
      _Thread_record* 		_M_thread_freelist;
383
      void*			_M_thread_freelist_initial;
384
 
385
      void
386
      _M_initialize();
387
    };
388
#endif
389
 
390
  template