1 /*
2  *   Copyright (c) 1998, 2002 Michael J. Roberts.  All Rights Reserved.
3  *
4  *   Please see the accompanying license file, LICENSE.TXT, for information
5  *   on using and copying this software.
6  */
7 /*
8 Name
9   vmpool.cpp - constant pool implementation
10 Function
11 
12 Notes
13 
14 Modified
15   10/20/98 MJRoberts  - Creation
16 */
17 
18 #include <stdlib.h>
19 #include <memory.h>
20 
21 #include "t3std.h"
22 #include "vmpool.h"
23 
24 
25 /* ------------------------------------------------------------------------ */
26 /*
27  *   Basic pool implementation
28  */
29 
30 /*
31  *   Get the number of pages in the pool
32  */
get_page_count() const33 size_t CVmPool::get_page_count() const
34 {
35     /* get the page count from the backing store */
36     return backing_store_->vmpbs_get_page_count();
37 }
38 
39 /*
40  *   Attach to a backing store
41  */
attach_backing_store(CVmPoolBackingStore * backing_store)42 void CVmPool::attach_backing_store(CVmPoolBackingStore *backing_store)
43 {
44     /* remember the backing store */
45     backing_store_ = backing_store;
46 
47     /* get the page size from the backing store */
48     page_size_ = backing_store->vmpbs_get_common_page_size();
49 }
50 
51 /* ------------------------------------------------------------------------ */
52 /*
53  *   Base paged pool implementation
54  */
55 
56 /*
57  *   delete our page list
58  */
delete_page_list()59 void CVmPoolPaged::delete_page_list()
60 {
61     /* if there's a page list, delete it */
62     if (pages_ != 0)
63     {
64         /* free the page array */
65         t3free(pages_);
66 
67         /* forget it */
68         pages_ = 0;
69         page_slots_ = 0;
70         page_slots_max_ = 0;
71     }
72 
73     /* we can no longer have a backing store */
74     backing_store_ = 0;
75 }
76 
77 /*
78  *   Attach to a backing store
79  */
attach_backing_store(CVmPoolBackingStore * backing_store)80 void CVmPoolPaged::attach_backing_store(CVmPoolBackingStore *backing_store)
81 {
82     size_t cur;
83     size_t log2;
84 
85     /* delete any existing page list */
86     delete_page_list();
87 
88     /* inherit default handling */
89     CVmPool::attach_backing_store(backing_store);
90 
91     /*
92      *   if the page size is zero, there must not be any pages at all -
93      *   use a dummy default page size
94      */
95     if (page_size_ == 0)
96         page_size_ = 1024;
97 
98     /*
99      *   Compute log2 of the page size.  If the page size isn't a power of
100      *   two, throw an error.
101      */
102     for (cur = page_size_, log2 = 0 ; (cur & 1) == 0 ; cur >>= 1, ++log2) ;
103     if (cur != 1)
104         err_throw(VMERR_BAD_POOL_PAGE_SIZE);
105 
106     /* store log2(page_size_) in log2_page_size_ */
107     log2_page_size_ = log2;
108 
109     /* allocate the pages */
110     alloc_page_slots(backing_store_->vmpbs_get_page_count());
111 }
112 
113 /*
114  *   Allocate a page slot
115  */
alloc_page_slots(size_t slots)116 void CVmPoolPaged::alloc_page_slots(size_t slots)
117 {
118     size_t old_slots;
119     size_t i;
120 
121     /* note the old slot count */
122     old_slots = page_slots_;
123 
124     /* if the new size isn't bigger than the old size, ignore the request */
125     if (slots <= page_slots_)
126         return;
127 
128     /* if necessary, expand the master page array */
129     if (slots > page_slots_max_)
130     {
131         size_t siz;
132 
133         /*
134          *   Increase the maximum, leaving some room for dynamically added
135          *   pages.
136          */
137         page_slots_max_ = slots + 10;
138 
139         /* calculate the new allocation size */
140         siz = page_slots_max_ * sizeof(pages_[0]);
141 
142         /* allocate or reallocate at the new size */
143         if (pages_ == 0)
144             pages_ = (CVmPool_pg *)t3malloc(siz);
145         else
146             pages_ = (CVmPool_pg *)t3realloc(pages_, siz);
147     }
148 
149     /* set the new size */
150     page_slots_ = slots;
151 
152     /* clear the new subarrays */
153     for (i = old_slots ; i < page_slots_ ; ++i)
154         pages_[i].mem = 0;
155 }
156 
157 /* ------------------------------------------------------------------------ */
158 /*
159  *   Two-level paged pool implementation.  This is a variation of the regular
160  *   paged pool that uses a two-level page table.  This implementation is not
161  *   currently used, because it is less efficient than the single-page pool
162  *   and is not needed for modern machines with large contiguous address
163  *   spaces; however, we retain it in the event it's needed for 16-bit
164  *   segmented architectures, where it might not be possible or convenient to
165  *   allocate a sufficiently large master page table and thus a two-level
166  *   table is needed.
167  */
168 #if 0
169 
170 /*
171  *   delete the pool - deletes all allocated pages
172  */
173 CVmPoolPaged2::~CVmPoolPaged2()
174 {
175     /* free our page memory */
176     delete_page_list();
177 }
178 
179 /*
180  *   delete our page list
181  */
182 void CVmPoolPaged2::delete_page_list()
183 {
184     /* if there's a page list, delete it */
185     if (pages_ != 0)
186     {
187         size_t i;
188         size_t cnt;
189 
190         /* free each subarray */
191         cnt = get_subarray_count();
192         for (i = 0 ; i < cnt ; ++i)
193             t3free(pages_[i]);
194 
195         /* free the master array */
196         t3free(pages_);
197 
198         /* forget about the page list */
199         pages_ = 0;
200     }
201 }
202 
203 /*
204  *   Attach to a backing store
205  */
206 void CVmPoolPaged2::attach_backing_store(CVmPoolBackingStore *backing_store)
207 {
208     size_t cur;
209     size_t log2;
210 
211     /* delete any existing page list */
212     delete_page_list();
213 
214     /* remember the backing store */
215     backing_store_ = backing_store;
216 
217     /* get the page size from the backing store */
218     page_size_ = backing_store_->vmpbs_get_common_page_size();
219 
220     /*
221      *   if the page size is zero, there must not be any pages at all - use a
222      *   dummy default page size
223      */
224     if (page_size_ == 0)
225         page_size_ = 1024;
226 
227     /*
228      *   Compute log2 of the page size.  If the page size isn't a power of
229      *   two, throw an error.
230      */
231     for (cur = page_size_, log2 = 0 ; (cur & 1) == 0 ; cur >>= 1, ++log2) ;
232     if (cur != 1)
233         err_throw(VMERR_BAD_POOL_PAGE_SIZE);
234 
235     /* store log2(page_size_) in log2_page_size_ */
236     log2_page_size_ = log2;
237 
238     /* allocate the pages */
239     alloc_page_slots(backing_store_->vmpbs_get_page_count());
240 }
241 
242 /*
243  *   Allocate a page slot
244  */
245 void CVmPoolPaged2::alloc_page_slots(size_t slots)
246 {
247     size_t old_slots;
248     size_t old_sub_cnt;
249     size_t new_sub_cnt;
250 
251     /* note the old slot count */
252     old_slots = page_slots_;
253 
254     /* if the new size isn't bigger than the old size, ignore the request */
255     if (slots <= page_slots_)
256         return;
257 
258     /* note the original subarray count */
259     old_sub_cnt = get_subarray_count();
260 
261     /* set the new size */
262     page_slots_ = slots;
263 
264     /* note the new subarray count */
265     new_sub_cnt = get_subarray_count();
266 
267     /* allocate or expand the master array */
268     if (new_sub_cnt > old_sub_cnt)
269     {
270         size_t siz;
271         size_t i;
272 
273         /* figure the new size */
274         siz = new_sub_cnt * sizeof(pages_[0]);
275 
276         /* allocate or re-allocate the master array */
277         if (pages_ == 0)
278             pages_ = (CVmPool_pg **)t3malloc(siz);
279         else
280             pages_ = (CVmPool_pg **)t3realloc(pages_, siz);
281 
282         /* throw an error if that failed */
283         if (pages_ == 0)
284             err_throw(VMERR_OUT_OF_MEMORY);
285 
286         /* clear the new slots */
287         memset(pages_ + old_sub_cnt, 0,
288                (new_sub_cnt - old_sub_cnt) * sizeof(pages_[0]));
289 
290         /* allocate the subarrays */
291         for (i = old_sub_cnt ; i < new_sub_cnt ; ++i)
292         {
293             /* allocate this subarray */
294             pages_[i] = (CVmPool_pg *)t3malloc(VMPOOL_SUBARRAY_SIZE
295                                                * sizeof(pages_[i][0]));
296 
297             /* make sure we got the space */
298             if (pages_[i] == 0)
299                 err_throw(VMERR_OUT_OF_MEMORY);
300 
301             /* clear the page */
302             memset(pages_[i], 0, VMPOOL_SUBARRAY_SIZE * sizeof(pages_[i][0]));
303         }
304     }
305 }
306 
307 #endif /* removed 2-paged pool */
308