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 WIN16_GlobalAlloc(unsigned int flags
, unsigned long size
)
175 return GlobalAlloc(flags
& ~GLOBAL_FLAGS_MOVEABLE
, size
);
178 /**********************************************************************
182 GlobalAlloc(unsigned int flags
, unsigned long size
)
188 dprintf_heap(stddeb
,"GlobalAlloc flags %4X, size %ld\n", flags
, size
);
190 if (size
== 0) size
= 1;
193 * If this block is fixed or very big we need to allocate entire
196 if (size
> 0x8000 || !(flags
& GLOBAL_FLAGS_MOVEABLE
))
198 int segments
= ((size
- 1) >> 16) + 1;
200 g
= GlobalGetFreeSegments(flags
, segments
);
203 dprintf_heap(stddeb
, "==> NULL\n");
208 dprintf_heap(stddeb
, "==> %04x\n",g
->handle
);
213 * Otherwise we just need a little piece of a segment.
218 * Try to allocate from active free lists.
220 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
222 if (g
->handle
== 0 && g
->sequence
== 0)
224 m
= HEAP_Alloc((MDESC
**) g
->addr
, 0, size
);
231 * If we couldn't get the memory there, then we need to create
236 g
= GlobalGetFreeSegments(0, 1);
239 dprintf_heap(stddeb
, "==> Null\n");
245 HEAP_Init((MDESC
**) g
->addr
, (MDESC
**) g
->addr
+ 1,
246 0x10000 - sizeof(MDESC
**));
247 m
= HEAP_Alloc((MDESC
**) g
->addr
, flags
& GLOBAL_FLAGS_ZEROINIT
,
251 dprintf_heap(stddeb
, "==> Null\n");
257 * Save position of heap descriptor.
262 * We have a new block. Let's create a GDESC entry for it.
264 g
= malloc(sizeof(*g
));
265 dprintf_heap(stddeb
,"New GDESC %08x\n", (unsigned int) g
);
269 g
->handle
= next_unused_handle
;
273 g
->linear_addr
= NULL
;
277 g
->next
= g_prev
->next
;
278 if (g
->next
) g
->next
->prev
= g
;
284 next_unused_handle
++;
285 if ((next_unused_handle
& 7) == 7)
286 next_unused_handle
++;
288 dprintf_heap(stddeb
,"GlobalAlloc: returning %04x\n", g
->handle
);
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
>> 3] = 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
>> 3] = 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
>> 3) + 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 return max_free
<< 16;
556 /**********************************************************************
561 GlobalReAlloc(unsigned int block
, unsigned int new_size
, unsigned int flags
)
564 unsigned int n_segments
;
571 * Find GDESC for this block.
573 g
= GlobalGetGDesc(block
);
578 * If this is a heap allocated block, then use HEAP_ReAlloc() to
579 * reallocate the block. If this fails, call GlobalAlloc() to get
582 if (g
->sequence
== 0)
587 free_list
= (MDESC
**) ((unsigned int) g
->addr
& 0xffff0000);
588 p
= HEAP_ReAlloc(free_list
, g
->addr
, new_size
, flags
) ;
591 unsigned int handle
= GlobalAlloc(flags
, new_size
);
594 p
= GlobalLock(handle
);
595 memcpy(p
, g
->addr
, g
->length
);
596 GlobalUnlock(handle
);
597 GlobalFree(g
->handle
);
604 g
->length
= new_size
;
610 * Otherwise, we need to do the work ourselves. First verify the
615 if (g
->sequence
!= 1)
619 * Do we need more memory? Segments are in ascending order in
622 n_segments
= (new_size
>> 16) + 1;
623 if (n_segments
> g
->length
)
627 /* int old_segments = g_start->length;*/
628 unsigned short next_handle
= g_start
->handle
;
630 for (i
= 1; i
<= n_segments
; i
++, g
= g
->next
)
633 * If we run into a block allocated to something else,
634 * try GlobalGetFreeSegments() and memcpy(). (Yuk!)
636 if (g
->sequence
!= i
|| g
->handle
!= next_handle
)
638 g
= GlobalGetFreeSegments(flags
, n_segments
);
642 memcpy(g
->addr
, g_start
->addr
,
643 g_start
->length
<< 16);
650 * Otherwise this block is used by us or free. So,
651 * snatch it. If this block is new and we are supposed to
652 * zero init, then do some erasing.
654 if (g
->sequence
== -1 && (flags
& GLOBAL_FLAGS_ZEROINIT
))
655 memset(g
->addr
, 0, 0x10000);
658 g
->length
= n_segments
;
662 * If the next descriptor is non-existant, then use
663 * GlobalGetFreeSegments to create them.
665 if (i
!= n_segments
&& g
->next
== NULL
)
667 g_new
= GlobalGetFreeSegments(flags
, n_segments
- i
);
670 GlobalFree(g_new
->handle
);
674 return g_start
->handle
;
678 * Do we need less memory?
680 else if (n_segments
< g
->length
)
683 int old_length
= g
->length
;
686 for (i
= 0; i
< n_segments
; i
++)
688 if (g_free
->sequence
!= i
+ 1)
690 g_free
->length
= n_segments
;
691 g_free
= g_free
->next
;
694 for ( ; i
< old_length
; i
++)
696 g_free
->length
= 0x10000;
697 g_free
->sequence
= -1;
698 g_free
= g_free
->next
;
705 * We already have exactly the right amount of memory.
712 * If we fall through it must be an error.
717 /**********************************************************************
721 GlobalQuickAlloc(int size
)
725 hmem
= GlobalAlloc(GLOBAL_FLAGS_MOVEABLE
, size
);
729 return GlobalLock(hmem
);
732 /**********************************************************************
733 * GlobalHandleFromPointer
737 GlobalHandleFromPointer(void *block
)
745 * Find GDESC for this block.
747 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
748 if (g
->handle
> 0 && g
->addr
== block
)
757 /**********************************************************************
758 * GetFreeSpace (kernel.169)
761 DWORD
GetFreeSpace(UINT wFlags
)
762 /* windows 3.1 doesn't use the wFlags parameter !!
763 (so I won't either) */
766 unsigned char free_map
[512];
767 unsigned int max_selector_used
= 0;
769 unsigned int selector
;
773 * Initialize free list to all items not controlled by GlobalAlloc()
775 for (i
= 0; i
< 512; i
++)
779 * Traverse table looking for used and free selectors.
781 for (g
= GlobalList
; g
!= NULL
; g
= g
->next
)
784 * Check for free segments.
786 if (g
->sequence
== -1)
788 free_map
[g
->handle
>> 3] = 1;
789 if (g
->handle
> max_selector_used
)
790 max_selector_used
= g
->handle
;
794 * Check for heap allocated segments.
796 else if (g
->handle
== 0)
798 selector
= (unsigned int) g
->addr
>> 16;
799 free_map
[selector
>> 3] = 0;
800 if (selector
> max_selector_used
)
801 max_selector_used
= selector
;
806 * All segments past the biggest selector used are free.
808 for (i
= (max_selector_used
>> 3) + 1; i
< 512; i
++)
812 * Add up the total free segments (obviously this amount of memory
813 may not be contiguous, use GlobalCompact to get largest contiguous
817 for (i
= 0; i
< 512; i
++)
818 if (free_map
[i
] == 1)
821 dprintf_heap(stddeb
,"GetFreeSpace // return %ld !\n", (long) (total_free
<< 16));
822 return total_free
<< 16;
825 /**********************************************************************
826 * MemManInfo (toolhelp.72)
828 BOOL
MemManInfo(LPMEMMANINFO lpmmi
)
833 /***********************************************************************
834 * SetSwapAreaSize (KERNEL.106)
836 LONG
SetSwapAreaSize( WORD size
)
838 dprintf_heap(stdnimp
, "STUB: SetSwapAreaSize(%d)\n", size
);
839 return MAKELONG( size
, 0xffff );
842 /***********************************************************************
843 * IsBadCodePtr (KERNEL.336)
845 BOOL
IsBadCodePtr( FARPROC lpfn
)
847 printf( "STUB: IsBadCodePtr(%p)\n", lpfn
);
851 /***********************************************************************
852 * IsBadHugeWritePtr (KERNEL.347)
854 BOOL
IsBadHugeWritePtr( const char *lp
, DWORD cb
)
856 return !test_memory(&lp
[cb
-1], TRUE
);
859 /***********************************************************************
860 * IsBadWritePtr (KERNEL.335)
862 BOOL
IsBadWritePtr( const char *lp
, DWORD cb
)
864 if ((0xffff & (unsigned int) lp
) + cb
> 0xffff)
866 return !test_memory(&lp
[cb
-1], TRUE
);
869 /***********************************************************************
870 * IsBadReadPtr (KERNEL.334)
872 BOOL
IsBadReadPtr( const char *lp
, DWORD cb
)
874 if ((0xffff & (unsigned int) lp
) + cb
> 0xffff)
876 return !test_memory(&lp
[cb
-1], FALSE
);
879 /***********************************************************************
880 * IsBadHugeReadPtr (KERNEL.346)
882 BOOL
IsBadHugeReadPtr( const char *lp
, DWORD cb
)
884 if ((0xffff & (unsigned int) lp
) + cb
> 0xffff)
886 return !test_memory(&lp
[cb
-1], FALSE
);
889 /***********************************************************************
890 * IsBadStringPtr (KERNEL.337)
892 BOOL
IsBadStringPtr( const char *lp
, UINT cb
)
894 if (!IsBadReadPtr(lp
, cb
+1))