/* * Local heap functions * * Copyright 1995 Alexandre Julliard * Copyright 1996 Huw Davies * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * Note: * All local heap functions need the current DS as first parameter * when called from the emulation library, so they take one more * parameter than usual. */ #include "config.h" #include #include #include "wine/winbase16.h" #include "instance.h" #include "local.h" #include "module.h" #include "stackframe.h" #include "toolhelp.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(local); typedef struct { /* Arena header */ WORD prev; /* Previous arena | arena type */ WORD next; /* Next arena */ /* Start of the memory block or free-list info */ WORD size; /* Size of the free block */ WORD free_prev; /* Previous free block */ WORD free_next; /* Next free block */ } LOCALARENA; #define ARENA_HEADER_SIZE 4 #define ARENA_HEADER( handle) ((handle) - ARENA_HEADER_SIZE) /* Arena types (stored in 'prev' field of the arena) */ #define LOCAL_ARENA_FREE 0 #define LOCAL_ARENA_FIXED 1 #include "pshpack1.h" typedef struct { WORD check; /* 00 Heap checking flag */ WORD freeze; /* 02 Heap frozen flag */ WORD items; /* 04 Count of items on the heap */ WORD first; /* 06 First item of the heap */ WORD pad1; /* 08 Always 0 */ WORD last; /* 0a Last item of the heap */ WORD pad2; /* 0c Always 0 */ BYTE ncompact; /* 0e Compactions counter */ BYTE dislevel; /* 0f Discard level */ DWORD distotal; /* 10 Total bytes discarded */ WORD htable; /* 14 Pointer to handle table */ WORD hfree; /* 16 Pointer to free handle table */ WORD hdelta; /* 18 Delta to expand the handle table */ WORD expand; /* 1a Pointer to expand function (unused) */ WORD pstat; /* 1c Pointer to status structure (unused) */ FARPROC16 notify WINE_PACKED; /* 1e Pointer to LocalNotify() function */ WORD lock; /* 22 Lock count for the heap */ WORD extra; /* 24 Extra bytes to allocate when expanding */ WORD minsize; /* 26 Minimum size of the heap */ WORD magic; /* 28 Magic number */ } LOCALHEAPINFO; #include "poppack.h" #define LOCAL_HEAP_MAGIC 0x484c /* 'LH' */ /* All local heap allocations are aligned on 4-byte boundaries */ #define LALIGN(word) (((word) + 3) & ~3) #define ARENA_PTR(ptr,arena) ((LOCALARENA *)((char*)(ptr)+(arena))) #define ARENA_PREV(ptr,arena) (ARENA_PTR((ptr),(arena))->prev & ~3) #define ARENA_NEXT(ptr,arena) (ARENA_PTR((ptr),(arena))->next) #define ARENA_FLAGS(ptr,arena) (ARENA_PTR((ptr),(arena))->prev & 3) /*********************************************************************** * LocalInit (KERNEL.4) */ BOOL16 WINAPI LocalInit16( HANDLE16 selector, WORD start, WORD end ) { char *ptr; WORD heapInfoArena, freeArena, lastArena; LOCALHEAPINFO *pHeapInfo; LOCALARENA *pArena, *pFirstArena, *pLastArena; NE_MODULE *pModule; BOOL16 ret = FALSE; /* The initial layout of the heap is: */ /* - first arena (FIXED) */ /* - heap info structure (FIXED) */ /* - large free block (FREE) */ /* - last arena (FREE) */ TRACE("%04x %04x-%04x\n", selector, start, end); if (!selector) selector = CURRENT_DS; if (start == 0) { /* start == 0 means: put the local heap at the end of the segment */ DWORD size = GlobalSize16( GlobalHandle16( selector ) ); start = (WORD)(size > 0xffff ? 0xffff : size) - 1; if ( end > 0xfffe ) end = 0xfffe; start -= end; end += start; /* Paranoid check */ if ((pModule = NE_GetPtr( GlobalHandle16( selector ) ))) { SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule ); int segNr; for ( segNr = 0; segNr < pModule->seg_count; segNr++, pSeg++ ) if ( GlobalHandleToSel16(pSeg->hSeg) == selector ) break; if ( segNr < pModule->seg_count ) { WORD minsize = pSeg->minsize; if ( pModule->ss == segNr+1 ) minsize += pModule->stack_size; TRACE(" new start %04x, minstart: %04x\n", start, minsize); } } } ptr = MapSL( MAKESEGPTR( selector, 0 ) ); start = LALIGN( max( start, sizeof(INSTANCEDATA) ) ); heapInfoArena = LALIGN(start + sizeof(LOCALARENA) ); freeArena = LALIGN( heapInfoArena + ARENA_HEADER_SIZE + sizeof(LOCALHEAPINFO) ); lastArena = (end - sizeof(LOCALARENA)) & ~3; /* Make sure there's enough space. */ if (freeArena + sizeof(LOCALARENA) >= lastArena) goto done; /* Initialise the first arena */ pFirstArena = ARENA_PTR( ptr, start ); pFirstArena->prev = start | LOCAL_ARENA_FIXED; pFirstArena->next = heapInfoArena; pFirstArena->size = LALIGN(sizeof(LOCALARENA)); pFirstArena->free_prev = start; /* this one */ pFirstArena->free_next = freeArena; /* Initialise the arena of the heap info structure */ pArena = ARENA_PTR( ptr, heapInfoArena ); pArena->prev = start | LOCAL_ARENA_FIXED; pArena->next = freeArena; /* Initialise the heap info structure */ pHeapInfo = (LOCALHEAPINFO *) (ptr + heapInfoArena + ARENA_HEADER_SIZE ); memset( pHeapInfo, 0, sizeof(LOCALHEAPINFO) ); pHeapInfo->items = 4; pHeapInfo->first = start; pHeapInfo->last = lastArena; pHeapInfo->htable = 0; pHeapInfo->hdelta = 0x20; pHeapInfo->extra = 0x200; pHeapInfo->minsize = lastArena - freeArena; pHeapInfo->magic = LOCAL_HEAP_MAGIC; /* Initialise the large free block */ pArena = ARENA_PTR( ptr, freeArena ); pArena->prev = heapInfoArena | LOCAL_ARENA_FREE; pArena->next = lastArena; pArena->size = lastArena - freeArena; pArena->free_prev = start; pArena->free_next = lastArena; /* Initialise the last block */ pLastArena = ARENA_PTR( ptr, lastArena ); pLastArena->prev = freeArena | LOCAL_ARENA_FREE; pLastArena->next = lastArena; /* this one */ pLastArena->size = LALIGN(sizeof(LOCALARENA)); pLastArena->free_prev = freeArena; pLastArena->free_next = lastArena; /* this one */ /* Store the local heap address in the instance data */ ((INSTANCEDATA *)ptr)->heap = heapInfoArena + ARENA_HEADER_SIZE; ret = TRUE; done: CURRENT_STACK16->ecx = ret; /* must be returned in cx too */ return ret; } /*********************************************************************** * LocalAlloc (KERNEL32.@) * RETURNS * Handle: Success * NULL: Failure */ HLOCAL WINAPI LocalAlloc( UINT flags, /* [in] Allocation attributes */ SIZE_T size /* [in] Number of bytes to allocate */ ) { return (HLOCAL)GlobalAlloc( flags, size ); } /*********************************************************************** * LocalCompact (KERNEL32.@) */ SIZE_T WINAPI LocalCompact( UINT minfree ) { return 0; /* LocalCompact does nothing in Win32 */ } /*********************************************************************** * LocalFlags (KERNEL32.@) * RETURNS * Value specifying allocation flags and lock count. * LMEM_INVALID_HANDLE: Failure */ UINT WINAPI LocalFlags( HLOCAL handle /* [in] Handle of memory object */ ) { return GlobalFlags( (HGLOBAL)handle ); } /*********************************************************************** * LocalFree (KERNEL32.@) * RETURNS * NULL: Success * Handle: Failure */ HLOCAL WINAPI LocalFree( HLOCAL handle /* [in] Handle of memory object */ ) { return (HLOCAL)GlobalFree( (HGLOBAL)handle ); } /*********************************************************************** * LocalHandle (KERNEL32.@) * RETURNS * Handle: Success * NULL: Failure */ HLOCAL WINAPI LocalHandle( LPCVOID ptr /* [in] Address of local memory object */ ) { return (HLOCAL)GlobalHandle( ptr ); } /*********************************************************************** * LocalLock (KERNEL32.@) * Locks a local memory object and returns pointer to the first byte * of the memory block. * * RETURNS * Pointer: Success * NULL: Failure */ LPVOID WINAPI LocalLock( HLOCAL handle /* [in] Address of local memory object */ ) { return GlobalLock( (HGLOBAL)handle ); } /*********************************************************************** * LocalReAlloc (KERNEL32.@) * RETURNS * Handle: Success * NULL: Failure */ HLOCAL WINAPI LocalReAlloc( HLOCAL handle, /* [in] Handle of memory object */ SIZE_T size, /* [in] New size of block */ UINT flags /* [in] How to reallocate object */ ) { return (HLOCAL)GlobalReAlloc( (HGLOBAL)handle, size, flags ); } /*********************************************************************** * LocalShrink (KERNEL32.@) */ SIZE_T WINAPI LocalShrink( HGLOBAL handle, UINT newsize ) { return 0; /* LocalShrink does nothing in Win32 */ } /*********************************************************************** * LocalSize (KERNEL32.@) * RETURNS * Size: Success * 0: Failure */ SIZE_T WINAPI LocalSize( HLOCAL handle /* [in] Handle of memory object */ ) { return GlobalSize( (HGLOBAL)handle ); } /*********************************************************************** * LocalUnlock (KERNEL32.@) * RETURNS * TRUE: Object is still locked * FALSE: Object is unlocked */ BOOL WINAPI LocalUnlock( HLOCAL handle /* [in] Handle of memory object */ ) { return GlobalUnlock( (HGLOBAL)handle ); }