Release 950216
[wine.git] / memory / global.c
bloba3e5eb73735bd071e3b198fdf09daa933e6ad2e8
1 /*
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";
4 */
6 #define GLOBAL_SOURCE
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include "windows.h"
12 #include "prototypes.h"
13 #include "toolhelp.h"
14 #include "heap.h"
15 #include "segmem.h"
16 #include "selectors.h"
17 #include "stddebug.h"
18 /* #define DEBUG_HEAP */
19 #include "debug.h"
22 GDESC *GlobalList = NULL;
23 static unsigned short next_unused_handle = 1;
25 /**********************************************************************
26 * GlobalGetGDesc
28 GDESC *GlobalGetGDesc(unsigned int block)
30 GDESC *g;
32 if (block == 0)
33 return NULL;
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)
42 break;
44 else
46 for (g = GlobalList; g != NULL; g = g->next)
47 if (g->handle == block)
48 break;
51 return g;
54 /**********************************************************************
55 * GlobalGetFreeSegments
57 GDESC *
58 GlobalGetFreeSegments(unsigned int flags, int n_segments)
60 struct segment_descriptor_s *s;
61 GDESC *g;
62 GDESC *g_start;
63 GDESC *g_prev;
64 int count, i;
67 * Try to find some empty segments in our list.
69 count = 0;
70 for (g = GlobalList; g != NULL && count != n_segments; g = g->next)
72 if ((int) g->sequence == -1)
74 if (count > 0)
76 if (g->prev->handle + 8 != g->handle)
77 count = 0;
78 else
79 count++;
81 else
83 g_start = g;
84 count = 1;
87 else if (count)
88 count = 0;
92 * If we couldn't find enough segments, then we need to create some.
94 if (count != n_segments)
97 * Find list tail.
99 g_prev = NULL;
100 for (g = GlobalList; g != NULL; g = g->next)
101 g_prev = g;
104 * Allocate segments.
106 s = CreateNewSegments(0, 0, 0x10000, n_segments);
107 if (s == NULL)
109 fprintf(stderr,"GlobalGetFreeSegments // bad CreateNewSegments !\n");
110 return NULL;
112 for (count = 0; count < n_segments; count++, s++)
114 g = (GDESC *) malloc(sizeof(*g));
115 if (g == NULL)
117 fprintf(stderr,"GlobalGetFreeSegments // bad GDESC malloc !\n");
118 return NULL;
120 g->prev = g_prev;
121 g->next = NULL;
122 g->handle = s->selector;
123 g->sequence = -1;
124 g->addr = s->base_addr;
125 g->length = s->length;
126 g->alias = 0;
127 g->linear_addr = NULL;
128 g->linear_key = 0;
129 g->linear_count = 0;
130 if (!(flags & GLOBAL_FLAGS_MOVEABLE))
131 g->lock_count = 1;
132 else
133 g->lock_count = 0;
135 if (count == 0) g_start = g;
137 if (g_prev != NULL)
139 g_prev->next = g;
141 else
142 GlobalList = g;
143 g_prev = g;
148 * We have all of the segments we need. Let's adjust their contents.
150 g = g_start;
151 for (i = 0; i < n_segments; i++, g = g->next)
153 if (g == NULL)
155 fprintf(stderr,"GlobalGetFreeSegments // bad Segments chain !\n");
156 return NULL;
158 g->sequence = i + 1;
159 g->length = n_segments;
160 g->alias = 0;
161 g->linear_addr = NULL;
162 g->linear_key = 0;
163 g->linear_count = 0;
166 return g_start;
169 /**********************************************************************
170 * GlobalAlloc
172 HANDLE
173 GlobalAlloc(unsigned int flags, unsigned long size)
175 GDESC *g;
176 GDESC *g_prev;
177 void *m;
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
185 * segments.
187 if (size > 0x8000 || !(flags & GLOBAL_FLAGS_MOVEABLE))
189 int segments = ((size - 1) >> 16) + 1;
191 g = GlobalGetFreeSegments(flags, segments);
192 if (g == NULL)
194 dprintf_heap(stddeb, "==> NULL\n");
195 return 0;
197 else
199 dprintf_heap(stddeb, "==> %04x\n",g->handle);
200 return g->handle;
204 * Otherwise we just need a little piece of a segment.
206 else
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);
216 if (m != NULL)
217 break;
222 * If we couldn't get the memory there, then we need to create
223 * a new free list.
225 if (g == NULL)
227 g = GlobalGetFreeSegments(0, 1);
228 if (g == NULL)
230 dprintf_heap(stddeb, "==> Null\n");
231 return 0;
234 g->handle = 0;
235 g->sequence = 0;
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,
239 size);
240 if (m == NULL)
242 dprintf_heap(stddeb, "==> Null\n");
243 return 0;
248 * Save position of heap descriptor.
250 g_prev = g;
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);
257 if (g == NULL)
258 return 0;
260 g->handle = next_unused_handle;
261 g->sequence = 0;
262 g->addr = m;
263 g->alias = 0;
264 g->linear_addr = NULL;
265 g->linear_key = 0;
266 g->linear_count = 0;
267 g->length = size;
268 g->next = g_prev->next;
269 if (g->next) g->next->prev = g;
270 g->lock_count = 0;
272 g_prev->next = g;
273 g->prev = g_prev;
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);
280 return g->handle;
284 /**********************************************************************
285 * WIN16_GlobalAlloc
287 HANDLE
288 WIN16_GlobalAlloc(unsigned int flags, unsigned long size)
290 return GlobalAlloc(flags & ~GLOBAL_FLAGS_MOVEABLE, size);
293 /**********************************************************************
294 * GlobalFree
296 * Windows programs will pass a handle in the "block" parameter, but
297 * this function will also accept a 32-bit address.
299 HANDLE
300 GlobalFree(unsigned int block)
302 GDESC *g;
304 if (block == 0)
305 return 0;
308 * Find GDESC for this block.
310 g = GlobalGetGDesc(block);
311 if (g == NULL)
312 return 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;
324 if (g->next != NULL)
325 g->next->prev = g->prev;
327 free(g);
331 * Otherwise just mark these descriptors as free.
333 else
335 int i, limit;
337 limit = g->length;
338 for (i = g->sequence - 1; i < limit && g != NULL; i++, g = g->next)
340 g->sequence = -1;
341 g->length = 0x10000;
345 return 0;
348 /**********************************************************************
349 * GlobalLock
352 void *
353 GlobalLock(unsigned int block)
355 GDESC *g;
357 if ((g = GlobalGetGDesc(block)) == NULL)
358 return 0;
360 g->lock_count++;
362 dprintf_heap(stddeb,"GlobalLock: returning %08x\n",(unsigned int)g->addr);
363 return g->addr;
366 /**********************************************************************
367 * GlobalUnlock
371 GlobalUnlock(unsigned int block)
373 GDESC *g;
375 if (block == 0)
376 return 0;
379 * Find GDESC for this block.
381 for (g = GlobalList; g != NULL; g = g->next)
383 if (g->handle == block && g->lock_count > 0)
385 g->lock_count--;
386 return 0;
390 return 1;
393 /**********************************************************************
394 * GlobalFlags
397 unsigned int
398 GlobalFlags(unsigned int block)
400 GDESC *g;
402 if (block == 0)
403 return 0;
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;
414 return 0;
417 /**********************************************************************
418 * GlobalSize
421 unsigned int
422 GlobalSize(unsigned int block)
424 GDESC *g = GlobalGetGDesc(block);
426 if (g == NULL)
427 return 0;
429 if (g->sequence == 0)
431 MDESC *m = (MDESC *) g->addr - 1;
433 return m->length;
435 else if (g->sequence >= 1)
437 return g->length * 0x10000;
440 return g->length;
443 /**********************************************************************
444 * GlobalHandle
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.
451 unsigned int
452 GlobalHandle(unsigned int selector)
454 GDESC *g;
456 if (selector == 0)
457 return 0;
460 * Find GDESC for this block.
462 for (g = GlobalList; g != NULL; g = g->next)
464 if (g->handle == selector)
466 if (g->sequence > 0)
467 return MAKELONG(g->handle, selector);
468 else
470 fprintf(stderr, "Attempt to get a handle "
471 "from a selector to a far heap.\n");
472 return 0;
476 dprintf_heap(stddeb, "GlobalHandle ==> Null\n");
477 return 0;
480 /**********************************************************************
481 * GlobalCompact
484 unsigned int
485 GlobalCompact(unsigned int desired)
487 GDESC *g;
488 unsigned char free_map[512];
489 unsigned int max_selector_used = 0;
490 unsigned int i;
491 unsigned int selector;
492 int current_free;
493 int max_free;
496 * Initialize free list to all items not controlled by GlobalAlloc()
498 for (i = 0; i < 512; i++)
499 free_map[i] = -1;
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++)
532 free_map[i] = 1;
535 * Find the largest free block of segments
537 current_free = 0;
538 max_free = 0;
539 for (i = 0; i < 512; i++)
541 if (free_map[i] == 1)
543 current_free++;
545 else
547 if (current_free > max_free)
548 max_free = current_free;
549 current_free = 0;
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 /**********************************************************************
564 * GlobalReAlloc
567 unsigned int
568 GlobalReAlloc(unsigned int block, unsigned int new_size, unsigned int flags)
570 GDESC *g;
571 unsigned int n_segments;
572 int i;
574 if (block == 0)
575 return 0;
578 * Find GDESC for this block.
580 g = GlobalGetGDesc(block);
581 if (g == NULL)
582 return 0;
585 * If this is a heap allocated block, then use HEAP_ReAlloc() to
586 * reallocate the block. If this fails, call GlobalAlloc() to get
587 * a new block.
589 if (g->sequence == 0)
591 MDESC **free_list;
592 void *p;
594 free_list = (MDESC **) ((unsigned int) g->addr & 0xffff0000);
595 p = HEAP_ReAlloc(free_list, g->addr, new_size, flags) ;
596 if (p == NULL)
598 unsigned int handle = GlobalAlloc(flags, new_size);
599 if (handle == 0)
600 return 0;
601 p = GlobalLock(handle);
602 memcpy(p, g->addr, g->length);
603 GlobalUnlock(handle);
604 GlobalFree(g->handle);
606 return handle;
608 else
610 g->addr = p;
611 g->length = new_size;
612 return g->handle;
617 * Otherwise, we need to do the work ourselves. First verify the
618 * handle.
620 else
622 if (g->sequence != 1)
623 return 0;
626 * Do we need more memory? Segments are in ascending order in
627 * the GDESC list.
629 n_segments = (new_size >> 16) + 1;
630 if (n_segments > g->length)
632 GDESC *g_new;
633 GDESC *g_start = g;
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);
646 if (g == NULL)
647 return 0;
649 memcpy(g->addr, g_start->addr,
650 g_start->length << 16);
652 GlobalFree(block);
653 return g->handle;
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);
664 g->sequence = i;
665 g->length = n_segments;
666 next_handle += 8;
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);
675 if (g_new == NULL)
676 return 0;
677 GlobalFree(g_new->handle);
681 return g_start->handle;
685 * Do we need less memory?
687 else if (n_segments < g->length)
689 GDESC *g_free;
690 int old_length = g->length;
692 g_free = g;
693 for (i = 0; i < n_segments; i++)
695 if (g_free->sequence != i + 1)
696 return 0;
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;
708 return g->handle;
712 * We already have exactly the right amount of memory.
714 else
715 return block;
719 * If we fall through it must be an error.
721 return 0;
724 /**********************************************************************
725 * GlobalQuickAlloc
727 void *
728 GlobalQuickAlloc(int size)
730 unsigned int hmem;
732 hmem = GlobalAlloc(GLOBAL_FLAGS_MOVEABLE, size);
733 if (hmem == 0)
734 return NULL;
735 else
736 return GlobalLock(hmem);
739 /**********************************************************************
740 * GlobalHandleFromPointer
743 unsigned int
744 GlobalHandleFromPointer(void *block)
746 GDESC *g;
748 if (block == NULL)
749 return 0;
752 * Find GDESC for this block.
754 for (g = GlobalList; g != NULL; g = g->next)
755 if (g->handle > 0 && g->addr == block)
756 break;
758 if (g == NULL)
759 return 0;
760 else
761 return g->handle;
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) */
772 GDESC *g;
773 unsigned char free_map[512];
774 unsigned int max_selector_used = 0;
775 unsigned int i;
776 unsigned int selector;
777 int total_free;
780 * Initialize free list to all items not controlled by GlobalAlloc()
782 for (i = 0; i < 512; i++)
783 free_map[i] = -1;
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++)
816 free_map[i] = 1;
819 * Add up the total free segments (obviously this amount of memory
820 may not be contiguous, use GlobalCompact to get largest contiguous
821 memory available).
823 total_free=0;
824 for (i = 0; i < 512; i++)
825 if (free_map[i] == 1)
826 total_free++;
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)
837 return 1;
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 );
855 return FALSE;
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)
872 return TRUE;
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)
882 return TRUE;
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)
892 return TRUE;
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))
902 return FALSE;
903 if (lp[cb])
904 return FALSE;
905 return TRUE;