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
558 if (g
->sequence
== 0)
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
)