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 printf("GlobalAlloc flags %4X, size %d\n", flags
, size
);
171 * If this block is fixed or very big we need to allocate entire
174 if (size
> 0x8000 || !(flags
& GLOBAL_FLAGS_MOVEABLE
))
176 int segments
= (size
>> 16) + 1;
178 g
= GlobalGetFreeSegments(flags
, segments
);
185 * Otherwise we just need a little piece of a segment.
190 * Try to allocate from active free lists.
192 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
194 if (g
->handle
== 0 && g
->sequence
== 0)
196 m
= HEAP_Alloc((MDESC
**) g
->addr
, 0, size
);
203 * If we couldn't get the memory there, then we need to create
208 g
= GlobalGetFreeSegments(0, 1);
214 HEAP_Init((MDESC
**) g
->addr
, (MDESC
**) g
->addr
+ 1,
215 0x10000 - sizeof(MDESC
**));
216 m
= HEAP_Alloc((MDESC
**) g
->addr
, flags
& GLOBAL_FLAGS_ZEROINIT
,
223 * Save position of heap descriptor.
228 * We have a new block. Let's create a GDESC entry for it.
230 g
= malloc(sizeof(*g
));
232 printf("New GDESC %08x\n", g
);
237 g
->handle
= next_unused_handle
;
240 g
->linear_addr
= NULL
;
244 g
->next
= g_prev
->next
;
245 if (g
->next
) g
->next
->prev
= g
;
251 next_unused_handle
++;
252 if ((next_unused_handle
& 7) == 7)
253 next_unused_handle
++;
256 printf("GlobalAlloc: returning %04x\n", g
->handle
);
262 /**********************************************************************
265 * Windows programs will pass a handle in the "block" parameter, but
266 * this function will also accept a 32-bit address.
269 GlobalFree(unsigned int block
)
277 * Find GDESC for this block.
279 g
= GlobalGetGDesc(block
);
284 * If the sequence number is zero then use HEAP_Free to deallocate
285 * memory, and throw away this descriptor.
287 if (g
->sequence
== 0)
289 HEAP_Free((MDESC
**) ((int) g
->addr
& 0xffff0000), (void *) g
->addr
);
291 g
->prev
->next
= g
->next
;
294 g
->next
->prev
= g
->prev
;
300 * Otherwise just mark these descriptors as free.
307 for (i
= g
->sequence
- 1; i
< limit
&& g
!= NULL
; i
++, g
= g
->next
)
317 /**********************************************************************
322 GlobalLock(unsigned int block
)
330 * Find GDESC for this block.
332 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
334 if (g
->handle
== block
)
338 printf("GlobalLock: returning %08x\n", g
->addr
);
345 printf("GlobalLock: returning %08x\n", 0);
350 /**********************************************************************
355 GlobalUnlock(unsigned int block
)
363 * Find GDESC for this block.
365 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
367 if (g
->handle
== block
&& g
->lock_count
> 0)
377 /**********************************************************************
382 GlobalFlags(unsigned int block
)
390 * Find GDESC for this block.
392 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
394 if (g
->handle
== block
)
395 return g
->lock_count
;
401 /**********************************************************************
406 GlobalSize(unsigned int block
)
414 * Find GDESC for this block.
416 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
418 if (g
->handle
== block
)
425 /**********************************************************************
428 * This routine is not strictly correct. MS Windows creates a selector
429 * for every locked global block. We do not. If the allocation is small
430 * enough, we only give out a little piece of a selector. Thus this
431 * function cannot be implemented.
434 GlobalHandle(unsigned int selector
)
442 * Find GDESC for this block.
444 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
446 if (g
->handle
== selector
)
452 fprintf(stderr
, "Attempt to get a handle "
453 "from a selector to a far heap.\n");
462 /**********************************************************************
467 GlobalCompact(unsigned int desired
)
470 unsigned char free_map
[512];
471 unsigned int max_selector_used
= 0;
473 unsigned int selector
;
478 * Initialize free list to all items not controlled by GlobalAlloc()
480 for (i
= 0; i
< 512; i
++)
484 * Traverse table looking for used and free selectors.
486 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
489 * Check for free segments.
491 if (g
->sequence
== -1)
493 free_map
[g
->handle
>> 3] = 1;
494 if (g
->handle
> max_selector_used
)
495 max_selector_used
= g
->handle
;
499 * Check for heap allocated segments.
501 else if (g
->handle
== 0)
503 selector
= (unsigned int) g
->addr
>> 16;
504 free_map
[selector
>> 3] = 0;
505 if (selector
> max_selector_used
)
506 max_selector_used
= selector
;
511 * All segments past the biggest selector used are free.
513 for (i
= (max_selector_used
>> 3) + 1; i
< 512; i
++)
517 * Find the largest free block of segments
521 for (i
= 0; i
< 512; i
++)
523 if (free_map
[i
] == 1)
529 if (current_free
> max_free
)
530 max_free
= current_free
;
535 return max_free
<< 16;
538 /**********************************************************************
543 GlobalReAlloc(unsigned int block
, unsigned int new_size
, unsigned int flags
)
546 unsigned int n_segments
;
553 * Find GDESC for this block.
555 g
= GlobalGetGDesc(block
);
560 * If this is a heap allocated block, then use HEAP_ReAlloc() to
561 * reallocate the block. If this fails, call GlobalAlloc() to get
564 if (g
->sequence
== 0)
569 free_list
= (MDESC
**) ((unsigned int) g
->addr
& 0xffff0000);
570 p
= HEAP_ReAlloc(free_list
, g
->addr
, new_size
, flags
) ;
573 unsigned int handle
= GlobalAlloc(flags
, new_size
);
576 p
= GlobalLock(handle
);
577 memcpy(p
, g
->addr
, g
->length
);
578 GlobalUnlock(handle
);
579 GlobalFree(g
->handle
);
586 g
->length
= new_size
;
592 * Otherwise, we need to do the work ourselves. First verify the
597 if (g
->sequence
!= 1)
601 * Do we need more memory? Segments are in ascending order in
604 n_segments
= (new_size
>> 16) + 1;
605 if (n_segments
> g
->length
)
609 int old_segments
= g_start
->length
;
610 unsigned short next_handle
= g_start
->handle
;
612 for (i
= 1; i
<= n_segments
; i
++, g
= g
->next
)
615 * If we run into a block allocated to something else,
616 * try GlobalGetFreeSegments() and memcpy(). (Yuk!)
618 if (g
->sequence
!= i
|| g
->handle
!= next_handle
)
620 g
= GlobalGetFreeSegments(flags
, n_segments
);
624 memcpy(g
->addr
, g_start
->addr
,
625 g_start
->length
<< 16);
632 * Otherwise this block is used by us or free. So,
633 * snatch it. If this block is new and we are supposed to
634 * zero init, then do some erasing.
636 if (g
->sequence
== -1 && (flags
& GLOBAL_FLAGS_ZEROINIT
))
637 memset(g
->addr
, 0, 0x10000);
640 g
->length
= n_segments
;
644 * If the next descriptor is non-existant, then use
645 * GlobalGetFreeSegments to create them.
647 if (i
!= n_segments
&& g
->next
== NULL
)
649 g_new
= GlobalGetFreeSegments(flags
, n_segments
- i
);
652 GlobalFree(g_new
->handle
);
656 return g_start
->handle
;
660 * Do we need less memory?
662 else if (n_segments
< g
->length
)
667 for (i
= 0; i
< n_segments
; i
++)
669 if (g_free
->sequence
!= i
+ 1)
671 g_free
= g_free
->next
;
676 * We already have exactly the right amount of memory.
683 * If we fall through it must be an error.
688 /**********************************************************************
692 GlobalQuickAlloc(int size
)
696 hmem
= GlobalAlloc(GLOBAL_FLAGS_MOVEABLE
, size
);
700 return GlobalLock(hmem
);
703 /**********************************************************************
704 * GlobalHandleFromPointer
708 GlobalHandleFromPointer(void *block
)
716 * Find GDESC for this block.
718 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
719 if (g
->handle
> 0 && g
->addr
== block
)
728 /**********************************************************************
729 * GetFreeSpace (kernel.169)
732 DWORD
GetFreeSpace(UINT wFlags
)
733 /* windows 3.1 doesn't use the wFlags parameter !!
734 (so I won't either) */
737 unsigned char free_map
[512];
738 unsigned int max_selector_used
= 0;
740 unsigned int selector
;
744 * Initialize free list to all items not controlled by GlobalAlloc()
746 for (i
= 0; i
< 512; i
++)
750 * Traverse table looking for used and free selectors.
752 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
755 * Check for free segments.
757 if (g
->sequence
== -1)
759 free_map
[g
->handle
>> 3] = 1;
760 if (g
->handle
> max_selector_used
)
761 max_selector_used
= g
->handle
;
765 * Check for heap allocated segments.
767 else if (g
->handle
== 0)
769 selector
= (unsigned int) g
->addr
>> 16;
770 free_map
[selector
>> 3] = 0;
771 if (selector
> max_selector_used
)
772 max_selector_used
= selector
;
777 * All segments past the biggest selector used are free.
779 for (i
= (max_selector_used
>> 3) + 1; i
< 512; i
++)
783 * Add up the total free segments (obviously this amount of memory
784 may not be contiguous, use GlobalCompact to get largest contiguous
788 for (i
= 0; i
< 512; i
++)
789 if (free_map
[i
] == 1)
792 return total_free
<< 16;