Release 941210
[wine/multimedia.git] / memory / global.c
blobe6b0f007ce0d7172f7040d9aa10db4409241812c
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 * WIN16_GlobalAlloc
172 HANDLE
173 WIN16_GlobalAlloc(unsigned int flags, unsigned long size)
175 return GlobalAlloc(flags & ~GLOBAL_FLAGS_MOVEABLE, size);
178 /**********************************************************************
179 * GlobalAlloc
181 HANDLE
182 GlobalAlloc(unsigned int flags, unsigned long size)
184 GDESC *g;
185 GDESC *g_prev;
186 void *m;
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
194 * segments.
196 if (size > 0x8000 || !(flags & GLOBAL_FLAGS_MOVEABLE))
198 int segments = ((size - 1) >> 16) + 1;
200 g = GlobalGetFreeSegments(flags, segments);
201 if (g == NULL)
203 dprintf_heap(stddeb, "==> NULL\n");
204 return 0;
206 else
208 dprintf_heap(stddeb, "==> %04x\n",g->handle);
209 return g->handle;
213 * Otherwise we just need a little piece of a segment.
215 else
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);
225 if (m != NULL)
226 break;
231 * If we couldn't get the memory there, then we need to create
232 * a new free list.
234 if (g == NULL)
236 g = GlobalGetFreeSegments(0, 1);
237 if (g == NULL)
239 dprintf_heap(stddeb, "==> Null\n");
240 return 0;
243 g->handle = 0;
244 g->sequence = 0;
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,
248 size);
249 if (m == NULL)
251 dprintf_heap(stddeb, "==> Null\n");
252 return 0;
257 * Save position of heap descriptor.
259 g_prev = g;
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);
266 if (g == NULL)
267 return 0;
269 g->handle = next_unused_handle;
270 g->sequence = 0;
271 g->addr = m;
272 g->alias = 0;
273 g->linear_addr = NULL;
274 g->linear_key = 0;
275 g->linear_count = 0;
276 g->length = size;
277 g->next = g_prev->next;
278 if (g->next) g->next->prev = g;
279 g->lock_count = 0;
281 g_prev->next = g;
282 g->prev = g_prev;
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);
289 return g->handle;
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 >> 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++)
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 return max_free << 16;
556 /**********************************************************************
557 * GlobalReAlloc
560 unsigned int
561 GlobalReAlloc(unsigned int block, unsigned int new_size, unsigned int flags)
563 GDESC *g;
564 unsigned int n_segments;
565 int i;
567 if (block == 0)
568 return 0;
571 * Find GDESC for this block.
573 g = GlobalGetGDesc(block);
574 if (g == NULL)
575 return 0;
578 * If this is a heap allocated block, then use HEAP_ReAlloc() to
579 * reallocate the block. If this fails, call GlobalAlloc() to get
580 * a new block.
582 if (g->sequence == 0)
584 MDESC **free_list;
585 void *p;
587 free_list = (MDESC **) ((unsigned int) g->addr & 0xffff0000);
588 p = HEAP_ReAlloc(free_list, g->addr, new_size, flags) ;
589 if (p == NULL)
591 unsigned int handle = GlobalAlloc(flags, new_size);
592 if (handle == 0)
593 return 0;
594 p = GlobalLock(handle);
595 memcpy(p, g->addr, g->length);
596 GlobalUnlock(handle);
597 GlobalFree(g->handle);
599 return handle;
601 else
603 g->addr = p;
604 g->length = new_size;
605 return g->handle;
610 * Otherwise, we need to do the work ourselves. First verify the
611 * handle.
613 else
615 if (g->sequence != 1)
616 return 0;
619 * Do we need more memory? Segments are in ascending order in
620 * the GDESC list.
622 n_segments = (new_size >> 16) + 1;
623 if (n_segments > g->length)
625 GDESC *g_new;
626 GDESC *g_start = g;
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);
639 if (g == NULL)
640 return 0;
642 memcpy(g->addr, g_start->addr,
643 g_start->length << 16);
645 GlobalFree(block);
646 return g->handle;
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);
657 g->sequence = i;
658 g->length = n_segments;
659 next_handle += 8;
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);
668 if (g_new == NULL)
669 return 0;
670 GlobalFree(g_new->handle);
674 return g_start->handle;
678 * Do we need less memory?
680 else if (n_segments < g->length)
682 GDESC *g_free;
683 int old_length = g->length;
685 g_free = g;
686 for (i = 0; i < n_segments; i++)
688 if (g_free->sequence != i + 1)
689 return 0;
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;
701 return g->handle;
705 * We already have exactly the right amount of memory.
707 else
708 return block;
712 * If we fall through it must be an error.
714 return 0;
717 /**********************************************************************
718 * GlobalQuickAlloc
720 void *
721 GlobalQuickAlloc(int size)
723 unsigned int hmem;
725 hmem = GlobalAlloc(GLOBAL_FLAGS_MOVEABLE, size);
726 if (hmem == 0)
727 return NULL;
728 else
729 return GlobalLock(hmem);
732 /**********************************************************************
733 * GlobalHandleFromPointer
736 unsigned int
737 GlobalHandleFromPointer(void *block)
739 GDESC *g;
741 if (block == NULL)
742 return 0;
745 * Find GDESC for this block.
747 for (g = GlobalList; g != NULL; g = g->next)
748 if (g->handle > 0 && g->addr == block)
749 break;
751 if (g == NULL)
752 return 0;
753 else
754 return g->handle;
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) */
765 GDESC *g;
766 unsigned char free_map[512];
767 unsigned int max_selector_used = 0;
768 unsigned int i;
769 unsigned int selector;
770 int total_free;
773 * Initialize free list to all items not controlled by GlobalAlloc()
775 for (i = 0; i < 512; i++)
776 free_map[i] = -1;
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++)
809 free_map[i] = 1;
812 * Add up the total free segments (obviously this amount of memory
813 may not be contiguous, use GlobalCompact to get largest contiguous
814 memory available).
816 total_free=0;
817 for (i = 0; i < 512; i++)
818 if (free_map[i] == 1)
819 total_free++;
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)
830 return 1;
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 );
848 return FALSE;
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)
865 return TRUE;
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)
875 return TRUE;
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)
885 return TRUE;
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))
895 return FALSE;
896 if (lp[cb])
897 return FALSE;
898 return TRUE;