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";
9 #include "prototypes.h"
13 GDESC
*GlobalList
= NULL
;
14 static unsigned short next_unused_handle
= 1;
16 /**********************************************************************
19 GDESC
*GlobalGetGDesc(unsigned int block
)
27 * Find GDESC for this block.
29 if (block
& 0xffff0000)
31 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
32 if (g
->handle
> 0 && (unsigned int) g
->addr
== block
)
37 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
38 if (g
->handle
== block
)
45 /**********************************************************************
46 * GlobalGetFreeSegments
49 GlobalGetFreeSegments(unsigned int flags
, int n_segments
)
51 struct segment_descriptor_s
*s
;
58 * Try to find some empty segments in our list.
61 for (g
= GlobalList
; g
!= NULL
&& count
!= n_segments
; g
= g
->next
)
63 if ((int) g
->sequence
== -1)
67 if (g
->prev
->handle
+ 8 != g
->handle
)
83 * If we couldn't find enough segments, then we need to create some.
85 if (count
!= n_segments
)
91 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
97 s
= CreateNewSegments(0, 0, 0x10000, n_segments
);
100 printf("GlobalGetFreeSegments // bad CreateNewSegments !\n");
103 for (count
= 0; count
< n_segments
; count
++, s
++)
105 g
= (GDESC
*) malloc(sizeof(*g
));
107 printf("GlobalGetFreeSegments // bad GDESC malloc !\n");
112 g
->handle
= s
->selector
;
114 g
->addr
= s
->base_addr
;
115 g
->length
= s
->length
;
116 g
->linear_addr
= NULL
;
119 if (!(flags
& GLOBAL_FLAGS_MOVEABLE
))
124 if (count
== 0) g_start
= g
;
137 * We have all of the segments we need. Let's adjust their contents.
140 for (i
= 0; i
< n_segments
; i
++, g
= g
->next
)
143 printf("GlobalGetFreeSegments // bad Segments chain !\n");
147 g
->length
= n_segments
;
148 g
->linear_addr
= NULL
;
156 /**********************************************************************
160 GlobalAlloc(unsigned int flags
, unsigned long size
)
167 * If this block is fixed or very big we need to allocate entire
170 if (size
> 0x8000 || !(flags
& GLOBAL_FLAGS_MOVEABLE
))
172 int segments
= (size
>> 16) + 1;
174 g
= GlobalGetFreeSegments(flags
, segments
);
181 * Otherwise we just need a little piece of a segment.
186 * Try to allocate from active free lists.
188 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
190 if (g
->handle
== 0 && g
->sequence
== 0)
192 m
= HEAP_Alloc((MDESC
**) g
->addr
, 0, size
);
199 * If we couldn't get the memory there, then we need to create
204 g
= GlobalGetFreeSegments(0, 1);
210 HEAP_Init((MDESC
**) g
->addr
, (MDESC
**) g
->addr
+ 1,
211 0x10000 - sizeof(MDESC
**));
212 m
= HEAP_Alloc((MDESC
**) g
->addr
, flags
& GLOBAL_FLAGS_ZEROINIT
,
219 * Save position of heap descriptor.
224 * We have a new block. Let's create a GDESC entry for it.
226 g
= malloc(sizeof(*g
));
228 printf("New GDESC %08x\n", g
);
233 g
->handle
= next_unused_handle
;
236 g
->linear_addr
= NULL
;
240 g
->next
= g_prev
->next
;
241 if (g
->next
) g
->next
->prev
= g
;
247 next_unused_handle
++;
248 if ((next_unused_handle
& 7) == 7)
249 next_unused_handle
++;
252 printf("GlobalAlloc: returning %04x\n", g
->handle
);
258 /**********************************************************************
261 * Windows programs will pass a handle in the "block" parameter, but
262 * this function will also accept a 32-bit address.
265 GlobalFree(unsigned int block
)
273 * Find GDESC for this block.
275 g
= GlobalGetGDesc(block
);
280 * If the sequence number is zero then use HEAP_Free to deallocate
281 * memory, and throw away this descriptor.
283 if (g
->sequence
== 0)
285 HEAP_Free((MDESC
**) ((int) g
->addr
& 0xffff0000), (void *) g
->addr
);
287 g
->prev
->next
= g
->next
;
290 g
->next
->prev
= g
->prev
;
296 * Otherwise just mark these descriptors as free.
303 for (i
= g
->sequence
- 1; i
< limit
&& g
!= NULL
; i
++, g
= g
->next
)
313 /**********************************************************************
318 GlobalLock(unsigned int block
)
326 * Find GDESC for this block.
328 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
330 if (g
->handle
== block
)
334 printf("GlobalLock: returning %08x\n", g
->addr
);
341 printf("GlobalLock: returning %08x\n", 0);
346 /**********************************************************************
351 GlobalUnlock(unsigned int block
)
359 * Find GDESC for this block.
361 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
363 if (g
->handle
== block
&& g
->lock_count
> 0)
373 /**********************************************************************
378 GlobalFlags(unsigned int block
)
386 * Find GDESC for this block.
388 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
390 if (g
->handle
== block
)
391 return g
->lock_count
;
397 /**********************************************************************
402 GlobalSize(unsigned int block
)
410 * Find GDESC for this block.
412 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
414 if (g
->handle
== block
)
421 /**********************************************************************
424 * This routine is not strictly correct. MS Windows creates a selector
425 * for every locked global block. We do not. If the allocation is small
426 * enough, we only give out a little piece of a selector. Thus this
427 * function cannot be implemented.
430 GlobalHandle(unsigned int selector
)
438 * Find GDESC for this block.
440 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
442 if (g
->handle
== selector
)
448 fprintf(stderr
, "Attempt to get a handle "
449 "from a selector to a far heap.\n");
458 /**********************************************************************
463 GlobalCompact(unsigned int desired
)
466 unsigned char free_map
[512];
467 unsigned int max_selector_used
= 0;
469 unsigned int selector
;
474 * Initialize free list to all items not controlled by GlobalAlloc()
476 for (i
= 0; i
< 512; i
++)
480 * Traverse table looking for used and free selectors.
482 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
485 * Check for free segments.
487 if (g
->sequence
== -1)
489 free_map
[g
->handle
>> 3] = 1;
490 if (g
->handle
> max_selector_used
)
491 max_selector_used
= g
->handle
;
495 * Check for heap allocated segments.
497 else if (g
->handle
== 0)
499 selector
= (unsigned int) g
->addr
>> 16;
500 free_map
[selector
>> 3] = 0;
501 if (selector
> max_selector_used
)
502 max_selector_used
= selector
;
507 * All segments past the biggest selector used are free.
509 for (i
= (max_selector_used
>> 3) + 1; i
< 512; i
++)
513 * Find the largest free block of segments
517 for (i
= 0; i
< 512; i
++)
519 if (free_map
[i
] == 1)
525 if (current_free
> max_free
)
526 max_free
= current_free
;
531 return max_free
<< 16;
534 /**********************************************************************
539 GlobalReAlloc(unsigned int block
, unsigned int new_size
, unsigned int flags
)
542 unsigned int n_segments
;
549 * Find GDESC for this block.
551 g
= GlobalGetGDesc(block
);
556 * If this is a heap allocated block, then use HEAP_ReAlloc() to
557 * reallocate the block. If this fails, call GlobalAlloc() to get
560 if (g
->sequence
== 0)
565 free_list
= (MDESC
**) ((unsigned int) g
->addr
& 0xffff0000);
566 p
= HEAP_ReAlloc(free_list
, g
->addr
, new_size
, flags
) ;
569 unsigned int handle
= GlobalAlloc(flags
, new_size
);
572 p
= GlobalLock(handle
);
573 memcpy(p
, g
->addr
, g
->length
);
574 GlobalUnlock(handle
);
575 GlobalFree(g
->handle
);
582 g
->length
= new_size
;
588 * Otherwise, we need to do the work ourselves. First verify the
593 if (g
->sequence
!= 1)
597 * Do we need more memory? Segments are in ascending order in
600 n_segments
= (new_size
>> 16) + 1;
601 if (n_segments
> g
->length
)
605 int old_segments
= g_start
->length
;
606 unsigned short next_handle
= g_start
->handle
;
608 for (i
= 1; i
<= n_segments
; i
++, g
= g
->next
)
611 * If we run into a block allocated to something else,
612 * try GlobalGetFreeSegments() and memcpy(). (Yuk!)
614 if (g
->sequence
!= i
|| g
->handle
!= next_handle
)
616 g
= GlobalGetFreeSegments(flags
, n_segments
);
620 memcpy(g
->addr
, g_start
->addr
,
621 g_start
->length
<< 16);
628 * Otherwise this block is used by us or free. So,
629 * snatch it. If this block is new and we are supposed to
630 * zero init, then do some erasing.
632 if (g
->sequence
== -1 && (flags
& GLOBAL_FLAGS_ZEROINIT
))
633 memset(g
->addr
, 0, 0x10000);
636 g
->length
= n_segments
;
640 * If the next descriptor is non-existant, then use
641 * GlobalGetFreeSegments to create them.
643 if (i
!= n_segments
&& g
->next
== NULL
)
645 g_new
= GlobalGetFreeSegments(flags
, n_segments
- i
);
648 GlobalFree(g_new
->handle
);
652 return g_start
->handle
;
656 * Do we need less memory?
658 else if (n_segments
< g
->length
)
663 for (i
= 0; i
< n_segments
; i
++)
665 if (g_free
->sequence
!= i
+ 1)
667 g_free
= g_free
->next
;
672 * We already have exactly the right amount of memory.
679 * If we fall through it must be an error.
684 /**********************************************************************
688 GlobalQuickAlloc(int size
)
692 hmem
= GlobalAlloc(GLOBAL_FLAGS_MOVEABLE
, size
);
696 return GlobalLock(hmem
);
699 /**********************************************************************
700 * GlobalHandleFromPointer
704 GlobalHandleFromPointer(void *block
)
712 * Find GDESC for this block.
714 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
715 if (g
->handle
> 0 && g
->addr
== block
)
724 /**********************************************************************
725 * GetFreeSpace (kernel.169)
728 DWORD
GetFreeSpace(UINT wFlags
)
729 /* windows 3.1 doesn't use the wFlags parameter !!
730 (so I won't either) */
733 unsigned char free_map
[512];
734 unsigned int max_selector_used
= 0;
736 unsigned int selector
;
740 * Initialize free list to all items not controlled by GlobalAlloc()
742 for (i
= 0; i
< 512; i
++)
746 * Traverse table looking for used and free selectors.
748 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
751 * Check for free segments.
753 if (g
->sequence
== -1)
755 free_map
[g
->handle
>> 3] = 1;
756 if (g
->handle
> max_selector_used
)
757 max_selector_used
= g
->handle
;
761 * Check for heap allocated segments.
763 else if (g
->handle
== 0)
765 selector
= (unsigned int) g
->addr
>> 16;
766 free_map
[selector
>> 3] = 0;
767 if (selector
> max_selector_used
)
768 max_selector_used
= selector
;
773 * All segments past the biggest selector used are free.
775 for (i
= (max_selector_used
>> 3) + 1; i
< 512; i
++)
779 * Add up the total free segments (obviously this amount of memory
780 may not be contiguous, use GlobalCompact to get largest contiguous
784 for (i
= 0; i
< 512; i
++)
785 if (free_map
[i
] == 1)
788 return total_free
<< 16;