Beispiel #1
0
/**
 * Creates MidpSession for the specified XRPC client id. Invoked on the XRPC
 * thread under synchronization.
 */
STATIC MidpSession* GWENG_MidpCreateSession(EcmtGateway* gw, int xrpcSid)
{
    MidpSession* ses = MEM_New(MidpSession);
    if (ses) {
        LUID luid;
        /* Just in case if AllocateLocallyUniqueId fails... */
        luid.LowPart = (DWORD)ses;
        AllocateLocallyUniqueId(&luid);
        memset(ses, 0, sizeof(*ses));
        ses->key.xrpcSid = xrpcSid;
        ses->key.xrpcSession = XRPC_GetCurrentSession(gw->xrpc);
        ses->sid = luid.LowPart;
        ASSERT(!HASH_Contains(&gw->ecmtSessionMap,(HashKey)ses->sid));
        ASSERT(!HASH_Contains(&gw->midpSessionMap,&ses->key));
        if (HASH_Init(&ses->connMap, 1, NULL, NULL, hashFreeValueProc)) {
            /* Create context for the control connection (number zero) */
            MidpConnection* conn = MEM_New(MidpConnection);
            if (conn) {
                memset(conn, 0, sizeof(*conn));
                if (HASH_Put(&ses->connMap, (HashKey)0, conn)) {
                    if (HASH_Put(&gw->ecmtSessionMap,(HashKey)ses->sid,ses)) {
                        if (HASH_Put(&gw->midpSessionMap, &ses->key, ses)) {
                            if (MUTEX_Init(&ses->xrpcMutex)) {
                                ses->xrpcWorkThread = WKQ_Create();
                                if (ses->xrpcWorkThread) {
                                    ses->xrpcWorkItem = WKI_Create(
                                        ses->xrpcWorkThread, GWENG_AsyncXRpc,
                                        ses);
                                    if (ses->xrpcWorkItem) {
                                        QUEUE_Init(&ses->xrpcQueue);
                                        TRACE3("GW: new session %08x for "
                                            "%08x.%08x\n", ses->sid,
                                            ses->key.xrpcSession,
                                            ses->key.xrpcSid);
                                        return ses;
                                    }
                                    WKQ_Delete(ses->xrpcWorkThread);
                                }
                                MUTEX_Destroy(&ses->xrpcMutex);
                            }
                            HASH_Remove(&gw->midpSessionMap, &ses->key);
                        }
                        HASH_Remove(&gw->ecmtSessionMap, (HashKey)ses->sid);
                    }
                } else {
                    MEM_Free(conn);
                }
            }
            HASH_Destroy(&ses->connMap);
        }
        MEM_Free(ses);
    }
    return NULL;
}
Beispiel #2
0
void RA_Free(struct RA_ARENA *pArena, u32 base, IMG_BOOL bFreeBackingStore)
{
	struct BT *pBT;

	PVR_ASSERT(pArena != NULL);

	if (pArena == NULL) {
		PVR_DPF(PVR_DBG_ERROR, "RA_Free: invalid parameter - pArena");
		return;
	}

	PVR_DPF(PVR_DBG_MESSAGE,
		 "RA_Free: name='%s', base=0x%x", pArena->name, base);

	pBT = (struct BT *)HASH_Remove(pArena->pSegmentHash, base);
	PVR_ASSERT(pBT != NULL);

	if (pBT) {
		PVR_ASSERT(pBT->base == base);

#ifdef RA_STATS
		pArena->sStatistics.uCumulativeFrees++;
#endif

		_FreeBT(pArena, pBT, bFreeBackingStore);
	}
}
Beispiel #3
0
IMG_VOID
BM_Free (BM_HANDLE hBuf,
		IMG_UINT32 ui32Flags)
{
	BM_BUF *pBuf = (BM_BUF *)hBuf;
	SYS_DATA *psSysData;
	IMG_SYS_PHYADDR sHashAddr;

	PVR_DPF ((PVR_DBG_MESSAGE, "BM_Free (h=0x%x)", (IMG_UINTPTR_T)hBuf));
	PVR_ASSERT (pBuf!=IMG_NULL);

	if (pBuf == IMG_NULL)
	{
		PVR_DPF((PVR_DBG_ERROR, "BM_Free: invalid parameter"));
		return;
	}

	SysAcquireData(&psSysData);

	pBuf->ui32RefCount--;

	if(pBuf->ui32RefCount == 0)
	{
		if(pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped || pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped_virtaddr)
		{
			sHashAddr = SysCpuPAddrToSysPAddr(pBuf->CpuPAddr);

			HASH_Remove (pBuf->pMapping->pBMHeap->pBMContext->pBufferHash,	(IMG_UINTPTR_T)sHashAddr.uiAddr);
		}
		FreeBuf (pBuf, ui32Flags, IMG_TRUE);
	}
}
void BM_Free(void *hBuf, u32 ui32Flags)
{
	struct BM_BUF *pBuf = (struct BM_BUF *)hBuf;
	struct SYS_DATA *psSysData;
	struct IMG_SYS_PHYADDR sHashAddr;

	PVR_DPF(PVR_DBG_MESSAGE, "BM_Free (h=%08X)", hBuf);
	PVR_ASSERT(pBuf != NULL);

	if (pBuf == NULL) {
		PVR_DPF(PVR_DBG_ERROR, "BM_Free: invalid parameter");
		return;
	}

	if (SysAcquireData(&psSysData) != PVRSRV_OK)
		return;

	pBuf->ui32RefCount--;

	if (pBuf->ui32RefCount == 0) {
		struct BM_MAPPING *map = pBuf->pMapping;
		struct BM_CONTEXT *ctx = map->pBMHeap->pBMContext;

		if (map->eCpuMemoryOrigin == hm_wrapped ||
		    map->eCpuMemoryOrigin == hm_wrapped_virtaddr) {
			sHashAddr = SysCpuPAddrToSysPAddr(pBuf->CpuPAddr);

			HASH_Remove(ctx->pBufferHash, (u32)sHashAddr.uiAddr);
		}
		FreeBuf(pBuf, ui32Flags);
		pvr_put_ctx(ctx);
	}
}
/*!
******************************************************************************

 @Function	PVRSRVTimeTraceBufferDestroy

 @Description

 Destroy a trace buffer.

 Note: We assume that this will only be called once per process.

 @Input ui32PID : PID of the process that is creating the buffer

 @Return none

******************************************************************************/
PVRSRV_ERROR PVRSRVTimeTraceBufferDestroy(IMG_UINT32 ui32PID)
{
#if !defined(TTRACE_KEEP_BUFFER_ON_EXIT)
	sTimeTraceBuffer *psBuffer;

#if defined(DUMP_TTRACE_BUFFERS_ON_EXIT)
	PVRSRVDumpTimeTraceBuffers();
#endif
    LinuxLockMutex(&g_sTTraceMutex);
	psBuffer = (sTimeTraceBuffer *) HASH_Retrieve(g_psBufferTable, (IMG_UINTPTR_T) ui32PID);
	if (psBuffer)
	{
		OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(sTimeTraceBuffer) + TIME_TRACE_BUFFER_SIZE,
				psBuffer, NULL);
		HASH_Remove(g_psBufferTable, (IMG_UINTPTR_T) ui32PID);
        LinuxUnLockMutex(&g_sTTraceMutex);
		return PVRSRV_OK;
	}

	PVR_DPF((PVR_DBG_ERROR, "PVRSRVTimeTraceBufferDestroy: Can't find trace buffer in hash table"));
	LinuxUnLockMutex(&g_sTTraceMutex);
	return PVRSRV_ERROR_INVALID_PARAMS;
#else
	return PVRSRV_OK;
#endif
}
Beispiel #6
0
IMG_VOID
RA_Free (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_BOOL bFreeBackingStore)
{
	BT *pBT;

	PVR_ASSERT (pArena != IMG_NULL);

	if (pArena == IMG_NULL)
	{
		PVR_DPF ((PVR_DBG_ERROR,"RA_Free: invalid parameter - pArena"));
		return;
	}

#ifdef USE_BM_FREESPACE_CHECK
	CheckBMFreespace();
#endif

	PVR_DPF ((PVR_DBG_MESSAGE,
			  "RA_Free: name='%s', base=0x%x", pArena->name, base));

	pBT = (BT *) HASH_Remove (pArena->pSegmentHash, base);
	PVR_ASSERT (pBT != IMG_NULL);

	if (pBT)
	{
		PVR_ASSERT (pBT->base == base);

#ifdef RA_STATS
		pArena->sStatistics.uCumulativeFrees++;
#endif

#ifdef USE_BM_FREESPACE_CHECK
{
	IMG_BYTE* p;
	IMG_BYTE* endp;

	p = (IMG_BYTE*)pBT->base + SysGetDevicePhysOffset();
	endp = (IMG_BYTE*)((IMG_UINT32)(p + pBT->uSize));
	while ((IMG_UINT32)p & 3)
	{
		*p++ = 0xAA;
	}
	while (p < (IMG_BYTE*)((IMG_UINT32)endp & 0xfffffffc))
	{
		*(IMG_UINT32*)p = 0xAAAAAAAA;
		p += sizeof(IMG_UINT32);
	}
	while (p < endp)
	{
		*p++ = 0xAA;
	}
	PVR_DPF((PVR_DBG_MESSAGE,"BM_FREESPACE_CHECK: RA_Free Cleared %08X to %08X (size=0x%x)",(IMG_BYTE*)pBT->base + SysGetDevicePhysOffset(),endp-1,pBT->uSize));
}
#endif
		_FreeBT (pArena, pBT, bFreeBackingStore);
	}
}
Beispiel #7
0
/**
 * Deallocates the MIDP session context.
 */
STATIC void GWENG_MidpFree(EcmtGateway* gw, MidpSession* midp)
{
    if (midp) {
        QEntry* e;
        VERIFY(HASH_Remove(&gw->midpSessionMap, &midp->key));
        HASH_Remove(&gw->ecmtSessionMap, (HashKey)midp->sid);
        HASH_Destroy(&midp->connMap);
        WKI_Cancel(midp->xrpcWorkItem);
        WKI_Detach(midp->xrpcWorkItem);
        WKQ_Delete(midp->xrpcWorkThread);
        MUTEX_Destroy(&midp->xrpcMutex);
        while ((e = QUEUE_RemoveHead(&midp->xrpcQueue)) != NULL) {
            AsyncXRpcEntry* a = QCAST(e,AsyncXRpcEntry,entry);
            XRPC_FreeContainer(a->params);
            MEM_Free(a);
        }
        MEM_Free(midp);
    }
}
static inline
void put_syncinfo(struct PVRSRV_KERNEL_SYNC_INFO *syncinfo)
{
	struct PVRSRV_DEVICE_NODE *dev = syncinfo->dev_cookie;

	syncinfo->refcount--;

	if (!syncinfo->refcount) {
		HASH_Remove(dev->sync_table,
			    syncinfo->phys_addr.uiAddr);
		PVRSRVFreeSyncInfoKM(syncinfo);
	}
}
Beispiel #9
0
static enum PVRSRV_ERROR FreePerProcessData(
				struct PVRSRV_PER_PROCESS_DATA *psPerProc)
{
	enum PVRSRV_ERROR eError;
	u32 uiPerProc;

	PVR_ASSERT(psPerProc != NULL);

	uiPerProc = HASH_Remove(psHashTab, (u32)psPerProc->ui32PID);
	if (uiPerProc == 0) {
		PVR_DPF(PVR_DBG_ERROR, "FreePerProcessData: "
		       "Couldn't find process in per-process data hash table");

		PVR_ASSERT(psPerProc->ui32PID == 0);
	} else {
		PVR_ASSERT((struct PVRSRV_PER_PROCESS_DATA *)
				uiPerProc == psPerProc);
		PVR_ASSERT(((struct PVRSRV_PER_PROCESS_DATA *)uiPerProc)->
				ui32PID == psPerProc->ui32PID);
	}

	if (psPerProc->psHandleBase != NULL) {
		eError = PVRSRVFreeHandleBase(psPerProc->psHandleBase);
		if (eError != PVRSRV_OK) {
			PVR_DPF(PVR_DBG_ERROR, "FreePerProcessData: "
				"Couldn't free handle base for process (%d)",
				 eError);
			return eError;
		}
	}

	if (psPerProc->hPerProcData != NULL) {
		eError =
		    PVRSRVReleaseHandle(KERNEL_HANDLE_BASE,
					psPerProc->hPerProcData,
					PVRSRV_HANDLE_TYPE_PERPROC_DATA);

		if (eError != PVRSRV_OK) {
			PVR_DPF(PVR_DBG_ERROR, "FreePerProcessData: "
				"Couldn't release per-process data handle (%d)",
				 eError);
			return eError;
		}
	}

	OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(*psPerProc),
			psPerProc, psPerProc->hBlockAlloc);

	return PVRSRV_OK;
}
Beispiel #10
0
/**
 * Sends "reset" event to both XRPC and ECMT clients and deallocates the 
 * connection context. Caller must hold the mutex.
 */
STATIC void GWENG_MidpResetConn(EcmtGateway* gw, MidpSession* midp, I32u cid,
                                Bool resetEcmt, Bool resetXrpc)
{
    TRACE1("GW: resetting connection %u\n",cid);
    HASH_Remove(&midp->connMap, (HashKey)cid);

    if (resetEcmt) {
        char pkt[ECMT_MIDP_DEBUG_RESET_SIZE];
        GWENG_MidpFillHeader(pkt, midp->sid, ECMT_MIDP_DEBUG_OPCODE_RESET);
        *((I32u*)(pkt+ECMT_MIDP_DEBUG_RESET_CID_OFFSET)) = htonl(cid);
        GWENG_QueueAdd(gw->handsetQueue, KECMT_MIDP_DEBUG_PLUGIN_UID, pkt,
            ECMT_MIDP_DEBUG_RESET_SIZE);
    }

    if (resetXrpc) {
        GWENG_SubmitAsyncCall(midp,
            ECMTGW_SEI_RESET_METHOD,
            GWENG_CreateXRpcParams(midp,
                ECMTGW_SEI_RESET_SID_PARAM, 
                ECMTGW_SEI_RESET_CID_PARAM, cid));
    }
}
Beispiel #11
0
/*!
******************************************************************************

 @Function	PVRSRVTimeTraceBufferDestroy

 @Description

 Destroy a trace buffer.

 Note: We assume that this will only be called once per process.

 @Input ui32PID : PID of the process that is creating the buffer

 @Return none

******************************************************************************/
PVRSRV_ERROR PVRSRVTimeTraceBufferDestroy(IMG_UINT32 ui32PID)
{
	sTimeTraceBuffer *psBuffer;

#if defined(DUMP_TTRACE_BUFFERS_ON_EXIT)
	PVRSRVDumpTimeTraceBuffers();
#endif
	psBuffer = (sTimeTraceBuffer *) HASH_Retrieve(g_psBufferTable, (IMG_UINTPTR_T) ui32PID);
	if (psBuffer)
	{
		if (psBuffer->pui8Data)
			OSFreeMem(PVRSRV_PAGEABLE_SELECT, TIME_TRACE_BUFFER_SIZE,
					psBuffer->pui8Data, NULL);
		OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(sTimeTraceBuffer),
				psBuffer, NULL);
		HASH_Remove(g_psBufferTable, (IMG_UINTPTR_T) ui32PID);
		return PVRSRV_OK;
	}

	PVR_DPF((PVR_DBG_ERROR, "PVRSRVTimeTraceBufferDestroy: Can't find trace buffer in hash table"));
	return PVRSRV_ERROR_INVALID_PARAMS;
}
Beispiel #12
0
/*!
******************************************************************************

 @Function	FreePerProcData

 @Description	Free a per-process data area

 @Input		psPerProc - pointer to per-process data area

 @Return	Error code, or PVRSRV_OK

******************************************************************************/
static PVRSRV_ERROR FreePerProcessData(PVRSRV_PER_PROCESS_DATA *psPerProc)
{
	PVRSRV_ERROR eError;
	IMG_UINTPTR_T uiPerProc;

	PVR_ASSERT(psPerProc != IMG_NULL);

	if (psPerProc == IMG_NULL)
	{
		PVR_DPF((PVR_DBG_ERROR, "FreePerProcessData: invalid parameter"));
		return PVRSRV_ERROR_INVALID_PARAMS;
	}

	uiPerProc = HASH_Remove(psHashTab, (IMG_UINTPTR_T)psPerProc->ui32PID);
	if (uiPerProc == 0)
	{
		PVR_DPF((PVR_DBG_ERROR, "FreePerProcessData: Couldn't find process in per-process data hash table"));
		/*
		 * We must have failed early in the per-process data area
		 * creation, before the process ID was set.
		 */
		PVR_ASSERT(psPerProc->ui32PID == 0);
	}
	else
	{
		PVR_ASSERT((PVRSRV_PER_PROCESS_DATA *)uiPerProc == psPerProc);
		PVR_ASSERT(((PVRSRV_PER_PROCESS_DATA *)uiPerProc)->ui32PID == psPerProc->ui32PID);
	}

	/* Free handle base for this process */
	if (psPerProc->psHandleBase != IMG_NULL)
	{
		eError = PVRSRVFreeHandleBase(psPerProc->psHandleBase);
		if (eError != PVRSRV_OK)
		{
			PVR_DPF((PVR_DBG_ERROR, "FreePerProcessData: Couldn't free handle base for process (%d)", eError));
			return eError;
		}
	}

	/* Release handle for per-process data area */
	if (psPerProc->hPerProcData != IMG_NULL)
	{
		eError = PVRSRVReleaseHandle(KERNEL_HANDLE_BASE, psPerProc->hPerProcData, PVRSRV_HANDLE_TYPE_PERPROC_DATA);

		if (eError != PVRSRV_OK)
		{
			PVR_DPF((PVR_DBG_ERROR, "FreePerProcessData: Couldn't release per-process data handle (%d)", eError));
			return eError;
		}
	}

	/* Call environment specific per process deinit function */
	eError = OSPerProcessPrivateDataDeInit(psPerProc->hOsPrivateData);
	if (eError != PVRSRV_OK)
	{
		 PVR_DPF((PVR_DBG_ERROR, "FreePerProcessData: OSPerProcessPrivateDataDeInit failed (%d)", eError));
		return eError;
	}

	eError = OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
		sizeof(*psPerProc),
		psPerProc,
		psPerProc->hBlockAlloc);
	/*not nulling pointer, copy on stack*/
	if (eError != PVRSRV_OK)
	{
		PVR_DPF((PVR_DBG_ERROR, "FreePerProcessData: Couldn't free per-process data (%d)", eError));
		return eError;
	}

	return PVRSRV_OK;
}
static PVRSRV_ERROR FreePerProcessData(PVRSRV_PER_PROCESS_DATA *psPerProc)
{
	PVRSRV_ERROR eError;
	IMG_UINTPTR_T uiPerProc;

	PVR_ASSERT(psPerProc != IMG_NULL);

	if (psPerProc == IMG_NULL)
	{
		PVR_DPF((PVR_DBG_ERROR, "FreePerProcessData: invalid parameter"));
		return PVRSRV_ERROR_INVALID_PARAMS;
	}

	uiPerProc = HASH_Remove(psHashTab, (IMG_UINTPTR_T)psPerProc->ui32PID);
	if (uiPerProc == 0)
	{
		PVR_DPF((PVR_DBG_ERROR, "FreePerProcessData: Couldn't find process in per-process data hash table"));
		
		PVR_ASSERT(psPerProc->ui32PID == 0);
	}
	else
	{
		PVR_ASSERT((PVRSRV_PER_PROCESS_DATA *)uiPerProc == psPerProc);
		PVR_ASSERT(((PVRSRV_PER_PROCESS_DATA *)uiPerProc)->ui32PID == psPerProc->ui32PID);
	}

	
	if (psPerProc->psHandleBase != IMG_NULL)
	{
		eError = PVRSRVFreeHandleBase(psPerProc->psHandleBase);
		if (eError != PVRSRV_OK)
		{
			PVR_DPF((PVR_DBG_ERROR, "FreePerProcessData: Couldn't free handle base for process (%d)", eError));
			return eError;
		}
	}

	
	if (psPerProc->hPerProcData != IMG_NULL)
	{
		eError = PVRSRVReleaseHandle(KERNEL_HANDLE_BASE, psPerProc->hPerProcData, PVRSRV_HANDLE_TYPE_PERPROC_DATA);

		if (eError != PVRSRV_OK)
		{
			PVR_DPF((PVR_DBG_ERROR, "FreePerProcessData: Couldn't release per-process data handle (%d)", eError));
			return eError;
		}
	}

	
	eError = OSPerProcessPrivateDataDeInit(psPerProc->hOsPrivateData);
	if (eError != PVRSRV_OK)
	{
		 PVR_DPF((PVR_DBG_ERROR, "FreePerProcessData: OSPerProcessPrivateDataDeInit failed (%d)", eError));
		return eError;
	}

	eError = OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
		sizeof(*psPerProc),
		psPerProc,
		psPerProc->hBlockAlloc);
	
	if (eError != PVRSRV_OK)
	{
		PVR_DPF((PVR_DBG_ERROR, "FreePerProcessData: Couldn't free per-process data (%d)", eError));
		return eError;
	}

	return PVRSRV_OK;
}
Beispiel #14
0
/**
 * @brief Unit test function.
 */
bool HASH_test () {
	// return value
	bool result = true;

	/* test 1: create the hash table, delete the hash table */
	hashTable_s* table = HASH_NewTable(true, true, true);
	HASH_DeleteTable (&table);
	/* check table pointer is correctly set to nil */
	result = result && (table == NULL);
	if (!result) return false;
	/* check alloc total */
	result = result && (_num_allocs == 0);
	if (!result) return false;

	/* test 2: create the hash table, insert 3 values, delete the hash table */
	table = HASH_NewTable(true, true, true);
	HASH_Insert (table, "AAA", 4, "AAA", 4);
	HASH_Insert (table, "BBB", 4, "BBB", 4);
	HASH_Insert (table, "CCC", 4, "CCC", 4);
	if (HASH_Count(table) != 3) return false;
	HASH_Clear (table);
	if (HASH_Count(table) != 0) return false;
	HASH_DeleteTable (&table);
	/* check table pointer is correctly set to nil */
	result = result && (table == NULL);
	if (!result) return false;
	/* check alloc total */
	result = result && (_num_allocs == 0);
	if (!result) return false;

	/* test 3: create the hash table, insert/remove 3 values, delete the hash table */
	table = HASH_NewTable(true, true, true);
	HASH_Insert (table, "AAA", 4, "AAA", 4);
	HASH_Remove (table, "AAA", 4);
	HASH_Insert (table, "BBB", 4, "BBB", 4);
	HASH_Remove (table, "BBB", 4);
	HASH_Insert (table, "CCC", 4, "CCC", 4);
	HASH_Remove (table, "CCC", 4);
	HASH_DeleteTable (&table);
	/* check table pointer is correctly set to nil */
	result = result && (table == NULL);
	if (!result) return false;
	/* check alloc total */
	result = result && (_num_allocs == 0);
	if (!result) return false;

	/* test 4: create the hash table, insert/count/search/delete 3 values, delete the hash table */
	table = HASH_NewTable(true, true, true);
	HASH_Insert (table, "AAA", 4, "AAA", 4);
	HASH_Insert (table, "BBB", 4, "BBB", 4);
	HASH_Insert (table, "CCC", 4, "CCC", 4);
	/* check count items */
	if (HASH_Count(table) != 3) return false;
    char* aaa = (char*)HASH_Get(table, "AAA", 4);
    if (strncmp (aaa, "AAA", 4) != 0) return false;
    char* bbb = (char*)HASH_Get(table, "BBB", 4);
    if (strncmp (bbb, "BBB", 4) != 0) return false;
    char* ccc = (char*)HASH_Get(table, "CCC", 4);
    if (strncmp (ccc, "CCC", 4) != 0) return false;
	HASH_Remove (table, "AAA", 4);
	HASH_Remove (table, "BBB", 4);
	HASH_Remove (table, "CCC", 4);
	if (HASH_Count(table) != 0) return false;
	HASH_DeleteTable (&table);
	/* check table pointer is correctly set to nil */
	result = result && (table == NULL);
	if (!result) return false;
	/* check alloc total */
	result = result && (_num_allocs == 0);
	if (!result) return false;

	/* test 5: hash function test */
	const char AZ[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
	char buffer[26];
	/* compute the averag of the hash index of 400 random keys */
    int total = 0;
    srand(time(NULL));
    for(int i=0; i < 4000; i++) {
		/* create random key of random length between 4..23 charachters */
		int len = 4 + (rand() % 20);
		memset (buffer, 0, sizeof(buffer));
		for (int j=0; j < len; j++) {
			int v = rand() % sizeof(AZ);
			buffer[j]=AZ[v];
		}
		/* compute the hash index */
		int idx = default_hash (buffer, len);
		/* sum index */
		total += idx;
    }
    /* now compute the average of the indices */
    int avg = (total / 4000);
	/* the average idx should be somewhere halfway, allow a %10 error margin */
	int idx_low = (HASH_TABLE_SIZE/2) - (HASH_TABLE_SIZE/10);
	int idx_high = (HASH_TABLE_SIZE/2) + (HASH_TABLE_SIZE/10);
	if ( !((idx_low <= avg) && (idx_high >= avg)) ) return false;

	/* test 6: hash table without ownership test */
	table = HASH_NewTable(true, false, true);
	char item1[] = "AAA";
	char item2[] = "BBB";
	char item3[] = "CCC";
	HASH_Insert (table, item1, 4, item1, 4);
	HASH_Insert (table, item2, 4, item2, 4);
	HASH_Insert (table, item3, 4, item3, 4);
	/* check if we get the correct value pointers */
	aaa = (char*)HASH_Get(table, "AAA", 4);
	if (aaa != item1) return false;
	bbb = (char*)HASH_Get(table, "BBB", 4);
	if (bbb != item2) return false;
	ccc = (char*)HASH_Get(table, "CCC", 4);
	if (ccc != item3) return false;
	HASH_DeleteTable (&table);
	/* check table pointer is correctly set to nil */
	result = result && (table == NULL);
	if (!result) return false;
	/* check alloc total */
	result = result && (_num_allocs == 0);
	if (!result) return false;


	/* end of unit test, everything OK */
	return true;
}