Release 940510
[wine/multimedia.git] / memory / heap.c
blob471d5fea8e6fe400372ef4587399b48660f62b21
1 static char RCSId[] = "$Id: heap.c,v 1.3 1993/07/04 04:04:21 root Exp root $";
2 static char Copyright[] = "Copyright Robert J. Amstadt, 1993";
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include "prototypes.h"
8 #include "segmem.h"
9 #include "heap.h"
10 #include "regfunc.h"
12 /* #define DEBUG_HEAP */
14 LHEAP *LocalHeaps = NULL;
16 /**********************************************************************
17 * HEAP_Init
19 void
20 HEAP_Init(MDESC **free_list, void *start, int length)
22 if (length < 2 * sizeof(MDESC))
23 return;
25 *free_list = (MDESC *) start;
26 (*free_list)->prev = NULL;
27 (*free_list)->next = NULL;
28 (*free_list)->length = length - sizeof(MDESC);
31 /**********************************************************************
32 * HEAP_Alloc
34 void *
35 HEAP_Alloc(MDESC **free_list, int flags, int bytes)
37 MDESC *m, *m_new;
39 #ifdef DEBUG_HEAP
40 printf("HeapAlloc: free_list %08x, flags %x, bytes %d\n",
41 free_list, flags, bytes);
42 #endif
45 * Find free block big enough.
47 for (m = *free_list; m != NULL; m = m->next)
49 if (m->length >= bytes && m->length < bytes + 4 * sizeof(MDESC))
51 break;
53 else if (m->length > bytes)
55 m_new = m + (bytes / sizeof(MDESC)) + 2;
56 if (m->prev == NULL)
57 *free_list = m_new;
58 else
59 m->prev->next = m_new;
61 if (m->next != NULL)
62 m->next->prev = m_new;
64 m_new->next = m->next;
65 m_new->prev = m->prev;
66 m_new->length = m->length - ((int) m_new - (int) m);
67 m->length -= (m_new->length + sizeof(MDESC));
69 m->prev = m;
70 m->next = m;
71 m->lock = 0;
72 m->flags = 0;
73 if (flags & GLOBAL_FLAGS_ZEROINIT)
74 memset(m + 1, 0, bytes);
75 #ifdef DEBUG_HEAP
76 printf("HeapAlloc: returning %08x\n", (m + 1));
77 #endif
78 return (void *) (m + 1);
82 if (m != NULL)
84 if (m->prev == NULL)
85 *free_list = m->next;
86 else
87 m->prev->next = m->next;
89 if (m->next != NULL)
90 m->next->prev = m->prev;
92 m->prev = m;
93 m->next = m;
94 m->lock = 0;
95 m->flags = 0;
96 if (flags & GLOBAL_FLAGS_ZEROINIT)
97 memset(m + 1, 0, bytes);
98 #ifdef DEBUG_HEAP
99 printf("HeapAlloc: returning %08x\n", (m + 1));
100 #endif
101 return (void *) (m + 1);
104 #ifdef DEBUG_HEAP
105 printf("HeapAlloc: returning %08x\n", 0);
106 #endif
107 return 0;
110 /**********************************************************************
111 * HEAP_ReAlloc
113 void *
114 HEAP_ReAlloc(MDESC **free_list, void *old_block,
115 int new_size, unsigned int flags)
117 MDESC *m_free;
118 MDESC *m;
120 * Check validity of block
122 m = (MDESC *) old_block - 1;
123 #ifdef DEBUG_HEAP
124 printf("HEAP_ReAlloc new_size=%d !\n", new_size);
125 printf("HEAP_ReAlloc old_block=%08X !\n", old_block);
126 printf("HEAP_ReAlloc m=%08X free_list=%08X !\n", m, free_list);
127 printf("HEAP_ReAlloc m->prev=%08X !\n", m->prev);
128 printf("HEAP_ReAlloc m->next=%08X !\n", m->next);
129 printf("HEAP_ReAlloc *free_list=%08X !\n", *free_list);
130 #endif
131 if (m->prev != m || m->next != m ||
132 ((int) m & 0xffff0000) != ((int) *free_list & 0xffff0000))
134 printf("Attempt to resize bad pointer, m = %08x, *free_list = %08x\n",
135 m, free_list);
136 #ifdef DEBUG_HEAP
137 printf("Attempt to resize bad pointer, m = %08x, *free_list = %08x\n",
138 m, free_list);
139 #endif
140 return NULL;
144 * Check for grow block
146 #ifdef DEBUG_HEAP
147 printf("HEAP_ReAlloc Check for grow block !\n");
148 #endif
149 if (new_size > m->length)
151 m_free = m + 1 + m->length / sizeof(MDESC);
152 if (m_free->next == m_free ||
153 m_free->prev == m_free ||
154 m_free->length + sizeof(MDESC) < new_size)
156 void *new_p = HEAP_Alloc(free_list, flags, new_size);
157 if (new_p ==NULL)
158 return NULL;
159 memcpy(new_p, old_block, m->length);
160 HEAP_Free(free_list, old_block);
161 return new_p;
164 if (m_free->prev == NULL)
165 *free_list = m_free->next;
166 else
167 m_free->prev->next = m_free->next;
169 if (m_free->next != NULL)
170 m_free->next->prev = m_free->prev;
172 m->length += sizeof(MDESC) + m_free->length;
173 #ifdef DEBUG_HEAP
174 printf("HEAP_ReAlloc before GLOBAL_FLAGS_ZEROINIT !\n");
175 #endif
176 if (flags & GLOBAL_FLAGS_ZEROINIT)
177 memset(m_free, '\0', sizeof(MDESC) + m_free->length);
181 * Check for shrink block.
183 #ifdef DEBUG_HEAP
184 printf("HEAP_ReAlloc Check for shrink block !\n");
185 #endif
186 if (new_size < m->length - 4 * sizeof(MDESC))
188 m_free = m + new_size / sizeof(MDESC) + 2;
189 m_free->next = m_free;
190 m_free->prev = m_free;
191 m_free->length = m->length - (int) m_free - (int) m;
192 m->length = (int) m_free - (int) (m + 1);
193 HEAP_Free(free_list, m_free + 1);
196 return old_block;
200 /**********************************************************************
201 * HEAP_Free
204 HEAP_Free(MDESC **free_list, void *block)
206 MDESC *m_free;
207 MDESC *m;
208 MDESC *m_prev;
211 * Validate pointer.
213 m_free = (MDESC *) block - 1;
214 if (m_free->prev != m_free || m_free->next != m_free ||
215 ((int) m_free & 0xffff0000) != ((int) *free_list & 0xffff0000))
217 #ifdef DEBUG_HEAP
218 printf("Attempt to free bad pointer,"
219 "m_free = %08x, *free_list = %08x\n",
220 m_free, free_list);
221 #endif
222 return -1;
226 * Find location in free list.
228 m_prev = NULL;
229 for (m = *free_list; m != NULL && m < m_free; m = m->next)
230 m_prev = m;
232 if (m_prev != NULL && (int) m_prev + m_prev->length > (int) m_free)
234 #ifdef DEBUG_HEAP
235 printf("Attempt to free bad pointer,"
236 "m_free = %08x, m_prev = %08x (length %x)\n",
237 m_free, m_prev, m_prev->length);
238 #endif
239 return -1;
242 if ((m != NULL && (int) m_free + m_free->length > (int) m) ||
243 (int) m_free + m_free->length > ((int) m_free | 0xffff))
245 #ifdef DEBUG_HEAP
246 printf("Attempt to free bad pointer,"
247 "m_free = %08x (length %x), m = %08x\n",
248 m_free, m_free->length, m);
249 #endif
250 return -1;
254 * Put block back in free list.
255 * Does it merge with the previos block?
257 if (m_prev != NULL)
259 if ((int) m_prev + m_prev->length == (int) m_free)
261 m_prev->length += sizeof(MDESC) + m_free->length;
262 m_free = m_prev;
264 else
266 m_prev->next = m_free;
267 m_free->prev = m_prev;
270 else
272 *free_list = m_free;
273 m_free->prev = NULL;
277 * Does it merge with the next block?
279 if (m != NULL)
281 if ((int) m_free + m_free->length == (int) m)
283 m_free->length += sizeof(MDESC) + m->length;
284 m_free->next = m->next;
286 else
288 m->prev = m_free;
289 m_free->next = m;
292 else
294 m_free->next = NULL;
297 return 0;
300 /**********************************************************************
301 * HEAP_LocalFindHeap
303 LHEAP *
304 HEAP_LocalFindHeap(unsigned short owner)
306 LHEAP *lh;
308 #ifdef DEBUG_HEAP
309 printf("HEAP_LocalFindHeap: owner %04x\n", owner);
310 #endif
312 for (lh = LocalHeaps; lh != NULL; lh = lh->next)
314 if (lh->selector == owner)
315 return lh;
318 return NULL;
321 /**********************************************************************
322 * HEAP_LocalInit
324 void
325 HEAP_LocalInit(unsigned short owner, void *start, int length)
327 LHEAP *lh;
329 #ifdef DEBUG_HEAP
330 printf("HEAP_LocalInit: owner %04x, start %08x, length %04x\n",
331 owner, start, length);
332 #endif
334 if (length < 2 * sizeof(MDESC))
335 return;
337 lh = (LHEAP *) malloc(sizeof(*lh));
338 if (lh == NULL)
339 return;
341 lh->next = LocalHeaps;
342 lh->selector = owner;
343 lh->local_table = NULL;
344 HEAP_Init(&lh->free_list, start, length);
345 LocalHeaps = lh;
348 /**********************************************************************
349 * WIN16_LocalAlloc
351 void *
352 WIN16_LocalAlloc(int flags, int bytes)
354 void *m;
356 #ifdef DEBUG_HEAP
357 printf("WIN16_LocalAlloc: flags %x, bytes %d\n", flags, bytes);
358 printf(" called from segment %04x\n", Stack16Frame[11]);
359 #endif
361 m = HEAP_Alloc(LOCALHEAP(), flags, bytes);
363 #ifdef DEBUG_HEAP
364 printf("WIN16_LocalAlloc: returning %x\n", (int) m);
365 #endif
366 return m;
369 /**********************************************************************
370 * WIN16_LocalCompact
373 WIN16_LocalCompact(int min_free)
375 MDESC *m;
376 int max_block;
378 max_block = 0;
379 for (m = *LOCALHEAP(); m != NULL; m = m->next)
380 if (m->length > max_block)
381 max_block = m->length;
383 return max_block;
386 /**********************************************************************
387 * WIN16_LocalFlags
389 unsigned int
390 WIN16_LocalFlags(unsigned int handle)
392 MDESC *m;
394 m = (MDESC *) (((int) *LOCALHEAP() & 0xffff0000) |
395 (handle & 0xffff)) - 1;
396 if (m->next != m || m->prev != m)
397 return 0;
399 return m->lock;
402 /**********************************************************************
403 * WIN16_LocalFree
405 unsigned int
406 WIN16_LocalFree(unsigned int handle)
408 unsigned int addr;
410 addr = ((int) *LOCALHEAP() & 0xffff0000) | (handle & 0xffff);
411 if (HEAP_Free(LOCALHEAP(), (void *) addr) < 0)
412 return handle;
413 else
414 return 0;
417 /**********************************************************************
418 * WIN16_LocalInit
420 unsigned int
421 WIN16_LocalInit(unsigned int segment, unsigned int start, unsigned int end)
423 unsigned short owner = HEAP_OWNER;
424 LHEAP *lh = HEAP_LocalFindHeap(owner);
426 if (segment == 0)
428 /* Get current DS */
429 segment = Stack16Frame[6];
432 if (lh == NULL)
434 HEAP_LocalInit(owner,
435 (void *) ((segment << 16) | start), end - start + 1);
437 else
439 HEAP_Init(&lh->free_list,
440 (void *) ((segment << 16) | start), end - start + 1);
442 printf("WIN16_LocalInit // return segment=%04X !\n", segment);
443 return segment;
446 /**********************************************************************
447 * WIN16_LocalLock
449 void *
450 WIN16_LocalLock(unsigned int handle)
452 MDESC *m;
454 m = (MDESC *) (((int) *LOCALHEAP() & 0xffff0000) |
455 (handle & 0xffff)) - 1;
456 if (m->next != m || m->prev != m)
457 return 0;
459 m->lock++;
460 return (void *) (m + 1);
463 /**********************************************************************
464 * WIN16_LocalReAlloc
466 void *
467 WIN16_LocalReAlloc(unsigned int handle, int bytes, int flags)
469 void *m;
470 #ifdef DEBUG_HEAP
471 printf("WIN16_LocalReAlloc(%04X, %d, %04X); !\n", handle, bytes, flags);
472 printf("WIN16_LocalReAlloc // LOCALHEAP()=%08X !\n", LOCALHEAP());
473 printf("WIN16_LocalReAlloc // *LOCALHEAP()=%08X !\n", *LOCALHEAP());
474 #endif
475 m = HEAP_ReAlloc(LOCALHEAP(), (void *)
476 (((int) *LOCALHEAP() & 0xffff0000) | (handle & 0xffff)),
477 bytes, flags);
479 return m;
482 /**********************************************************************
483 * WIN16_LocalSize
485 unsigned int
486 WIN16_LocalSize(unsigned int handle)
488 MDESC *m;
490 m = (MDESC *) (((int) *LOCALHEAP() & 0xffff0000) |
491 (handle & 0xffff)) - 1;
492 if (m->next != m || m->prev != m)
493 return 0;
495 return m->length;
498 /**********************************************************************
499 * WIN16_LocalUnlock
501 unsigned int
502 WIN16_LocalUnlock(unsigned int handle)
504 MDESC *m;
506 m = (MDESC *) (((int) *LOCALHEAP() & 0xffff0000) |
507 (handle & 0xffff)) - 1;
508 if (m->next != m || m->prev != m)
509 return 1;
511 if (m->lock > 0)
512 m->lock--;
514 return 0;
517 /**********************************************************************
518 * GetFreeSystemResources (user.284)
521 #define USERRESOURCES 2
522 #define GDIRESOURCES 1
523 #define SYSTEMRESOURCES 0
524 #include <user.h>
525 #include <gdi.h>
527 WORD GetFreeSystemResources(WORD SystemResourceType)
529 unsigned int GdiFree=0,GdiResult=0;
530 unsigned int UserFree=0,UserResult=0;
531 unsigned int result=0;
532 MDESC *m;
534 printf("GetFreeSystemResources(%u)\n",SystemResourceType);
536 switch(SystemResourceType) {
537 case(USERRESOURCES):
538 for (m = USER_Heap; m != NULL; m = m->next) /* add up free area in heap */
539 UserFree += m->length;
540 result=(UserFree*100)/65516; /* 65516 == 64K */
541 break;
542 case(GDIRESOURCES):
543 for (m = GDI_Heap; m != NULL; m = m->next)
544 GdiFree += m->length;
545 result=(GdiFree*100)/65516;
546 break;
547 case(SYSTEMRESOURCES):
548 for (m = USER_Heap; m != NULL; m = m->next)
549 UserFree += m->length;
550 UserResult=(UserFree*100)/65516;
551 for (m = GDI_Heap; m != NULL; m = m->next)
552 GdiFree += m->length;
553 GdiResult=(GdiFree*100)/65516;
554 result=(UserResult < GdiResult) ? UserResult:GdiResult;
555 break;
556 default:
557 result=0;
558 break;
560 return(result);