2 static char RCSId[] = "$Id: global.c,v 1.2 1993/07/04 04:04:21 root Exp root $";
3 static char Copyright[] = "Copyright Robert J. Amstadt, 1993";
12 #include "prototypes.h"
16 #include "selectors.h"
18 /* #define DEBUG_HEAP */
22 GDESC
*GlobalList
= NULL
;
23 static unsigned short next_unused_handle
= 1;
25 /**********************************************************************
28 GDESC
*GlobalGetGDesc(unsigned int block
)
36 * Find GDESC for this block.
38 if (block
& 0xffff0000)
40 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
41 if (g
->handle
> 0 && (unsigned int) g
->addr
== block
)
46 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
47 if (g
->handle
== block
)
54 /**********************************************************************
55 * GlobalGetFreeSegments
58 GlobalGetFreeSegments(unsigned int flags
, int n_segments
)
60 struct segment_descriptor_s
*s
;
67 * Try to find some empty segments in our list.
70 for (g
= GlobalList
; g
!= NULL
&& count
!= n_segments
; g
= g
->next
)
72 if ((int) g
->sequence
== -1)
76 if (g
->prev
->handle
+ 8 != g
->handle
)
92 * If we couldn't find enough segments, then we need to create some.
94 if (count
!= n_segments
)
100 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
106 s
= CreateNewSegments(0, 0, 0x10000, n_segments
);
109 fprintf(stderr
,"GlobalGetFreeSegments // bad CreateNewSegments !\n");
112 for (count
= 0; count
< n_segments
; count
++, s
++)
114 g
= (GDESC
*) malloc(sizeof(*g
));
117 fprintf(stderr
,"GlobalGetFreeSegments // bad GDESC malloc !\n");
122 g
->handle
= s
->selector
;
124 g
->addr
= s
->base_addr
;
125 g
->length
= s
->length
;
127 g
->linear_addr
= NULL
;
130 if (!(flags
& GLOBAL_FLAGS_MOVEABLE
))
135 if (count
== 0) g_start
= g
;
148 * We have all of the segments we need. Let's adjust their contents.
151 for (i
= 0; i
< n_segments
; i
++, g
= g
->next
)
155 fprintf(stderr
,"GlobalGetFreeSegments // bad Segments chain !\n");
159 g
->length
= n_segments
;
161 g
->linear_addr
= NULL
;
169 /**********************************************************************
173 GlobalAlloc(unsigned int flags
, unsigned long size
)
179 dprintf_heap(stddeb
,"GlobalAlloc flags %4X, size %ld\n", flags
, size
);
181 if (size
== 0) size
= 1;
184 * If this block is fixed or very big we need to allocate entire
187 if (size
> 0x8000 || !(flags
& GLOBAL_FLAGS_MOVEABLE
))
189 int segments
= ((size
- 1) >> 16) + 1;
191 g
= GlobalGetFreeSegments(flags
, segments
);
194 dprintf_heap(stddeb
, "==> NULL\n");
199 dprintf_heap(stddeb
, "==> %04x\n",g
->handle
);
204 * Otherwise we just need a little piece of a segment.
209 * Try to allocate from active free lists.
211 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
213 if (g
->handle
== 0 && g
->sequence
== 0)
215 m
= HEAP_Alloc((MDESC
**) g
->addr
, 0, size
);
222 * If we couldn't get the memory there, then we need to create
227 g
= GlobalGetFreeSegments(0, 1);
230 dprintf_heap(stddeb
, "==> Null\n");
236 HEAP_Init((MDESC
**) g
->addr
, (MDESC
**) g
->addr
+ 1,
237 0x10000 - sizeof(MDESC
**));
238 m
= HEAP_Alloc((MDESC
**) g
->addr
, flags
& GLOBAL_FLAGS_ZEROINIT
,
242 dprintf_heap(stddeb
, "==> Null\n");
248 * Save position of heap descriptor.
253 * We have a new block. Let's create a GDESC entry for it.
255 g
= malloc(sizeof(*g
));
256 dprintf_heap(stddeb
,"New GDESC %08x\n", (unsigned int) g
);
260 g
->handle
= next_unused_handle
;
264 g
->linear_addr
= NULL
;
268 g
->next
= g_prev
->next
;
269 if (g
->next
) g
->next
->prev
= g
;
275 next_unused_handle
++;
276 if ((next_unused_handle
& 7) == 7)
277 next_unused_handle
++;
279 dprintf_heap(stddeb
,"GlobalAlloc: returning %04x\n", g
->handle
);
284 /**********************************************************************
288 WIN16_GlobalAlloc(unsigned int flags
, unsigned long size
)
290 return GlobalAlloc(flags
& ~GLOBAL_FLAGS_MOVEABLE
, size
);
293 /**********************************************************************
296 * Windows programs will pass a handle in the "block" parameter, but
297 * this function will also accept a 32-bit address.
300 GlobalFree(unsigned int block
)
308 * Find GDESC for this block.
310 g
= GlobalGetGDesc(block
);
315 * If the sequence number is zero then use HEAP_Free to deallocate
316 * memory, and throw away this descriptor.
318 if (g
->sequence
== 0)
320 HEAP_Free((MDESC
**) ((int) g
->addr
& 0xffff0000), (void *) g
->addr
);
322 g
->prev
->next
= g
->next
;
325 g
->next
->prev
= g
->prev
;
331 * Otherwise just mark these descriptors as free.
338 for (i
= g
->sequence
- 1; i
< limit
&& g
!= NULL
; i
++, g
= g
->next
)
348 /**********************************************************************
353 GlobalLock(unsigned int block
)
357 if ((g
= GlobalGetGDesc(block
)) == NULL
)
362 dprintf_heap(stddeb
,"GlobalLock: returning %08x\n",(unsigned int)g
->addr
);
366 /**********************************************************************
371 GlobalUnlock(unsigned int block
)
379 * Find GDESC for this block.
381 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
383 if (g
->handle
== block
&& g
->lock_count
> 0)
393 /**********************************************************************
398 GlobalFlags(unsigned int block
)
406 * Find GDESC for this block.
408 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
410 if (g
->handle
== block
)
411 return g
->lock_count
;
417 /**********************************************************************
422 GlobalSize(unsigned int block
)
424 GDESC
*g
= GlobalGetGDesc(block
);
429 if (g
->sequence
== 0)
431 MDESC
*m
= (MDESC
*) g
->addr
- 1;
435 else if (g
->sequence
>= 1)
437 return g
->length
* 0x10000;
443 /**********************************************************************
446 * This routine is not strictly correct. MS Windows creates a selector
447 * for every locked global block. We do not. If the allocation is small
448 * enough, we only give out a little piece of a selector. Thus this
449 * function cannot be implemented.
452 GlobalHandle(unsigned int selector
)
460 * Find GDESC for this block.
462 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
464 if (g
->handle
== selector
)
467 return MAKELONG(g
->handle
, selector
);
470 fprintf(stderr
, "Attempt to get a handle "
471 "from a selector to a far heap.\n");
476 dprintf_heap(stddeb
, "GlobalHandle ==> Null\n");
480 /**********************************************************************
485 GlobalCompact(unsigned int desired
)
488 unsigned char free_map
[512];
489 unsigned int max_selector_used
= 0;
491 unsigned int selector
;
496 * Initialize free list to all items not controlled by GlobalAlloc()
498 for (i
= 0; i
< 512; i
++)
502 * Traverse table looking for used and free selectors.
504 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
507 * Check for free segments.
509 if (g
->sequence
== -1)
511 free_map
[g
->handle
>> __AHSHIFT
] = 1;
512 if (g
->handle
> max_selector_used
)
513 max_selector_used
= g
->handle
;
517 * Check for heap allocated segments.
519 else if (g
->handle
== 0)
521 selector
= (unsigned int) g
->addr
>> 16;
522 free_map
[selector
>> __AHSHIFT
] = 0;
523 if (selector
> max_selector_used
)
524 max_selector_used
= selector
;
529 * All segments past the biggest selector used are free.
531 for (i
= (max_selector_used
>> __AHSHIFT
) + 1; i
< 512; i
++)
535 * Find the largest free block of segments
539 for (i
= 0; i
< 512; i
++)
541 if (free_map
[i
] == 1)
547 if (current_free
> max_free
)
548 max_free
= current_free
;
553 /* One final check just in case the last block was also marked free, in
554 * which case the above test against max_free doesn't occur for the
555 * last run of free blocks.
557 if (current_free
> max_free
)
558 max_free
= current_free
;
560 return max_free
<< 16;
563 /**********************************************************************
568 GlobalReAlloc(unsigned int block
, unsigned int new_size
, unsigned int flags
)
571 unsigned int n_segments
;
578 * Find GDESC for this block.
580 g
= GlobalGetGDesc(block
);
585 * If this is a heap allocated block, then use HEAP_ReAlloc() to
586 * reallocate the block. If this fails, call GlobalAlloc() to get
589 if (g
->sequence
== 0)
594 free_list
= (MDESC
**) ((unsigned int) g
->addr
& 0xffff0000);
595 p
= HEAP_ReAlloc(free_list
, g
->addr
, new_size
, flags
) ;
598 unsigned int handle
= GlobalAlloc(flags
, new_size
);
601 p
= GlobalLock(handle
);
602 memcpy(p
, g
->addr
, g
->length
);
603 GlobalUnlock(handle
);
604 GlobalFree(g
->handle
);
611 g
->length
= new_size
;
617 * Otherwise, we need to do the work ourselves. First verify the
622 if (g
->sequence
!= 1)
626 * Do we need more memory? Segments are in ascending order in
629 n_segments
= (new_size
>> 16) + 1;
630 if (n_segments
> g
->length
)
634 /* int old_segments = g_start->length;*/
635 unsigned short next_handle
= g_start
->handle
;
637 for (i
= 1; i
<= n_segments
; i
++, g
= g
->next
)
640 * If we run into a block allocated to something else,
641 * try GlobalGetFreeSegments() and memcpy(). (Yuk!)
643 if (g
->sequence
!= i
|| g
->handle
!= next_handle
)
645 g
= GlobalGetFreeSegments(flags
, n_segments
);
649 memcpy(g
->addr
, g_start
->addr
,
650 g_start
->length
<< 16);
657 * Otherwise this block is used by us or free. So,
658 * snatch it. If this block is new and we are supposed to
659 * zero init, then do some erasing.
661 if (g
->sequence
== -1 && (flags
& GLOBAL_FLAGS_ZEROINIT
))
662 memset(g
->addr
, 0, 0x10000);
665 g
->length
= n_segments
;
669 * If the next descriptor is non-existant, then use
670 * GlobalGetFreeSegments to create them.
672 if (i
!= n_segments
&& g
->next
== NULL
)
674 g_new
= GlobalGetFreeSegments(flags
, n_segments
- i
);
677 GlobalFree(g_new
->handle
);
681 return g_start
->handle
;
685 * Do we need less memory?
687 else if (n_segments
< g
->length
)
690 int old_length
= g
->length
;
693 for (i
= 0; i
< n_segments
; i
++)
695 if (g_free
->sequence
!= i
+ 1)
697 g_free
->length
= n_segments
;
698 g_free
= g_free
->next
;
701 for ( ; i
< old_length
; i
++)
703 g_free
->length
= 0x10000;
704 g_free
->sequence
= -1;
705 g_free
= g_free
->next
;
712 * We already have exactly the right amount of memory.
719 * If we fall through it must be an error.
724 /**********************************************************************
728 GlobalQuickAlloc(int size
)
732 hmem
= GlobalAlloc(GLOBAL_FLAGS_MOVEABLE
, size
);
736 return GlobalLock(hmem
);
739 /**********************************************************************
740 * GlobalHandleFromPointer
744 GlobalHandleFromPointer(void *block
)
752 * Find GDESC for this block.
754 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
755 if (g
->handle
> 0 && g
->addr
== block
)
764 /**********************************************************************
765 * GetFreeSpace (kernel.169)
768 DWORD
GetFreeSpace(UINT wFlags
)
769 /* windows 3.1 doesn't use the wFlags parameter !!
770 (so I won't either) */
773 unsigned char free_map
[512];
774 unsigned int max_selector_used
= 0;
776 unsigned int selector
;
780 * Initialize free list to all items not controlled by GlobalAlloc()
782 for (i
= 0; i
< 512; i
++)
786 * Traverse table looking for used and free selectors.
788 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
791 * Check for free segments.
793 if (g
->sequence
== -1)
795 free_map
[g
->handle
>> __AHSHIFT
] = 1;
796 if (g
->handle
> max_selector_used
)
797 max_selector_used
= g
->handle
;
801 * Check for heap allocated segments.
803 else if (g
->handle
== 0)
805 selector
= (unsigned int) g
->addr
>> 16;
806 free_map
[selector
>> __AHSHIFT
] = 0;
807 if (selector
> max_selector_used
)
808 max_selector_used
= selector
;
813 * All segments past the biggest selector used are free.
815 for (i
= (max_selector_used
>> __AHSHIFT
) + 1; i
< 512; i
++)
819 * Add up the total free segments (obviously this amount of memory
820 may not be contiguous, use GlobalCompact to get largest contiguous
824 for (i
= 0; i
< 512; i
++)
825 if (free_map
[i
] == 1)
828 dprintf_heap(stddeb
,"GetFreeSpace // return %ld !\n", (long) (total_free
<< 16));
829 return total_free
<< 16;
832 /**********************************************************************
833 * MemManInfo (toolhelp.72)
835 BOOL
MemManInfo(LPMEMMANINFO lpmmi
)
840 /***********************************************************************
841 * SetSwapAreaSize (KERNEL.106)
843 LONG
SetSwapAreaSize( WORD size
)
845 dprintf_heap(stdnimp
, "STUB: SetSwapAreaSize(%d)\n", size
);
846 return MAKELONG( size
, 0xffff );
849 /***********************************************************************
850 * IsBadCodePtr (KERNEL.336)
852 BOOL
IsBadCodePtr( FARPROC lpfn
)
854 printf( "STUB: IsBadCodePtr(%p)\n", lpfn
);
858 /***********************************************************************
859 * IsBadHugeWritePtr (KERNEL.347)
861 BOOL
IsBadHugeWritePtr( const char *lp
, DWORD cb
)
863 return !test_memory(&lp
[cb
-1], TRUE
);
866 /***********************************************************************
867 * IsBadWritePtr (KERNEL.335)
869 BOOL
IsBadWritePtr( const char *lp
, DWORD cb
)
871 if ((0xffff & (unsigned int) lp
) + cb
> 0xffff)
873 return !test_memory(&lp
[cb
-1], TRUE
);
876 /***********************************************************************
877 * IsBadReadPtr (KERNEL.334)
879 BOOL
IsBadReadPtr( const char *lp
, DWORD cb
)
881 if ((0xffff & (unsigned int) lp
) + cb
> 0xffff)
883 return !test_memory(&lp
[cb
-1], FALSE
);
886 /***********************************************************************
887 * IsBadHugeReadPtr (KERNEL.346)
889 BOOL
IsBadHugeReadPtr( const char *lp
, DWORD cb
)
891 if ((0xffff & (unsigned int) lp
) + cb
> 0xffff)
893 return !test_memory(&lp
[cb
-1], FALSE
);
896 /***********************************************************************
897 * IsBadStringPtr (KERNEL.337)
899 BOOL
IsBadStringPtr( const char *lp
, UINT cb
)
901 if (!IsBadReadPtr(lp
, cb
+1))