/************************************************************
* MultiUser - MultiUser Task/File Support System				*
* ---------------------------------------------------------	*
* Memory management														*
* ---------------------------------------------------------	*
* © Copyright 1993-1994 Geert Uytterhoeven						*
* All Rights Reserved.													*
************************************************************/


#include <exec/memory.h>
#include <exec/semaphores.h>
#include <proto/exec.h>
#include <string.h>

#include "Memory.h"


	/*
	 *		Memory Pool Characteristics
	 *
	 *		At the moment the memory overhead of each puddle seems to be 40 bytes.
	 *		I hope puddles of 4000 bytes will still fit in one 4K page in future
	 *		AmigaOS versions.
	 */

#define MEM_PUDDLESIZE	4000
#define MEM_THRESHSIZE	4000


	/*
	 *		Prototypes for the Memory Pool Support functions in amiga.lib
	 */

APTR __asm AsmCreatePool(register __d0 ULONG, register __d1 ULONG, register __d2 ULONG,
								 register __a6 struct ExecBase *);
void __asm AsmDeletePool(register __a0 APTR, register __a6 struct ExecBase *);
APTR __asm AsmAllocPooled(register __a0 APTR, register __d0 ULONG, register __a6 struct ExecBase *);
void __asm AsmFreePooled(register __a0 APTR, register __a1 APTR, register __d0 ULONG,
								 register __a6 struct ExecBase *);


	/*
	 *		Our Private Memory Pool
	 */

APTR Pool = NULL;


	/*
	 *		Access Control Semaphore
	 */

struct SignalSemaphore Semaphore;


	/*
	 *		Initialisation
	 */

BOOL InitMemory(void)
{
	InitSemaphore(&Semaphore);
	ObtainSemaphore(&Semaphore);
	Pool = AsmCreatePool(MEMF_PUBLIC, MEM_PUDDLESIZE, MEM_THRESHSIZE, SysBase);
	ReleaseSemaphore(&Semaphore);
	return((BOOL)(Pool ? TRUE : FALSE));
}


	/*
	 *		Clean Up
	 */

void CleanUpMemory(void)
{
	ObtainSemaphore(&Semaphore);
	if (Pool) {
		AsmDeletePool(Pool, SysBase);
		Pool = NULL;
	}
	ReleaseSemaphore(&Semaphore);
}


	/*
	 *		Replacement for AllocMem()
	 */

APTR MAlloc(ULONG size)
{
	ULONG *block;

	ObtainSemaphore(&Semaphore);
	if (block = AsmAllocPooled(Pool, size, SysBase))
		memset(block, NULL, size);
	ReleaseSemaphore(&Semaphore);
	return(block);
}


	/*
	 *		Replacement for FreeMem()
	 */

void Free(APTR block, ULONG size)
{
	if (block) {
		ObtainSemaphore(&Semaphore);
		AsmFreePooled(Pool, block, size, SysBase);
		ReleaseSemaphore(&Semaphore);
	}
}


	/*
	 *		Replacement for AllocVec()
	 */

APTR MAllocV(ULONG size)
{
	ULONG *block;

	ObtainSemaphore(&Semaphore);
	if (block = AsmAllocPooled(Pool, size+4, SysBase)) {
		*(block++) = size;
		memset(block, NULL, size);
	}
	ReleaseSemaphore(&Semaphore);
	return(block);
}


	/*
	 *		Replacement for FreeVec()
	 */

void FreeV(APTR block)
{
	if (block) {
		ObtainSemaphore(&Semaphore);
		AsmFreePooled(Pool, (APTR)((ULONG)block-4), *(ULONG *)((ULONG)block-4), SysBase);
		ReleaseSemaphore(&Semaphore);
	}
}
