Release 960521
[wine.git] / memory / local.c
blob00c564dcc10a7e92fd2cfc0fe0701f26c419c4e7
1 /*
2 * Local heap functions
4 * Copyright 1995 Alexandre Julliard
5 * Copyright 1996 Huw Davies
6 */
8 /*
9 * Note:
10 * All local heap functions need the current DS as first parameter
11 * when called from the emulation library, so they take one more
12 * parameter than usual.
15 #include <stdlib.h>
16 #include <string.h>
17 #include "windows.h"
18 #include "ldt.h"
19 #include "global.h"
20 #include "heap.h"
21 #include "instance.h"
22 #include "local.h"
23 #include "module.h"
24 #include "stackframe.h"
25 #include "toolhelp.h"
26 #include "stddebug.h"
27 #include "debug.h"
29 #ifndef WINELIB
30 #pragma pack(1)
31 #endif
33 typedef struct
35 /* Arena header */
36 WORD prev; /* Previous arena | arena type */
37 WORD next; /* Next arena */
38 /* Start of the memory block or free-list info */
39 WORD size; /* Size of the free block */
40 WORD free_prev; /* Previous free block */
41 WORD free_next; /* Next free block */
42 } LOCALARENA;
44 #define ARENA_HEADER_SIZE 4
45 #define ARENA_HEADER( handle) ( ((handle) & ~3) - ARENA_HEADER_SIZE)
47 /* Arena types (stored in 'prev' field of the arena) */
48 #define LOCAL_ARENA_FREE 0
49 #define LOCAL_ARENA_FIXED 1
51 /* Layout of a handle entry table
53 * WORD count of entries
54 * LOCALHANDLEENTRY[count] entries
55 * WORD near ptr to next table
57 typedef struct
59 WORD addr; /* Address of the MOVEABLE block */
60 BYTE flags; /* Flags for this block */
61 BYTE lock; /* Lock count */
62 } LOCALHANDLEENTRY;
64 typedef struct
66 WORD check; /* 00 Heap checking flag */
67 WORD freeze; /* 02 Heap frozen flag */
68 WORD items; /* 04 Count of items on the heap */
69 WORD first; /* 06 First item of the heap */
70 WORD pad1; /* 08 Always 0 */
71 WORD last; /* 0a Last item of the heap */
72 WORD pad2; /* 0c Always 0 */
73 BYTE ncompact; /* 0e Compactions counter */
74 BYTE dislevel; /* 0f Discard level */
75 DWORD distotal; /* 10 Total bytes discarded */
76 WORD htable; /* 14 Pointer to handle table */
77 WORD hfree; /* 16 Pointer to free handle table */
78 WORD hdelta; /* 18 Delta to expand the handle table */
79 WORD expand; /* 1a Pointer to expand function (unused) */
80 WORD pstat; /* 1c Pointer to status structure (unused) */
81 FARPROC notify WINE_PACKED; /* 1e Pointer to LocalNotify() function */
82 WORD lock; /* 22 Lock count for the heap */
83 WORD extra; /* 24 Extra bytes to allocate when expanding */
84 WORD minsize; /* 26 Minimum size of the heap */
85 WORD magic; /* 28 Magic number */
86 } LOCALHEAPINFO;
88 #ifndef WINELIB
89 #pragma pack(4)
90 #endif
92 #define LOCAL_HEAP_MAGIC 0x484c /* 'LH' */
95 /* All local heap allocations are aligned on 4-byte boundaries */
96 #define LALIGN(word) (((word) + 3) & ~3)
98 #define ARENA_PTR(ptr,arena) ((LOCALARENA *)((char*)(ptr)+(arena)))
99 #define ARENA_PREV(ptr,arena) (ARENA_PTR((ptr),(arena))->prev & ~3)
100 #define ARENA_NEXT(ptr,arena) (ARENA_PTR((ptr),(arena))->next)
101 #define ARENA_FLAGS(ptr,arena) (ARENA_PTR((ptr),(arena))->prev & 3)
103 /* determine whether the handle belongs to a fixed or a moveable block */
104 #define HANDLE_FIXED(handle) (((handle) & 3) == 0)
105 #define HANDLE_MOVEABLE(handle) (((handle) & 3) == 2)
107 /***********************************************************************
108 * LOCAL_GetHeap
110 * Return a pointer to the local heap, making sure it exists.
112 static LOCALHEAPINFO *LOCAL_GetHeap( HANDLE16 ds )
114 LOCALHEAPINFO *pInfo;
115 INSTANCEDATA *ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( ds, 0 );
116 dprintf_local( stddeb, "Heap at %p, %04x\n", ptr, ptr->heap );
117 if (!ptr || !ptr->heap) return NULL;
118 if (IsBadReadPtr((SEGPTR)MAKELONG( ptr->heap, ds ), sizeof(LOCALHEAPINFO)))
119 return NULL;
120 pInfo = (LOCALHEAPINFO*)((char*)ptr + ptr->heap);
121 if (pInfo->magic != LOCAL_HEAP_MAGIC) return NULL;
122 return pInfo;
126 /***********************************************************************
127 * LOCAL_MakeBlockFree
129 * Make a block free, inserting it in the free-list.
130 * 'block' is the handle of the block arena; 'baseptr' points to
131 * the beginning of the data segment containing the heap.
133 static void LOCAL_MakeBlockFree( char *baseptr, WORD block )
135 LOCALARENA *pArena, *pNext;
136 WORD next;
138 /* Mark the block as free */
140 pArena = ARENA_PTR( baseptr, block );
141 pArena->prev = (pArena->prev & ~3) | LOCAL_ARENA_FREE;
142 pArena->size = pArena->next - block;
144 /* Find the next free block (last block is always free) */
146 next = pArena->next;
147 for (;;)
149 pNext = ARENA_PTR( baseptr, next );
150 if ((pNext->prev & 3) == LOCAL_ARENA_FREE) break;
151 next = pNext->next;
154 dprintf_local( stddeb, "Local_AddFreeBlock %04x, next %04x\n", block, next );
155 /* Insert the free block in the free-list */
157 pArena->free_prev = pNext->free_prev;
158 pArena->free_next = next;
159 ARENA_PTR(baseptr,pNext->free_prev)->free_next = block;
160 pNext->free_prev = block;
164 /***********************************************************************
165 * LOCAL_RemoveFreeBlock
167 * Remove a block from the free-list.
168 * 'block' is the handle of the block arena; 'baseptr' points to
169 * the beginning of the data segment containing the heap.
171 static void LOCAL_RemoveFreeBlock( char *baseptr, WORD block )
173 /* Mark the block as fixed */
175 LOCALARENA *pArena = ARENA_PTR( baseptr, block );
176 pArena->prev = (pArena->prev & ~3) | LOCAL_ARENA_FIXED;
178 /* Remove it from the list */
180 ARENA_PTR(baseptr,pArena->free_prev)->free_next = pArena->free_next;
181 ARENA_PTR(baseptr,pArena->free_next)->free_prev = pArena->free_prev;
185 /***********************************************************************
186 * LOCAL_AddBlock
188 * Insert a new block in the heap.
189 * 'new' is the handle of the new block arena; 'baseptr' points to
190 * the beginning of the data segment containing the heap; 'prev' is
191 * the block before the new one.
193 static void LOCAL_AddBlock( char *baseptr, WORD prev, WORD new )
195 LOCALARENA *pPrev = ARENA_PTR( baseptr, prev );
196 LOCALARENA *pNew = ARENA_PTR( baseptr, new );
198 pNew->prev = (prev & ~3) | LOCAL_ARENA_FIXED;
199 pNew->next = pPrev->next;
200 ARENA_PTR(baseptr,pPrev->next)->prev &= 3;
201 ARENA_PTR(baseptr,pPrev->next)->prev |= new;
202 pPrev->next = new;
206 /***********************************************************************
207 * LOCAL_RemoveBlock
209 * Remove a block from the heap.
210 * 'block' is the handle of the block arena; 'baseptr' points to
211 * the beginning of the data segment containing the heap.
213 static void LOCAL_RemoveBlock( char *baseptr, WORD block )
215 LOCALARENA *pArena, *pTmp;
217 /* Remove the block from the free-list */
219 dprintf_local( stddeb, "Local_RemoveBlock\n");
220 pArena = ARENA_PTR( baseptr, block );
221 if ((pArena->prev & 3) == LOCAL_ARENA_FREE)
222 LOCAL_RemoveFreeBlock( baseptr, block );
224 /* If the previous block is free, expand its size */
226 pTmp = ARENA_PTR( baseptr, pArena->prev & ~3 );
227 if ((pTmp->prev & 3) == LOCAL_ARENA_FREE)
228 pTmp->size += pArena->next - block;
230 /* Remove the block from the linked list */
232 pTmp->next = pArena->next;
233 pTmp = ARENA_PTR( baseptr, pArena->next );
234 pTmp->prev = (pTmp->prev & 3) | (pArena->prev & ~3);
238 /***********************************************************************
239 * LOCAL_PrintHeap
241 static void LOCAL_PrintHeap( HANDLE16 ds )
243 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
244 LOCALHEAPINFO *pInfo = LOCAL_GetHeap( ds );
245 WORD arena;
247 if (!debugging_local) return;
248 if (!pInfo)
250 printf( "Local Heap corrupted! ds=%04x\n", ds );
251 return;
253 printf( "Local Heap ds=%04x first=%04x last=%04x items=%d\n",
254 ds, pInfo->first, pInfo->last, pInfo->items );
256 arena = pInfo->first;
257 for (;;)
259 LOCALARENA *pArena = ARENA_PTR(ptr,arena);
260 printf( " %04x: prev=%04x next=%04x type=%d\n", arena,
261 pArena->prev & ~3, pArena->next, pArena->prev & 3 );
262 if (arena == pInfo->first)
264 printf( " size=%d free_prev=%04x free_next=%04x\n",
265 pArena->size, pArena->free_prev, pArena->free_next );
267 if ((pArena->prev & 3) == LOCAL_ARENA_FREE)
269 printf( " size=%d free_prev=%04x free_next=%04x\n",
270 pArena->size, pArena->free_prev, pArena->free_next );
271 if (pArena->next == arena) break; /* last one */
272 if (ARENA_PTR(ptr,pArena->free_next)->free_prev != arena)
274 printf( "*** arena->free_next->free_prev != arena\n" );
275 break;
278 if (pArena->next == arena)
280 printf( "*** last block is not marked free\n" );
281 break;
283 if ((ARENA_PTR(ptr,pArena->next)->prev & ~3) != arena)
285 printf( "*** arena->next->prev != arena (%04x, %04x)\n",
286 pArena->next, ARENA_PTR(ptr,pArena->next)->prev);
287 break;
289 arena = pArena->next;
294 /***********************************************************************
295 * LocalInit (KERNEL.4)
297 BOOL LocalInit( HANDLE selector, WORD start, WORD end )
299 char *ptr;
300 WORD heapInfoArena, freeArena, lastArena;
301 LOCALHEAPINFO *pHeapInfo;
302 LOCALARENA *pArena, *pFirstArena, *pLastArena;
303 NE_MODULE *pModule;
305 /* The initial layout of the heap is: */
306 /* - first arena (FIXED) */
307 /* - heap info structure (FIXED) */
308 /* - large free block (FREE) */
309 /* - last arena (FREE) */
311 dprintf_local(stddeb, "LocalInit: %04x %04x-%04x\n", selector, start, end);
312 if (!selector) selector = CURRENT_DS;
313 pHeapInfo = LOCAL_GetHeap(selector);
315 if (pHeapInfo) {
316 fprintf( stderr, "LocalInit: Heap %04x initialized twice.\n", selector);
317 if (debugging_local) LOCAL_PrintHeap(selector);
320 if (start == 0) {
321 /* Check if the segment is the DGROUP of a module */
323 if ((pModule = MODULE_GetPtr( GetExePtr( selector ) )))
325 SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
326 if (pModule->dgroup && (pSeg->selector == selector)) {
327 /* We can't just use the simple method of using the value
328 * of minsize + stacksize, since there are programs that
329 * resize the data segment before calling InitTask(). So,
330 * we must put it at the end of the segment */
331 start = GlobalSize16( GlobalHandle16( selector ) );
332 start -= end;
333 end += start;
334 dprintf_local( stddeb," new start %04x, minstart: %04x\n", start, pSeg->minsize + pModule->stack_size);
338 ptr = PTR_SEG_OFF_TO_LIN( selector, 0 );
340 start = LALIGN( MAX( start, sizeof(INSTANCEDATA) ) );
341 heapInfoArena = LALIGN(start + sizeof(LOCALARENA) );
342 freeArena = LALIGN( heapInfoArena + ARENA_HEADER_SIZE
343 + sizeof(LOCALHEAPINFO) );
344 lastArena = (end - sizeof(LOCALARENA)) & ~3;
346 /* Make sure there's enough space. */
348 if (freeArena + sizeof(LOCALARENA) >= lastArena) return FALSE;
350 /* Initialise the first arena */
352 pFirstArena = ARENA_PTR( ptr, start );
353 pFirstArena->prev = start | LOCAL_ARENA_FIXED;
354 pFirstArena->next = heapInfoArena;
355 pFirstArena->size = LALIGN(sizeof(LOCALARENA));
356 pFirstArena->free_prev = start; /* this one */
357 pFirstArena->free_next = freeArena;
359 /* Initialise the arena of the heap info structure */
361 pArena = ARENA_PTR( ptr, heapInfoArena );
362 pArena->prev = start | LOCAL_ARENA_FIXED;
363 pArena->next = freeArena;
365 /* Initialise the heap info structure */
367 pHeapInfo = (LOCALHEAPINFO *) (ptr + heapInfoArena + ARENA_HEADER_SIZE );
368 memset( pHeapInfo, 0, sizeof(LOCALHEAPINFO) );
369 pHeapInfo->items = 4;
370 pHeapInfo->first = start;
371 pHeapInfo->last = lastArena;
372 pHeapInfo->htable = 0;
373 pHeapInfo->hdelta = 0x20;
374 pHeapInfo->extra = 0x200;
375 pHeapInfo->minsize = lastArena - freeArena;
376 pHeapInfo->magic = LOCAL_HEAP_MAGIC;
378 /* Initialise the large free block */
380 pArena = ARENA_PTR( ptr, freeArena );
381 pArena->prev = heapInfoArena | LOCAL_ARENA_FREE;
382 pArena->next = lastArena;
383 pArena->size = lastArena - freeArena;
384 pArena->free_prev = start;
385 pArena->free_next = lastArena;
387 /* Initialise the last block */
389 pLastArena = ARENA_PTR( ptr, lastArena );
390 pLastArena->prev = freeArena | LOCAL_ARENA_FREE;
391 pLastArena->next = lastArena; /* this one */
392 pLastArena->size = LALIGN(sizeof(LOCALARENA));
393 pLastArena->free_prev = freeArena;
394 pLastArena->free_next = lastArena; /* this one */
396 /* Store the local heap address in the instance data */
398 ((INSTANCEDATA *)ptr)->heap = heapInfoArena + ARENA_HEADER_SIZE;
399 LOCAL_PrintHeap( selector );
400 return TRUE;
403 /***********************************************************************
404 * LOCAL_GrowHeap
406 static void LOCAL_GrowHeap( HANDLE16 ds )
408 HANDLE hseg = GlobalHandle16( ds );
409 LONG oldsize = GlobalSize16( hseg );
410 LONG end;
411 LOCALHEAPINFO *pHeapInfo;
412 WORD freeArena, lastArena;
413 LOCALARENA *pArena, *pLastArena;
414 char *ptr;
416 /* if nothing can be gained, return */
417 if (oldsize > 0xfff0) return;
418 hseg = GlobalReAlloc16( hseg, 0x10000, GMEM_FIXED );
419 ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
420 pHeapInfo = LOCAL_GetHeap( ds );
421 if (pHeapInfo == NULL) {
422 fprintf( stderr, "Local_GrowHeap: heap not found\n" );
423 return;
425 end = GlobalSize16( hseg );
426 lastArena = (end - sizeof(LOCALARENA)) & ~3;
428 /* Update the HeapInfo */
429 pHeapInfo->items++;
430 freeArena = pHeapInfo->last;
431 pHeapInfo->last = lastArena;
432 pHeapInfo->minsize += end - oldsize;
434 /* grow the old last block */
435 pArena = ARENA_PTR( ptr, freeArena );
436 pArena->size = lastArena - freeArena;
437 pArena->next = lastArena;
438 pArena->free_next = lastArena;
440 /* Initialise the new last block */
442 pLastArena = ARENA_PTR( ptr, lastArena );
443 pLastArena->prev = freeArena | LOCAL_ARENA_FREE;
444 pLastArena->next = lastArena; /* this one */
445 pLastArena->size = LALIGN(sizeof(LOCALARENA));
446 pLastArena->free_prev = freeArena;
447 pLastArena->free_next = lastArena; /* this one */
449 /* If block before freeArena is also free then merge them */
450 if((ARENA_PTR(ptr, (pArena->prev & ~3))->prev & 3) == LOCAL_ARENA_FREE)
452 LOCAL_RemoveBlock(ptr, freeArena);
453 pHeapInfo->items--;
456 dprintf_local( stddeb, "Heap expanded\n" );
457 LOCAL_PrintHeap( ds );
461 /***********************************************************************
462 * LOCAL_FreeArena
464 static HLOCAL16 LOCAL_FreeArena( WORD ds, WORD arena )
466 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
467 LOCALHEAPINFO *pInfo;
468 LOCALARENA *pArena, *pPrev, *pNext;
470 dprintf_local( stddeb, "LocalFreeArena: %04x ds=%04x\n", arena, ds );
471 if (!(pInfo = LOCAL_GetHeap( ds ))) return arena;
473 pArena = ARENA_PTR( ptr, arena );
474 if ((pArena->prev & 3) == LOCAL_ARENA_FREE)
476 /* shouldn't happen */
477 fprintf( stderr, "LocalFreeArena: Trying to free block %04x twice!\n",
478 arena );
479 LOCAL_PrintHeap( ds );
480 return arena;
483 /* Check if we can merge with the previous block */
485 pPrev = ARENA_PTR( ptr, pArena->prev & ~3 );
486 pNext = ARENA_PTR( ptr, pArena->next );
487 if ((pPrev->prev & 3) == LOCAL_ARENA_FREE)
489 arena = pArena->prev & ~3;
490 pArena = pPrev;
491 LOCAL_RemoveBlock( ptr, pPrev->next );
492 pInfo->items--;
494 else /* Make a new free block */
496 LOCAL_MakeBlockFree( ptr, arena );
499 /* Check if we can merge with the next block */
501 if ((pArena->next == pArena->free_next) &&
502 (pArena->next != pInfo->last))
504 LOCAL_RemoveBlock( ptr, pArena->next );
505 pInfo->items--;
507 return 0;
511 /***********************************************************************
512 * LOCAL_ShrinkArena
514 * Shrink an arena by creating a free block at its end if possible.
515 * 'size' includes the arena header, and must be aligned.
517 static void LOCAL_ShrinkArena( WORD ds, WORD arena, WORD size )
519 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
520 LOCALARENA *pArena = ARENA_PTR( ptr, arena );
522 if (arena + size + LALIGN(sizeof(LOCALARENA)) < pArena->next)
524 LOCALHEAPINFO *pInfo = LOCAL_GetHeap( ds );
525 if (!pInfo) return;
526 LOCAL_AddBlock( ptr, arena, arena + size );
527 pInfo->items++;
528 LOCAL_FreeArena( ds, arena + size );
533 /***********************************************************************
534 * LOCAL_GrowArenaDownward
536 * Grow an arena downward by using the previous arena (must be free).
538 static void LOCAL_GrowArenaDownward( WORD ds, WORD arena, WORD newsize )
540 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
541 LOCALHEAPINFO *pInfo;
542 LOCALARENA *pArena = ARENA_PTR( ptr, arena );
543 WORD prevArena = pArena->prev & ~3;
544 LOCALARENA *pPrevArena = ARENA_PTR( ptr, prevArena );
545 WORD offset, size;
546 char *p;
548 if (!(pInfo = LOCAL_GetHeap( ds ))) return;
549 offset = pPrevArena->size;
550 size = pArena->next - arena - ARENA_HEADER_SIZE;
551 LOCAL_RemoveFreeBlock( ptr, prevArena );
552 LOCAL_RemoveBlock( ptr, arena );
553 pInfo->items--;
554 p = (char *)pPrevArena + ARENA_HEADER_SIZE;
555 while (offset < size)
557 memcpy( p, p + offset, offset );
558 p += offset;
559 size -= offset;
561 if (size) memcpy( p, p + offset, size );
562 LOCAL_ShrinkArena( ds, prevArena, newsize );
566 /***********************************************************************
567 * LOCAL_GetFreeSpace
569 static WORD LOCAL_GetFreeSpace(WORD ds, WORD countdiscard)
571 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
572 LOCALHEAPINFO *pInfo;
573 LOCALARENA *pArena;
574 WORD arena;
575 WORD freespace = 0;
577 if (!(pInfo = LOCAL_GetHeap( ds )))
579 fprintf( stderr, "LOCAL_GetFreeSpace: Local heap not found\n" );
580 LOCAL_PrintHeap(ds);
581 return 0;
583 arena = pInfo->first;
584 pArena = ARENA_PTR( ptr, arena );
585 while (arena != pArena->free_next)
587 arena = pArena->free_next;
588 pArena = ARENA_PTR( ptr, arena );
589 if (pArena->size >= freespace) freespace = pArena->size;
591 /* FIXME doesn't yet calculate space that would become free if everything
592 were discarded when countdiscard == 1 */
593 if (freespace < ARENA_HEADER_SIZE) freespace = 0;
594 else freespace -= ARENA_HEADER_SIZE;
595 return freespace;
599 /***********************************************************************
600 * LOCAL_Compact
602 static WORD LOCAL_Compact( HANDLE16 ds, WORD minfree, WORD flags )
604 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
605 LOCALHEAPINFO *pInfo;
606 LOCALARENA *pArena, *pMoveArena, *pFinalArena;
607 WORD arena, movearena, finalarena, table;
608 WORD count, movesize, size;
609 WORD freespace;
610 LOCALHANDLEENTRY *pEntry;
612 if (!(pInfo = LOCAL_GetHeap( ds )))
614 fprintf( stderr, "Local_Compact: Local heap not found\n" );
615 LOCAL_PrintHeap(ds);
616 return 0;
618 dprintf_local(stddeb,
619 "LOCAL_Compact: ds = %04x, minfree = %04x, flags = %04x\n",
620 ds, minfree, flags);
621 freespace = LOCAL_GetFreeSpace(ds, minfree ? 0 : 1);
622 if(freespace >= minfree || (flags & LMEM_NOCOMPACT))
624 dprintf_local(stddeb, "Returning %04x.\n", freespace);
625 return freespace;
627 dprintf_local(stddeb, "Local_Compact: Compacting heap %04x.\n", ds);
628 table = pInfo->htable;
629 while(table)
631 pEntry = (LOCALHANDLEENTRY *)(ptr + table + sizeof(WORD));
632 for(count = *(WORD *)(ptr + table); count > 0; count--, pEntry++)
634 if((pEntry->lock == 0) && !(pEntry->flags &
635 (LMEM_DISCARDED >> 8)))
637 /* OK we can move this one if we want */
638 dprintf_local(stddeb,
639 "handle %04x (block %04x) can be moved.\n",
640 (WORD)((char *)pEntry - ptr), pEntry->addr);
641 movearena = ARENA_HEADER(pEntry->addr);
642 pMoveArena = ARENA_PTR(ptr, movearena);
643 movesize = pMoveArena->next - movearena;
644 arena = pInfo->first;
645 pArena = ARENA_PTR(ptr, arena);
646 size = 0xffff;
647 finalarena = 0;
648 /* Try to find the smallest arena that will do, */
649 /* which is below us in memory */
650 for(;;)
652 arena = pArena->free_next;
653 pArena = ARENA_PTR(ptr, arena);
654 if(arena >= movearena)
655 break;
656 if(arena == pArena->free_next)
657 break;
658 if((pArena->size >= movesize) && (pArena->size < size))
660 size = pArena->size;
661 finalarena = arena;
664 if (finalarena) /* Actually got somewhere to move */
666 dprintf_local(stddeb, "Moving it to %04x.\n", finalarena);
667 pFinalArena = ARENA_PTR(ptr, finalarena);
668 size = pFinalArena->size;
669 LOCAL_RemoveFreeBlock(ptr, finalarena);
670 LOCAL_ShrinkArena( ds, finalarena, movesize );
671 /* Copy the arena to it's new location */
672 memcpy((char *)pFinalArena + ARENA_HEADER_SIZE,
673 (char *)pMoveArena + ARENA_HEADER_SIZE,
674 movesize - ARENA_HEADER_SIZE );
675 /* Free the old location */
676 LOCAL_FreeArena(ds, movearena);
677 /* Update handle table entry */
678 pEntry->addr = finalarena + ARENA_HEADER_SIZE;
680 else if((ARENA_PTR(ptr, pMoveArena->prev & ~3)->prev & 3)
681 == LOCAL_ARENA_FREE)
683 /* Previous arena is free (but < movesize) */
684 /* so we can 'slide' movearena down into it */
685 finalarena = pMoveArena->prev & ~3;
686 LOCAL_GrowArenaDownward( ds, movearena, movesize );
687 /* Update handle table entry */
688 pEntry->addr = finalarena + ARENA_HEADER_SIZE;
692 table = *(WORD *)pEntry;
694 freespace = LOCAL_GetFreeSpace(ds, minfree ? 0 : 1);
695 if(freespace >= minfree || (flags & LMEM_NODISCARD))
697 dprintf_local(stddeb, "Returning %04x.\n", freespace);
698 return freespace;
701 table = pInfo->htable;
702 while(table)
704 pEntry = (LOCALHANDLEENTRY *)(ptr + table + sizeof(WORD));
705 for(count = *(WORD *)(ptr + table); count > 0; count--, pEntry++)
707 if((pEntry->flags & (LMEM_DISCARDABLE >> 8)) &&
708 pEntry->lock == 0 && !(pEntry->flags & (LMEM_DISCARDED >> 8)))
710 dprintf_local(stddeb, "Discarding handle %04x (block %04x).\n",
711 (char *)pEntry - ptr, pEntry->addr);
712 LOCAL_FreeArena(ds, pEntry->addr);
713 pEntry->addr = 0;
714 pEntry->flags |= (LMEM_DISCARDED >> 8);
715 /* Call localnotify proc */
718 table = *(WORD *)pEntry;
720 return LOCAL_Compact(ds, 0xffff, LMEM_NODISCARD);
724 /***********************************************************************
725 * LOCAL_FindFreeBlock
727 static HLOCAL16 LOCAL_FindFreeBlock( HANDLE16 ds, WORD size )
729 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
730 LOCALHEAPINFO *pInfo;
731 LOCALARENA *pArena;
732 WORD arena;
734 if (!(pInfo = LOCAL_GetHeap( ds )))
736 fprintf( stderr, "Local_FindFreeBlock: Local heap not found\n" );
737 LOCAL_PrintHeap(ds);
738 return 0;
741 arena = pInfo->first;
742 pArena = ARENA_PTR( ptr, arena );
743 for (;;) {
744 arena = pArena->free_next;
745 pArena = ARENA_PTR( ptr, arena );
746 if (arena == pArena->free_next) break;
747 if (pArena->size >= size) return arena;
749 dprintf_local( stddeb, "Local_FindFreeBlock: not enough space\n" );
750 if (debugging_local) LOCAL_PrintHeap(ds);
751 return 0;
754 /***********************************************************************
755 * LOCAL_GetBlock
756 * The segment may get moved around in this function, so all callers
757 * should reset their pointer variables.
759 static HLOCAL16 LOCAL_GetBlock( HANDLE16 ds, WORD size, WORD flags )
761 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
762 LOCALHEAPINFO *pInfo;
763 LOCALARENA *pArena;
764 WORD arena;
766 if (!(pInfo = LOCAL_GetHeap( ds )))
768 fprintf( stderr, "Local_GetBlock: Local heap not found\n");
769 LOCAL_PrintHeap(ds);
770 return 0;
773 size += ARENA_HEADER_SIZE;
774 size = LALIGN( MAX( size, sizeof(LOCALARENA) ) );
776 /* Find a suitable free block */
777 arena = LOCAL_FindFreeBlock( ds, size );
778 if (arena == 0) {
779 /* no space: try to make some */
780 LOCAL_Compact( ds, size, flags );
781 arena = LOCAL_FindFreeBlock( ds, size );
783 if (arena == 0) {
784 /* still no space: try to grow the segment */
785 LOCAL_GrowHeap( ds );
786 ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
787 pInfo = LOCAL_GetHeap( ds );
788 arena = LOCAL_FindFreeBlock( ds, size );
790 if (arena == 0) {
791 fprintf( stderr, "Local_GetBlock: not enough space in heap %04x for %d bytes\n",
792 ds, size );
793 return 0;
796 /* Make a block out of the free arena */
797 pArena = ARENA_PTR( ptr, arena );
798 dprintf_local(stddeb, "LOCAL_GetBlock size = %04x, arena %04x size %04x\n",
799 size, arena, pArena->size );
800 LOCAL_RemoveFreeBlock( ptr, arena );
801 LOCAL_ShrinkArena( ds, arena, size );
803 if (flags & LMEM_ZEROINIT) memset( (char *)pArena + ARENA_HEADER_SIZE, 0,
804 size - ARENA_HEADER_SIZE );
805 return arena + ARENA_HEADER_SIZE;
809 /***********************************************************************
810 * LOCAL_NewHTable
812 static BOOL LOCAL_NewHTable( HANDLE16 ds )
814 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
815 LOCALHEAPINFO *pInfo;
816 LOCALHANDLEENTRY *pEntry;
817 HLOCAL16 handle;
818 int i;
820 dprintf_local( stddeb, "Local_NewHTable\n" );
821 if (!(pInfo = LOCAL_GetHeap( ds )))
823 fprintf( stderr, "Local heap not found\n");
824 LOCAL_PrintHeap(ds);
825 return FALSE;
828 if (!(handle = LOCAL_GetBlock( ds, pInfo->hdelta * sizeof(LOCALHANDLEENTRY)
829 + 2 * sizeof(WORD), LMEM_FIXED )))
830 return FALSE;
831 if (!(ptr = PTR_SEG_OFF_TO_LIN( ds, 0 )))
832 fprintf(stderr, "LOCAL_NewHTable: ptr == NULL after GetBlock.\n");
833 if (!(pInfo = LOCAL_GetHeap( ds )))
834 fprintf(stderr,"LOCAL_NewHTable: pInfo == NULL after GetBlock.\n");
836 /* Fill the entry table */
838 *(WORD *)(ptr + handle) = pInfo->hdelta;
839 pEntry = (LOCALHANDLEENTRY *)(ptr + handle + sizeof(WORD));
840 for (i = pInfo->hdelta; i > 0; i--) (pEntry++)->lock = 0xff;
841 *(WORD *)pEntry = pInfo->htable;
842 pInfo->htable = handle;
843 return TRUE;
847 /***********************************************************************
848 * LOCAL_GetNewHandleEntry
850 static HLOCAL16 LOCAL_GetNewHandleEntry( HANDLE16 ds )
852 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
853 LOCALHEAPINFO *pInfo;
854 LOCALHANDLEENTRY *pEntry = NULL;
855 WORD table;
857 if (!(pInfo = LOCAL_GetHeap( ds )))
859 fprintf( stderr, "LOCAL_GetNewHandleEntry: Local heap not found\n");
860 LOCAL_PrintHeap(ds);
861 return 0;
864 /* Find a free slot in existing tables */
866 table = pInfo->htable;
867 while (table)
869 WORD count = *(WORD *)(ptr + table);
870 pEntry = (LOCALHANDLEENTRY *)(ptr + table + sizeof(WORD));
871 for (; count > 0; count--, pEntry++)
872 if (pEntry->lock == 0xff) break;
873 if (count) break;
874 table = *(WORD *)pEntry;
877 if (!table) /* We need to create a new table */
879 if (!LOCAL_NewHTable( ds )) return 0;
880 ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
881 pInfo = LOCAL_GetHeap( ds );
882 pEntry = (LOCALHANDLEENTRY *)(ptr + pInfo->htable + sizeof(WORD));
885 /* Now allocate this entry */
887 pEntry->lock = 0;
888 dprintf_local( stddeb, "LOCAL_GetNewHandleEntry(%04x): %04x\n",
889 ds, ((char *)pEntry - ptr) );
890 return (HLOCAL16)((char *)pEntry - ptr);
894 /***********************************************************************
895 * LOCAL_FreeHandleEntry
897 * Free a handle table entry.
899 static void LOCAL_FreeHandleEntry( HANDLE16 ds, HLOCAL16 handle )
901 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
902 LOCALHANDLEENTRY *pEntry = (LOCALHANDLEENTRY *)(ptr + handle);
903 LOCALHEAPINFO *pInfo;
904 WORD *pTable;
905 WORD table, count, i;
907 if (!(pInfo = LOCAL_GetHeap( ds ))) return;
909 /* Find the table where this handle comes from */
911 pTable = &pInfo->htable;
912 while (*pTable)
914 WORD size = (*(WORD *)(ptr + *pTable)) * sizeof(LOCALHANDLEENTRY);
915 if ((handle >= *pTable + sizeof(WORD)) &&
916 (handle < *pTable + sizeof(WORD) + size)) break; /* Found it */
917 pTable = (WORD *)(ptr + *pTable + sizeof(WORD) + size);
919 if (!*pTable)
921 fprintf(stderr, "LOCAL_FreeHandleEntry: invalid entry %04x\n", handle);
922 LOCAL_PrintHeap( ds );
923 return;
926 /* Make the entry free */
928 pEntry->addr = 0; /* just in case */
929 pEntry->lock = 0xff;
931 /* Now check if all entries in this table are free */
933 table = *pTable;
934 pEntry = (LOCALHANDLEENTRY *)(ptr + table + sizeof(WORD));
935 count = *(WORD *)(ptr + table);
936 for (i = count; i > 0; i--, pEntry++) if (pEntry->lock != 0xff) return;
938 /* Remove the table from the linked list and free it */
940 dprintf_local( stddeb, "LOCAL_FreeHandleEntry(%04x): freeing table %04x\n",
941 ds, table);
942 *pTable = *(WORD *)pEntry;
943 LOCAL_FreeArena( ds, ARENA_HEADER( table ) );
947 /***********************************************************************
948 * LOCAL_Free
950 * Implementation of LocalFree().
952 HLOCAL16 LOCAL_Free( HANDLE16 ds, HLOCAL16 handle )
954 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
956 dprintf_local( stddeb, "LocalFree: %04x ds=%04x\n", handle, ds );
958 if (!handle) { fprintf( stderr, "LOCAL_Free: handle is 0.\n" ); return 0; }
959 if (HANDLE_FIXED( handle ))
961 if (!LOCAL_FreeArena( ds, ARENA_HEADER( handle ) )) return 0; /* OK */
962 else return handle; /* couldn't free it */
964 else
966 LOCALHANDLEENTRY *pEntry = (LOCALHANDLEENTRY *)(ptr + handle);
967 if (!(pEntry->flags & (LMEM_DISCARDED >> 8)))
969 dprintf_local( stddeb, "LocalFree: real block at %04x\n",
970 pEntry->addr );
971 if (LOCAL_FreeArena( ds, ARENA_HEADER(pEntry->addr) ))
972 return handle; /* couldn't free it */
974 LOCAL_FreeHandleEntry( ds, handle );
975 return 0; /* OK */
980 /***********************************************************************
981 * LOCAL_Alloc
983 * Implementation of LocalAlloc().
985 HLOCAL16 LOCAL_Alloc( HANDLE16 ds, WORD flags, WORD size )
987 char *ptr;
988 HLOCAL16 handle;
990 dprintf_local( stddeb, "LocalAlloc: %04x %d ds=%04x\n", flags, size, ds );
992 if (flags & LMEM_MOVEABLE)
994 LOCALHANDLEENTRY *plhe;
995 HLOCAL16 hmem;
997 if (!(hmem = LOCAL_GetBlock( ds, size, flags ))) return 0;
998 if (!(handle = LOCAL_GetNewHandleEntry( ds )))
1000 fprintf( stderr, "LocalAlloc: couldn't get handle\n");
1001 LOCAL_FreeArena( ds, ARENA_HEADER(hmem) );
1002 return 0;
1004 ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
1005 plhe = (LOCALHANDLEENTRY *)(ptr + handle);
1006 plhe->addr = hmem;
1007 plhe->flags = (BYTE)(flags >> 8);
1008 plhe->lock = 0;
1010 else handle = LOCAL_GetBlock( ds, size, flags );
1012 return handle;
1016 /***********************************************************************
1017 * LOCAL_ReAlloc
1019 * Implementation of LocalReAlloc().
1021 HLOCAL16 LOCAL_ReAlloc( HANDLE16 ds, HLOCAL16 handle, WORD size, WORD flags )
1023 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
1024 LOCALHEAPINFO *pInfo;
1025 LOCALARENA *pArena, *pNext;
1026 LOCALHANDLEENTRY *pEntry;
1027 WORD arena, newhandle, blockhandle, oldsize;
1028 LONG nextarena;
1030 if (!handle) return LOCAL_Alloc( ds, size, flags );
1032 dprintf_local( stddeb, "LocalReAlloc: %04x %d %04x ds=%04x\n",
1033 handle, size, flags, ds );
1034 if (!(pInfo = LOCAL_GetHeap( ds ))) return 0;
1036 if (HANDLE_FIXED( handle )) blockhandle = handle;
1037 else
1039 pEntry = (LOCALHANDLEENTRY *) (ptr + handle);
1040 if(pEntry->flags & (LMEM_DISCARDED >> 8))
1042 dprintf_local(stddeb, "ReAllocating discarded block\n");
1043 if (!(pEntry->addr = LOCAL_GetBlock( ds, size, flags))) return 0;
1044 ptr = PTR_SEG_OFF_TO_LIN( ds, 0 ); /* Reload ptr */
1045 pEntry = (LOCALHANDLEENTRY *) (ptr + handle);
1046 pEntry->flags = (BYTE) (flags >> 8);
1047 pEntry->lock = 0;
1048 return handle;
1050 if (!(blockhandle = pEntry->addr))
1052 fprintf( stderr, "Local_ReAlloc(%04x,%04x): invalid handle\n",
1053 ds, handle );
1054 return 0;
1058 arena = ARENA_HEADER( blockhandle );
1059 dprintf_local( stddeb, "LocalReAlloc: arena is %04x\n", arena );
1060 pArena = ARENA_PTR( ptr, arena );
1062 if ((flags & LMEM_MODIFY) && (flags & LMEM_DISCARDABLE))
1064 if (HANDLE_FIXED(handle))
1066 fprintf(stderr,"LocalReAlloc: LMEM_MODIFY & LMEM_DISCARDABLE on a fixed handle.\n");
1067 return handle;
1069 dprintf_local( stddeb, "Making block discardable.\n" );
1070 pEntry = (LOCALHANDLEENTRY *)(ptr + handle);
1071 pEntry->flags |= (LMEM_DISCARDABLE >> 8);
1072 return handle;
1075 if ((flags & LMEM_MODIFY) || (flags & LMEM_DISCARDABLE))
1077 fprintf(stderr,"LocalReAlloc: flags %04x. MODIFY & DISCARDABLE should both be set\n", flags);
1078 return handle;
1081 if (!size)
1083 if (HANDLE_FIXED(handle))
1085 if (flags & LMEM_MOVEABLE)
1087 dprintf_local(stddeb, "Freeing fixed block.\n");
1088 return LOCAL_Free( ds, handle );
1090 else size = 1;
1092 else
1094 pEntry = (LOCALHANDLEENTRY *)(ptr + handle);
1095 if (pEntry->lock == 0)
1097 /* discards moveable blocks is this right? */
1098 dprintf_local(stddeb,"Discarding block\n");
1099 LOCAL_FreeArena(ds, ARENA_HEADER(pEntry->addr));
1100 pEntry->addr = 0;
1101 pEntry->flags = (LMEM_DISCARDED >> 8);
1102 return 0;
1104 return handle;
1108 size = LALIGN( size );
1109 oldsize = pArena->next - arena - ARENA_HEADER_SIZE;
1110 nextarena = LALIGN(blockhandle + size);
1112 /* Check for size reduction */
1114 if (nextarena <= pArena->next)
1116 if (nextarena < pArena->next - LALIGN(sizeof(LOCALARENA)))
1118 dprintf_local( stddeb, "size reduction, making new free block\n");
1119 /* It is worth making a new free block */
1120 LOCAL_AddBlock( ptr, arena, nextarena );
1121 pInfo->items++;
1122 LOCAL_FreeArena( ds, nextarena );
1124 dprintf_local( stddeb, "LocalReAlloc: returning %04x\n", handle );
1125 return handle;
1128 /* Check if the next block is free */
1130 pNext = ARENA_PTR( ptr, pArena->next );
1131 if (((pNext->prev & 3) == LOCAL_ARENA_FREE) &&
1132 (nextarena <= pNext->next))
1134 LOCAL_RemoveBlock( ptr, pArena->next );
1135 if (nextarena < pArena->next - LALIGN(sizeof(LOCALARENA)))
1137 dprintf_local( stddeb, "size increase, making new free block\n");
1138 /* It is worth making a new free block */
1139 LOCAL_AddBlock( ptr, arena, nextarena );
1140 pInfo->items++;
1141 LOCAL_FreeArena( ds, nextarena );
1143 dprintf_local( stddeb, "LocalReAlloc: returning %04x\n", handle );
1144 return handle;
1147 /* Now we have to allocate a new block, but not if fixed block and no
1148 LMEM_MOVEABLE */
1150 if (HANDLE_FIXED(handle) && !(flags & LMEM_MOVEABLE))
1152 dprintf_local(stddeb, "Needed to move fixed block, but LMEM_MOVEABLE not specified.\n");
1153 return 0; /* FIXME: should we free it here? */
1156 newhandle = LOCAL_GetBlock( ds, size, flags );
1157 ptr = PTR_SEG_OFF_TO_LIN( ds, 0 ); /* Reload ptr */
1158 if (!newhandle)
1160 /* Remove the block from the heap and try again */
1161 LPSTR buffer = HeapAlloc( SystemHeap, 0, oldsize );
1162 if (!buffer) return 0;
1163 memcpy( buffer, ptr + (arena + ARENA_HEADER_SIZE), oldsize );
1164 LOCAL_FreeArena( ds, arena );
1165 if (!(newhandle = LOCAL_GetBlock( ds, size, flags )))
1167 if (!(newhandle = LOCAL_GetBlock( ds, oldsize, flags )))
1169 fprintf( stderr, "LocalRealloc: can't restore saved block\n" );
1170 HeapFree( SystemHeap, 0, buffer );
1171 return 0;
1173 size = oldsize;
1175 ptr = PTR_SEG_OFF_TO_LIN( ds, 0 ); /* Reload ptr */
1176 memcpy( ptr + newhandle, buffer, oldsize );
1177 HeapFree( SystemHeap, 0, buffer );
1179 else
1181 memcpy( ptr + newhandle, ptr + (arena + ARENA_HEADER_SIZE), oldsize );
1182 LOCAL_FreeArena( ds, arena );
1184 if (HANDLE_MOVEABLE( handle ))
1186 dprintf_local( stddeb, "LocalReAlloc: fixing handle\n");
1187 pEntry = (LOCALHANDLEENTRY *)(ptr + handle);
1188 pEntry->addr = newhandle;
1189 pEntry->lock = 0;
1190 newhandle = handle;
1192 if (size == oldsize) newhandle = 0; /* Realloc failed */
1193 dprintf_local( stddeb, "LocalReAlloc: returning %04x\n", newhandle );
1194 return newhandle;
1198 /***********************************************************************
1199 * LOCAL_InternalLock
1201 static HLOCAL16 LOCAL_InternalLock( LPSTR heap, HLOCAL16 handle )
1203 dprintf_local( stddeb, "LocalLock: %04x ", handle );
1204 if (HANDLE_MOVEABLE(handle))
1206 LOCALHANDLEENTRY *pEntry = (LOCALHANDLEENTRY *)(heap + handle);
1207 if (pEntry->lock < 0xfe) pEntry->lock++;
1208 handle = pEntry->addr;
1210 dprintf_local( stddeb, "returning %04x\n", handle );
1211 return handle;
1215 /***********************************************************************
1216 * LOCAL_Lock
1218 LPSTR LOCAL_Lock( HANDLE16 ds, HLOCAL16 handle )
1220 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
1221 return handle ? ptr + LOCAL_InternalLock( ptr, handle ) : NULL;
1225 /***********************************************************************
1226 * LOCAL_Unlock
1228 BOOL LOCAL_Unlock( HANDLE16 ds, HLOCAL16 handle )
1230 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
1232 dprintf_local( stddeb, "LocalUnlock: %04x\n", handle );
1233 if (HANDLE_MOVEABLE(handle))
1235 LOCALHANDLEENTRY *pEntry = (LOCALHANDLEENTRY *)(ptr + handle);
1236 if (!pEntry->lock || (pEntry->lock == 0xff)) return FALSE;
1237 /* For moveable block, return the new lock count */
1238 /* (see _Windows_Internals_ p. 197) */
1239 return --pEntry->lock;
1241 else return FALSE;
1245 /***********************************************************************
1246 * LOCAL_Size
1248 * Implementation of LocalSize().
1250 WORD LOCAL_Size( HANDLE16 ds, HLOCAL16 handle )
1252 char *ptr = PTR_SEG_OFF_TO_LIN( CURRENT_DS, 0 );
1253 LOCALARENA *pArena;
1255 dprintf_local( stddeb, "LocalSize: %04x ds=%04x\n", handle, ds );
1257 if (HANDLE_MOVEABLE( handle )) handle = *(WORD *)(ptr + handle);
1258 pArena = ARENA_PTR( ptr, ARENA_HEADER(handle) );
1259 return pArena->next - handle;
1263 /***********************************************************************
1264 * LOCAL_Flags
1266 * Implementation of LocalFlags().
1268 WORD LOCAL_Flags( HANDLE16 ds, HLOCAL16 handle )
1270 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
1272 if (HANDLE_MOVEABLE(handle))
1274 LOCALHANDLEENTRY *pEntry = (LOCALHANDLEENTRY *)(ptr + handle);
1275 dprintf_local( stddeb, "LOCAL_Flags(%04x,%04x): returning %04x\n",
1276 ds, handle, pEntry->lock | (pEntry->flags << 8) );
1277 return pEntry->lock | (pEntry->flags << 8);
1279 else
1281 dprintf_local( stddeb, "LOCAL_Flags(%04x,%04x): returning 0\n",
1282 ds, handle );
1283 return 0;
1288 /***********************************************************************
1289 * LOCAL_HeapSize
1291 * Implementation of LocalHeapSize().
1293 WORD LOCAL_HeapSize( HANDLE16 ds )
1295 LOCALHEAPINFO *pInfo = LOCAL_GetHeap( ds );
1296 if (!pInfo) return 0;
1297 return pInfo->last - pInfo->first;
1301 /***********************************************************************
1302 * LOCAL_CountFree
1304 * Implementation of LocalCountFree().
1306 WORD LOCAL_CountFree( HANDLE16 ds )
1308 WORD arena, total;
1309 LOCALARENA *pArena;
1310 LOCALHEAPINFO *pInfo;
1311 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
1313 if (!(pInfo = LOCAL_GetHeap( ds )))
1315 fprintf( stderr, "LOCAL_Handle(%04x): Local heap not found\n", ds );
1316 LOCAL_PrintHeap( ds );
1317 return 0;
1320 total = 0;
1321 arena = pInfo->first;
1322 pArena = ARENA_PTR( ptr, arena );
1323 for (;;)
1325 arena = pArena->free_next;
1326 pArena = ARENA_PTR( ptr, arena );
1327 if (arena == pArena->free_next) break;
1328 total += pArena->size;
1330 dprintf_local( stddeb, "LOCAL_CountFree(%04x): returning %d\n", ds, total);
1331 return total;
1335 /***********************************************************************
1336 * LOCAL_Handle
1338 * Implementation of LocalHandle().
1340 HLOCAL16 LOCAL_Handle( HANDLE16 ds, WORD addr )
1342 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
1343 LOCALHEAPINFO *pInfo;
1344 WORD table;
1346 if (!(pInfo = LOCAL_GetHeap( ds )))
1348 fprintf( stderr, "LOCAL_Handle(%04x): Local heap not found\n", ds );
1349 LOCAL_PrintHeap( ds );
1350 return 0;
1353 /* Find the address in the entry tables */
1355 table = pInfo->htable;
1356 while (table)
1358 WORD count = *(WORD *)(ptr + table);
1359 LOCALHANDLEENTRY *pEntry = (LOCALHANDLEENTRY*)(ptr+table+sizeof(WORD));
1360 for (; count > 0; count--, pEntry++)
1361 if (pEntry->addr == addr) return (HLOCAL16)((char *)pEntry - ptr);
1362 table = *(WORD *)pEntry;
1365 return (HLOCAL16)addr; /* Fixed block handle is addr */
1369 /***********************************************************************
1370 * LocalAlloc16 (KERNEL.5)
1372 HLOCAL16 LocalAlloc16( UINT16 flags, WORD size )
1374 return LOCAL_Alloc( CURRENT_DS, flags, size );
1378 /***********************************************************************
1379 * LocalReAlloc16 (KERNEL.6)
1381 HLOCAL16 LocalReAlloc16( HLOCAL16 handle, WORD size, UINT16 flags )
1383 return LOCAL_ReAlloc( CURRENT_DS, handle, size, flags );
1387 /***********************************************************************
1388 * LocalFree16 (KERNEL.7)
1390 HLOCAL16 LocalFree16( HLOCAL16 handle )
1392 return LOCAL_Free( CURRENT_DS, handle );
1396 /***********************************************************************
1397 * LocalLock16 (KERNEL.8)
1399 * Note: only the offset part of the pointer is returned by the relay code.
1401 SEGPTR LocalLock16( HLOCAL16 handle )
1403 HANDLE16 ds = CURRENT_DS;
1404 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
1405 return PTR_SEG_OFF_TO_SEGPTR( ds, LOCAL_InternalLock( ptr, handle ) );
1409 /***********************************************************************
1410 * LocalUnlock16 (KERNEL.9)
1412 BOOL16 LocalUnlock16( HLOCAL16 handle )
1414 return LOCAL_Unlock( CURRENT_DS, handle );
1418 /***********************************************************************
1419 * LocalSize16 (KERNEL.10)
1421 UINT16 LocalSize16( HLOCAL16 handle )
1423 return LOCAL_Size( CURRENT_DS, handle );
1427 /***********************************************************************
1428 * LocalHandle16 (KERNEL.11)
1430 HLOCAL16 LocalHandle16( WORD addr )
1432 return LOCAL_Handle( CURRENT_DS, addr );
1436 /***********************************************************************
1437 * LocalFlags16 (KERNEL.12)
1439 UINT16 LocalFlags16( HLOCAL16 handle )
1441 return LOCAL_Flags( CURRENT_DS, handle );
1445 /***********************************************************************
1446 * LocalCompact16 (KERNEL.13)
1448 UINT16 LocalCompact16( UINT16 minfree )
1450 dprintf_local( stddeb, "LocalCompact: %04x\n", minfree );
1451 return LOCAL_Compact( CURRENT_DS, minfree, 0 );
1455 /***********************************************************************
1456 * LocalNotify (KERNEL.14)
1458 FARPROC LocalNotify( FARPROC func )
1460 LOCALHEAPINFO *pInfo;
1461 FARPROC oldNotify;
1462 HANDLE16 ds = CURRENT_DS;
1464 if (!(pInfo = LOCAL_GetHeap( ds )))
1466 fprintf( stderr, "LOCAL_Notify(%04x): Local heap not found\n", ds );
1467 LOCAL_PrintHeap( ds );
1468 return 0;
1470 dprintf_local( stddeb, "LocalNotify(%04x): %08lx\n", ds, (DWORD)func );
1471 oldNotify = pInfo->notify;
1472 pInfo->notify = func;
1473 return oldNotify;
1477 /***********************************************************************
1478 * LocalShrink16 (KERNEL.121)
1480 UINT16 LocalShrink16( HGLOBAL16 handle, UINT16 newsize )
1482 dprintf_local( stddeb, "LocalShrink: %04x %04x\n", handle, newsize );
1483 return 0;
1487 /***********************************************************************
1488 * GetHeapSpaces (KERNEL.138)
1490 DWORD GetHeapSpaces( HMODULE module )
1492 NE_MODULE *pModule;
1493 WORD ds;
1495 module = GetExePtr( module );
1496 if (!(pModule = MODULE_GetPtr( module ))) return 0;
1497 ds = (NE_SEG_TABLE( pModule ) + pModule->dgroup - 1)->selector;
1498 return MAKELONG( LOCAL_CountFree( ds ), LOCAL_HeapSize( ds ) );
1502 /***********************************************************************
1503 * LocalCountFree (KERNEL.161)
1505 WORD LocalCountFree(void)
1507 return LOCAL_CountFree( CURRENT_DS );
1511 /***********************************************************************
1512 * LocalHeapSize (KERNEL.162)
1514 WORD LocalHeapSize()
1516 dprintf_local( stddeb, "LocalHeapSize:\n" );
1517 return LOCAL_HeapSize( CURRENT_DS );
1521 /***********************************************************************
1522 * LocalHandleDelta (KERNEL.310)
1524 WORD LocalHandleDelta( WORD delta )
1526 LOCALHEAPINFO *pInfo;
1528 if (!(pInfo = LOCAL_GetHeap( CURRENT_DS )))
1530 fprintf( stderr, "LocalHandleDelta: Local heap not found\n");
1531 LOCAL_PrintHeap( CURRENT_DS );
1532 return 0;
1534 if (delta) pInfo->hdelta = delta;
1535 dprintf_local(stddeb, "LocalHandleDelta: returning %04x\n", pInfo->hdelta);
1536 return pInfo->hdelta;
1540 /***********************************************************************
1541 * LocalInfo (TOOLHELP.56)
1543 BOOL LocalInfo( LOCALINFO *pLocalInfo, HGLOBAL handle )
1545 LOCALHEAPINFO *pInfo = LOCAL_GetHeap(SELECTOROF(WIN16_GlobalLock16(handle)));
1546 if (!pInfo) return FALSE;
1547 pLocalInfo->wcItems = pInfo->items;
1548 return TRUE;
1552 /***********************************************************************
1553 * LocalFirst (TOOLHELP.57)
1555 BOOL LocalFirst( LOCALENTRY *pLocalEntry, HGLOBAL handle )
1557 WORD ds = GlobalHandleToSel( handle );
1558 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
1559 LOCALHEAPINFO *pInfo = LOCAL_GetHeap( ds );
1560 if (!pInfo) return FALSE;
1562 pLocalEntry->hHandle = pInfo->first + ARENA_HEADER_SIZE;
1563 pLocalEntry->wAddress = pLocalEntry->hHandle;
1564 pLocalEntry->wFlags = LF_FIXED;
1565 pLocalEntry->wcLock = 0;
1566 pLocalEntry->wType = LT_NORMAL;
1567 pLocalEntry->hHeap = handle;
1568 pLocalEntry->wHeapType = NORMAL_HEAP;
1569 pLocalEntry->wNext = ARENA_PTR(ptr,pInfo->first)->next;
1570 pLocalEntry->wSize = pLocalEntry->wNext - pLocalEntry->hHandle;
1571 return TRUE;
1575 /***********************************************************************
1576 * LocalNext (TOOLHELP.58)
1578 BOOL LocalNext( LOCALENTRY *pLocalEntry )
1580 WORD ds = GlobalHandleToSel( pLocalEntry->hHeap );
1581 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
1582 LOCALARENA *pArena;
1584 if (!LOCAL_GetHeap( ds )) return FALSE;
1585 if (!pLocalEntry->wNext) return FALSE;
1586 pArena = ARENA_PTR( ptr, pLocalEntry->wNext );
1588 pLocalEntry->hHandle = pLocalEntry->wNext + ARENA_HEADER_SIZE;
1589 pLocalEntry->wAddress = pLocalEntry->hHandle;
1590 pLocalEntry->wFlags = (pArena->prev & 3) + 1;
1591 pLocalEntry->wcLock = 0;
1592 pLocalEntry->wType = LT_NORMAL;
1593 if (pArena->next != pLocalEntry->wNext) /* last one? */
1594 pLocalEntry->wNext = pArena->next;
1595 else
1596 pLocalEntry->wNext = 0;
1597 pLocalEntry->wSize = pLocalEntry->wNext - pLocalEntry->hHandle;
1598 return TRUE;
1601 #ifndef WINELIB
1603 #endif /* WINELIB */
1605 /***********************************************************************
1606 * LocalAlloc32 (KERNEL32.371)
1608 HLOCAL32 LocalAlloc32( UINT32 flags, DWORD size )
1610 return (HLOCAL32)GlobalAlloc32( flags, size );
1614 /***********************************************************************
1615 * LocalCompact32 (KERNEL32.372)
1617 UINT32 LocalCompact32( UINT32 minfree )
1619 return 0; /* LocalCompact does nothing in Win32 */
1623 /***********************************************************************
1624 * LocalFlags32 (KERNEL32.374)
1626 UINT32 LocalFlags32( HLOCAL32 handle )
1628 return GlobalFlags32( (HGLOBAL32)handle );
1632 /***********************************************************************
1633 * LocalFree32 (KERNEL32.375)
1635 HLOCAL32 LocalFree32( HLOCAL32 handle )
1637 return (HLOCAL32)GlobalFree32( (HGLOBAL32)handle );
1641 /***********************************************************************
1642 * LocalHandle32 (KERNEL32.376)
1644 HLOCAL32 LocalHandle32( LPCVOID ptr )
1646 return (HLOCAL32)GlobalHandle32( ptr );
1650 /***********************************************************************
1651 * LocalLock32 (KERNEL32.377)
1653 LPVOID LocalLock32( HLOCAL32 handle )
1655 return GlobalLock32( (HGLOBAL32)handle );
1659 /***********************************************************************
1660 * LocalReAlloc32 (KERNEL32.378)
1662 HLOCAL32 LocalReAlloc32( HLOCAL32 handle, DWORD size, UINT32 flags )
1664 return (HLOCAL32)GlobalReAlloc32( (HGLOBAL32)handle, size, flags );
1668 /***********************************************************************
1669 * LocalShrink32 (KERNEL32.379)
1671 UINT32 LocalShrink32( HGLOBAL32 handle, UINT32 newsize )
1673 return 0; /* LocalShrink does nothing in Win32 */
1677 /***********************************************************************
1678 * LocalSize32 (KERNEL32.380)
1680 UINT32 LocalSize32( HLOCAL32 handle )
1682 return GlobalSize32( (HGLOBAL32)handle );
1686 /***********************************************************************
1687 * LocalUnlock32 (KERNEL32.381)
1689 BOOL32 LocalUnlock32( HLOCAL32 handle )
1691 return GlobalUnlock32( (HGLOBAL32)handle );