Release 940815
[wine/multimedia.git] / memory / global.c
blob117c5328277ec795c2e73e887d0555b36387795c
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 /* */
5 #define GLOBAL_SOURCE
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include "prototypes.h"
11 #include "toolhelp.h"
12 #include "heap.h"
13 #include "segmem.h"
15 GDESC *GlobalList = NULL;
16 static unsigned short next_unused_handle = 1;
18 /**********************************************************************
19 * GlobalGetGDesc
21 GDESC *GlobalGetGDesc(unsigned int block)
23 GDESC *g;
25 if (block == 0)
26 return NULL;
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)
35 break;
37 else
39 for (g = GlobalList; g != NULL; g = g->next)
40 if (g->handle == block)
41 break;
44 return g;
47 /**********************************************************************
48 * GlobalGetFreeSegments
50 GDESC *
51 GlobalGetFreeSegments(unsigned int flags, int n_segments)
53 struct segment_descriptor_s *s;
54 GDESC *g;
55 GDESC *g_start;
56 GDESC *g_prev;
57 int count, i;
60 * Try to find some empty segments in our list.
62 count = 0;
63 for (g = GlobalList; g != NULL && count != n_segments; g = g->next)
65 if ((int) g->sequence == -1)
67 if (count > 0)
69 if (g->prev->handle + 8 != g->handle)
70 count = 0;
71 else
72 count++;
74 else
76 g_start = g;
77 count = 1;
80 else if (count)
81 count = 0;
85 * If we couldn't find enough segments, then we need to create some.
87 if (count != n_segments)
90 * Find list tail.
92 g_prev = NULL;
93 for (g = GlobalList; g != NULL; g = g->next)
94 g_prev = g;
97 * Allocate segments.
99 s = CreateNewSegments(0, 0, 0x10000, n_segments);
100 if (s == NULL)
102 printf("GlobalGetFreeSegments // bad CreateNewSegments !\n");
103 return NULL;
105 for (count = 0; count < n_segments; count++, s++)
107 g = (GDESC *) malloc(sizeof(*g));
108 if (g == NULL)
110 printf("GlobalGetFreeSegments // bad GDESC malloc !\n");
111 return NULL;
113 g->prev = g_prev;
114 g->next = NULL;
115 g->handle = s->selector;
116 g->sequence = -1;
117 g->addr = s->base_addr;
118 g->length = s->length;
119 g->alias = 0;
120 g->linear_addr = NULL;
121 g->linear_key = 0;
122 g->linear_count = 0;
123 if (!(flags & GLOBAL_FLAGS_MOVEABLE))
124 g->lock_count = 1;
125 else
126 g->lock_count = 0;
128 if (count == 0) g_start = g;
130 if (g_prev != NULL)
132 g_prev->next = g;
134 else
135 GlobalList = g;
136 g_prev = g;
141 * We have all of the segments we need. Let's adjust their contents.
143 g = g_start;
144 for (i = 0; i < n_segments; i++, g = g->next)
146 if (g == NULL)
148 printf("GlobalGetFreeSegments // bad Segments chain !\n");
149 return NULL;
151 g->sequence = i + 1;
152 g->length = n_segments;
153 g->alias = 0;
154 g->linear_addr = NULL;
155 g->linear_key = 0;
156 g->linear_count = 0;
159 return g_start;
162 /**********************************************************************
163 * WIN16_GlobalAlloc
165 HANDLE
166 WIN16_GlobalAlloc(unsigned int flags, unsigned long size)
168 return GlobalAlloc(flags & ~GLOBAL_FLAGS_MOVEABLE, size);
171 /**********************************************************************
172 * GlobalAlloc
174 HANDLE
175 GlobalAlloc(unsigned int flags, unsigned long size)
177 GDESC *g;
178 GDESC *g_prev;
179 void *m;
181 #ifdef DEBUG_HEAP
182 printf("GlobalAlloc flags %4X, size %d\n", flags, size);
183 #endif
186 * If this block is fixed or very big we need to allocate entire
187 * segments.
189 if (size > 0x8000 || !(flags & GLOBAL_FLAGS_MOVEABLE))
191 int segments = ((size - 1) >> 16) + 1;
193 g = GlobalGetFreeSegments(flags, segments);
194 if (g == NULL)
195 return 0;
196 else
197 return g->handle;
200 * Otherwise we just need a little piece of a segment.
202 else
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);
212 if (m != NULL)
213 break;
218 * If we couldn't get the memory there, then we need to create
219 * a new free list.
221 if (g == NULL)
223 g = GlobalGetFreeSegments(0, 1);
224 if (g == NULL)
225 return 0;
227 g->handle = 0;
228 g->sequence = 0;
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,
232 size);
233 if (m == NULL)
234 return 0;
238 * Save position of heap descriptor.
240 g_prev = g;
243 * We have a new block. Let's create a GDESC entry for it.
245 g = malloc(sizeof(*g));
246 #ifdef DEBUG_HEAP
247 printf("New GDESC %08x\n", g);
248 #endif
249 if (g == NULL)
250 return 0;
252 g->handle = next_unused_handle;
253 g->sequence = 0;
254 g->addr = m;
255 g->alias = 0;
256 g->linear_addr = NULL;
257 g->linear_key = 0;
258 g->linear_count = 0;
259 g->length = size;
260 g->next = g_prev->next;
261 if (g->next) g->next->prev = g;
262 g->lock_count = 0;
264 g_prev->next = g;
265 g->prev = g_prev;
267 next_unused_handle++;
268 if ((next_unused_handle & 7) == 7)
269 next_unused_handle++;
271 #ifdef DEBUG_HEAP
272 printf("GlobalAlloc: returning %04x\n", g->handle);
273 #endif
274 return g->handle;
278 /**********************************************************************
279 * GlobalFree
281 * Windows programs will pass a handle in the "block" parameter, but
282 * this function will also accept a 32-bit address.
284 HANDLE
285 GlobalFree(unsigned int block)
287 GDESC *g;
289 if (block == 0)
290 return 0;
293 * Find GDESC for this block.
295 g = GlobalGetGDesc(block);
296 if (g == NULL)
297 return 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;
309 if (g->next != NULL)
310 g->next->prev = g->prev;
312 free(g);
316 * Otherwise just mark these descriptors as free.
318 else
320 int i, limit;
322 limit = g->length;
323 for (i = g->sequence - 1; i < limit && g != NULL; i++, g = g->next)
325 g->sequence = -1;
326 g->length = 0x10000;
330 return 0;
333 /**********************************************************************
334 * GlobalLock
337 void *
338 GlobalLock(unsigned int block)
340 GDESC *g;
342 if ((g = GlobalGetGDesc(block)) == NULL)
343 return 0;
345 g->lock_count++;
347 #ifdef DEBUG_HEAP
348 printf("GlobalLock: returning %08x\n", g->addr);
349 #endif
350 return g->addr;
353 /**********************************************************************
354 * GlobalUnlock
358 GlobalUnlock(unsigned int block)
360 GDESC *g;
362 if (block == 0)
363 return 0;
366 * Find GDESC for this block.
368 for (g = GlobalList; g != NULL; g = g->next)
370 if (g->handle == block && g->lock_count > 0)
372 g->lock_count--;
373 return 0;
377 return 1;
380 /**********************************************************************
381 * GlobalFlags
384 unsigned int
385 GlobalFlags(unsigned int block)
387 GDESC *g;
389 if (block == 0)
390 return 0;
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;
401 return 0;
404 /**********************************************************************
405 * GlobalSize
408 unsigned int
409 GlobalSize(unsigned int block)
411 GDESC *g = GlobalGetGDesc(block);
413 if (g == NULL)
414 return 0;
416 if (g->sequence == 0)
418 MDESC *m = (MDESC *) g->addr - 1;
420 return m->length;
422 else if (g->sequence >= 1)
424 return g->length * 0x10000;
427 return g->length;
430 /**********************************************************************
431 * GlobalHandle
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.
438 unsigned int
439 GlobalHandle(unsigned int selector)
441 GDESC *g;
443 if (selector == 0)
444 return 0;
447 * Find GDESC for this block.
449 for (g = GlobalList; g != NULL; g = g->next)
451 if (g->handle == selector)
453 if (g->sequence > 0)
454 return g->handle;
455 else
457 fprintf(stderr, "Attempt to get a handle "
458 "from a selector to a far heap.\n");
459 return 0;
464 return 0;
467 /**********************************************************************
468 * GlobalCompact
471 unsigned int
472 GlobalCompact(unsigned int desired)
474 GDESC *g;
475 unsigned char free_map[512];
476 unsigned int max_selector_used = 0;
477 unsigned int i;
478 unsigned int selector;
479 int current_free;
480 int max_free;
483 * Initialize free list to all items not controlled by GlobalAlloc()
485 for (i = 0; i < 512; i++)
486 free_map[i] = -1;
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++)
519 free_map[i] = 1;
522 * Find the largest free block of segments
524 current_free = 0;
525 max_free = 0;
526 for (i = 0; i < 512; i++)
528 if (free_map[i] == 1)
530 current_free++;
532 else
534 if (current_free > max_free)
535 max_free = current_free;
536 current_free = 0;
540 return max_free << 16;
543 /**********************************************************************
544 * GlobalReAlloc
547 unsigned int
548 GlobalReAlloc(unsigned int block, unsigned int new_size, unsigned int flags)
550 GDESC *g;
551 unsigned int n_segments;
552 int i;
554 if (block == 0)
555 return 0;
558 * Find GDESC for this block.
560 g = GlobalGetGDesc(block);
561 if (g == NULL)
562 return 0;
565 * If this is a heap allocated block, then use HEAP_ReAlloc() to
566 * reallocate the block. If this fails, call GlobalAlloc() to get
567 * a new block.
569 if (g->sequence == 0)
571 MDESC **free_list;
572 void *p;
574 free_list = (MDESC **) ((unsigned int) g->addr & 0xffff0000);
575 p = HEAP_ReAlloc(free_list, g->addr, new_size, flags) ;
576 if (p == NULL)
578 unsigned int handle = GlobalAlloc(flags, new_size);
579 if (handle == 0)
580 return 0;
581 p = GlobalLock(handle);
582 memcpy(p, g->addr, g->length);
583 GlobalUnlock(handle);
584 GlobalFree(g->handle);
586 return handle;
588 else
590 g->addr = p;
591 g->length = new_size;
592 return g->handle;
597 * Otherwise, we need to do the work ourselves. First verify the
598 * handle.
600 else
602 if (g->sequence != 1)
603 return 0;
606 * Do we need more memory? Segments are in ascending order in
607 * the GDESC list.
609 n_segments = (new_size >> 16) + 1;
610 if (n_segments > g->length)
612 GDESC *g_new;
613 GDESC *g_start = g;
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);
626 if (g == NULL)
627 return 0;
629 memcpy(g->addr, g_start->addr,
630 g_start->length << 16);
632 GlobalFree(block);
633 return g->handle;
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);
644 g->sequence = i;
645 g->length = n_segments;
646 next_handle += 8;
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);
655 if (g_new == NULL)
656 return 0;
657 GlobalFree(g_new->handle);
661 return g_start->handle;
665 * Do we need less memory?
667 else if (n_segments < g->length)
669 GDESC *g_free;
670 int old_length = g->length;
672 g_free = g;
673 for (i = 0; i < n_segments; i++)
675 if (g_free->sequence != i + 1)
676 return 0;
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;
688 return g->handle;
692 * We already have exactly the right amount of memory.
694 else
695 return block;
699 * If we fall through it must be an error.
701 return 0;
704 /**********************************************************************
705 * GlobalQuickAlloc
707 void *
708 GlobalQuickAlloc(int size)
710 unsigned int hmem;
712 hmem = GlobalAlloc(GLOBAL_FLAGS_MOVEABLE, size);
713 if (hmem == 0)
714 return NULL;
715 else
716 return GlobalLock(hmem);
719 /**********************************************************************
720 * GlobalHandleFromPointer
723 unsigned int
724 GlobalHandleFromPointer(void *block)
726 GDESC *g;
728 if (block == NULL)
729 return 0;
732 * Find GDESC for this block.
734 for (g = GlobalList; g != NULL; g = g->next)
735 if (g->handle > 0 && g->addr == block)
736 break;
738 if (g == NULL)
739 return 0;
740 else
741 return g->handle;
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) */
752 GDESC *g;
753 unsigned char free_map[512];
754 unsigned int max_selector_used = 0;
755 unsigned int i;
756 unsigned int selector;
757 int total_free;
760 * Initialize free list to all items not controlled by GlobalAlloc()
762 for (i = 0; i < 512; i++)
763 free_map[i] = -1;
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++)
796 free_map[i] = 1;
799 * Add up the total free segments (obviously this amount of memory
800 may not be contiguous, use GlobalCompact to get largest contiguous
801 memory available).
803 total_free=0;
804 for (i = 0; i < 512; i++)
805 if (free_map[i] == 1)
806 total_free++;
808 printf("GetFreeSpace // return %ld !\n", total_free << 16);
809 return total_free << 16;
812 /**********************************************************************
813 * MemManInfo (toolhelp.72)
815 BOOL MemManInfo(LPMEMMANINFO lpmmi)
817 return 1;