
/*
 * Copyright © 2001 Novell, Inc. All Rights Reserved.
 *
 * You may distribute under the terms of either the GNU General Public
 * License or the Artistic License, as specified in the README file.
 *
 */

/*
 * FILENAME		:	NWVMem.h
 * DESCRIPTION	:	Memory management for Perl Interpreter on NetWare.
 *                  Watcom's hash table is used to store memory pointers.
 *                  All malloc's, realloc's, free's go through this.
 * Author		:	HYAK, SGP
 * Date			:	January 2001.
 *
 */



#ifndef ___NWVMEM_H_INC___
#define ___NWVMEM_H_INC___


#include "win32ish.h"		// For "BOOL", "TRUE" and "FALSE"
#include <nwhashcls.h>		// CW changes
#include <nwmalloc.h>
#include "string.h"



class VMem
{
public:
    VMem();
    virtual ~VMem();
    virtual void* Malloc(size_t size);
    virtual void* Realloc(void* pMem, size_t size);
    virtual void Free(void* pMem);
	virtual void* Calloc(size_t num, size_t size);

protected:
	BOOL					m_dontTouchHashLists;
//	WCValHashTable<void*>*	m_allocList;		
	NWPerlHashList *m_allocList;			// CW changes
};




/*============================================================================================

 Function		:	fnAllocListHash

 Description	:	Hashing function for hash table of memory allocations.

 Parameters 	:	invalue	(IN).

 Returns		:	unsigned.

==============================================================================================*/

unsigned fnAllocListHash(void* const& invalue)
{
    return (((unsigned) invalue & 0x0000ff00) >> 8);
}



/*============================================================================================

 Function		:	fnFreeMemEntry

 Description	:	Called for each outstanding memory allocation at the end of a script run.
					Frees the outstanding allocations

 Parameters 	:	ptr	(IN).
					context (IN)

 Returns		:	Nothing.

==============================================================================================*/

void fnFreeMemEntry(void* ptr, void* context)
{
	VMem* pVMem = (VMem*) context;

	if(ptr && pVMem)
	{
		pVMem->Free(ptr);
		ptr=NULL;
		pVMem = NULL;
		context = NULL;
	}
}



/*============================================================================================

 Function		:	VMem Constructor

 Description	:	

 Parameters 	:	

 Returns		:	

==============================================================================================*/

VMem::VMem()
{
	//Constructor
	m_dontTouchHashLists = FALSE;
	m_allocList = NULL;
	// m_allocList = new WCValHashTable<void*> (fnAllocListHash, 256);  
	m_allocList = new NWPerlHashList();			// CW changes
}



/*============================================================================================

 Function		:	VMem Destructor

 Description	:	

 Parameters 	:	

 Returns		:	

==============================================================================================*/

VMem::~VMem(void)
{
	//Destructor
	m_dontTouchHashLists = TRUE;
	if (m_allocList)
	{
		m_allocList->forAll(fnFreeMemEntry, (void*) this);

		delete m_allocList;
		m_allocList = NULL;
	}
	m_dontTouchHashLists = FALSE;
}



/*============================================================================================

 Function		:	VMem::Malloc

 Description	:	Allocates memory.

 Parameters 	:	size	(IN)	-	Size of memory to be allocated.

 Returns		:	Pointer to the allocated memory block.

==============================================================================================*/

void* VMem::Malloc(size_t size)
{
	void *ptr = NULL;

	if (size <= 0)
		return NULL;

	ptr = malloc(size);
	if (ptr)
	{
		if(m_allocList)
			m_allocList->insert(ptr);
	}
	else
	{
		m_dontTouchHashLists = TRUE;
		if (m_allocList)
		{
			m_allocList->forAll(fnFreeMemEntry, (void*) this);
			delete m_allocList;
			m_allocList = NULL;
		}
		m_dontTouchHashLists = FALSE;

		// Serious error since memory allocation falied. So, exiting...
		ExitThread(TSR_THREAD, 1);
	}

	return(ptr);
}



/*============================================================================================

 Function		:	VMem::Realloc

 Description	:	Reallocates block of memory.

 Parameters 	:	block	(IN)	-	Points to a previously allocated memory block.
					size	(IN)	-	Size of memory to be allocated.

 Returns		:	Pointer to the allocated memory block.

==============================================================================================*/

void* VMem::Realloc(void* block, size_t size)
{
	void *ptr = NULL;

	if (size <= 0)
		return NULL;

	ptr = realloc(block, size);
	if (ptr)
	{
		if (block)
		{
			if (m_allocList)
				m_allocList->remove(block);
		}
		if (m_allocList)
			m_allocList->insert(ptr);
	}
	else
	{
		m_dontTouchHashLists = TRUE;
		if (m_allocList)
		{
			m_allocList->forAll(fnFreeMemEntry, (void*) this);
			delete m_allocList;
			m_allocList = NULL;
		}
		m_dontTouchHashLists = FALSE;

		// Serious error since memory allocation falied. So, exiting...
		ExitThread(TSR_THREAD, 1);
	}

	return(ptr);
}



/*============================================================================================

 Function		:	VMem::Calloc

 Description	:	Allocates and clears memory space for an array of objects.

 Parameters 	:	num	(IN)	-	Specifies the number of objects.
					size	(IN)	-	Size of each object.

 Returns		:	Pointer to the allocated memory block.

==============================================================================================*/

void* VMem::Calloc(size_t num, size_t size)
{
	void *ptr = NULL;

	if (size <= 0)
		return NULL;

	ptr = calloc(num, size);
	if (ptr)
	{
		if(m_allocList)
			m_allocList->insert(ptr);
	}
	else
	{
		m_dontTouchHashLists = TRUE;
		if (m_allocList)
		{
			m_allocList->forAll(fnFreeMemEntry, (void*) this);
			delete m_allocList;
			m_allocList = NULL;
		}
		m_dontTouchHashLists = FALSE;

		// Serious error since memory allocation falied. So, exiting...
		ExitThread(TSR_THREAD, 1);
	}

	return(ptr);
}



/*============================================================================================

 Function		:	VMem::Free

 Description	:	Frees allocated memory.

 Parameters 	:	p	(IN)	-	Points to the allocated memory.

 Returns		:	Nothing.

==============================================================================================*/

void VMem::Free(void* p)
{
	// Final clean up, free all the nodes from the hash list
	if (m_dontTouchHashLists)
	{
		if(p)
		{
			free(p);
			p = NULL;
		}
	}
	else
	{
		if(p && m_allocList)
		{
			if (m_allocList->remove(p))
			{
				free(p);
				p = NULL;
			}
			else
			{
				// If it comes here, that means that the memory pointer is not contained in the hash list.
				// But no need to free now, since if is deleted here, it will result in an abend!!
				// If the memory is still there, it will be cleaned during final cleanup anyway.
			}
		}
	}


	return;
}


#endif		//___NWVMEM_H_INC___

