1 static char RCSId[] = "$Id: global.c,v 1.2 1993/07/04 04:04:21 root Exp root $";
2 static char Copyright[] = "Copyright Robert J. Amstadt, 1993";
6 #include "prototypes.h"
11 * Global memory pool descriptor. Segments MUST be maintained in segment
12 * ascending order. If not the reallocation routine will die a horrible
15 * handle = 0, this descriptor contains the address of a free pool.
16 * != 0, this describes an allocated block.
18 * sequence = 0, this is not a huge block
19 * > 0, this is a portion of a huge block
20 * =-1, this is a free segment
22 * addr - address of this memory block.
24 * length - used to maintain huge blocks.
27 typedef struct global_mem_desc_s
29 struct global_mem_desc_s *next;
30 struct global_mem_desc_s *prev;
31 unsigned short handle;
38 GDESC *GlobalList = NULL;
39 static unsigned short next_unused_handle = 1;
42 /**********************************************************************
43 * GlobalGetFreeSegments
46 GlobalGetFreeSegments(unsigned int flags, int n_segments)
48 struct segment_descriptor_s *s;
55 * Try to find some empty segments in our list.
58 for (g = GlobalList; g != NULL && count != n_segments; g = g->next)
60 if ((int) g->sequence == -1)
64 if (g->prev->handle + 8 != g->handle)
80 * If we couldn't find enough segments, then we need to create some.
82 if (count != n_segments)
88 for (g = GlobalList; g != NULL; g = g->next)
94 for (count = 0; count < n_segments; count++)
96 s = GetNextSegment(flags, 0x10000);
100 g = (GDESC *) malloc(sizeof(*g));
104 g->handle = s->selector;
106 g->addr = s->base_addr;
107 g->length = s->length;
108 if (!(flags & GLOBAL_FLAGS_MOVEABLE))
129 * We have all of the segments we need. Let's adjust their contents.
132 for (i = 0; i < n_segments; i++, g = g->next)
135 g->length = n_segments;
141 /**********************************************************************
145 GlobalAlloc(unsigned int flags, unsigned long size)
152 * If this block is fixed or very big we need to allocate entire
155 if (size > 0x8000 || !(flags & GLOBAL_FLAGS_MOVEABLE))
157 int segments = (size >> 16) + 1;
159 g = GlobalGetFreeSegments(flags, segments);
166 * Otherwise we just need a little piece of a segment.
171 * Try to allocate from active free lists.
173 for (g = GlobalList; g != NULL; g = g->next)
175 if (g->handle == 0 && g->sequence == 0)
177 m = HEAP_Alloc((MDESC **) g->addr, 0, size);
184 * If we couldn't get the memory there, then we need to create
189 g = GlobalGetFreeSegments(0, 1);
195 HEAP_Init((MDESC **) g->addr, (MDESC **) g->addr + 1,
196 0x10000 - sizeof(MDESC **));
197 m = HEAP_Alloc((MDESC **) g->addr, flags & GLOBAL_FLAGS_ZEROINIT,
204 * Save position of heap descriptor.
209 * We have a new block. Let's create a GDESC entry for it.
211 g = malloc(sizeof(*g));
213 printf("New GDESC %08x\n", g);
218 g->handle = next_unused_handle;
222 g->next = g_prev->next;
223 if (g->next) g->next->prev = g;
229 next_unused_handle++;
230 if ((next_unused_handle & 7) == 7)
231 next_unused_handle++;
234 printf("GlobalAlloc: returning %04x\n", g->handle);
240 /**********************************************************************
243 * Windows programs will pass a handle in the "block" parameter, but
244 * this function will also accept a 32-bit address.
247 GlobalFree(unsigned int block)
255 * Find GDESC for this block.
257 if (block & 0xffff0000)
259 for (g = GlobalList; g != NULL; g = g->next)
260 if (g->handle > 0 && (unsigned int) g->addr == block)
265 for (g = GlobalList; g != NULL; g = g->next)
266 if (g->handle == block)
273 * If the sequence number is zero then use HEAP_Free to deallocate
274 * memory, and throw away this descriptor.
276 if (g->sequence == 0)
278 HEAP_Free((MDESC **) ((int) g->addr & 0xffff0000), (void *) g->addr);
280 g->prev->next = g->next;
283 g->next->prev = g->prev;
289 * Otherwise just mark these descriptors as free.
296 for (i = g->sequence - 1; i < limit && g != NULL; i++, g = g->next)
306 /**********************************************************************
311 GlobalLock(unsigned int block)
319 * Find GDESC for this block.
321 for (g = GlobalList; g != NULL; g = g->next)
323 if (g->handle == block)
327 printf("GlobalLock: returning %08x\n", g->addr);
334 printf("GlobalLock: returning %08x\n", 0);
339 /**********************************************************************
344 GlobalUnlock(unsigned int block)
352 * Find GDESC for this block.
354 for (g = GlobalList; g != NULL; g = g->next)
356 if (g->handle == block && g->lock_count > 0)
366 /**********************************************************************
371 GlobalFlags(unsigned int block)
379 * Find GDESC for this block.
381 for (g = GlobalList; g != NULL; g = g->next)
383 if (g->handle == block)
384 return g->lock_count;
390 /**********************************************************************
395 GlobalSize(unsigned int block)
403 * Find GDESC for this block.
405 for (g = GlobalList; g != NULL; g = g->next)
407 if (g->handle == block)
414 /**********************************************************************
417 * This routine is not strictly correct. MS Windows creates a selector
418 * for every locked global block. We do not. If the allocation is small
419 * enough, we only give out a little piece of a selector. Thus this
420 * function cannot be implemented.
423 GlobalHandle(unsigned int selector)
431 * Find GDESC for this block.
433 for (g = GlobalList; g != NULL; g = g->next)
435 if (g->handle == selector)
441 fprintf(stderr, "Attempt to get a handle "
442 "from a selector to a far heap.\n");
451 /**********************************************************************
456 GlobalCompact(unsigned int desired)
459 unsigned char free_map[512];
460 unsigned int max_selector_used = 0;
462 unsigned int selector;
467 * Initialize free list to all items not controlled by GlobalAlloc()
469 for (i = 0; i < 512; i++)
473 * Traverse table looking for used and free selectors.
475 for (g = GlobalList; g != NULL; g = g->next)
478 * Check for free segments.
480 if (g->sequence == -1)
482 free_map[g->handle >> 3] = 1;
483 if (g->handle > max_selector_used)
484 max_selector_used = g->handle;
488 * Check for heap allocated segments.
490 else if (g->handle == 0)
492 selector = (unsigned int) g->addr >> 16;
493 free_map[selector >> 3] = 0;
494 if (selector > max_selector_used)
495 max_selector_used = selector;
500 * All segments past the biggest selector used are free.
502 for (i = (max_selector_used >> 3) + 1; i < 512; i++)
506 * Find the largest free block of segments
510 for (i = 0; i < 512; i++)
512 if (free_map[i] == 1)
518 if (current_free > max_free)
519 max_free = current_free;
524 return max_free << 16;
527 /**********************************************************************
532 GlobalReAlloc(unsigned int block, unsigned int new_size, unsigned int flags)
535 unsigned int n_segments;
542 * Find GDESC for this block.
544 for (g = GlobalList; g != NULL; g = g->next)
546 if (g->handle == block)
554 * If this is a heap allocated block, then use HEAP_ReAlloc() to
555 * reallocate the block. If this fails, call GlobalAlloc() to get
563 free_list = (MDESC **) ((unsigned int) g->addr & 0xffff0000);
564 p = HEAP_ReAlloc(free_list, g->addr, new_size, flags) ;
567 unsigned int handle = GlobalAlloc(flags, new_size);
570 p = GlobalLock(handle);
571 memcpy(p, g->addr, g->length);
572 GlobalUnlock(handle);
573 GlobalFree(g->handle);
580 g->length = new_size;
586 * Otherwise, we need to do the work ourselves. First verify the
591 if (g->sequence != 1)
595 * Do we need more memory? Segments are in ascending order in
598 n_segments = (new_size >> 16) + 1;
599 if (n_segments > g->length)
603 int old_segments = g_start->length;
604 unsigned short next_handle = g_start->handle;
606 for (i = 1; i <= n_segments; i++, g = g->next)
609 * If we run into a block allocated to something else,
610 * try GlobalGetFreeSegments() and memcpy(). (Yuk!)
612 if (g->sequence != i || g->handle != next_handle)
614 g = GlobalGetFreeSegments(flags, n_segments);
618 memcpy(g->addr, g_start->addr,
619 g_start->length << 16);
626 * Otherwise this block is used by us or free. So,
627 * snatch it. If this block is new and we are supposed to
628 * zero init, then do some erasing.
630 if (g->sequence == -1 && (flags & GLOBAL_FLAGS_ZEROINIT))
631 memset(g->addr, 0, 0x10000);
634 g->length = n_segments;
638 * If the next descriptor is non-existant, then use
639 * GlobalGetFreeSegments to create them.
641 if (i != n_segments && g->next == NULL)
643 g_new = GlobalGetFreeSegments(flags, n_segments - i);
646 GlobalFree(g_new->handle);
650 return g_start->handle;
654 * Do we need less memory?
656 else if (n_segments < g->length)
661 for (i = 0; i < n_segments; i++)
663 if (g_free->sequence != i + 1)
665 g_free = g_free->next;
670 * We already have exactly the right amount of memory.
677 * If we fall through it must be an error.
682 /**********************************************************************
686 GlobalQuickAlloc(int size)
690 hmem = GlobalAlloc(GLOBAL_FLAGS_MOVEABLE, size);
694 return GlobalLock(hmem);
697 /**********************************************************************
698 * GlobalHandleFromPointer
702 GlobalHandleFromPointer(void *block)
710 * Find GDESC for this block.
712 for (g = GlobalList; g != NULL; g = g->next)
713 if (g->handle > 0 && g->addr == block)