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";
4 /* #define DEBUG_HEAP /* */
10 #include "prototypes.h"
15 GDESC
*GlobalList
= NULL
;
16 static unsigned short next_unused_handle
= 1;
18 /**********************************************************************
21 GDESC
*GlobalGetGDesc(unsigned int block
)
29 * Find GDESC for this block.
31 if (block
& 0xffff0000)
33 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
34 if (g
->handle
> 0 && (unsigned int) g
->addr
== block
)
39 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
40 if (g
->handle
== block
)
47 /**********************************************************************
48 * GlobalGetFreeSegments
51 GlobalGetFreeSegments(unsigned int flags
, int n_segments
)
53 struct segment_descriptor_s
*s
;
60 * Try to find some empty segments in our list.
63 for (g
= GlobalList
; g
!= NULL
&& count
!= n_segments
; g
= g
->next
)
65 if ((int) g
->sequence
== -1)
69 if (g
->prev
->handle
+ 8 != g
->handle
)
85 * If we couldn't find enough segments, then we need to create some.
87 if (count
!= n_segments
)
93 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
99 s
= CreateNewSegments(0, 0, 0x10000, n_segments
);
102 printf("GlobalGetFreeSegments // bad CreateNewSegments !\n");
105 for (count
= 0; count
< n_segments
; count
++, s
++)
107 g
= (GDESC
*) malloc(sizeof(*g
));
110 printf("GlobalGetFreeSegments // bad GDESC malloc !\n");
115 g
->handle
= s
->selector
;
117 g
->addr
= s
->base_addr
;
118 g
->length
= s
->length
;
120 g
->linear_addr
= NULL
;
123 if (!(flags
& GLOBAL_FLAGS_MOVEABLE
))
128 if (count
== 0) g_start
= g
;
141 * We have all of the segments we need. Let's adjust their contents.
144 for (i
= 0; i
< n_segments
; i
++, g
= g
->next
)
148 printf("GlobalGetFreeSegments // bad Segments chain !\n");
152 g
->length
= n_segments
;
154 g
->linear_addr
= NULL
;
162 /**********************************************************************
166 WIN16_GlobalAlloc(unsigned int flags
, unsigned long size
)
168 return GlobalAlloc(flags
& ~GLOBAL_FLAGS_MOVEABLE
, size
);
171 /**********************************************************************
175 GlobalAlloc(unsigned int flags
, unsigned long size
)
182 printf("GlobalAlloc flags %4X, size %d\n", flags
, size
);
186 * If this block is fixed or very big we need to allocate entire
189 if (size
> 0x8000 || !(flags
& GLOBAL_FLAGS_MOVEABLE
))
191 int segments
= ((size
- 1) >> 16) + 1;
193 g
= GlobalGetFreeSegments(flags
, segments
);
200 * Otherwise we just need a little piece of a segment.
205 * Try to allocate from active free lists.
207 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
209 if (g
->handle
== 0 && g
->sequence
== 0)
211 m
= HEAP_Alloc((MDESC
**) g
->addr
, 0, size
);
218 * If we couldn't get the memory there, then we need to create
223 g
= GlobalGetFreeSegments(0, 1);
229 HEAP_Init((MDESC
**) g
->addr
, (MDESC
**) g
->addr
+ 1,
230 0x10000 - sizeof(MDESC
**));
231 m
= HEAP_Alloc((MDESC
**) g
->addr
, flags
& GLOBAL_FLAGS_ZEROINIT
,
238 * Save position of heap descriptor.
243 * We have a new block. Let's create a GDESC entry for it.
245 g
= malloc(sizeof(*g
));
247 printf("New GDESC %08x\n", g
);
252 g
->handle
= next_unused_handle
;
256 g
->linear_addr
= NULL
;
260 g
->next
= g_prev
->next
;
261 if (g
->next
) g
->next
->prev
= g
;
267 next_unused_handle
++;
268 if ((next_unused_handle
& 7) == 7)
269 next_unused_handle
++;
272 printf("GlobalAlloc: returning %04x\n", g
->handle
);
278 /**********************************************************************
281 * Windows programs will pass a handle in the "block" parameter, but
282 * this function will also accept a 32-bit address.
285 GlobalFree(unsigned int block
)
293 * Find GDESC for this block.
295 g
= GlobalGetGDesc(block
);
300 * If the sequence number is zero then use HEAP_Free to deallocate
301 * memory, and throw away this descriptor.
303 if (g
->sequence
== 0)
305 HEAP_Free((MDESC
**) ((int) g
->addr
& 0xffff0000), (void *) g
->addr
);
307 g
->prev
->next
= g
->next
;
310 g
->next
->prev
= g
->prev
;
316 * Otherwise just mark these descriptors as free.
323 for (i
= g
->sequence
- 1; i
< limit
&& g
!= NULL
; i
++, g
= g
->next
)
333 /**********************************************************************
338 GlobalLock(unsigned int block
)
342 if ((g
= GlobalGetGDesc(block
)) == NULL
)
348 printf("GlobalLock: returning %08x\n", g
->addr
);
353 /**********************************************************************
358 GlobalUnlock(unsigned int block
)
366 * Find GDESC for this block.
368 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
370 if (g
->handle
== block
&& g
->lock_count
> 0)
380 /**********************************************************************
385 GlobalFlags(unsigned int block
)
393 * Find GDESC for this block.
395 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
397 if (g
->handle
== block
)
398 return g
->lock_count
;
404 /**********************************************************************
409 GlobalSize(unsigned int block
)
411 GDESC
*g
= GlobalGetGDesc(block
);
416 if (g
->sequence
== 0)
418 MDESC
*m
= (MDESC
*) g
->addr
- 1;
422 else if (g
->sequence
>= 1)
424 return g
->length
* 0x10000;
430 /**********************************************************************
433 * This routine is not strictly correct. MS Windows creates a selector
434 * for every locked global block. We do not. If the allocation is small
435 * enough, we only give out a little piece of a selector. Thus this
436 * function cannot be implemented.
439 GlobalHandle(unsigned int selector
)
447 * Find GDESC for this block.
449 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
451 if (g
->handle
== selector
)
457 fprintf(stderr
, "Attempt to get a handle "
458 "from a selector to a far heap.\n");
467 /**********************************************************************
472 GlobalCompact(unsigned int desired
)
475 unsigned char free_map
[512];
476 unsigned int max_selector_used
= 0;
478 unsigned int selector
;
483 * Initialize free list to all items not controlled by GlobalAlloc()
485 for (i
= 0; i
< 512; i
++)
489 * Traverse table looking for used and free selectors.
491 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
494 * Check for free segments.
496 if (g
->sequence
== -1)
498 free_map
[g
->handle
>> 3] = 1;
499 if (g
->handle
> max_selector_used
)
500 max_selector_used
= g
->handle
;
504 * Check for heap allocated segments.
506 else if (g
->handle
== 0)
508 selector
= (unsigned int) g
->addr
>> 16;
509 free_map
[selector
>> 3] = 0;
510 if (selector
> max_selector_used
)
511 max_selector_used
= selector
;
516 * All segments past the biggest selector used are free.
518 for (i
= (max_selector_used
>> 3) + 1; i
< 512; i
++)
522 * Find the largest free block of segments
526 for (i
= 0; i
< 512; i
++)
528 if (free_map
[i
] == 1)
534 if (current_free
> max_free
)
535 max_free
= current_free
;
540 return max_free
<< 16;
543 /**********************************************************************
548 GlobalReAlloc(unsigned int block
, unsigned int new_size
, unsigned int flags
)
551 unsigned int n_segments
;
558 * Find GDESC for this block.
560 g
= GlobalGetGDesc(block
);
565 * If this is a heap allocated block, then use HEAP_ReAlloc() to
566 * reallocate the block. If this fails, call GlobalAlloc() to get
569 if (g
->sequence
== 0)
574 free_list
= (MDESC
**) ((unsigned int) g
->addr
& 0xffff0000);
575 p
= HEAP_ReAlloc(free_list
, g
->addr
, new_size
, flags
) ;
578 unsigned int handle
= GlobalAlloc(flags
, new_size
);
581 p
= GlobalLock(handle
);
582 memcpy(p
, g
->addr
, g
->length
);
583 GlobalUnlock(handle
);
584 GlobalFree(g
->handle
);
591 g
->length
= new_size
;
597 * Otherwise, we need to do the work ourselves. First verify the
602 if (g
->sequence
!= 1)
606 * Do we need more memory? Segments are in ascending order in
609 n_segments
= (new_size
>> 16) + 1;
610 if (n_segments
> g
->length
)
614 int old_segments
= g_start
->length
;
615 unsigned short next_handle
= g_start
->handle
;
617 for (i
= 1; i
<= n_segments
; i
++, g
= g
->next
)
620 * If we run into a block allocated to something else,
621 * try GlobalGetFreeSegments() and memcpy(). (Yuk!)
623 if (g
->sequence
!= i
|| g
->handle
!= next_handle
)
625 g
= GlobalGetFreeSegments(flags
, n_segments
);
629 memcpy(g
->addr
, g_start
->addr
,
630 g_start
->length
<< 16);
637 * Otherwise this block is used by us or free. So,
638 * snatch it. If this block is new and we are supposed to
639 * zero init, then do some erasing.
641 if (g
->sequence
== -1 && (flags
& GLOBAL_FLAGS_ZEROINIT
))
642 memset(g
->addr
, 0, 0x10000);
645 g
->length
= n_segments
;
649 * If the next descriptor is non-existant, then use
650 * GlobalGetFreeSegments to create them.
652 if (i
!= n_segments
&& g
->next
== NULL
)
654 g_new
= GlobalGetFreeSegments(flags
, n_segments
- i
);
657 GlobalFree(g_new
->handle
);
661 return g_start
->handle
;
665 * Do we need less memory?
667 else if (n_segments
< g
->length
)
670 int old_length
= g
->length
;
673 for (i
= 0; i
< n_segments
; i
++)
675 if (g_free
->sequence
!= i
+ 1)
677 g_free
->length
= n_segments
;
678 g_free
= g_free
->next
;
681 for ( ; i
< old_length
; i
++)
683 g_free
->length
= 0x10000;
684 g_free
->sequence
= -1;
685 g_free
= g_free
->next
;
692 * We already have exactly the right amount of memory.
699 * If we fall through it must be an error.
704 /**********************************************************************
708 GlobalQuickAlloc(int size
)
712 hmem
= GlobalAlloc(GLOBAL_FLAGS_MOVEABLE
, size
);
716 return GlobalLock(hmem
);
719 /**********************************************************************
720 * GlobalHandleFromPointer
724 GlobalHandleFromPointer(void *block
)
732 * Find GDESC for this block.
734 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
735 if (g
->handle
> 0 && g
->addr
== block
)
744 /**********************************************************************
745 * GetFreeSpace (kernel.169)
748 DWORD
GetFreeSpace(UINT wFlags
)
749 /* windows 3.1 doesn't use the wFlags parameter !!
750 (so I won't either) */
753 unsigned char free_map
[512];
754 unsigned int max_selector_used
= 0;
756 unsigned int selector
;
760 * Initialize free list to all items not controlled by GlobalAlloc()
762 for (i
= 0; i
< 512; i
++)
766 * Traverse table looking for used and free selectors.
768 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
771 * Check for free segments.
773 if (g
->sequence
== -1)
775 free_map
[g
->handle
>> 3] = 1;
776 if (g
->handle
> max_selector_used
)
777 max_selector_used
= g
->handle
;
781 * Check for heap allocated segments.
783 else if (g
->handle
== 0)
785 selector
= (unsigned int) g
->addr
>> 16;
786 free_map
[selector
>> 3] = 0;
787 if (selector
> max_selector_used
)
788 max_selector_used
= selector
;
793 * All segments past the biggest selector used are free.
795 for (i
= (max_selector_used
>> 3) + 1; i
< 512; i
++)
799 * Add up the total free segments (obviously this amount of memory
800 may not be contiguous, use GlobalCompact to get largest contiguous
804 for (i
= 0; i
< 512; i
++)
805 if (free_map
[i
] == 1)
808 printf("GetFreeSpace // return %ld !\n", total_free
<< 16);
809 return total_free
<< 16;
812 /**********************************************************************
813 * MemManInfo (toolhelp.72)
815 BOOL
MemManInfo(LPMEMMANINFO lpmmi
)