4 * Copyright 1995 Alexandre Julliard
9 * All local heap functions need the current DS as first parameter
10 * when called from the emulation library, so they take one more
11 * parameter than usual.
23 #include "stackframe.h"
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 */
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
50 #define LOCAL_ARENA_MOVEABLE 3
52 /* Layout of a handle entry table
54 * WORD count of entries
55 * LOCALHANDLEENTRY[count] entries
56 * WORD near ptr to next table
60 WORD addr; /* Address of the MOVEABLE block */
61 BYTE flags; /* Flags for this block */
62 BYTE lock; /* Lock count */
67 WORD check; /* 00 Heap checking flag */
68 WORD freeze; /* 02 Heap frozen flag */
69 WORD items; /* 04 Count of items on the heap */
70 WORD first; /* 06 First item of the heap */
71 WORD pad1; /* 08 Always 0 */
72 WORD last; /* 0a Last item of the heap */
73 WORD pad2; /* 0c Always 0 */
74 BYTE ncompact; /* 0e Compactions counter */
75 BYTE dislevel; /* 0f Discard level */
76 DWORD distotal; /* 10 Total bytes discarded */
77 WORD htable; /* 14 Pointer to handle table */
78 WORD hfree; /* 16 Pointer to free handle table */
79 WORD hdelta; /* 18 Delta to expand the handle table */
80 WORD expand; /* 1a Pointer to expand function (unused) */
81 WORD pstat; /* 1c Pointer to status structure (unused) */
82 FARPROC notify WINE_PACKED; /* 1e Pointer to LocalNotify() function */
83 WORD lock; /* 22 Lock count for the heap */
84 WORD extra; /* 24 Extra bytes to allocate when expanding */
85 WORD minsize; /* 26 Minimum size of the heap */
86 WORD magic; /* 28 Magic number */
93 #define LOCAL_HEAP_MAGIC 0x484c /* 'LH' */
96 /* All local heap allocations are aligned on 4-byte boundaries */
97 #define LALIGN(word) (((word) + 3) & ~3)
99 #define ARENA_PTR(ptr,arena) ((LOCALARENA *)((char*)(ptr)+(arena)))
100 #define ARENA_PREV(ptr,arena) (ARENA_PTR(ptr,arena)->prev & ~3)
101 #define ARENA_NEXT(ptr,arena) (ARENA_PTR(ptr,arena)->next)
102 #define ARENA_FLAGS(ptr,arena) (ARENA_PTR(ptr,arena)->prev & 3)
104 /* determine whether the handle belongs to a fixed or a moveable block */
105 #define HANDLE_FIXED(handle) (((handle) & 3) == 0)
106 #define HANDLE_MOVEABLE(handle) (((handle) & 3) == 2)
108 /***********************************************************************
111 * Return a pointer to the local heap, making sure it exists.
113 static LOCALHEAPINFO *LOCAL_GetHeap( WORD ds )
115 LOCALHEAPINFO *pInfo;
116 INSTANCEDATA *ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( ds, 0 );
117 dprintf_local( stddeb, "Heap at %p, %04x\n", ptr, ptr->heap );
118 if (!ptr->heap) return NULL;
119 if (IsBadReadPtr((SEGPTR)MAKELONG( ptr->heap, ds ), sizeof(LOCALHEAPINFO)))
121 pInfo = (LOCALHEAPINFO*)((char*)ptr + ptr->heap);
122 if (pInfo->magic != LOCAL_HEAP_MAGIC) return NULL;
127 /***********************************************************************
128 * LOCAL_MakeBlockFree
130 * Make a block free, inserting it in the free-list.
131 * 'block' is the handle of the block arena; 'baseptr' points to
132 * the beginning of the data segment containing the heap.
134 static void LOCAL_MakeBlockFree( char *baseptr, WORD block )
136 LOCALARENA *pArena, *pNext;
139 /* Mark the block as free */
141 pArena = ARENA_PTR( baseptr, block );
142 pArena->prev = (pArena->prev & ~3) | LOCAL_ARENA_FREE;
143 pArena->size = pArena->next - block;
145 /* Find the next free block (last block is always free) */
150 pNext = ARENA_PTR( baseptr, next );
151 if ((pNext->prev & 3) == LOCAL_ARENA_FREE) break;
155 dprintf_local( stddeb, "Local_AddFreeBlock %04x, next %04x\n", block, next );
156 /* Insert the free block in the free-list */
158 pArena->free_prev = pNext->free_prev;
159 pArena->free_next = next;
160 ARENA_PTR(baseptr,pNext->free_prev)->free_next = block;
161 pNext->free_prev = block;
165 /***********************************************************************
166 * LOCAL_RemoveFreeBlock
168 * Remove a block from the free-list.
169 * 'block' is the handle of the block arena; 'baseptr' points to
170 * the beginning of the data segment containing the heap.
172 static void LOCAL_RemoveFreeBlock( char *baseptr, WORD block )
174 /* Mark the block as fixed */
176 LOCALARENA *pArena = ARENA_PTR( baseptr, block );
177 pArena->prev = (pArena->prev & ~3) | LOCAL_ARENA_FIXED;
179 /* Remove it from the list */
181 ARENA_PTR(baseptr,pArena->free_prev)->free_next = pArena->free_next;
182 ARENA_PTR(baseptr,pArena->free_next)->free_prev = pArena->free_prev;
186 /***********************************************************************
189 * Insert a new block in the heap.
190 * 'new' is the handle of the new block arena; 'baseptr' points to
191 * the beginning of the data segment containing the heap; 'prev' is
192 * the block before the new one.
194 static void LOCAL_AddBlock( char *baseptr, WORD prev, WORD new )
196 LOCALARENA *pPrev = ARENA_PTR( baseptr, prev );
197 LOCALARENA *pNew = ARENA_PTR( baseptr, new );
199 pNew->prev = prev | LOCAL_ARENA_FIXED;
200 pNew->next = pPrev->next;
201 ARENA_PTR(baseptr,pPrev->next)->prev &= 3;
202 ARENA_PTR(baseptr,pPrev->next)->prev |= new;
207 /***********************************************************************
210 * Remove a block from the heap.
211 * 'block' is the handle of the block arena; 'baseptr' points to
212 * the beginning of the data segment containing the heap.
214 static void LOCAL_RemoveBlock( char *baseptr, WORD block )
216 LOCALARENA *pArena, *pTmp;
218 /* Remove the block from the free-list */
220 dprintf_local( stddeb, "Local_RemoveBlock\n");
221 pArena = ARENA_PTR( baseptr, block );
222 if ((pArena->prev & 3) == LOCAL_ARENA_FREE)
223 LOCAL_RemoveFreeBlock( baseptr, block );
225 /* If the previous block is free, expand its size */
227 pTmp = ARENA_PTR( baseptr, pArena->prev & ~3 );
228 if ((pTmp->prev & 3) == LOCAL_ARENA_FREE)
229 pTmp->size += pArena->next - block;
231 /* Remove the block from the linked list */
233 pTmp->next = pArena->next;
234 pTmp = ARENA_PTR( baseptr, pArena->next );
235 pTmp->prev = (pTmp->prev & 3) | (pArena->prev & ~3);
239 /***********************************************************************
242 static void LOCAL_PrintHeap( WORD ds )
244 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
245 LOCALHEAPINFO *pInfo = LOCAL_GetHeap( ds );
248 if (!debugging_local) return;
251 printf( "Local Heap corrupted! ds=%04x\n", ds );
254 printf( "Local Heap ds=%04x first=%04x last=%04x items=%d\n",
255 ds, pInfo->first, pInfo->last, pInfo->items );
257 arena = pInfo->first;
260 LOCALARENA *pArena = ARENA_PTR(ptr,arena);
261 printf( " %04x: prev=%04x next=%04x type=%d\n", arena,
262 pArena->prev & ~3, pArena->next, pArena->prev & 3 );
263 if (arena == pInfo->first)
265 printf( " size=%d free_prev=%04x free_next=%04x\n",
266 pArena->size, pArena->free_prev, pArena->free_next );
268 if ((pArena->prev & 3) == LOCAL_ARENA_FREE)
270 printf( " size=%d free_prev=%04x free_next=%04x\n",
271 pArena->size, pArena->free_prev, pArena->free_next );
272 if (pArena->next == arena) break; /* last one */
273 if (ARENA_PTR(ptr,pArena->free_next)->free_prev != arena)
275 printf( "*** arena->free_next->free_prev != arena\n" );
279 if (pArena->next == arena)
281 printf( "*** last block is not marked free\n" );
284 if ((ARENA_PTR(ptr,pArena->next)->prev & ~3) != arena)
286 printf( "*** arena->next->prev != arena (%04x, %04x)\n",
287 pArena->next, ARENA_PTR(ptr,pArena->next)->prev);
290 arena = pArena->next;
295 /***********************************************************************
296 * LocalInit (KERNEL.4)
298 BOOL LocalInit( HANDLE selector, WORD start, WORD end )
301 WORD heapInfoArena, freeArena, lastArena;
302 LOCALHEAPINFO *pHeapInfo;
303 LOCALARENA *pArena, *pFirstArena, *pLastArena;
306 /* The initial layout of the heap is: */
307 /* - first arena (FIXED) */
308 /* - heap info structure (FIXED) */
309 /* - large free block (FREE) */
310 /* - last arena (FREE) */
312 dprintf_local(stddeb, "LocalInit: %04x %04x-%04x\n", selector, start, end);
313 if (!selector) selector = CURRENT_DS;
314 pHeapInfo = LOCAL_GetHeap(selector);
317 fprintf( stderr, "LocalInit: Heap %04x initialized twice.\n", selector);
318 if (debugging_local) LOCAL_PrintHeap(selector);
322 /* Check if the segment is the DGROUP of a module */
324 if ((pModule = MODULE_GetPtr( GetExePtr( selector ) )))
326 SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
327 if (pModule->dgroup && (pSeg->selector == selector)) {
328 /* We can't just use the simple method of using the value
329 * of minsize + stacksize, since there are programs that
330 * resize the data segment before calling InitTask(). So,
331 * we must put it at the end of the segment */
332 start = GlobalSize( GlobalHandle( selector ) );
335 dprintf_local( stddeb," new start %04x, minstart: %04x\n", start, pSeg->minsize + pModule->stack_size);
339 ptr = PTR_SEG_OFF_TO_LIN( selector, 0 );
341 start = LALIGN( MAX( start, sizeof(INSTANCEDATA) ) );
342 heapInfoArena = LALIGN(start + sizeof(LOCALARENA) );
343 freeArena = LALIGN( heapInfoArena + ARENA_HEADER_SIZE
344 + sizeof(LOCALHEAPINFO) );
345 lastArena = (end - sizeof(LOCALARENA)) & ~3;
347 /* Make sure there's enough space. */
349 if (freeArena + sizeof(LOCALARENA) >= lastArena) return FALSE;
351 /* Initialise the first arena */
353 pFirstArena = ARENA_PTR( ptr, start );
354 pFirstArena->prev = start | LOCAL_ARENA_FIXED;
355 pFirstArena->next = heapInfoArena;
356 pFirstArena->size = LALIGN(sizeof(LOCALARENA));
357 pFirstArena->free_prev = start; /* this one */
358 pFirstArena->free_next = freeArena;
360 /* Initialise the arena of the heap info structure */
362 pArena = ARENA_PTR( ptr, heapInfoArena );
363 pArena->prev = start | LOCAL_ARENA_FIXED;
364 pArena->next = freeArena;
366 /* Initialise the heap info structure */
368 pHeapInfo = (LOCALHEAPINFO *) (ptr + heapInfoArena + ARENA_HEADER_SIZE );
369 memset( pHeapInfo, 0, sizeof(LOCALHEAPINFO) );
370 pHeapInfo->items = 4;
371 pHeapInfo->first = start;
372 pHeapInfo->last = lastArena;
373 pHeapInfo->htable = 0;
374 pHeapInfo->hdelta = 0x20;
375 pHeapInfo->extra = 0x200;
376 pHeapInfo->minsize = lastArena - freeArena;
377 pHeapInfo->magic = LOCAL_HEAP_MAGIC;
379 /* Initialise the large free block */
381 pArena = ARENA_PTR( ptr, freeArena );
382 pArena->prev = heapInfoArena | LOCAL_ARENA_FREE;
383 pArena->next = lastArena;
384 pArena->size = lastArena - freeArena;
385 pArena->free_prev = start;
386 pArena->free_next = lastArena;
388 /* Initialise the last block */
390 pLastArena = ARENA_PTR( ptr, lastArena );
391 pLastArena->prev = freeArena | LOCAL_ARENA_FREE;
392 pLastArena->next = lastArena; /* this one */
393 pLastArena->size = LALIGN(sizeof(LOCALARENA));
394 pLastArena->free_prev = freeArena;
395 pLastArena->free_next = lastArena; /* this one */
397 /* Store the local heap address in the instance data */
399 ((INSTANCEDATA *)ptr)->heap = heapInfoArena + ARENA_HEADER_SIZE;
400 LOCAL_PrintHeap( selector );
404 /***********************************************************************
407 static void LOCAL_GrowHeap( WORD ds )
409 HANDLE hseg = GlobalHandle( ds );
410 LONG oldsize = GlobalSize( hseg );
412 LOCALHEAPINFO *pHeapInfo;
413 WORD freeArena, lastArena;
414 LOCALARENA *pArena, *pLastArena;
417 /* if nothing can be gained, return */
418 if (oldsize > 0xfff0) return;
419 hseg = GlobalReAlloc( hseg, 0x10000, GMEM_FIXED );
420 ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
421 pHeapInfo = LOCAL_GetHeap( ds );
422 if (pHeapInfo == NULL) {
423 fprintf( stderr, "Local_GrowHeap: heap not found\n" );
426 end = GlobalSize( hseg );
427 lastArena = (end - sizeof(LOCALARENA)) & ~3;
429 /* Update the HeapInfo */
431 freeArena = pHeapInfo->last;
432 pHeapInfo->last = lastArena;
433 pHeapInfo->minsize += end - oldsize;
435 /* grow the old last block */
436 /* FIXME: merge two adjacent free blocks */
437 pArena = ARENA_PTR( ptr, freeArena );
438 pArena->size = lastArena - freeArena;
439 pArena->next = lastArena;
440 pArena->free_next = lastArena;
442 /* Initialise the new last block */
444 pLastArena = ARENA_PTR( ptr, lastArena );
445 pLastArena->prev = freeArena | LOCAL_ARENA_FREE;
446 pLastArena->next = lastArena; /* this one */
447 pLastArena->size = LALIGN(sizeof(LOCALARENA));
448 pLastArena->free_prev = freeArena;
449 pLastArena->free_next = lastArena; /* this one */
451 dprintf_local( stddeb, "Heap expanded\n" );
452 LOCAL_PrintHeap( ds );
455 /***********************************************************************
458 static WORD LOCAL_Compact( WORD ds, WORD minfree, WORD flags )
460 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
461 LOCALHEAPINFO *pInfo;
466 if (!(pInfo = LOCAL_GetHeap( ds )))
468 fprintf( stderr, "Local_FindFreeBlock: Local heap not found\n" );
473 arena = pInfo->first;
474 pArena = ARENA_PTR( ptr, arena );
475 while (arena != pArena->free_next) {
476 arena = pArena->free_next;
477 pArena = ARENA_PTR( ptr, arena );
478 if (pArena->size >= freespace) freespace = pArena->size;
481 if(freespace < ARENA_HEADER_SIZE)
484 freespace -= ARENA_HEADER_SIZE;
486 if (flags & LMEM_NOCOMPACT) return freespace;
488 if (flags & LMEM_NODISCARD) return freespace;
492 /***********************************************************************
493 * LOCAL_FindFreeBlock
495 static HLOCAL LOCAL_FindFreeBlock( WORD ds, WORD size )
497 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
498 LOCALHEAPINFO *pInfo;
502 if (!(pInfo = LOCAL_GetHeap( ds )))
504 fprintf( stderr, "Local_FindFreeBlock: Local heap not found\n" );
509 arena = pInfo->first;
510 pArena = ARENA_PTR( ptr, arena );
512 arena = pArena->free_next;
513 pArena = ARENA_PTR( ptr, arena );
514 if (arena == pArena->free_next) break;
515 if (pArena->size >= size) return arena;
517 dprintf_local( stddeb, "Local_FindFreeBlock: not enough space\n" );
518 if (debugging_local) LOCAL_PrintHeap(ds);
522 /***********************************************************************
524 * The segment may get moved around in this function, so all callers
525 * should reset their pointer variables.
527 static HLOCAL LOCAL_GetBlock( WORD ds, WORD size, WORD flags )
529 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
530 LOCALHEAPINFO *pInfo;
534 if (!(pInfo = LOCAL_GetHeap( ds )))
536 fprintf( stderr, "Local_GetBlock: Local heap not found\n");
541 size += ARENA_HEADER_SIZE;
542 size = LALIGN( MAX( size, sizeof(LOCALARENA) ) );
544 /* Find a suitable free block */
545 arena = LOCAL_FindFreeBlock( ds, size );
547 /* no space: try to make some */
548 LOCAL_Compact( ds, size, flags );
549 arena = LOCAL_FindFreeBlock( ds, size );
552 /* still no space: try to grow the segment */
553 LOCAL_GrowHeap( ds );
554 ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
555 pInfo = LOCAL_GetHeap( ds );
556 arena = LOCAL_FindFreeBlock( ds, size );
559 fprintf( stderr, "Local_GetBlock: not enough space in heap %04x for %d bytes\n",
564 /* Make a block out of the free arena */
565 pArena = ARENA_PTR( ptr, arena );
566 dprintf_local( stddeb, "LOCAL_GetBlock size = %04x, arena at %04x size %04x\n", size,
567 arena, pArena->size );
568 if (pArena->size > size + LALIGN(sizeof(LOCALARENA)))
570 LOCAL_AddBlock( ptr, arena, arena+size );
571 LOCAL_MakeBlockFree( ptr, arena+size );
574 LOCAL_RemoveFreeBlock( ptr, arena );
576 if (flags & LMEM_ZEROINIT) {
577 memset( (char *)pArena + ARENA_HEADER_SIZE, 0, size - ARENA_HEADER_SIZE );
580 dprintf_local( stddeb, "Local_GetBlock: arena at %04x\n", arena );
581 return arena + ARENA_HEADER_SIZE;
585 /***********************************************************************
588 static BOOL LOCAL_NewHTable( WORD ds )
590 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
591 LOCALHEAPINFO *pInfo;
592 LOCALHANDLEENTRY *pEntry;
596 dprintf_local( stddeb, "Local_NewHTable\n" );
597 if (!(pInfo = LOCAL_GetHeap( ds )))
599 fprintf( stderr, "Local heap not found\n");
604 handle = LOCAL_GetBlock( ds, pInfo->hdelta * sizeof(LOCALHANDLEENTRY)
605 + 2 * sizeof(WORD), LMEM_FIXED );
606 ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
607 pInfo = LOCAL_GetHeap( ds );
608 if (handle == 0) return FALSE;
610 /* Fill the entry table */
612 *(WORD *)(ptr + handle) = pInfo->hdelta;
613 pEntry = (LOCALHANDLEENTRY *)(ptr + handle + sizeof(WORD));
614 for (i = pInfo->hdelta; i > 0; i--) (pEntry++)->lock = 0xff;
615 *(WORD *)pEntry = pInfo->htable;
616 pInfo->htable = handle;
621 /***********************************************************************
622 * LOCAL_GetNewHandleEntry
624 static HLOCAL LOCAL_GetNewHandleEntry( WORD ds )
626 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
627 LOCALHEAPINFO *pInfo;
628 LOCALHANDLEENTRY *pEntry = NULL;
631 if (!(pInfo = LOCAL_GetHeap( ds )))
633 fprintf( stderr, "LOCAL_GetNewHandleEntry: Local heap not found\n");
638 /* Find a free slot in existing tables */
640 table = pInfo->htable;
643 WORD count = *(WORD *)(ptr + table);
644 pEntry = (LOCALHANDLEENTRY *)(ptr + table + sizeof(WORD));
645 for (; count > 0; count--, pEntry++)
646 if (pEntry->lock == 0xff) break;
648 table = *(WORD *)pEntry;
651 if (!table) /* We need to create a new table */
653 if (!LOCAL_NewHTable( ds )) return 0;
654 ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
655 pInfo = LOCAL_GetHeap( ds );
656 pEntry = (LOCALHANDLEENTRY *)(ptr + pInfo->htable + sizeof(WORD));
659 /* Now allocate this entry */
662 dprintf_local( stddeb, "LOCAL_GetNewHandleEntry(%04x): %04x\n",
663 ds, ((char *)pEntry - ptr) );
664 return (HLOCAL)((char *)pEntry - ptr);
668 /***********************************************************************
671 static HLOCAL LOCAL_FreeArena( WORD ds, WORD arena )
673 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
674 LOCALHEAPINFO *pInfo;
675 LOCALARENA *pArena, *pPrev, *pNext;
677 dprintf_local( stddeb, "LocalFreeArena: %04x ds=%04x\n", arena, ds );
678 if (!(pInfo = LOCAL_GetHeap( ds ))) return arena;
680 pArena = ARENA_PTR( ptr, arena );
681 if ((pArena->prev & 3) == LOCAL_ARENA_FREE)
683 /* shouldn't happen */
684 fprintf( stderr, "LocalFreeArena: Trying to free block %04x twice!\n",
686 LOCAL_PrintHeap( ds );
690 /* Check if we can merge with the previous block */
692 pPrev = ARENA_PTR( ptr, pArena->prev & ~3 );
693 pNext = ARENA_PTR( ptr, pArena->next );
694 if ((pPrev->prev & 3) == LOCAL_ARENA_FREE)
696 arena = pArena->prev & ~3;
698 LOCAL_RemoveBlock( ptr, pPrev->next );
701 else /* Make a new free block */
703 LOCAL_MakeBlockFree( ptr, arena );
706 /* Check if we can merge with the next block */
708 if ((pArena->next == pArena->free_next) &&
709 (pArena->next != pInfo->last))
711 LOCAL_RemoveBlock( ptr, pArena->next );
718 /***********************************************************************
719 * LOCAL_FreeHandleEntry
721 * Free a handle table entry.
723 static void LOCAL_FreeHandleEntry( WORD ds, HLOCAL handle )
725 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
726 LOCALHANDLEENTRY *pEntry = (LOCALHANDLEENTRY *)(ptr + handle);
727 LOCALHEAPINFO *pInfo;
729 WORD table, count, i;
731 if (!(pInfo = LOCAL_GetHeap( ds ))) return;
733 /* Find the table where this handle comes from */
735 pTable = &pInfo->htable;
738 WORD size = (*(WORD *)(ptr + *pTable)) * sizeof(LOCALHANDLEENTRY);
739 if ((handle >= *pTable + sizeof(WORD)) &&
740 (handle < *pTable + sizeof(WORD) + size)) break; /* Found it */
741 pTable = (WORD *)(ptr + *pTable + sizeof(WORD) + size);
745 fprintf(stderr, "LOCAL_FreeHandleEntry: invalid entry %04x\n", handle);
746 LOCAL_PrintHeap( ds );
750 /* Make the entry free */
752 pEntry->addr = 0; /* just in case */
755 /* Now check if all entries in this table are free */
757 pEntry = (LOCALHANDLEENTRY *)(ptr + *pTable + sizeof(WORD));
758 count = *(WORD *)(ptr + *pTable);
759 for (i = count; i > 0; i--, pEntry++) if (pEntry->lock != 0xff) return;
761 /* Remove the table from the linked list and free it */
764 dprintf_local( stddeb, "LOCAL_FreeHandleEntry(%04x): freeing table %04x\n",
766 *pTable = *((WORD *)(ptr + count * sizeof(*pEntry)) + 1);
767 LOCAL_FreeArena( ds, ARENA_HEADER( table ) );
771 /***********************************************************************
774 * Implementation of LocalFree().
776 HLOCAL LOCAL_Free( HANDLE ds, HLOCAL handle )
778 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
780 dprintf_local( stddeb, "LocalFree: %04x ds=%04x\n", handle, ds );
782 if (!handle) { fprintf( stderr, "LOCAL_Free: handle is 0.\n" ); return 0; }
783 if (HANDLE_FIXED( handle ))
785 if (!LOCAL_FreeArena( ds, ARENA_HEADER( handle ) )) return 0; /* OK */
786 else return handle; /* couldn't free it */
790 WORD arena = ARENA_HEADER( *(WORD *)(ptr + handle) );
791 dprintf_local( stddeb, "LocalFree: real block at %04x\n", arena );
792 if (LOCAL_FreeArena( ds, arena )) return handle; /* couldn't free it */
793 LOCAL_FreeHandleEntry( ds, handle );
799 /***********************************************************************
802 * Implementation of LocalAlloc().
804 HLOCAL LOCAL_Alloc( HANDLE ds, WORD flags, WORD size )
809 dprintf_local( stddeb, "LocalAlloc: %04x %d ds=%04x\n", flags, size, ds );
811 if (flags & LMEM_MOVEABLE)
813 LOCALHANDLEENTRY *plhe;
816 if (!(hmem = LOCAL_GetBlock( ds, size, flags ))) return 0;
817 if (!(handle = LOCAL_GetNewHandleEntry( ds )))
819 fprintf( stderr, "LocalAlloc: couldn't get handle\n");
820 LOCAL_FreeArena( ds, ARENA_HEADER(hmem) );
823 ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
824 plhe = (LOCALHANDLEENTRY *)(ptr + handle);
826 plhe->flags = (BYTE)(flags >> 8);
829 else handle = LOCAL_GetBlock( ds, size, flags );
835 /***********************************************************************
838 * Implementation of LocalReAlloc().
840 HLOCAL LOCAL_ReAlloc( HANDLE ds, HLOCAL handle, WORD size, WORD flags )
842 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
843 LOCALHEAPINFO *pInfo;
844 LOCALARENA *pArena, *pNext;
845 WORD arena, newhandle, blockhandle;
848 if (!handle) return LOCAL_Alloc( ds, size, flags );
850 dprintf_local( stddeb, "LocalReAlloc: %04x %d %04x ds=%04x\n",
851 handle, size, flags, ds );
852 if (!(pInfo = LOCAL_GetHeap( ds ))) return 0;
854 if (HANDLE_FIXED( handle )) blockhandle = handle;
855 else blockhandle = *(WORD *)(ptr + handle);
857 arena = ARENA_HEADER( blockhandle );
858 dprintf_local( stddeb, "LocalReAlloc: arena is %04x\n", arena );
859 pArena = ARENA_PTR( ptr, arena );
861 if (flags & LMEM_MODIFY) {
862 dprintf_local( stddeb, "LMEM_MODIFY set\n");
866 size = LALIGN( size );
867 nextarena = LALIGN(blockhandle + size);
869 /* Check for size reduction */
871 if (nextarena < pArena->next)
873 if (nextarena < pArena->next - LALIGN(sizeof(LOCALARENA)))
875 dprintf_local( stddeb, "size reduction, making new free block\n");
876 /* It is worth making a new free block */
877 LOCAL_AddBlock( ptr, arena, nextarena );
878 LOCAL_MakeBlockFree( ptr, nextarena );
881 dprintf_local( stddeb, "LocalReAlloc: returning %04x\n", handle );
885 /* Check if the next block is free */
887 pNext = ARENA_PTR( ptr, pArena->next );
888 if (((pNext->prev & 3) == LOCAL_ARENA_FREE) &&
889 (nextarena <= pNext->next))
891 LOCAL_RemoveBlock( ptr, pArena->next );
892 if (nextarena < pArena->next - LALIGN(sizeof(LOCALARENA)))
894 dprintf_local( stddeb, "size increase, making new free block\n");
895 /* It is worth making a new free block */
896 LOCAL_AddBlock( ptr, arena, nextarena );
897 LOCAL_MakeBlockFree( ptr, nextarena );
900 dprintf_local( stddeb, "LocalReAlloc: returning %04x\n", handle );
904 /* Now we have to allocate a new block */
906 newhandle = LOCAL_GetBlock( ds, size, flags );
907 if (newhandle == 0) return 0;
908 ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
909 memcpy( ptr + newhandle, ptr + (arena + ARENA_HEADER_SIZE), size );
910 LOCAL_FreeArena( ds, arena );
911 if (HANDLE_MOVEABLE( handle ))
913 dprintf_local( stddeb, "LocalReAlloc: fixing handle\n");
914 *(WORD *)(ptr + handle) = newhandle;
917 dprintf_local( stddeb, "LocalReAlloc: returning %04x\n", newhandle );
922 /***********************************************************************
925 static HLOCAL LOCAL_InternalLock( LPSTR heap, HLOCAL handle )
927 dprintf_local( stddeb, "LocalLock: %04x ", handle );
928 if (HANDLE_MOVEABLE(handle))
930 LOCALHANDLEENTRY *pEntry = (LOCALHANDLEENTRY *)(heap + handle);
931 if (pEntry->lock < 0xfe) pEntry->lock++;
932 handle = pEntry->addr;
934 dprintf_local( stddeb, "returning %04x\n", handle );
939 /***********************************************************************
942 LPSTR LOCAL_Lock( HANDLE ds, HLOCAL handle )
944 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
945 return handle ? ptr + LOCAL_InternalLock( ptr, handle ) : NULL;
949 /***********************************************************************
952 BOOL LOCAL_Unlock( WORD ds, HLOCAL handle )
954 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
956 dprintf_local( stddeb, "LocalUnlock: %04x\n", handle );
957 if (HANDLE_MOVEABLE(handle))
959 LOCALHANDLEENTRY *pEntry = (LOCALHANDLEENTRY *)(ptr + handle);
960 if (!pEntry->lock || (pEntry->lock == 0xff)) return FALSE;
961 /* For moveable block, return the new lock count */
962 /* (see _Windows_Internals_ p. 197) */
963 return --pEntry->lock;
969 /***********************************************************************
972 * Implementation of LocalSize().
974 WORD LOCAL_Size( WORD ds, HLOCAL handle )
976 char *ptr = PTR_SEG_OFF_TO_LIN( CURRENT_DS, 0 );
979 dprintf_local( stddeb, "LocalSize: %04x ds=%04x\n", handle, ds );
981 if (HANDLE_MOVEABLE( handle )) handle = *(WORD *)(ptr + handle);
982 pArena = ARENA_PTR( ptr, ARENA_HEADER(handle) );
983 return pArena->next - handle;
987 /***********************************************************************
990 * Implementation of LocalFlags().
992 WORD LOCAL_Flags( WORD ds, HLOCAL handle )
994 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
996 if (HANDLE_MOVEABLE(handle))
998 LOCALHANDLEENTRY *pEntry = (LOCALHANDLEENTRY *)(ptr + handle);
999 dprintf_local( stddeb, "LOCAL_Flags(%04x,%04x): returning %04x\n",
1000 ds, handle, pEntry->lock | (pEntry->flags << 8) );
1001 return pEntry->lock | (pEntry->flags << 8);
1005 dprintf_local( stddeb, "LOCAL_Flags(%04x,%04x): returning 0\n",
1012 /***********************************************************************
1015 * Implementation of LocalHeapSize().
1017 WORD LOCAL_HeapSize( WORD ds )
1019 LOCALHEAPINFO *pInfo = LOCAL_GetHeap( ds );
1020 if (!pInfo) return 0;
1021 return pInfo->last - pInfo->first;
1025 /***********************************************************************
1028 * Implementation of LocalCountFree().
1030 WORD LOCAL_CountFree( WORD ds )
1034 LOCALHEAPINFO *pInfo;
1035 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
1037 if (!(pInfo = LOCAL_GetHeap( ds )))
1039 fprintf( stderr, "LOCAL_Handle(%04x): Local heap not found\n", ds );
1040 LOCAL_PrintHeap( ds );
1045 arena = pInfo->first;
1046 pArena = ARENA_PTR( ptr, arena );
1049 arena = pArena->free_next;
1050 pArena = ARENA_PTR( ptr, arena );
1051 if (arena == pArena->free_next) break;
1052 total += pArena->size;
1054 dprintf_local( stddeb, "LOCAL_CountFree(%04x): returning %d\n", ds, total);
1059 /***********************************************************************
1062 * Implementation of LocalHandle().
1064 HLOCAL LOCAL_Handle( WORD ds, WORD addr )
1066 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
1067 LOCALHEAPINFO *pInfo;
1070 if (!(pInfo = LOCAL_GetHeap( ds )))
1072 fprintf( stderr, "LOCAL_Handle(%04x): Local heap not found\n", ds );
1073 LOCAL_PrintHeap( ds );
1077 /* Find the address in the entry tables */
1079 table = pInfo->htable;
1082 WORD count = *(WORD *)(ptr + table);
1083 LOCALHANDLEENTRY *pEntry = (LOCALHANDLEENTRY*)(ptr+table+sizeof(WORD));
1084 for (; count > 0; count--, pEntry++)
1085 if (pEntry->addr == addr) return (HLOCAL)((char *)pEntry - ptr);
1086 table = *(WORD *)pEntry;
1089 return (HLOCAL)addr; /* Fixed block handle is addr */
1093 /***********************************************************************
1094 * LocalAlloc (KERNEL.5)
1096 HLOCAL LocalAlloc( WORD flags, WORD size )
1098 return LOCAL_Alloc( CURRENT_DS, flags, size );
1102 /***********************************************************************
1103 * LocalReAlloc (KERNEL.6)
1105 HLOCAL LocalReAlloc( HLOCAL handle, WORD size, WORD flags )
1107 return LOCAL_ReAlloc( CURRENT_DS, handle, size, flags );
1111 /***********************************************************************
1112 * LocalFree (KERNEL.7)
1114 HLOCAL LocalFree( HLOCAL handle )
1116 return LOCAL_Free( CURRENT_DS, handle );
1120 /***********************************************************************
1121 * LocalLock (KERNEL.8)
1123 NPVOID LocalLock( HLOCAL handle )
1125 char *ptr = PTR_SEG_OFF_TO_LIN( CURRENT_DS, 0 );
1126 return (NPVOID)LOCAL_InternalLock( ptr, handle );
1130 /***********************************************************************
1131 * LocalUnlock (KERNEL.9)
1133 BOOL LocalUnlock( HLOCAL handle )
1135 return LOCAL_Unlock( CURRENT_DS, handle );
1139 /***********************************************************************
1140 * LocalSize (KERNEL.10)
1142 WORD LocalSize( HLOCAL handle )
1144 return LOCAL_Size( CURRENT_DS, handle );
1148 /***********************************************************************
1149 * LocalHandle (KERNEL.11)
1151 HLOCAL LocalHandle( WORD addr )
1153 return LOCAL_Handle( CURRENT_DS, addr );
1157 /***********************************************************************
1158 * LocalFlags (KERNEL.12)
1160 WORD LocalFlags( HLOCAL handle )
1162 return LOCAL_Flags( CURRENT_DS, handle );
1166 /***********************************************************************
1167 * LocalCompact (KERNEL.13)
1169 WORD LocalCompact( WORD minfree )
1171 dprintf_local( stddeb, "LocalCompact: %04x\n", minfree );
1172 return LOCAL_Compact( CURRENT_DS, minfree, 0 );
1176 /***********************************************************************
1177 * LocalNotify (KERNEL.14)
1179 FARPROC LocalNotify( FARPROC func )
1181 LOCALHEAPINFO *pInfo;
1183 WORD ds = CURRENT_DS;
1185 if (!(pInfo = LOCAL_GetHeap( ds )))
1187 fprintf( stderr, "LOCAL_Notify(%04x): Local heap not found\n", ds );
1188 LOCAL_PrintHeap( ds );
1191 dprintf_local( stddeb, "LocalNotify(%04x): %08lx\n", ds, func );
1192 oldNotify = pInfo->notify;
1193 pInfo->notify = func;
1198 /***********************************************************************
1199 * LocalShrink (KERNEL.121)
1201 WORD LocalShrink( HLOCAL handle, WORD newsize )
1203 dprintf_local( stddeb, "LocalShrink: %04x %04x\n", handle, newsize );
1208 /***********************************************************************
1209 * GetHeapSpaces (KERNEL.138)
1211 DWORD GetHeapSpaces( HMODULE module )
1216 module = GetExePtr( module );
1217 if (!(pModule = MODULE_GetPtr( module ))) return 0;
1218 ds = (NE_SEG_TABLE( pModule ) + pModule->dgroup - 1)->selector;
1219 return MAKELONG( LOCAL_CountFree( ds ), LOCAL_HeapSize( ds ) );
1223 /***********************************************************************
1224 * LocalCountFree (KERNEL.161)
1226 WORD LocalCountFree(void)
1228 return LOCAL_CountFree( CURRENT_DS );
1232 /***********************************************************************
1233 * LocalHeapSize (KERNEL.162)
1235 WORD LocalHeapSize()
1237 dprintf_local( stddeb, "LocalHeapSize:\n" );
1238 return LOCAL_HeapSize( CURRENT_DS );
1242 /***********************************************************************
1243 * LocalHandleDelta (KERNEL.310)
1245 WORD LocalHandleDelta( WORD delta )
1247 LOCALHEAPINFO *pInfo;
1249 if (!(pInfo = LOCAL_GetHeap( CURRENT_DS )))
1251 fprintf( stderr, "LocalHandleDelta: Local heap not found\n");
1252 LOCAL_PrintHeap( CURRENT_DS );
1255 if (delta) pInfo->hdelta = delta;
1256 dprintf_local(stddeb, "LocalHandleDelta: returning %04x\n", pInfo->hdelta);
1257 return pInfo->hdelta;
1261 /***********************************************************************
1262 * LocalInfo (TOOLHELP.56)
1264 BOOL LocalInfo( LOCALINFO *pLocalInfo, HGLOBAL handle )
1266 LOCALHEAPINFO *pInfo = LOCAL_GetHeap(SELECTOROF(WIN16_GlobalLock(handle)));
1267 if (!pInfo) return FALSE;
1268 pLocalInfo->wcItems = pInfo->items;
1273 /***********************************************************************
1274 * LocalFirst (TOOLHELP.57)
1276 BOOL LocalFirst( LOCALENTRY *pLocalEntry, HGLOBAL handle )
1278 WORD ds = SELECTOROF( WIN16_GlobalLock( handle ) );
1279 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
1280 LOCALHEAPINFO *pInfo = LOCAL_GetHeap( ds );
1281 if (!pInfo) return FALSE;
1283 pLocalEntry->hHandle = pInfo->first + ARENA_HEADER_SIZE;
1284 pLocalEntry->wAddress = pLocalEntry->hHandle;
1285 pLocalEntry->wFlags = LF_FIXED;
1286 pLocalEntry->wcLock = 0;
1287 pLocalEntry->wType = LT_NORMAL;
1288 pLocalEntry->hHeap = handle;
1289 pLocalEntry->wHeapType = NORMAL_HEAP;
1290 pLocalEntry->wNext = ARENA_PTR(ptr,pInfo->first)->next;
1291 pLocalEntry->wSize = pLocalEntry->wNext - pLocalEntry->hHandle;
1296 /***********************************************************************
1297 * LocalNext (TOOLHELP.58)
1299 BOOL LocalNext( LOCALENTRY *pLocalEntry )
1301 WORD ds = SELECTOROF( pLocalEntry->hHeap );
1302 char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
1305 if (!LOCAL_GetHeap( ds )) return FALSE;
1306 if (!pLocalEntry->wNext) return FALSE;
1307 pArena = ARENA_PTR( ptr, pLocalEntry->wNext );
1309 pLocalEntry->hHandle = pLocalEntry->wNext + ARENA_HEADER_SIZE;
1310 pLocalEntry->wAddress = pLocalEntry->hHandle;
1311 pLocalEntry->wFlags = (pArena->prev & 3) + 1;
1312 pLocalEntry->wcLock = 0;
1313 pLocalEntry->wType = LT_NORMAL;
1314 if (pArena->next != pLocalEntry->wNext) /* last one? */
1315 pLocalEntry->wNext = pArena->next;
1317 pLocalEntry->wNext = 0;
1318 pLocalEntry->wSize = pLocalEntry->wNext - pLocalEntry->hHandle;
1322 #endif /* WINELIB */