Release 950109
[wine/multimedia.git] / memory / heap.c
blob939eb83b8f6dae35d360d39abaf06012bf509523
1 /*
2 static char RCSId[] = "$Id: heap.c,v 1.3 1993/07/04 04:04:21 root Exp root $";
3 static char Copyright[] = "Copyright Robert J. Amstadt, 1993";
4 */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include "prototypes.h"
10 #include "segmem.h"
11 #include "heap.h"
12 #include "regfunc.h"
13 #include "dlls.h"
14 #include "stddebug.h"
15 /* #define DEBUG_HEAP */
16 #include "debug.h"
19 LHEAP *LocalHeaps = NULL;
21 void
22 HEAP_CheckHeap(MDESC **free_list)
24 MDESC *m;
26 for (m = *free_list; m != NULL; m = m->next)
28 if (((int) m & 0xffff0000) != ((int) *free_list & 0xffff0000))
29 { dprintf_heap(stddeb,"Invalid block %p\n",m);
30 *(char *)0 = 0;
32 if (m->prev && (((int) m->prev & 0xffff0000) != ((int) *free_list & 0xffff0000)))
33 { dprintf_heap(stddeb,"Invalid prev %p from %p\n", m->prev, m);
34 *(char *)0 = 0;
39 /**********************************************************************
40 * HEAP_Init
42 void
43 HEAP_Init(MDESC **free_list, void *start, int length)
45 if (length < 2 * sizeof(MDESC))
46 return;
48 *free_list = (MDESC *) start;
49 (*free_list)->prev = NULL;
50 (*free_list)->next = NULL;
51 (*free_list)->length = length - sizeof(MDESC);
54 /**********************************************************************
55 * HEAP_Alloc
57 void *
58 HEAP_Alloc(MDESC **free_list, int flags, int bytes)
60 MDESC *m, *m_new;
62 dprintf_heap(stddeb,"HeapAlloc: free_list %08x(%08x), flags %x, bytes %d\n",
63 (unsigned int) free_list, (unsigned int) *free_list, flags, bytes);
64 if(debugging_heap)HEAP_CheckHeap(free_list);
67 * Find free block big enough.
69 for (m = *free_list; m != NULL; m = m->next)
71 if (m->length >= bytes && m->length < bytes + 4 * sizeof(MDESC))
73 break;
75 else if (m->length > bytes)
77 m_new = m + (bytes / sizeof(MDESC)) + 2;
78 if (m->prev == NULL)
79 *free_list = m_new;
80 else
81 m->prev->next = m_new;
83 if (m->next != NULL)
84 m->next->prev = m_new;
86 m_new->next = m->next;
87 m_new->prev = m->prev;
88 m_new->length = m->length - ((int) m_new - (int) m);
89 m->length -= (m_new->length + sizeof(MDESC));
91 m->prev = m;
92 m->next = m;
93 m->lock = 0;
94 m->flags = 0;
95 if (flags & GLOBAL_FLAGS_ZEROINIT)
96 memset(m + 1, 0, bytes);
97 dprintf_heap(stddeb,"HeapAlloc: returning %08x\n",
98 (unsigned int) (m + 1));
99 if(debugging_heap)HEAP_CheckHeap(free_list);
100 return (void *) (m + 1);
104 if (m != NULL)
106 if (m->prev == NULL)
107 *free_list = m->next;
108 else
109 m->prev->next = m->next;
111 if (m->next != NULL)
112 m->next->prev = m->prev;
114 m->prev = m;
115 m->next = m;
116 m->lock = 0;
117 m->flags = 0;
118 if (flags & GLOBAL_FLAGS_ZEROINIT)
119 memset(m + 1, 0, bytes);
120 dprintf_heap(stddeb,"HeapAlloc: returning %08x\n",
121 (unsigned int) (m + 1));
122 if(debugging_heap)HEAP_CheckHeap(free_list);
123 return (void *) (m + 1);
126 dprintf_heap(stddeb,"HeapAlloc: returning %08x\n", 0);
127 if(debugging_heap)HEAP_CheckHeap(free_list);
128 return 0;
131 /**********************************************************************
132 * HEAP_ReAlloc
134 void *
135 HEAP_ReAlloc(MDESC **free_list, void *old_block,
136 int new_size, unsigned int flags)
138 MDESC *m_free;
139 MDESC *m;
142 if (!old_block)
143 return HEAP_Alloc(free_list, flags, new_size);
146 * Check validity of block
148 m = (MDESC *) old_block - 1;
150 dprintf_heap(stddeb,"HEAP_ReAlloc new_size=%d !\n",
151 (unsigned int) new_size);
152 dprintf_heap(stddeb,"HEAP_ReAlloc old_block=%08X !\n",
153 (unsigned int) old_block);
154 dprintf_heap(stddeb,"HEAP_ReAlloc m=%08X free_list=%08X !\n",
155 (unsigned int) m, (unsigned int) free_list);
156 dprintf_heap(stddeb,"HEAP_ReAlloc m->prev=%08X !\n",
157 (unsigned int) m->prev);
158 dprintf_heap(stddeb,"HEAP_ReAlloc m->next=%08X !\n",
159 (unsigned int) m->next);
160 dprintf_heap(stddeb,"HEAP_ReAlloc *free_list=%08X !\n",
161 (unsigned int) *free_list);
162 if(debugging_heap)HEAP_CheckHeap(free_list);
164 if (m->prev != m || m->next != m ||
165 ((int) m & 0xffff0000) != ((int) *free_list & 0xffff0000))
167 fprintf(stderr,"Attempt to resize bad pointer, m = %p, *free_list = %p\n",
168 m, free_list);
169 HEAP_CheckHeap(free_list);
170 return NULL;
174 * Check for grow block
177 dprintf_heap(stddeb,"HEAP_ReAlloc Check for grow block !\n");
178 if (new_size > m->length)
180 m_free = m + 1 + m->length / sizeof(MDESC);
181 if (m_free->next == m_free ||
182 m_free->prev == m_free ||
183 m_free->length + 2*sizeof(MDESC) < new_size - m->length)
185 void *new_p = HEAP_Alloc(free_list, flags, new_size);
186 if (new_p ==NULL)
187 return NULL;
188 memcpy(new_p, old_block, m->length);
189 HEAP_Free(free_list, old_block);
190 if(debugging_heap)HEAP_CheckHeap(free_list);
191 return new_p;
194 if (m_free->prev == NULL)
195 *free_list = m_free->next;
196 else
197 m_free->prev->next = m_free->next;
199 if (m_free->next != NULL)
200 m_free->next->prev = m_free->prev;
202 m->length += sizeof(MDESC) + m_free->length;
204 dprintf_heap(stddeb,"HEAP_ReAlloc before GLOBAL_FLAGS_ZEROINIT !\n");
205 if (flags & GLOBAL_FLAGS_ZEROINIT)
206 memset(m_free, '\0', sizeof(MDESC) + m_free->length);
210 * Check for shrink block.
212 dprintf_heap(stddeb,"HEAP_ReAlloc Check for shrink block !\n");
213 if (new_size + 4*sizeof(MDESC) < m->length)
215 m_free = m + new_size / sizeof(MDESC) + 2;
216 m_free->next = m_free;
217 m_free->prev = m_free;
218 m_free->length = m->length - ((int) m_free - (int) m);
219 m->length = (int) m_free - (int) (m + 1);
220 HEAP_Free(free_list, m_free + 1);
223 if(debugging_heap)HEAP_CheckHeap(free_list);
224 return old_block;
228 /**********************************************************************
229 * HEAP_Free
232 HEAP_Free(MDESC **free_list, void *block)
234 MDESC *m_free;
235 MDESC *m;
236 MDESC *m_prev;
238 dprintf_heap(stddeb,"HeapFree: free_list %p, block %p\n",
239 free_list, block);
240 if(debugging_heap)HEAP_CheckHeap(free_list);
243 * Validate pointer.
245 m_free = (MDESC *) block - 1;
246 if (m_free->prev != m_free || m_free->next != m_free)
248 fprintf(stderr,"Attempt to free bad pointer,"
249 "m_free = %p, *free_list = %p\n",
250 m_free, free_list);
251 return -1;
254 if (*free_list == NULL)
256 *free_list = m_free;
257 (*free_list)->next = NULL;
258 (*free_list)->prev = NULL;
259 return 0;
261 else if (((int) m_free & 0xffff0000) != ((int) *free_list & 0xffff0000))
263 fprintf(stderr,"Attempt to free bad pointer,"
264 "m_free = %p, *free_list = %p\n",
265 m_free, free_list);
266 return -1;
270 * Find location in free list.
272 m_prev = NULL;
273 for (m = *free_list; m != NULL && m < m_free; m = m->next)
274 m_prev = m;
276 if (m_prev != NULL && (int) m_prev + m_prev->length > (int) m_free)
278 fprintf(stderr,"Attempt to free bad pointer,"
279 "m_free = %p, m_prev = %p (length %x)\n",
280 m_free, m_prev, m_prev->length);
281 return -1;
284 if ((m != NULL && (int) m_free + m_free->length > (int) m) ||
285 (int) m_free + m_free->length > ((int) m_free | 0xffff))
287 fprintf(stderr,"Attempt to free bad pointer,"
288 "m_free = %p (length %x), m = %p\n",
289 m_free, m_free->length, m);
290 return -1;
294 * Put block back in free list.
295 * Does it merge with the previos block?
297 if (m_prev != NULL)
299 if ((int) m_prev + m_prev->length == (int) m_free)
301 m_prev->length += sizeof(MDESC) + m_free->length;
302 m_free = m_prev;
304 else
306 m_prev->next = m_free;
307 m_free->prev = m_prev;
310 else
312 *free_list = m_free;
313 m_free->prev = NULL;
317 * Does it merge with the next block?
319 if (m != NULL)
321 if ((int) m_free + m_free->length == (int) m)
323 m_free->length += sizeof(MDESC) + m->length;
324 m_free->next = m->next;
326 else
328 m->prev = m_free;
329 m_free->next = m;
332 else
334 m_free->next = NULL;
337 if(debugging_heap)HEAP_CheckHeap(free_list);
338 return 0;
341 /**********************************************************************
342 * HEAP_CheckLocalHeaps
344 void
345 HEAP_CheckLocalHeaps(char *file,int line)
347 LHEAP *lh;
348 dprintf_heap(stddeb,"CheckLocalHeaps called from %s %d\n",file,line);
349 for(lh=LocalHeaps; lh!=NULL; lh = lh->next)
350 { dprintf_heap(stddeb,"Checking heap %p, free_list %p\n",
351 lh,lh->free_list);
352 HEAP_CheckHeap(&lh->free_list);
357 /**********************************************************************
358 * HEAP_LocalFindHeap
360 LHEAP *
361 HEAP_LocalFindHeap(unsigned short owner)
363 LHEAP *lh;
365 dprintf_heap(stddeb,"HEAP_LocalFindHeap: owner %04x\n", owner);
367 for (lh = LocalHeaps; lh != NULL; lh = lh->next)
369 if (lh->selector == owner)
370 return lh;
373 dprintf_heap(stddeb,"Warning: Local heap not found\n");
374 return NULL;
377 /**********************************************************************
378 * HEAP_LocalInit
380 void
381 HEAP_LocalInit(unsigned short owner, void *start, int length)
383 LHEAP *lh;
385 dprintf_heap(stddeb,"HEAP_LocalInit: owner %04x, start %p, length %04x\n"
386 ,owner, start, length);
388 if (length < 2 * sizeof(MDESC))
389 return;
391 lh = (LHEAP *) malloc(sizeof(*lh));
392 if (lh == NULL)
393 return;
395 lh->next = LocalHeaps;
396 lh->selector = owner;
397 lh->local_table = NULL;
398 lh->delta = 0x20;
399 HEAP_Init(&lh->free_list, start, length);
400 dprintf_heap(stddeb,"HEAP_LocalInit: free_list %p, length %04x, prev %p, next %p\n",&lh->free_list,lh->free_list->length, lh->free_list->prev,lh->free_list->next);
401 LocalHeaps = lh;
404 /**********************************************************************
405 * HEAP_LocalSize
407 unsigned int
408 HEAP_LocalSize(MDESC **free_list, unsigned int handle)
410 MDESC *m;
412 m = (MDESC *) (((int) *free_list & 0xffff0000) |
413 (handle & 0xffff)) - 1;
414 if (m->next != m || m->prev != m)
415 return 0;
417 return m->length;
420 /**********************************************************************
421 * WIN16_LocalAlloc
423 void *
424 WIN16_LocalAlloc(int flags, int bytes)
426 void *m;
428 dprintf_heap(stddeb,"WIN16_LocalAlloc: flags %x, bytes %d\n", flags,bytes);
429 dprintf_heap(stddeb," called from segment %04x, ds=%04x\n", Stack16Frame[11],Stack16Frame[6]);
431 m = HEAP_Alloc(LOCALHEAP(), flags, bytes);
433 dprintf_heap(stddeb,"WIN16_LocalAlloc: returning %x\n", (int) m);
434 return m;
437 /**********************************************************************
438 * WIN16_LocalCompact
441 WIN16_LocalCompact(int min_free)
443 MDESC *m;
444 int max_block;
446 max_block = 0;
447 for (m = *LOCALHEAP(); m != NULL; m = m->next)
448 if (m->length > max_block)
449 max_block = m->length;
451 return max_block;
454 /**********************************************************************
455 * WIN16_LocalFlags
457 unsigned int
458 WIN16_LocalFlags(unsigned int handle)
460 MDESC *m;
462 m = (MDESC *) (((int) *LOCALHEAP() & 0xffff0000) |
463 (handle & 0xffff)) - 1;
464 if (m->next != m || m->prev != m)
465 return 0;
467 return m->lock;
470 /**********************************************************************
471 * WIN16_LocalFree
473 unsigned int
474 WIN16_LocalFree(unsigned int handle)
476 unsigned int addr;
478 addr = ((int) *LOCALHEAP() & 0xffff0000) | (handle & 0xffff);
479 if (HEAP_Free(LOCALHEAP(), (void *) addr) < 0)
480 return handle;
481 else
482 return 0;
485 /**********************************************************************
486 * WIN16_LocalInit
488 unsigned int
489 WIN16_LocalInit(unsigned int segment, unsigned int start, unsigned int end)
491 unsigned short owner = HEAP_OWNER;
492 LHEAP *lh = HEAP_LocalFindHeap(owner);
494 if (segment == 0)
496 /* Get current DS */
497 segment = Stack16Frame[6];
500 dprintf_heap(stddeb, "WIN16_LocalInit segment=%04x start=%04x end=%04x\n", segment, start, end);
502 /* start=0 doesn't mean the first byte of the segment if the segment
503 is an auto data segment. Instead it should start after the actual
504 data (and the stack if there is one). As we don't know the length
505 of the data and stack right now, we simply put the local heap at the
506 end of the segment */
507 if ((start==0)&&(Segments[segment>>3].owner==segment))
509 return;
510 start = Segments[segment>>3].length-end-2;
511 end = Segments[segment>>3].length-1;
512 dprintf_heap(stddeb, "Changed to start=%04x end=%04x\n",start,end);
515 if (lh == NULL)
517 HEAP_LocalInit(owner,
518 (void *) ((segment << 16) | start), end - start + 1);
520 else
522 HEAP_Init(&lh->free_list,
523 (void *) ((segment << 16) | start), end - start + 1);
525 dprintf_heap(stddeb,"WIN16_LocalInit // return segment=%04X !\n", segment);
526 return segment;
529 /**********************************************************************
530 * WIN16_LocalLock
532 void *
533 WIN16_LocalLock(unsigned int handle)
535 MDESC *m;
537 m = (MDESC *) (((int) *LOCALHEAP() & 0xffff0000) |
538 (handle & 0xffff)) - 1;
539 if (m->next != m || m->prev != m)
540 return 0;
542 m->lock++;
543 return (void *) (m + 1);
546 /**********************************************************************
547 * WIN16_LocalReAlloc
549 void *
550 WIN16_LocalReAlloc(unsigned int handle, int bytes, int flags)
552 void *m;
553 dprintf_heap(stddeb,"WIN16_LocalReAlloc(%04X, %d, %04X); !\n",
554 handle, bytes, flags);
555 dprintf_heap(stddeb,"WIN16_LocalReAlloc // LOCALHEAP()=%p !\n",
556 LOCALHEAP());
557 dprintf_heap(stddeb,"WIN16_LocalReAlloc // *LOCALHEAP()=%p !\n",
558 *LOCALHEAP());
559 m = HEAP_ReAlloc(LOCALHEAP(), (void *)
560 (((int) *LOCALHEAP() & 0xffff0000) | (handle & 0xffff)),
561 bytes, flags);
563 return m;
566 /**********************************************************************
567 * WIN16_LocalSize
569 unsigned int
570 WIN16_LocalSize(unsigned int handle)
572 MDESC *m;
574 m = (MDESC *) (((int) *LOCALHEAP() & 0xffff0000) |
575 (handle & 0xffff)) - 1;
576 if (m->next != m || m->prev != m)
577 return 0;
579 return m->length;
582 /**********************************************************************
583 * WIN16_LocalUnlock
585 unsigned int
586 WIN16_LocalUnlock(unsigned int handle)
588 MDESC *m;
590 m = (MDESC *) (((int) *LOCALHEAP() & 0xffff0000) |
591 (handle & 0xffff)) - 1;
592 if (m->next != m || m->prev != m)
593 return 1;
595 if (m->lock > 0)
596 m->lock--;
598 return 0;
601 /**********************************************************************
602 * WIN16_LocalHandleDelta
604 unsigned int
605 WIN16_LocalHandleDelta(unsigned int new_delta)
607 LHEAP *lh;
609 lh = HEAP_LocalFindHeap(HEAP_OWNER);
610 if (lh == NULL)
611 return 0;
613 if (new_delta)
614 lh->delta = new_delta;
616 return lh->delta;
619 /**********************************************************************
620 * GetFreeSystemResources (user.284)
623 #define USERRESOURCES 2
624 #define GDIRESOURCES 1
625 #define SYSTEMRESOURCES 0
626 #include <user.h>
627 #include <gdi.h>
629 WORD GetFreeSystemResources(WORD SystemResourceType)
631 unsigned int GdiFree=0,GdiResult=0;
632 unsigned int UserFree=0,UserResult=0;
633 unsigned int result=0;
634 MDESC *m;
635 dprintf_heap(stddeb,"GetFreeSystemResources(%u)\n",SystemResourceType);
636 switch(SystemResourceType) {
637 case(USERRESOURCES):
638 for (m = USER_Heap; m != NULL; m = m->next) /* add up free area in heap */
639 UserFree += m->length;
640 result=(UserFree*100)/65516; /* 65516 == 64K */
641 break;
642 case(GDIRESOURCES):
643 for (m = GDI_Heap; m != NULL; m = m->next)
644 GdiFree += m->length;
645 result=(GdiFree*100)/65516;
646 break;
647 case(SYSTEMRESOURCES):
648 for (m = USER_Heap; m != NULL; m = m->next)
649 UserFree += m->length;
650 UserResult=(UserFree*100)/65516;
651 for (m = GDI_Heap; m != NULL; m = m->next)
652 GdiFree += m->length;
653 GdiResult=(GdiFree*100)/65516;
654 result=(UserResult < GdiResult) ? UserResult:GdiResult;
655 break;
656 default:
657 result=0;
658 break;
660 return(result);