| /* | 
 |  * msvcrt.dll heap functions | 
 |  * | 
 |  * Copyright 2000 Jon Griffiths | 
 |  * | 
 |  * 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: Win32 heap operations are MT safe. We only lock the new | 
 |  *       handler and non atomic heap operations | 
 |  */ | 
 |  | 
 | #include "msvcrt.h" | 
 | #include "ms_errno.h" | 
 |  | 
 | #include "msvcrt/malloc.h" | 
 | #include "mtdll.h" | 
 |  | 
 | #include "wine/debug.h" | 
 |  | 
 | WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); | 
 |  | 
 | /* MT */ | 
 | #define LOCK_HEAP   _mlock( _HEAP_LOCK ) | 
 | #define UNLOCK_HEAP _munlock( _HEAP_LOCK ) | 
 |  | 
 |  | 
 | typedef void (*MSVCRT_new_handler_func)(unsigned long size); | 
 |  | 
 | static MSVCRT_new_handler_func MSVCRT_new_handler; | 
 | static int MSVCRT_new_mode; | 
 |  | 
 |  | 
 | /********************************************************************* | 
 |  *		??2@YAPAXI@Z (MSVCRT.@) | 
 |  */ | 
 | void* MSVCRT_operator_new(unsigned long size) | 
 | { | 
 |   void *retval = HeapAlloc(GetProcessHeap(), 0, size); | 
 |   TRACE("(%ld) returning %p\n", size, retval); | 
 |   LOCK_HEAP; | 
 |   if(retval && MSVCRT_new_handler) | 
 |     (*MSVCRT_new_handler)(size); | 
 |   UNLOCK_HEAP; | 
 |   return retval; | 
 | } | 
 |  | 
 | /********************************************************************* | 
 |  *		??3@YAXPAX@Z (MSVCRT.@) | 
 |  */ | 
 | void MSVCRT_operator_delete(void *mem) | 
 | { | 
 |   TRACE("(%p)\n", mem); | 
 |   HeapFree(GetProcessHeap(), 0, mem); | 
 | } | 
 |  | 
 |  | 
 | /********************************************************************* | 
 |  *		?_query_new_handler@@YAP6AHI@ZXZ (MSVCRT.@) | 
 |  */ | 
 | MSVCRT_new_handler_func MSVCRT__query_new_handler(void) | 
 | { | 
 |   return MSVCRT_new_handler; | 
 | } | 
 |  | 
 |  | 
 | /********************************************************************* | 
 |  *		?_query_new_mode@@YAHXZ (MSVCRT.@) | 
 |  */ | 
 | int MSVCRT__query_new_mode(void) | 
 | { | 
 |   return MSVCRT_new_mode; | 
 | } | 
 |  | 
 | /********************************************************************* | 
 |  *		?_set_new_handler@@YAP6AHI@ZP6AHI@Z@Z (MSVCRT.@) | 
 |  */ | 
 | MSVCRT_new_handler_func MSVCRT__set_new_handler(MSVCRT_new_handler_func func) | 
 | { | 
 |   MSVCRT_new_handler_func old_handler; | 
 |   LOCK_HEAP; | 
 |   old_handler = MSVCRT_new_handler; | 
 |   MSVCRT_new_handler = func; | 
 |   UNLOCK_HEAP; | 
 |   return old_handler; | 
 | } | 
 |  | 
 | /********************************************************************* | 
 |  *		?set_new_handler@@YAP6AXXZP6AXXZ@Z (MSVCRT.@) | 
 |  */ | 
 | MSVCRT_new_handler_func MSVCRT_set_new_handler(void *func) | 
 | { | 
 |   TRACE("(%p)\n",func); | 
 |   MSVCRT__set_new_handler(NULL); | 
 |   return NULL; | 
 | } | 
 |  | 
 | /********************************************************************* | 
 |  *		?_set_new_mode@@YAHH@Z (MSVCRT.@) | 
 |  */ | 
 | int MSVCRT__set_new_mode(int mode) | 
 | { | 
 |   int old_mode; | 
 |   LOCK_HEAP; | 
 |   old_mode = MSVCRT_new_mode; | 
 |   MSVCRT_new_mode = mode; | 
 |   UNLOCK_HEAP; | 
 |   return old_mode; | 
 | } | 
 |  | 
 | /********************************************************************* | 
 |  *		_callnewh (MSVCRT.@) | 
 |  */ | 
 | int _callnewh(unsigned long size) | 
 | { | 
 |   if(MSVCRT_new_handler) | 
 |     (*MSVCRT_new_handler)(size); | 
 |   return 0; | 
 | } | 
 |  | 
 | /********************************************************************* | 
 |  *		_expand (MSVCRT.@) | 
 |  */ | 
 | void* _expand(void* mem, MSVCRT_size_t size) | 
 | { | 
 |   return HeapReAlloc(GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, mem, size); | 
 | } | 
 |  | 
 | /********************************************************************* | 
 |  *		_heapchk (MSVCRT.@) | 
 |  */ | 
 | int _heapchk(void) | 
 | { | 
 |   if (!HeapValidate( GetProcessHeap(), 0, NULL)) | 
 |   { | 
 |     MSVCRT__set_errno(GetLastError()); | 
 |     return _HEAPBADNODE; | 
 |   } | 
 |   return _HEAPOK; | 
 | } | 
 |  | 
 | /********************************************************************* | 
 |  *		_heapmin (MSVCRT.@) | 
 |  */ | 
 | int _heapmin(void) | 
 | { | 
 |   if (!HeapCompact( GetProcessHeap(), 0 )) | 
 |   { | 
 |     if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) | 
 |       MSVCRT__set_errno(GetLastError()); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | /********************************************************************* | 
 |  *		_heapwalk (MSVCRT.@) | 
 |  */ | 
 | int _heapwalk(_HEAPINFO* next) | 
 | { | 
 |   PROCESS_HEAP_ENTRY phe; | 
 |  | 
 |   LOCK_HEAP; | 
 |   phe.lpData = next->_pentry; | 
 |   phe.cbData = next->_size; | 
 |   phe.wFlags = next->_useflag == _USEDENTRY ? PROCESS_HEAP_ENTRY_BUSY : 0; | 
 |  | 
 |   if (phe.lpData && phe.wFlags & PROCESS_HEAP_ENTRY_BUSY && | 
 |       !HeapValidate( GetProcessHeap(), 0, phe.lpData )) | 
 |   { | 
 |     UNLOCK_HEAP; | 
 |     MSVCRT__set_errno(GetLastError()); | 
 |     return _HEAPBADNODE; | 
 |   } | 
 |  | 
 |   do | 
 |   { | 
 |     if (!HeapWalk( GetProcessHeap(), &phe )) | 
 |     { | 
 |       UNLOCK_HEAP; | 
 |       if (GetLastError() == ERROR_NO_MORE_ITEMS) | 
 |          return _HEAPEND; | 
 |       MSVCRT__set_errno(GetLastError()); | 
 |       if (!phe.lpData) | 
 |         return _HEAPBADBEGIN; | 
 |       return _HEAPBADNODE; | 
 |     } | 
 |   } while (phe.wFlags & (PROCESS_HEAP_REGION|PROCESS_HEAP_UNCOMMITTED_RANGE)); | 
 |  | 
 |   UNLOCK_HEAP; | 
 |   next->_pentry = phe.lpData; | 
 |   next->_size = phe.cbData; | 
 |   next->_useflag = phe.wFlags & PROCESS_HEAP_ENTRY_BUSY ? _USEDENTRY : _FREEENTRY; | 
 |   return _HEAPOK; | 
 | } | 
 |  | 
 | /********************************************************************* | 
 |  *		_heapset (MSVCRT.@) | 
 |  */ | 
 | int _heapset(unsigned int value) | 
 | { | 
 |   int retval; | 
 |   _HEAPINFO heap; | 
 |  | 
 |   memset( &heap, 0, sizeof(_HEAPINFO) ); | 
 |   LOCK_HEAP; | 
 |   while ((retval = _heapwalk(&heap)) == _HEAPOK) | 
 |   { | 
 |     if (heap._useflag == _FREEENTRY) | 
 |       memset(heap._pentry, value, heap._size); | 
 |   } | 
 |   UNLOCK_HEAP; | 
 |   return retval == _HEAPEND? _HEAPOK : retval; | 
 | } | 
 |  | 
 | /********************************************************************* | 
 |  *		_heapadd (MSVCRT.@) | 
 |  */ | 
 | int _heapadd(void* mem, MSVCRT_size_t size) | 
 | { | 
 |   TRACE("(%p,%d) unsupported in Win32\n", mem,size); | 
 |   SET_THREAD_VAR(errno,MSVCRT_ENOSYS); | 
 |   return -1; | 
 | } | 
 |  | 
 | /********************************************************************* | 
 |  *		_msize (MSVCRT.@) | 
 |  */ | 
 | MSVCRT_size_t _msize(void* mem) | 
 | { | 
 |   long size = HeapSize(GetProcessHeap(),0,mem); | 
 |   if (size == -1) | 
 |   { | 
 |     WARN(":Probably called with non wine-allocated memory, ret = -1\n"); | 
 |     /* At least the Win32 crtdll/msvcrt also return -1 in this case */ | 
 |   } | 
 |   return size; | 
 | } | 
 |  | 
 | /********************************************************************* | 
 |  *		calloc (MSVCRT.@) | 
 |  */ | 
 | void* MSVCRT_calloc(MSVCRT_size_t size, MSVCRT_size_t count) | 
 | { | 
 |   return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size * count ); | 
 | } | 
 |  | 
 | /********************************************************************* | 
 |  *		free (MSVCRT.@) | 
 |  */ | 
 | void MSVCRT_free(void* ptr) | 
 | { | 
 |   HeapFree(GetProcessHeap(),0,ptr); | 
 | } | 
 |  | 
 | /********************************************************************* | 
 |  *                  malloc (MSVCRT.@) | 
 |  */ | 
 | void* MSVCRT_malloc(MSVCRT_size_t size) | 
 | { | 
 |   void *ret = HeapAlloc(GetProcessHeap(),0,size); | 
 |   if (!ret) | 
 |     MSVCRT__set_errno(GetLastError()); | 
 |   return ret; | 
 | } | 
 |  | 
 | /********************************************************************* | 
 |  *		realloc (MSVCRT.@) | 
 |  */ | 
 | void* MSVCRT_realloc(void* ptr, MSVCRT_size_t size) | 
 | { | 
 |   return HeapReAlloc(GetProcessHeap(), 0, ptr, size); | 
 | } |