Merged r11452:11459 from jcorgan/pmt-gruel into trunk. Trunk passes distcheck.
[debian/gnuradio] / gruel / src / lib / pmt_pool.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2007,2009 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  * 
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <gruel/pmt_pool.h>
26 #include <algorithm>
27 #include <stdint.h>
28
29 namespace gruel {
30
31 static inline size_t
32 ROUNDUP(size_t x, size_t stride)
33 {
34   return ((((x) + (stride) - 1)/(stride)) * (stride));
35 }
36
37 pmt_pool::pmt_pool(size_t itemsize, size_t alignment,
38                    size_t allocation_size, size_t max_items)
39   : d_itemsize(ROUNDUP(itemsize, alignment)),
40     d_alignment(alignment),
41     d_allocation_size(std::max(allocation_size, 16 * itemsize)),
42     d_max_items(max_items), d_n_items(0),
43     d_freelist(0)
44 {
45 }
46
47 pmt_pool::~pmt_pool()
48 {
49   for (unsigned int i = 0; i < d_allocations.size(); i++){
50     delete [] d_allocations[i];
51   }
52 }
53
54 void *
55 pmt_pool::malloc()
56 {
57   scoped_lock guard(d_mutex);
58   item *p;
59
60   if (d_max_items != 0){
61     while (d_n_items >= d_max_items)
62       d_cond.wait(guard);
63   }
64
65   if (d_freelist){      // got something?
66     p = d_freelist;
67     d_freelist = p->d_next;
68     d_n_items++;
69     return p;
70   }
71
72   // allocate a new chunk
73   char *alloc = new char[d_allocation_size + d_alignment - 1];
74   d_allocations.push_back(alloc);
75
76   // get the alignment we require
77   char *start = (char *)(((uintptr_t)alloc + d_alignment-1) & -d_alignment);
78   char *end = alloc + d_allocation_size + d_alignment - 1;
79   size_t n = (end - start) / d_itemsize;
80
81   // link the new items onto the free list.
82   p = (item *) start;
83   for (size_t i = 0; i < n; i++){
84     p->d_next = d_freelist;
85     d_freelist = p;
86     p = (item *)((char *) p + d_itemsize);
87   }
88
89   // now return the first one
90   p = d_freelist;
91   d_freelist = p->d_next;
92   d_n_items++;
93   return p;
94 }
95
96 void
97 pmt_pool::free(void *foo)
98 {
99   if (!foo)
100     return;
101
102   scoped_lock guard(d_mutex);
103
104   item *p = (item *) foo;
105   p->d_next = d_freelist;
106   d_freelist = p;
107   d_n_items--;
108   if (d_max_items != 0)
109     d_cond.notify_one();
110 }
111
112 } /* namespace gruel */