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
;
228 next_unused_handle
++;
229 if ((next_unused_handle
& 7) == 7)
230 next_unused_handle
++;
233 printf("GlobalAlloc: returning %04x\n", g
->handle
);
239 /**********************************************************************
242 * Windows programs will pass a handle in the "block" parameter, but
243 * this function will also accept a 32-bit address.
246 GlobalFree(unsigned int block
)
254 * Find GDESC for this block.
256 if (block
& 0xffff0000)
258 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
259 if (g
->handle
> 0 && (unsigned int) g
->addr
== block
)
264 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
265 if (g
->handle
== block
)
272 * If the sequence number is zero then use HEAP_Free to deallocate
273 * memory, and throw away this descriptor.
275 if (g
->sequence
== 0)
277 HEAP_Free((MDESC
**) (block
& 0xffff0000), (void *) block
);
279 g
->prev
->next
= g
->next
;
282 g
->next
->prev
= g
->prev
;
288 * Otherwise just mark these descriptors as free.
295 for (i
= g
->sequence
- 1; i
< limit
&& g
!= NULL
; i
++, g
= g
->next
)
305 /**********************************************************************
310 GlobalLock(unsigned int block
)
318 * Find GDESC for this block.
320 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
322 if (g
->handle
== block
)
326 printf("GlobalLock: returning %08x\n", g
->addr
);
333 printf("GlobalLock: returning %08x\n", 0);
338 /**********************************************************************
343 GlobalUnlock(unsigned int block
)
351 * Find GDESC for this block.
353 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
355 if (g
->handle
== block
&& g
->lock_count
> 0)
365 /**********************************************************************
370 GlobalFlags(unsigned int block
)
378 * Find GDESC for this block.
380 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
382 if (g
->handle
== block
)
383 return g
->lock_count
;
389 /**********************************************************************
394 GlobalSize(unsigned int block
)
402 * Find GDESC for this block.
404 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
406 if (g
->handle
== block
)
413 /**********************************************************************
416 * This routine is not strictly correct. MS Windows creates a selector
417 * for every locked global block. We do not. If the allocation is small
418 * enough, we only give out a little piece of a selector. Thus this
419 * function cannot be implemented.
422 GlobalHandle(unsigned int selector
)
430 * Find GDESC for this block.
432 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
434 if (g
->handle
== selector
)
440 fprintf(stderr
, "Attempt to get a handle "
441 "from a selector to a far heap.\n");
450 /**********************************************************************
455 GlobalCompact(unsigned int desired
)
458 unsigned char free_map
[512];
459 unsigned int max_selector_used
= 0;
461 unsigned int selector
;
466 * Initialize free list to all items not controlled by GlobalAlloc()
468 for (i
= 0; i
< 512; i
++)
472 * Traverse table looking for used and free selectors.
474 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
477 * Check for free segments.
479 if (g
->sequence
== -1)
481 free_map
[g
->handle
>> 3] = 1;
482 if (g
->handle
> max_selector_used
)
483 max_selector_used
= g
->handle
;
487 * Check for heap allocated segments.
489 else if (g
->handle
== 0)
491 selector
= (unsigned int) g
->addr
>> 16;
492 free_map
[selector
>> 3] = 0;
493 if (selector
> max_selector_used
)
494 max_selector_used
= selector
;
499 * All segments past the biggest selector used are free.
501 for (i
= (max_selector_used
>> 3) + 1; i
< 512; i
++)
505 * Find the largest free block of segments
509 for (i
= 0; i
< 512; i
++)
511 if (free_map
[i
] == 1)
517 if (current_free
> max_free
)
518 max_free
= current_free
;
523 return max_free
<< 16;
526 /**********************************************************************
531 GlobalReAlloc(unsigned int block
, unsigned int new_size
, unsigned int flags
)
534 unsigned int n_segments
;
541 * Find GDESC for this block.
543 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
545 if (g
->handle
== block
)
553 * If this is a heap allocated block, then use HEAP_ReAlloc() to
554 * reallocate the block. If this fails, call GlobalAlloc() to get
562 free_list
= (MDESC
**) ((unsigned int) g
->addr
& 0xffff0000);
563 p
= HEAP_ReAlloc(free_list
, g
->addr
, new_size
, flags
) ;
566 unsigned int handle
= GlobalAlloc(flags
, new_size
);
569 p
= GlobalLock(handle
);
570 memcpy(p
, g
->addr
, g
->length
);
571 GlobalUnlock(handle
);
572 GlobalFree(g
->handle
);
579 g
->length
= new_size
;
585 * Otherwise, we need to do the work ourselves. First verify the
590 if (g
->sequence
!= 1)
594 * Do we need more memory? Segments are in ascending order in
597 n_segments
= (new_size
>> 16) + 1;
598 if (n_segments
> g
->length
)
602 int old_segments
= g_start
->length
;
603 unsigned short next_handle
= g_start
->handle
;
605 for (i
= 1; i
<= n_segments
; i
++, g
= g
->next
)
608 * If we run into a block allocated to something else,
609 * try GlobalGetFreeSegments() and memcpy(). (Yuk!)
611 if (g
->sequence
!= i
|| g
->handle
!= next_handle
)
613 g
= GlobalGetFreeSegments(flags
, n_segments
);
617 memcpy(g
->addr
, g_start
->addr
,
618 g_start
->length
<< 16);
625 * Otherwise this block is used by us or free. So,
626 * snatch it. If this block is new and we are supposed to
627 * zero init, then do some erasing.
629 if (g
->sequence
== -1 && (flags
& GLOBAL_FLAGS_ZEROINIT
))
630 memset(g
->addr
, 0, 0x10000);
633 g
->length
= n_segments
;
637 * If the next descriptor is non-existant, then use
638 * GlobalGetFreeSegments to create them.
640 if (i
!= n_segments
&& g
->next
== NULL
)
642 g_new
= GlobalGetFreeSegments(flags
, n_segments
- i
);
645 GlobalFree(g_new
->handle
);
649 return g_start
->handle
;
653 * Do we need less memory?
655 else if (n_segments
< g
->length
)
660 for (i
= 0; i
< n_segments
; i
++)
662 if (g_free
->sequence
!= i
+ 1)
664 g_free
= g_free
->next
;
669 * We already have exactly the right amount of memory.
676 * If we fall through it must be an error.