Release 940405
[wine/gsoc-2012-control.git] / memory / global.c
blob11ab363123204d3803ac7483f2e011932e87eb24
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 GLOBAL_SOURCE
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include "prototypes.h"
10 #include "heap.h"
11 #include "segmem.h"
13 GDESC *GlobalList = NULL;
14 static unsigned short next_unused_handle = 1;
16 /**********************************************************************
17 * GlobalGetGDesc
19 GDESC *GlobalGetGDesc(unsigned int block)
21 GDESC *g;
23 if (block == 0)
24 return NULL;
27 * Find GDESC for this block.
29 if (block & 0xffff0000)
31 for (g = GlobalList; g != NULL; g = g->next)
32 if (g->handle > 0 && (unsigned int) g->addr == block)
33 break;
35 else
37 for (g = GlobalList; g != NULL; g = g->next)
38 if (g->handle == block)
39 break;
42 return g;
45 /**********************************************************************
46 * GlobalGetFreeSegments
48 GDESC *
49 GlobalGetFreeSegments(unsigned int flags, int n_segments)
51 struct segment_descriptor_s *s;
52 GDESC *g;
53 GDESC *g_start;
54 GDESC *g_prev;
55 int count, i;
58 * Try to find some empty segments in our list.
60 count = 0;
61 for (g = GlobalList; g != NULL && count != n_segments; g = g->next)
63 if ((int) g->sequence == -1)
65 if (count > 0)
67 if (g->prev->handle + 8 != g->handle)
68 count = 0;
69 else
70 count++;
72 else
74 g_start = g;
75 count = 1;
78 else if (count)
79 count = 0;
83 * If we couldn't find enough segments, then we need to create some.
85 if (count != n_segments)
88 * Find list tail.
90 g_prev = NULL;
91 for (g = GlobalList; g != NULL; g = g->next)
92 g_prev = g;
95 * Allocate segments.
97 s = CreateNewSegments(0, 0, 0x10000, n_segments);
98 if (s == NULL)
100 printf("GlobalGetFreeSegments // bad CreateNewSegments !\n");
101 return NULL;
103 for (count = 0; count < n_segments; count++, s++)
105 g = (GDESC *) malloc(sizeof(*g));
106 if (g == NULL) {
107 printf("GlobalGetFreeSegments // bad GDESC malloc !\n");
108 return NULL;
110 g->prev = g_prev;
111 g->next = NULL;
112 g->handle = s->selector;
113 g->sequence = -1;
114 g->addr = s->base_addr;
115 g->length = s->length;
116 g->linear_addr = NULL;
117 g->linear_key = 0;
118 g->linear_count = 0;
119 if (!(flags & GLOBAL_FLAGS_MOVEABLE))
120 g->lock_count = 1;
121 else
122 g->lock_count = 0;
124 if (count == 0) g_start = g;
126 if (g_prev != NULL)
128 g_prev->next = g;
130 else
131 GlobalList = g;
132 g_prev = g;
137 * We have all of the segments we need. Let's adjust their contents.
139 g = g_start;
140 for (i = 0; i < n_segments; i++, g = g->next)
142 if (g == NULL) {
143 printf("GlobalGetFreeSegments // bad Segments chain !\n");
144 return NULL;
146 g->sequence = i + 1;
147 g->length = n_segments;
148 g->linear_addr = NULL;
149 g->linear_key = 0;
150 g->linear_count = 0;
153 return g_start;
156 /**********************************************************************
157 * GlobalAlloc
159 HANDLE
160 GlobalAlloc(unsigned int flags, unsigned long size)
162 GDESC *g;
163 GDESC *g_prev;
164 void *m;
167 * If this block is fixed or very big we need to allocate entire
168 * segments.
170 if (size > 0x8000 || !(flags & GLOBAL_FLAGS_MOVEABLE))
172 int segments = (size >> 16) + 1;
174 g = GlobalGetFreeSegments(flags, segments);
175 if (g == NULL)
176 return 0;
177 else
178 return g->handle;
181 * Otherwise we just need a little piece of a segment.
183 else
186 * Try to allocate from active free lists.
188 for (g = GlobalList; g != NULL; g = g->next)
190 if (g->handle == 0 && g->sequence == 0)
192 m = HEAP_Alloc((MDESC **) g->addr, 0, size);
193 if (m != NULL)
194 break;
199 * If we couldn't get the memory there, then we need to create
200 * a new free list.
202 if (g == NULL)
204 g = GlobalGetFreeSegments(0, 1);
205 if (g == NULL)
206 return 0;
208 g->handle = 0;
209 g->sequence = 0;
210 HEAP_Init((MDESC **) g->addr, (MDESC **) g->addr + 1,
211 0x10000 - sizeof(MDESC **));
212 m = HEAP_Alloc((MDESC **) g->addr, flags & GLOBAL_FLAGS_ZEROINIT,
213 size);
214 if (m == NULL)
215 return 0;
219 * Save position of heap descriptor.
221 g_prev = g;
224 * We have a new block. Let's create a GDESC entry for it.
226 g = malloc(sizeof(*g));
227 #ifdef DEBUG_HEAP
228 printf("New GDESC %08x\n", g);
229 #endif
230 if (g == NULL)
231 return 0;
233 g->handle = next_unused_handle;
234 g->sequence = 0;
235 g->addr = m;
236 g->linear_addr = NULL;
237 g->linear_key = 0;
238 g->linear_count = 0;
239 g->length = size;
240 g->next = g_prev->next;
241 if (g->next) g->next->prev = g;
242 g->lock_count = 0;
244 g_prev->next = g;
245 g->prev = g_prev;
247 next_unused_handle++;
248 if ((next_unused_handle & 7) == 7)
249 next_unused_handle++;
251 #ifdef DEBUG_HEAP
252 printf("GlobalAlloc: returning %04x\n", g->handle);
253 #endif
254 return g->handle;
258 /**********************************************************************
259 * GlobalFree
261 * Windows programs will pass a handle in the "block" parameter, but
262 * this function will also accept a 32-bit address.
264 HANDLE
265 GlobalFree(unsigned int block)
267 GDESC *g;
269 if (block == 0)
270 return 0;
273 * Find GDESC for this block.
275 g = GlobalGetGDesc(block);
276 if (g == NULL)
277 return block;
280 * If the sequence number is zero then use HEAP_Free to deallocate
281 * memory, and throw away this descriptor.
283 if (g->sequence == 0)
285 HEAP_Free((MDESC **) ((int) g->addr & 0xffff0000), (void *) g->addr);
287 g->prev->next = g->next;
289 if (g->next != NULL)
290 g->next->prev = g->prev;
292 free(g);
296 * Otherwise just mark these descriptors as free.
298 else
300 int i, limit;
302 limit = g->length;
303 for (i = g->sequence - 1; i < limit && g != NULL; i++, g = g->next)
305 g->sequence = -1;
306 g->length = 0x10000;
310 return 0;
313 /**********************************************************************
314 * GlobalLock
317 void *
318 GlobalLock(unsigned int block)
320 GDESC *g;
322 if (block == 0)
323 return 0;
326 * Find GDESC for this block.
328 for (g = GlobalList; g != NULL; g = g->next)
330 if (g->handle == block)
332 g->lock_count++;
333 #ifdef DEBUG_HEAP
334 printf("GlobalLock: returning %08x\n", g->addr);
335 #endif
336 return g->addr;
340 #ifdef DEBUG_HEAP
341 printf("GlobalLock: returning %08x\n", 0);
342 #endif
343 return NULL;
346 /**********************************************************************
347 * GlobalUnlock
351 GlobalUnlock(unsigned int block)
353 GDESC *g;
355 if (block == 0)
356 return 0;
359 * Find GDESC for this block.
361 for (g = GlobalList; g != NULL; g = g->next)
363 if (g->handle == block && g->lock_count > 0)
365 g->lock_count--;
366 return 0;
370 return 1;
373 /**********************************************************************
374 * GlobalFlags
377 unsigned int
378 GlobalFlags(unsigned int block)
380 GDESC *g;
382 if (block == 0)
383 return 0;
386 * Find GDESC for this block.
388 for (g = GlobalList; g != NULL; g = g->next)
390 if (g->handle == block)
391 return g->lock_count;
394 return 0;
397 /**********************************************************************
398 * GlobalSize
401 unsigned int
402 GlobalSize(unsigned int block)
404 GDESC *g;
406 if (block == 0)
407 return 0;
410 * Find GDESC for this block.
412 for (g = GlobalList; g != NULL; g = g->next)
414 if (g->handle == block)
415 return g->length;
418 return 0;
421 /**********************************************************************
422 * GlobalHandle
424 * This routine is not strictly correct. MS Windows creates a selector
425 * for every locked global block. We do not. If the allocation is small
426 * enough, we only give out a little piece of a selector. Thus this
427 * function cannot be implemented.
429 unsigned int
430 GlobalHandle(unsigned int selector)
432 GDESC *g;
434 if (selector == 0)
435 return 0;
438 * Find GDESC for this block.
440 for (g = GlobalList; g != NULL; g = g->next)
442 if (g->handle == selector)
444 if (g->sequence > 0)
445 return g->handle;
446 else
448 fprintf(stderr, "Attempt to get a handle "
449 "from a selector to a far heap.\n");
450 return 0;
455 return 0;
458 /**********************************************************************
459 * GlobalCompact
462 unsigned int
463 GlobalCompact(unsigned int desired)
465 GDESC *g;
466 unsigned char free_map[512];
467 unsigned int max_selector_used = 0;
468 unsigned int i;
469 unsigned int selector;
470 int current_free;
471 int max_free;
474 * Initialize free list to all items not controlled by GlobalAlloc()
476 for (i = 0; i < 512; i++)
477 free_map[i] = -1;
480 * Traverse table looking for used and free selectors.
482 for (g = GlobalList; g != NULL; g = g->next)
485 * Check for free segments.
487 if (g->sequence == -1)
489 free_map[g->handle >> 3] = 1;
490 if (g->handle > max_selector_used)
491 max_selector_used = g->handle;
495 * Check for heap allocated segments.
497 else if (g->handle == 0)
499 selector = (unsigned int) g->addr >> 16;
500 free_map[selector >> 3] = 0;
501 if (selector > max_selector_used)
502 max_selector_used = selector;
507 * All segments past the biggest selector used are free.
509 for (i = (max_selector_used >> 3) + 1; i < 512; i++)
510 free_map[i] = 1;
513 * Find the largest free block of segments
515 current_free = 0;
516 max_free = 0;
517 for (i = 0; i < 512; i++)
519 if (free_map[i] == 1)
521 current_free++;
523 else
525 if (current_free > max_free)
526 max_free = current_free;
527 current_free = 0;
531 return max_free << 16;
534 /**********************************************************************
535 * GlobalReAlloc
538 unsigned int
539 GlobalReAlloc(unsigned int block, unsigned int new_size, unsigned int flags)
541 GDESC *g;
542 unsigned int n_segments;
543 int i;
545 if (block == 0)
546 return 0;
549 * Find GDESC for this block.
551 g = GlobalGetGDesc(block);
552 if (g == NULL)
553 return 0;
556 * If this is a heap allocated block, then use HEAP_ReAlloc() to
557 * reallocate the block. If this fails, call GlobalAlloc() to get
558 * a new block.
560 if (g->sequence == 0)
562 MDESC **free_list;
563 void *p;
565 free_list = (MDESC **) ((unsigned int) g->addr & 0xffff0000);
566 p = HEAP_ReAlloc(free_list, g->addr, new_size, flags) ;
567 if (p == NULL)
569 unsigned int handle = GlobalAlloc(flags, new_size);
570 if (handle == 0)
571 return 0;
572 p = GlobalLock(handle);
573 memcpy(p, g->addr, g->length);
574 GlobalUnlock(handle);
575 GlobalFree(g->handle);
577 return handle;
579 else
581 g->addr = p;
582 g->length = new_size;
583 return g->handle;
588 * Otherwise, we need to do the work ourselves. First verify the
589 * handle.
591 else
593 if (g->sequence != 1)
594 return 0;
597 * Do we need more memory? Segments are in ascending order in
598 * the GDESC list.
600 n_segments = (new_size >> 16) + 1;
601 if (n_segments > g->length)
603 GDESC *g_new;
604 GDESC *g_start = g;
605 int old_segments = g_start->length;
606 unsigned short next_handle = g_start->handle;
608 for (i = 1; i <= n_segments; i++, g = g->next)
611 * If we run into a block allocated to something else,
612 * try GlobalGetFreeSegments() and memcpy(). (Yuk!)
614 if (g->sequence != i || g->handle != next_handle)
616 g = GlobalGetFreeSegments(flags, n_segments);
617 if (g == NULL)
618 return 0;
620 memcpy(g->addr, g_start->addr,
621 g_start->length << 16);
623 GlobalFree(block);
624 return g->handle;
628 * Otherwise this block is used by us or free. So,
629 * snatch it. If this block is new and we are supposed to
630 * zero init, then do some erasing.
632 if (g->sequence == -1 && (flags & GLOBAL_FLAGS_ZEROINIT))
633 memset(g->addr, 0, 0x10000);
635 g->sequence = i;
636 g->length = n_segments;
637 next_handle += 8;
640 * If the next descriptor is non-existant, then use
641 * GlobalGetFreeSegments to create them.
643 if (i != n_segments && g->next == NULL)
645 g_new = GlobalGetFreeSegments(flags, n_segments - i);
646 if (g_new == NULL)
647 return 0;
648 GlobalFree(g_new->handle);
652 return g_start->handle;
656 * Do we need less memory?
658 else if (n_segments < g->length)
660 GDESC *g_free;
662 g_free = g;
663 for (i = 0; i < n_segments; i++)
665 if (g_free->sequence != i + 1)
666 return 0;
667 g_free = g_free->next;
672 * We already have exactly the right amount of memory.
674 else
675 return block;
679 * If we fall through it must be an error.
681 return 0;
684 /**********************************************************************
685 * GlobalQuickAlloc
687 void *
688 GlobalQuickAlloc(int size)
690 unsigned int hmem;
692 hmem = GlobalAlloc(GLOBAL_FLAGS_MOVEABLE, size);
693 if (hmem == 0)
694 return NULL;
695 else
696 return GlobalLock(hmem);
699 /**********************************************************************
700 * GlobalHandleFromPointer
703 unsigned int
704 GlobalHandleFromPointer(void *block)
706 GDESC *g;
708 if (block == NULL)
709 return 0;
712 * Find GDESC for this block.
714 for (g = GlobalList; g != NULL; g = g->next)
715 if (g->handle > 0 && g->addr == block)
716 break;
718 if (g == NULL)
719 return 0;
720 else
721 return g->handle;
724 /**********************************************************************
725 * GetFreeSpace (kernel.169)
728 DWORD GetFreeSpace(UINT wFlags)
729 /* windows 3.1 doesn't use the wFlags parameter !!
730 (so I won't either) */
732 GDESC *g;
733 unsigned char free_map[512];
734 unsigned int max_selector_used = 0;
735 unsigned int i;
736 unsigned int selector;
737 int total_free;
740 * Initialize free list to all items not controlled by GlobalAlloc()
742 for (i = 0; i < 512; i++)
743 free_map[i] = -1;
746 * Traverse table looking for used and free selectors.
748 for (g = GlobalList; g != NULL; g = g->next)
751 * Check for free segments.
753 if (g->sequence == -1)
755 free_map[g->handle >> 3] = 1;
756 if (g->handle > max_selector_used)
757 max_selector_used = g->handle;
761 * Check for heap allocated segments.
763 else if (g->handle == 0)
765 selector = (unsigned int) g->addr >> 16;
766 free_map[selector >> 3] = 0;
767 if (selector > max_selector_used)
768 max_selector_used = selector;
773 * All segments past the biggest selector used are free.
775 for (i = (max_selector_used >> 3) + 1; i < 512; i++)
776 free_map[i] = 1;
779 * Add up the total free segments (obviously this amount of memory
780 may not be contiguous, use GlobalCompact to get largest contiguous
781 memory available).
783 total_free=0;
784 for (i = 0; i < 512; i++)
785 if (free_map[i] == 1)
786 total_free++;
788 return total_free << 16;