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);
98 printf("GlobalGetFreeSegments // bad GetNextSegment !\n");
101 g
= (GDESC
*) malloc(sizeof(*g
));
103 printf("GlobalGetFreeSegments // bad GDESC malloc !\n");
108 g
->handle
= s
->selector
;
110 g
->addr
= s
->base_addr
;
111 g
->length
= s
->length
;
112 if (!(flags
& GLOBAL_FLAGS_MOVEABLE
))
117 if (count
== 0) g_start
= g
;
130 * We have all of the segments we need. Let's adjust their contents.
133 for (i
= 0; i
< n_segments
; i
++, g
= g
->next
)
136 printf("GlobalGetFreeSegments // bad Segments chain !\n");
140 g
->length
= n_segments
;
146 /**********************************************************************
150 GlobalAlloc(unsigned int flags
, unsigned long size
)
157 * If this block is fixed or very big we need to allocate entire
160 if (size
> 0x8000 || !(flags
& GLOBAL_FLAGS_MOVEABLE
))
162 int segments
= (size
>> 16) + 1;
164 g
= GlobalGetFreeSegments(flags
, segments
);
171 * Otherwise we just need a little piece of a segment.
176 * Try to allocate from active free lists.
178 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
180 if (g
->handle
== 0 && g
->sequence
== 0)
182 m
= HEAP_Alloc((MDESC
**) g
->addr
, 0, size
);
189 * If we couldn't get the memory there, then we need to create
194 g
= GlobalGetFreeSegments(0, 1);
200 HEAP_Init((MDESC
**) g
->addr
, (MDESC
**) g
->addr
+ 1,
201 0x10000 - sizeof(MDESC
**));
202 m
= HEAP_Alloc((MDESC
**) g
->addr
, flags
& GLOBAL_FLAGS_ZEROINIT
,
209 * Save position of heap descriptor.
214 * We have a new block. Let's create a GDESC entry for it.
216 g
= malloc(sizeof(*g
));
218 printf("New GDESC %08x\n", g
);
223 g
->handle
= next_unused_handle
;
227 g
->next
= g_prev
->next
;
228 if (g
->next
) g
->next
->prev
= g
;
234 next_unused_handle
++;
235 if ((next_unused_handle
& 7) == 7)
236 next_unused_handle
++;
239 printf("GlobalAlloc: returning %04x\n", g
->handle
);
245 /**********************************************************************
248 * Windows programs will pass a handle in the "block" parameter, but
249 * this function will also accept a 32-bit address.
252 GlobalFree(unsigned int block
)
260 * Find GDESC for this block.
262 if (block
& 0xffff0000)
264 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
265 if (g
->handle
> 0 && (unsigned int) g
->addr
== block
)
270 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
271 if (g
->handle
== block
)
278 * If the sequence number is zero then use HEAP_Free to deallocate
279 * memory, and throw away this descriptor.
281 if (g
->sequence
== 0)
283 HEAP_Free((MDESC
**) ((int) g
->addr
& 0xffff0000), (void *) g
->addr
);
285 g
->prev
->next
= g
->next
;
288 g
->next
->prev
= g
->prev
;
294 * Otherwise just mark these descriptors as free.
301 for (i
= g
->sequence
- 1; i
< limit
&& g
!= NULL
; i
++, g
= g
->next
)
311 /**********************************************************************
316 GlobalLock(unsigned int block
)
324 * Find GDESC for this block.
326 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
328 if (g
->handle
== block
)
332 printf("GlobalLock: returning %08x\n", g
->addr
);
339 printf("GlobalLock: returning %08x\n", 0);
344 /**********************************************************************
349 GlobalUnlock(unsigned int block
)
357 * Find GDESC for this block.
359 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
361 if (g
->handle
== block
&& g
->lock_count
> 0)
371 /**********************************************************************
376 GlobalFlags(unsigned int block
)
384 * Find GDESC for this block.
386 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
388 if (g
->handle
== block
)
389 return g
->lock_count
;
395 /**********************************************************************
400 GlobalSize(unsigned int block
)
408 * Find GDESC for this block.
410 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
412 if (g
->handle
== block
)
419 /**********************************************************************
422 * This routine is not strictly correct. MS Windows creates a selector
423 * for every locked global block. We do not. If the allocation is small
424 * enough, we only give out a little piece of a selector. Thus this
425 * function cannot be implemented.
428 GlobalHandle(unsigned int selector
)
436 * Find GDESC for this block.
438 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
440 if (g
->handle
== selector
)
446 fprintf(stderr
, "Attempt to get a handle "
447 "from a selector to a far heap.\n");
456 /**********************************************************************
461 GlobalCompact(unsigned int desired
)
464 unsigned char free_map
[512];
465 unsigned int max_selector_used
= 0;
467 unsigned int selector
;
472 * Initialize free list to all items not controlled by GlobalAlloc()
474 for (i
= 0; i
< 512; i
++)
478 * Traverse table looking for used and free selectors.
480 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
483 * Check for free segments.
485 if (g
->sequence
== -1)
487 free_map
[g
->handle
>> 3] = 1;
488 if (g
->handle
> max_selector_used
)
489 max_selector_used
= g
->handle
;
493 * Check for heap allocated segments.
495 else if (g
->handle
== 0)
497 selector
= (unsigned int) g
->addr
>> 16;
498 free_map
[selector
>> 3] = 0;
499 if (selector
> max_selector_used
)
500 max_selector_used
= selector
;
505 * All segments past the biggest selector used are free.
507 for (i
= (max_selector_used
>> 3) + 1; i
< 512; i
++)
511 * Find the largest free block of segments
515 for (i
= 0; i
< 512; i
++)
517 if (free_map
[i
] == 1)
523 if (current_free
> max_free
)
524 max_free
= current_free
;
529 return max_free
<< 16;
532 /**********************************************************************
537 GlobalReAlloc(unsigned int block
, unsigned int new_size
, unsigned int flags
)
540 unsigned int n_segments
;
547 * Find GDESC for this block.
549 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
551 if (g
->handle
== block
)
559 * If this is a heap allocated block, then use HEAP_ReAlloc() to
560 * reallocate the block. If this fails, call GlobalAlloc() to get
563 if (g
->sequence
== 0)
568 free_list
= (MDESC
**) ((unsigned int) g
->addr
& 0xffff0000);
569 p
= HEAP_ReAlloc(free_list
, g
->addr
, new_size
, flags
) ;
572 unsigned int handle
= GlobalAlloc(flags
, new_size
);
575 p
= GlobalLock(handle
);
576 memcpy(p
, g
->addr
, g
->length
);
577 GlobalUnlock(handle
);
578 GlobalFree(g
->handle
);
585 g
->length
= new_size
;
591 * Otherwise, we need to do the work ourselves. First verify the
596 if (g
->sequence
!= 1)
600 * Do we need more memory? Segments are in ascending order in
603 n_segments
= (new_size
>> 16) + 1;
604 if (n_segments
> g
->length
)
608 int old_segments
= g_start
->length
;
609 unsigned short next_handle
= g_start
->handle
;
611 for (i
= 1; i
<= n_segments
; i
++, g
= g
->next
)
614 * If we run into a block allocated to something else,
615 * try GlobalGetFreeSegments() and memcpy(). (Yuk!)
617 if (g
->sequence
!= i
|| g
->handle
!= next_handle
)
619 g
= GlobalGetFreeSegments(flags
, n_segments
);
623 memcpy(g
->addr
, g_start
->addr
,
624 g_start
->length
<< 16);
631 * Otherwise this block is used by us or free. So,
632 * snatch it. If this block is new and we are supposed to
633 * zero init, then do some erasing.
635 if (g
->sequence
== -1 && (flags
& GLOBAL_FLAGS_ZEROINIT
))
636 memset(g
->addr
, 0, 0x10000);
639 g
->length
= n_segments
;
643 * If the next descriptor is non-existant, then use
644 * GlobalGetFreeSegments to create them.
646 if (i
!= n_segments
&& g
->next
== NULL
)
648 g_new
= GlobalGetFreeSegments(flags
, n_segments
- i
);
651 GlobalFree(g_new
->handle
);
655 return g_start
->handle
;
659 * Do we need less memory?
661 else if (n_segments
< g
->length
)
666 for (i
= 0; i
< n_segments
; i
++)
668 if (g_free
->sequence
!= i
+ 1)
670 g_free
= g_free
->next
;
675 * We already have exactly the right amount of memory.
682 * If we fall through it must be an error.
687 /**********************************************************************
691 GlobalQuickAlloc(int size
)
695 hmem
= GlobalAlloc(GLOBAL_FLAGS_MOVEABLE
, size
);
699 return GlobalLock(hmem
);
702 /**********************************************************************
703 * GlobalHandleFromPointer
707 GlobalHandleFromPointer(void *block
)
715 * Find GDESC for this block.
717 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
718 if (g
->handle
> 0 && g
->addr
== block
)