Mercurial > emacs
comparison src/ralloc.c @ 9459:a1569f00a6a6
Install Hiroshi Nakano's rewrite to allow multiple heaps, for implementations
where the C library makes calls to sbrk directly.
author | Karl Heuer <kwzh@gnu.org> |
---|---|
date | Wed, 12 Oct 1994 00:48:03 +0000 |
parents | b628561b185b |
children | 134f7085c56b |
comparison
equal
deleted
inserted
replaced
9458:a6d5f1c10986 | 9459:a1569f00a6a6 |
---|---|
94 static POINTER virtual_break_value; | 94 static POINTER virtual_break_value; |
95 | 95 |
96 /* The break value, viewed by the relocatable blocs. */ | 96 /* The break value, viewed by the relocatable blocs. */ |
97 static POINTER break_value; | 97 static POINTER break_value; |
98 | 98 |
99 /* The REAL (i.e., page aligned) break value of the process. */ | |
100 static POINTER page_break_value; | |
101 | |
102 /* This is the size of a page. We round memory requests to this boundary. */ | 99 /* This is the size of a page. We round memory requests to this boundary. */ |
103 static int page_size; | 100 static int page_size; |
104 | 101 |
105 /* Whenever we get memory from the system, get this many extra bytes. This | 102 /* Whenever we get memory from the system, get this many extra bytes. This |
106 must be a multiple of page_size. */ | 103 must be a multiple of page_size. */ |
111 #define PAGE (getpagesize ()) | 108 #define PAGE (getpagesize ()) |
112 #define ALIGNED(addr) (((unsigned long int) (addr) & (page_size - 1)) == 0) | 109 #define ALIGNED(addr) (((unsigned long int) (addr) & (page_size - 1)) == 0) |
113 #define ROUNDUP(size) (((unsigned long int) (size) + page_size - 1) \ | 110 #define ROUNDUP(size) (((unsigned long int) (size) + page_size - 1) \ |
114 & ~(page_size - 1)) | 111 & ~(page_size - 1)) |
115 #define ROUND_TO_PAGE(addr) (addr & (~(page_size - 1))) | 112 #define ROUND_TO_PAGE(addr) (addr & (~(page_size - 1))) |
113 | |
114 #define MEM_ALIGN sizeof(double) | |
115 #define MEM_ROUNDUP(addr) (((unsigned long int)(addr) + MEM_ALIGN - 1) \ | |
116 & ~(MEM_ALIGN - 1)) | |
116 | 117 |
117 /* Functions to get and return memory from the system. */ | 118 /* Data structures of heaps and blocs */ |
118 | 119 typedef struct heap |
119 /* Obtain SIZE bytes of space. If enough space is not presently available | 120 { |
120 in our process reserve, (i.e., (page_break_value - break_value)), | 121 struct heap *next; |
121 this means getting more page-aligned space from the system. | 122 struct heap *prev; |
122 | 123 POINTER start; |
123 Return non-zero if all went well, or zero if we couldn't allocate | 124 POINTER end; |
124 the memory. */ | 125 POINTER bloc_start; /* start of relocatable blocs */ |
125 static int | 126 } *heap_ptr; |
126 obtain (size) | 127 |
127 SIZE size; | 128 #define NIL_HEAP ((heap_ptr) 0) |
128 { | 129 #define HEAP_PTR_SIZE (sizeof (struct heap)) |
129 SIZE already_available = page_break_value - break_value; | 130 |
130 | 131 /* Head and tail of the list of heaps. */ |
131 if (already_available < size) | 132 static heap_ptr first_heap, last_heap; |
132 { | |
133 SIZE get = ROUNDUP (size - already_available); | |
134 /* Get some extra, so we can come here less often. */ | |
135 get += extra_bytes; | |
136 | |
137 if ((*real_morecore) (get) == 0) | |
138 return 0; | |
139 | |
140 page_break_value += get; | |
141 } | |
142 | |
143 break_value += size; | |
144 | |
145 return 1; | |
146 } | |
147 | |
148 /* Obtain SIZE bytes of space and return a pointer to the new area. | |
149 If we could not allocate the space, return zero. */ | |
150 | |
151 static POINTER | |
152 get_more_space (size) | |
153 SIZE size; | |
154 { | |
155 POINTER ptr = break_value; | |
156 if (obtain (size)) | |
157 return ptr; | |
158 else | |
159 return 0; | |
160 } | |
161 | |
162 /* Note that SIZE bytes of space have been relinquished by the process. | |
163 If SIZE is more than a page, return the space to the system. */ | |
164 | |
165 static void | |
166 relinquish (size) | |
167 SIZE size; | |
168 { | |
169 POINTER new_page_break; | |
170 int excess; | |
171 | |
172 break_value -= size; | |
173 new_page_break = (POINTER) ROUNDUP (break_value); | |
174 excess = (char *) page_break_value - (char *) new_page_break; | |
175 | |
176 if (excess > extra_bytes * 2) | |
177 { | |
178 /* Keep extra_bytes worth of empty space. | |
179 And don't free anything unless we can free at least extra_bytes. */ | |
180 if ((*real_morecore) (extra_bytes - excess) == 0) | |
181 abort (); | |
182 | |
183 page_break_value += extra_bytes - excess; | |
184 } | |
185 | |
186 /* Zero the space from the end of the "official" break to the actual | |
187 break, so that bugs show up faster. */ | |
188 bzero (break_value, ((char *) page_break_value - (char *) break_value)); | |
189 } | |
190 | |
191 /* The meat - allocating, freeing, and relocating blocs. */ | |
192 | 133 |
193 /* These structures are allocated in the malloc arena. | 134 /* These structures are allocated in the malloc arena. |
194 The linked list is kept in order of increasing '.data' members. | 135 The linked list is kept in order of increasing '.data' members. |
195 The data blocks abut each other; if b->next is non-nil, then | 136 The data blocks abut each other; if b->next is non-nil, then |
196 b->data + b->size == b->next->data. */ | 137 b->data + b->size == b->next->data. */ |
199 struct bp *next; | 140 struct bp *next; |
200 struct bp *prev; | 141 struct bp *prev; |
201 POINTER *variable; | 142 POINTER *variable; |
202 POINTER data; | 143 POINTER data; |
203 SIZE size; | 144 SIZE size; |
145 POINTER new_data; /* tmporarily used for relocation */ | |
204 } *bloc_ptr; | 146 } *bloc_ptr; |
205 | 147 |
206 #define NIL_BLOC ((bloc_ptr) 0) | 148 #define NIL_BLOC ((bloc_ptr) 0) |
207 #define BLOC_PTR_SIZE (sizeof (struct bp)) | 149 #define BLOC_PTR_SIZE (sizeof (struct bp)) |
208 | 150 |
209 /* Head and tail of the list of relocatable blocs. */ | 151 /* Head and tail of the list of relocatable blocs. */ |
210 static bloc_ptr first_bloc, last_bloc; | 152 static bloc_ptr first_bloc, last_bloc; |
153 | |
154 | |
155 /* Functions to get and return memory from the system. */ | |
156 | |
157 /* Obtain SIZE bytes of space starting at ADDRESS in a heap. | |
158 If enough space is not presently available in our reserve, this means | |
159 getting more page-aligned space from the system. If the retuned space | |
160 is not contiguos to the last heap, allocate a new heap, and append it | |
161 to the heap list. | |
162 | |
163 Return the address of the space if all went well, or zero if we couldn't | |
164 allocate the memory. */ | |
165 static POINTER | |
166 obtain (address, size) | |
167 POINTER address; | |
168 SIZE size; | |
169 { | |
170 heap_ptr heap; | |
171 SIZE already_available; | |
172 | |
173 for (heap = last_heap; heap; heap = heap->prev) | |
174 { | |
175 if (heap->start <= address && address <= heap->end) | |
176 break; | |
177 } | |
178 | |
179 if (! heap) | |
180 abort(); | |
181 | |
182 while (heap && address + size > heap->end) | |
183 { | |
184 heap = heap->next; | |
185 if (heap == NIL_HEAP) | |
186 break; | |
187 address = heap->bloc_start; | |
188 } | |
189 | |
190 if (heap == NIL_HEAP) | |
191 { | |
192 POINTER new = (*real_morecore)(0); | |
193 SIZE get; | |
194 | |
195 already_available = (char *)last_heap->end - (char *)address; | |
196 | |
197 if (new != last_heap->end) | |
198 { | |
199 /* Someone else called sbrk(). */ | |
200 heap_ptr new_heap = (heap_ptr) MEM_ROUNDUP(new); | |
201 POINTER bloc_start = (POINTER) MEM_ROUNDUP((POINTER)(new_heap + 1)); | |
202 | |
203 if ((*real_morecore) (bloc_start - new) != new) | |
204 return 0; | |
205 | |
206 new_heap->start = new; | |
207 new_heap->end = bloc_start; | |
208 new_heap->bloc_start = bloc_start; | |
209 new_heap->next = NIL_HEAP; | |
210 new_heap->prev = last_heap; | |
211 last_heap->next = new_heap; | |
212 last_heap = new_heap; | |
213 | |
214 address = bloc_start; | |
215 already_available = 0; | |
216 } | |
217 | |
218 /* Get some extra, so we can come here less often. */ | |
219 get = size + extra_bytes - already_available; | |
220 get = (char *) ROUNDUP((char *)last_heap->end + get) | |
221 - (char *) last_heap->end; | |
222 | |
223 if ((*real_morecore) (get) != last_heap->end) | |
224 return 0; | |
225 | |
226 last_heap->end += get; | |
227 } | |
228 | |
229 return address; | |
230 } | |
231 | |
232 /* If the last heap has a excessive space, return it to the system. */ | |
233 static void | |
234 relinquish () | |
235 { | |
236 register heap_ptr h; | |
237 int excess = 0; | |
238 | |
239 for (h = last_heap; h && break_value < h->end; h = h->prev) | |
240 { | |
241 excess += (char *) h->end - (char *) ((break_value < h->bloc_start) | |
242 ? h->bloc_start : break_value); | |
243 } | |
244 | |
245 if (excess > extra_bytes * 2 && (*real_morecore) (0) == last_heap->end) | |
246 { | |
247 /* Keep extra_bytes worth of empty space. | |
248 And don't free anything unless we can free at least extra_bytes. */ | |
249 excess -= extra_bytes; | |
250 | |
251 if ((char *)last_heap->end - (char *)last_heap->bloc_start <= excess) | |
252 { | |
253 /* Return the last heap with its header to the system */ | |
254 excess = (char *)last_heap->end - (char *)last_heap->start; | |
255 last_heap = last_heap->prev; | |
256 last_heap->next = NIL_HEAP; | |
257 } | |
258 else | |
259 { | |
260 excess = (char *) last_heap->end | |
261 - (char *) ROUNDUP((char *)last_heap->end - excess); | |
262 last_heap->end -= excess; | |
263 } | |
264 | |
265 if ((*real_morecore) (- excess) == 0) | |
266 abort (); | |
267 } | |
268 } | |
269 | |
270 /* The meat - allocating, freeing, and relocating blocs. */ | |
211 | 271 |
212 /* Find the bloc referenced by the address in PTR. Returns a pointer | 272 /* Find the bloc referenced by the address in PTR. Returns a pointer |
213 to that block. */ | 273 to that block. */ |
214 | 274 |
215 static bloc_ptr | 275 static bloc_ptr |
238 SIZE size; | 298 SIZE size; |
239 { | 299 { |
240 register bloc_ptr new_bloc; | 300 register bloc_ptr new_bloc; |
241 | 301 |
242 if (! (new_bloc = (bloc_ptr) malloc (BLOC_PTR_SIZE)) | 302 if (! (new_bloc = (bloc_ptr) malloc (BLOC_PTR_SIZE)) |
243 || ! (new_bloc->data = get_more_space (size))) | 303 || ! (new_bloc->data = obtain (break_value, size))) |
244 { | 304 { |
245 if (new_bloc) | 305 if (new_bloc) |
246 free (new_bloc); | 306 free (new_bloc); |
247 | 307 |
248 return 0; | 308 return 0; |
249 } | 309 } |
310 | |
311 break_value = new_bloc->data + size; | |
250 | 312 |
251 new_bloc->size = size; | 313 new_bloc->size = size; |
252 new_bloc->next = NIL_BLOC; | 314 new_bloc->next = NIL_BLOC; |
253 new_bloc->variable = (POINTER *) NIL; | 315 new_bloc->variable = (POINTER *) NIL; |
316 new_bloc->new_data = 0; | |
254 | 317 |
255 if (first_bloc) | 318 if (first_bloc) |
256 { | 319 { |
257 new_bloc->prev = last_bloc; | 320 new_bloc->prev = last_bloc; |
258 last_bloc->next = new_bloc; | 321 last_bloc->next = new_bloc; |
265 } | 328 } |
266 | 329 |
267 return new_bloc; | 330 return new_bloc; |
268 } | 331 } |
269 | 332 |
270 /* Relocate all blocs from BLOC on upward in the list to the zone | 333 /* Calculate new locations of blocs in the list begining with BLOC, |
271 indicated by ADDRESS. Direction of relocation is determined by | 334 whose spaces is started at ADDRESS in HEAP. If enough space is |
272 the position of ADDRESS relative to BLOC->data. | 335 not presently available in our reserve, obtain() is called for |
273 | 336 more space. |
274 If BLOC is NIL_BLOC, nothing is done. | 337 |
275 | 338 Do not touch the contents of blocs or break_value. */ |
276 Note that ordering of blocs is not affected by this function. */ | 339 |
277 | 340 static int |
278 static void | 341 relocate_blocs (bloc, heap, address) |
279 relocate_some_blocs (bloc, address) | 342 bloc_ptr bloc; |
280 bloc_ptr bloc; | 343 heap_ptr heap; |
281 POINTER address; | 344 POINTER address; |
282 { | 345 { |
283 if (bloc != NIL_BLOC) | 346 register bloc_ptr b = bloc; |
284 { | 347 |
285 register SIZE offset = address - bloc->data; | 348 while (b) |
286 register SIZE data_size = 0; | 349 { |
287 register bloc_ptr b; | 350 while (heap && address + b->size > heap->end) |
288 | 351 { |
352 heap = heap->next; | |
353 if (heap == NIL_HEAP) | |
354 break; | |
355 address = heap->bloc_start; | |
356 } | |
357 | |
358 if (heap == NIL_HEAP) | |
359 { | |
360 register bloc_ptr tb = b; | |
361 register SIZE s = 0; | |
362 | |
363 while (tb != NIL_BLOC) | |
364 { | |
365 s += tb->size; | |
366 tb = tb->next; | |
367 } | |
368 | |
369 if (! (address = obtain(address, s))) | |
370 return 0; | |
371 | |
372 heap = last_heap; | |
373 } | |
374 | |
375 b->new_data = address; | |
376 address += b->size; | |
377 b = b->next; | |
378 } | |
379 | |
380 return 1; | |
381 } | |
382 | |
383 /* Resize BLOC to SIZE bytes. */ | |
384 static int | |
385 resize_bloc (bloc, size) | |
386 bloc_ptr bloc; | |
387 SIZE size; | |
388 { | |
389 register bloc_ptr b; | |
390 heap_ptr heap; | |
391 POINTER address; | |
392 SIZE old_size; | |
393 | |
394 if (bloc == NIL_BLOC || size == bloc->size) | |
395 return 1; | |
396 | |
397 for (heap = first_heap; heap != NIL_HEAP; heap = heap->next) | |
398 { | |
399 if (heap->bloc_start <= bloc->data && bloc->data <= heap->end) | |
400 break; | |
401 } | |
402 | |
403 if (heap == NIL_HEAP) | |
404 abort(); | |
405 | |
406 old_size = bloc->size; | |
407 bloc->size = size; | |
408 | |
409 /* Note that bloc could be moved into the previous heap. */ | |
410 address = bloc->prev ? bloc->prev->data + bloc->prev->size | |
411 : first_heap->bloc_start; | |
412 while (heap) | |
413 { | |
414 if (heap->bloc_start <= address && address <= heap->end) | |
415 break; | |
416 heap = heap->prev; | |
417 } | |
418 | |
419 if (! relocate_blocs (bloc, heap, address)) | |
420 { | |
421 bloc->size = old_size; | |
422 return 0; | |
423 } | |
424 | |
425 if (size > old_size) | |
426 { | |
427 for (b = last_bloc; b != bloc; b = b->prev) | |
428 { | |
429 safe_bcopy (b->data, b->new_data, b->size); | |
430 *b->variable = b->data = b->new_data; | |
431 } | |
432 safe_bcopy (bloc->data, bloc->new_data, old_size); | |
433 bzero (bloc->new_data + old_size, size - old_size); | |
434 *bloc->variable = bloc->data = bloc->new_data; | |
435 } | |
436 else | |
437 { | |
289 for (b = bloc; b != NIL_BLOC; b = b->next) | 438 for (b = bloc; b != NIL_BLOC; b = b->next) |
290 { | 439 { |
291 data_size += b->size; | 440 safe_bcopy (b->data, b->new_data, b->size); |
292 b->data += offset; | 441 *b->variable = b->data = b->new_data; |
293 *b->variable = b->data; | 442 } |
294 } | 443 } |
295 | 444 |
296 safe_bcopy (address - offset, address, data_size); | 445 break_value = last_bloc ? last_bloc->data + last_bloc->size |
297 } | 446 : first_heap->bloc_start; |
298 } | 447 return 1; |
299 | 448 } |
300 | 449 |
301 /* Free BLOC from the chain of blocs, relocating any blocs above it | 450 /* Free BLOC from the chain of blocs, relocating any blocs above it |
302 and returning BLOC->size bytes to the free area. */ | 451 and returning BLOC->size bytes to the free area. */ |
303 | 452 |
304 static void | 453 static void |
305 free_bloc (bloc) | 454 free_bloc (bloc) |
306 bloc_ptr bloc; | 455 bloc_ptr bloc; |
307 { | 456 { |
457 resize_bloc (bloc, 0); | |
458 | |
308 if (bloc == first_bloc && bloc == last_bloc) | 459 if (bloc == first_bloc && bloc == last_bloc) |
309 { | 460 { |
310 first_bloc = last_bloc = NIL_BLOC; | 461 first_bloc = last_bloc = NIL_BLOC; |
311 } | 462 } |
312 else if (bloc == last_bloc) | 463 else if (bloc == last_bloc) |
323 { | 474 { |
324 bloc->next->prev = bloc->prev; | 475 bloc->next->prev = bloc->prev; |
325 bloc->prev->next = bloc->next; | 476 bloc->prev->next = bloc->next; |
326 } | 477 } |
327 | 478 |
328 relocate_some_blocs (bloc->next, bloc->data); | 479 relinquish (); |
329 relinquish (bloc->size); | |
330 free (bloc); | 480 free (bloc); |
331 } | 481 } |
332 | 482 |
333 /* Interface routines. */ | 483 /* Interface routines. */ |
334 | 484 |
348 | 498 |
349 POINTER | 499 POINTER |
350 r_alloc_sbrk (size) | 500 r_alloc_sbrk (size) |
351 long size; | 501 long size; |
352 { | 502 { |
353 /* This is the first address not currently available for the heap. */ | 503 register bloc_ptr b; |
354 POINTER top; | 504 POINTER address; |
355 /* Amount of empty space below that. */ | |
356 /* It is not correct to use SIZE here, because that is usually unsigned. | |
357 ptrdiff_t would be okay, but is not always available. | |
358 `long' will work in all cases, in practice. */ | |
359 long already_available; | |
360 POINTER ptr; | |
361 | 505 |
362 if (! use_relocatable_buffers) | 506 if (! use_relocatable_buffers) |
363 return (*real_morecore) (size); | 507 return (*real_morecore) (size); |
364 | 508 |
365 top = first_bloc ? first_bloc->data : page_break_value; | 509 if (size == 0) |
366 already_available = (char *) top - (char *) virtual_break_value; | 510 return virtual_break_value; |
367 | 511 |
368 /* Do we not have enough gap already? */ | 512 if (size > 0) |
369 if (size > 0 && already_available < size) | 513 { |
370 { | 514 /* Allocate a page-aligned space. GNU malloc would reclaim an |
371 /* Get what we need, plus some extra so we can come here less often. */ | 515 extra space if we passed an unaligned one. But we could |
372 SIZE get = size - already_available + extra_bytes; | 516 not always find a space which is contiguos to the previous. */ |
373 | 517 POINTER new_bloc_start; |
374 if (r_alloc_freeze_level > 0 || ! obtain (get)) | 518 heap_ptr h = first_heap; |
375 return 0; | 519 SIZE get = ROUNDUP(size); |
376 | 520 |
377 if (first_bloc) | 521 address = (POINTER) ROUNDUP(virtual_break_value); |
378 relocate_some_blocs (first_bloc, first_bloc->data + get); | 522 |
379 | 523 /* Search the list upward for a heap which is large enough. */ |
380 /* Zero out the space we just allocated, to help catch bugs | 524 while ((char *) h->end < (char *) MEM_ROUNDUP((char *)address + get)) |
381 quickly. */ | 525 { |
382 bzero (virtual_break_value, get); | 526 h = h->next; |
383 } | 527 if (h == NIL_HEAP) |
384 /* Can we keep extra_bytes of gap while freeing at least extra_bytes? */ | 528 break; |
385 else if (size < 0 && already_available - size > 2 * extra_bytes | 529 address = (POINTER) ROUNDUP(h->start); |
386 && r_alloc_freeze_level == 0) | 530 } |
387 { | 531 |
388 /* Ok, do so. This is how many to free. */ | 532 /* If not found, obatin more space. */ |
389 SIZE give_back = already_available - size - extra_bytes; | 533 if (h == NIL_HEAP) |
390 | 534 { |
391 if (first_bloc) | 535 get += extra_bytes + page_size; |
392 relocate_some_blocs (first_bloc, first_bloc->data - give_back); | 536 |
393 relinquish (give_back); | 537 if (r_alloc_freeze_level > 0 || ! obtain(address, get)) |
394 } | 538 return 0; |
395 | 539 |
396 ptr = virtual_break_value; | 540 if (first_heap == last_heap) |
397 virtual_break_value += size; | 541 address = (POINTER) ROUNDUP(virtual_break_value); |
398 | 542 else |
399 return ptr; | 543 address = (POINTER) ROUNDUP(last_heap->start); |
544 h = last_heap; | |
545 } | |
546 | |
547 new_bloc_start = (POINTER) MEM_ROUNDUP((char *)address + get); | |
548 | |
549 if (first_heap->bloc_start < new_bloc_start) | |
550 { | |
551 /* Move all blocs upward. */ | |
552 if (r_alloc_freeze_level > 0 | |
553 || ! relocate_blocs (first_bloc, h, new_bloc_start)) | |
554 return 0; | |
555 | |
556 /* Note that (POINTER)(h+1) <= new_bloc_start since | |
557 get >= page_size, so the following does not destroy the heap | |
558 header. */ | |
559 for (b = last_bloc; b != NIL_BLOC; b = b->prev) | |
560 { | |
561 safe_bcopy (b->data, b->new_data, b->size); | |
562 *b->variable = b->data = b->new_data; | |
563 } | |
564 | |
565 h->bloc_start = new_bloc_start; | |
566 } | |
567 | |
568 if (h != first_heap) | |
569 { | |
570 /* Give up managing heaps below the one the new | |
571 virtual_break_value points to. */ | |
572 first_heap->prev = NIL_HEAP; | |
573 first_heap->next = h->next; | |
574 first_heap->start = h->start; | |
575 first_heap->end = h->end; | |
576 first_heap->bloc_start = h->bloc_start; | |
577 | |
578 if (first_heap->next) | |
579 first_heap->next->prev = first_heap; | |
580 else | |
581 last_heap = first_heap; | |
582 } | |
583 | |
584 bzero (address, size); | |
585 } | |
586 else /* size < 0 */ | |
587 { | |
588 SIZE excess = (char *)first_heap->bloc_start | |
589 - ((char *)virtual_break_value + size); | |
590 | |
591 address = virtual_break_value; | |
592 | |
593 if (r_alloc_freeze_level == 0 && excess > 2 * extra_bytes) | |
594 { | |
595 excess -= extra_bytes; | |
596 first_heap->bloc_start | |
597 = (POINTER) MEM_ROUNDUP((char *)first_heap->bloc_start - excess); | |
598 | |
599 relocate_blocs(first_bloc, first_heap, first_heap->bloc_start); | |
600 | |
601 for (b = first_bloc; b != NIL_BLOC; b = b->next) | |
602 { | |
603 safe_bcopy (b->data, b->new_data, b->size); | |
604 *b->variable = b->data = b->new_data; | |
605 } | |
606 } | |
607 | |
608 if ((char *)virtual_break_value + size < (char *)first_heap->start) | |
609 { | |
610 /* We found an additional space below the first heap */ | |
611 first_heap->start = (POINTER) ((char *)virtual_break_value + size); | |
612 } | |
613 } | |
614 | |
615 virtual_break_value = (POINTER) ((char *)address + size); | |
616 break_value = last_bloc ? last_bloc->data + last_bloc->size | |
617 : first_heap->bloc_start; | |
618 if (size < 0) | |
619 relinquish(); | |
620 | |
621 return address; | |
400 } | 622 } |
401 | 623 |
402 /* Allocate a relocatable bloc of storage of size SIZE. A pointer to | 624 /* Allocate a relocatable bloc of storage of size SIZE. A pointer to |
403 the data is returned in *PTR. PTR is thus the address of some variable | 625 the data is returned in *PTR. PTR is thus the address of some variable |
404 which will use the data area. | 626 which will use the data area. |
414 register bloc_ptr new_bloc; | 636 register bloc_ptr new_bloc; |
415 | 637 |
416 if (! r_alloc_initialized) | 638 if (! r_alloc_initialized) |
417 r_alloc_init (); | 639 r_alloc_init (); |
418 | 640 |
419 new_bloc = get_bloc (size); | 641 new_bloc = get_bloc (MEM_ROUNDUP(size)); |
420 if (new_bloc) | 642 if (new_bloc) |
421 { | 643 { |
422 new_bloc->variable = ptr; | 644 new_bloc->variable = ptr; |
423 *ptr = new_bloc->data; | 645 *ptr = new_bloc->data; |
424 } | 646 } |
468 | 690 |
469 if (size <= bloc->size) | 691 if (size <= bloc->size) |
470 /* Wouldn't it be useful to actually resize the bloc here? */ | 692 /* Wouldn't it be useful to actually resize the bloc here? */ |
471 return *ptr; | 693 return *ptr; |
472 | 694 |
473 if (! obtain (size - bloc->size)) | 695 if (! resize_bloc (bloc, MEM_ROUNDUP(size))) |
474 return 0; | 696 return 0; |
475 | |
476 relocate_some_blocs (bloc->next, bloc->data + size); | |
477 | |
478 /* Zero out the new space in the bloc, to help catch bugs faster. */ | |
479 bzero (bloc->data + bloc->size, size - bloc->size); | |
480 | |
481 /* Indicate that this block has a new size. */ | |
482 bloc->size = size; | |
483 | 697 |
484 return *ptr; | 698 return *ptr; |
485 } | 699 } |
486 | 700 |
487 /* Disable relocations, after making room for at least SIZE bytes | 701 /* Disable relocations, after making room for at least SIZE bytes |
517 /* Initialize various things for memory allocation. */ | 731 /* Initialize various things for memory allocation. */ |
518 | 732 |
519 static void | 733 static void |
520 r_alloc_init () | 734 r_alloc_init () |
521 { | 735 { |
736 static struct heap heap_base; | |
737 POINTER end; | |
738 | |
522 if (r_alloc_initialized) | 739 if (r_alloc_initialized) |
523 return; | 740 return; |
524 | 741 |
525 r_alloc_initialized = 1; | 742 r_alloc_initialized = 1; |
526 real_morecore = __morecore; | 743 real_morecore = __morecore; |
527 __morecore = r_alloc_sbrk; | 744 __morecore = r_alloc_sbrk; |
528 | 745 |
529 virtual_break_value = break_value = (*real_morecore) (0); | 746 first_heap = last_heap = &heap_base; |
747 first_heap->next = first_heap->prev = NIL_HEAP; | |
748 first_heap->start = first_heap->bloc_start | |
749 = virtual_break_value = break_value = (*real_morecore) (0); | |
530 if (break_value == NIL) | 750 if (break_value == NIL) |
531 abort (); | 751 abort (); |
532 | 752 |
533 page_size = PAGE; | 753 page_size = PAGE; |
534 extra_bytes = ROUNDUP (50000); | 754 extra_bytes = ROUNDUP (50000); |
535 | 755 |
536 page_break_value = (POINTER) ROUNDUP (break_value); | 756 first_heap->end = (POINTER) ROUNDUP (first_heap->start); |
537 | 757 |
538 /* The extra call to real_morecore guarantees that the end of the | 758 /* The extra call to real_morecore guarantees that the end of the |
539 address space is a multiple of page_size, even if page_size is | 759 address space is a multiple of page_size, even if page_size is |
540 not really the page size of the system running the binary in | 760 not really the page size of the system running the binary in |
541 which page_size is stored. This allows a binary to be built on a | 761 which page_size is stored. This allows a binary to be built on a |
542 system with one page size and run on a system with a smaller page | 762 system with one page size and run on a system with a smaller page |
543 size. */ | 763 size. */ |
544 (*real_morecore) (page_break_value - break_value); | 764 (*real_morecore) (first_heap->end - first_heap->start); |
545 | 765 |
546 /* Clear the rest of the last page; this memory is in our address space | 766 /* Clear the rest of the last page; this memory is in our address space |
547 even though it is after the sbrk value. */ | 767 even though it is after the sbrk value. */ |
548 /* Doubly true, with the additional call that explicitly adds the | 768 /* Doubly true, with the additional call that explicitly adds the |
549 rest of that page to the address space. */ | 769 rest of that page to the address space. */ |
550 bzero (break_value, (page_break_value - break_value)); | 770 bzero (first_heap->start, first_heap->end - first_heap->start); |
551 virtual_break_value = break_value = page_break_value; | 771 virtual_break_value = break_value = first_heap->bloc_start = first_heap->end; |
552 use_relocatable_buffers = 1; | 772 use_relocatable_buffers = 1; |
553 } | 773 } |
774 #ifdef DEBUG | |
775 #include <assert.h> | |
776 | |
777 int | |
778 r_alloc_check () | |
779 { | |
780 int found = 0; | |
781 heap_ptr h, ph = 0; | |
782 bloc_ptr b, pb = 0; | |
783 | |
784 if (!r_alloc_initialized) | |
785 return; | |
786 | |
787 assert(first_heap); | |
788 assert(last_heap->end <= (POINTER) sbrk(0)); | |
789 assert((POINTER) first_heap < first_heap->start); | |
790 assert(first_heap->start <= virtual_break_value); | |
791 assert(virtual_break_value <= first_heap->end); | |
792 | |
793 for (h = first_heap; h; h = h->next) | |
794 { | |
795 assert(h->prev == ph); | |
796 assert((POINTER) ROUNDUP(h->end) == h->end); | |
797 assert((POINTER) MEM_ROUNDUP(h->start) == h->start); | |
798 assert((POINTER) MEM_ROUNDUP(h->bloc_start) == h->bloc_start); | |
799 assert(h->start <= h->bloc_start && h->bloc_start <= h->end); | |
800 | |
801 if (ph) | |
802 { | |
803 assert (ph->end < h->start); | |
804 assert (h->start <= (POINTER)h && (POINTER)(h+1) <= h->bloc_start); | |
805 } | |
806 | |
807 if (h->bloc_start <= break_value && break_value <= h->end) | |
808 found = 1; | |
809 | |
810 ph = h; | |
811 } | |
812 | |
813 assert(found); | |
814 assert(last_heap == ph); | |
815 | |
816 for (b = first_bloc; b; b = b->next) | |
817 { | |
818 assert(b->prev == pb); | |
819 assert((POINTER) MEM_ROUNDUP(b->data) == b->data); | |
820 assert((SIZE) MEM_ROUNDUP(b->size) == b->size); | |
821 | |
822 ph = 0; | |
823 for (h = first_heap; h; h = h->next) | |
824 { | |
825 if (h->bloc_start <= b->data && b->data + b->size <= h->end) | |
826 break; | |
827 ph = h; | |
828 } | |
829 | |
830 assert(h); | |
831 | |
832 if (pb && pb->data + pb->size != b->data) | |
833 { | |
834 assert(ph && b->data == h->bloc_start); | |
835 while (ph) | |
836 { | |
837 if (ph->bloc_start <= pb->data | |
838 && pb->data + pb->size <= ph->end) | |
839 { | |
840 assert(pb->data + pb->size + b->size > ph->end); | |
841 break; | |
842 } | |
843 else | |
844 { | |
845 assert(ph->bloc_start + b->size > ph->end); | |
846 } | |
847 ph = ph->prev; | |
848 } | |
849 } | |
850 pb = b; | |
851 } | |
852 | |
853 assert(last_bloc == pb); | |
854 | |
855 if (last_bloc) | |
856 assert(last_bloc->data + last_bloc->size == break_value); | |
857 else | |
858 assert(first_heap->bloc_start == break_value); | |
859 } | |
860 #endif /* DEBUG */ |