Home

Resume

Blog

Teikitu


/* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
/*  »Project«   Teikitu Gaming System (TgS) (∂)
    »File«      TgS Common - Event MGR [Time Event].c
    »Author«    Andrew Aye (EMail: mailto:andrew.aye@gmail.com, Web: http://www.andrewaye.com)
    »Version«   4.51 / »GUID« A9981407-3EC9-42AF-8B6F-8BE6DD919615                                                                                                        */
/*   -------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
/*  Copyright: © 2002-2017, Andrew Aye.  All Rights Reserved.
    This software is free for non-commercial use.  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
      following conditions are met:
        Redistribution of source code must retain this copyright notice, this list of conditions and the following disclaimers.
        Redistribution in binary form must reproduce this copyright notice, this list of conditions and the following disclaimers in the documentation and other materials
          provided with the distribution.
    The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
    The intellectual property rights of the algorithms used reside with Andrew Aye.
    You may not use this software, in whole or in part, in support of any commercial product without the express written consent of the author.
    There is no warranty or other guarantee of fitness of this software for any purpose. It is provided solely "as is".                                                   */
/* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */

#include "TgS Common - Event MGR - Internal.h"
#include "TgS Common - Event MGR.inl"


/* == Common ============================================================================================================================================================ */

/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
/* Life Time Sequence */

/* Birth: Check to see if there are available allocations in a pool.  The free list of pools should contain a sorted linked list with priority given to entries with the  */
/* most used allocations.  We want to encourage as much density as possible during the update.  Once a pool has been acquired (created or locked from the free list) the  */
/* first available item from the pools free list will be used for the new entity.  Once it has been initialized and set, the object is added to the new stack for         */
/* insertion to the processing lists on the next update.                                                                                                                  */
/* [Free -> New Stack] */

/* Life: Access is always controlled through the 1:1 matching lock lists to the data.  There is a spin lock and associated identity value for each item.  The ids are a   */
/* combination pool | index pair and a generated key value to prevent issues with stale ids being passed into the system.  The spin lock needs to be acquired and the ids */
/* match before gaining access to the data.  Keep in mind that this is probably a 2000+ cycle operation (memory miss on both the spin lock and id value).                 */
/* [New Stack -> Waiting -> Processing]                                                                                                                                   */

/* Death: The lock for the entity is invalidated and the object marked to be removed.  Since the entity is contained within lists that are access isolated, the removal   */
/* from the list has to be done on the update.  Once a list of all the deleted entities is generated during the update, they will be added in index priority to the free  */
/* list.  Keep in  mind once marked for deletion, since the id key is invalidated, no further use of the object will be possible.                                         */
/* [Processing -> Free] */

/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */


/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  Public Functions                                                                                                                                                      */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

/* ---- Time Event - Frame ------------------------------------------------------------------------------------------------------------------------------------------------ */

/* ---- tgEM_TE_FRM_NEW ------------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgEM_TE_FRM_ID tgEM_TE_FRM_NEW( TgFCN_EM_CALLBACK pfnCallback, C_TgUINTPTR uiParam, C_TgSINT32 iStart, C_TgSINT32 iEnd )
{
    TgSINT32                            iPool, iIndex;
    P_STg2_EM_TE_Pool                   psPool;
    TgEM_TE_FRM_ID                      tiTE;

    if (nullptr == pfnCallback || iStart < 0 || iEnd < 0)
    {
        return (KTgEM_TE_FRM_ID__INVALID);
    };

    tgCM_UTM_SN_Lock_Spin( &g_sEM_TE_FRM_Lock.m_sLock );

    /* Check to see if we need to allocate a new pool into the pool list */
    if (nullptr == g_psEM_TE_FRM_Free_List)
    {
        /* Find an available pool slot */
        for (iPool = 0; iPool < KTgEM_MAX_TE_FRM_POOL && nullptr != g_apsEM_TE_FRM[iPool]; ++iPool);
        TgCRITICAL( iPool < KTgEM_MAX_TE_FRM_POOL );

        /* Allocate and initialize a new pool */
        psPool = (P_STg2_EM_TE_Pool)TgMALLOC_POOL( sizeof( STg2_EM_TE_Pool ) );
        tgEM_TP_Init( psPool );
        psPool->m_iPool = iPool;
        psPool->m_niUsed = 1;

        tgCM_UTM_SN_Lock_Spin( &g_asEM_TE_FRM_NewDel_Lock[iPool].m_sLock );

        /* Assign the new pool into the array list, and as the free pool */
        g_psEM_TE_FRM_Free_List = psPool;
        g_apsEM_TE_FRM[iPool] = psPool;
    }
    else
    {
        psPool = (P_STg2_EM_TE_Pool)g_psEM_TE_FRM_Free_List;
        iPool = g_psEM_TE_FRM_Free_List->m_iPool;

        tgCM_UTM_SN_Lock_Spin( &g_asEM_TE_FRM_NewDel_Lock[iPool].m_sLock );

        TgERROR(psPool == g_apsEM_TE_FRM[iPool]);
        ++g_psEM_TE_FRM_Free_List->m_niUsed;

        /* Check to see if we have filled this pool (to remove from the free list */
        if (g_psEM_TE_FRM_Free_List->m_niUsed >= KTgEM_NUM_TE_IN_POOL)
        {
            g_psEM_TE_FRM_Free_List = g_psEM_TE_FRM_Free_List->m_psFree_Next;
            g_psEM_TE_FRM_Free_List->m_psFree_Next = nullptr;
        };
    };

    tgCM_UTM_SN_Signal( &g_sEM_TE_FRM_Lock.m_sLock );

    /* Remove the head of the free list for the allocation */
    iIndex = (TgSINT32)(psPool->m_psFree - psPool->m_asTB);
    psPool->m_psFree = psPool->m_psFree->m_sHead.psNext;
    tgCM_UTM_SN_Signal( &g_asEM_TE_FRM_NewDel_Lock[iPool].m_sLock );

    tgInit_EM_TE_FRM_ID( &tiTE, (iPool << 16) | iIndex );

    /* Initialize and acquire the look */
    psPool->m_asTB[iIndex].m_sHead.psNext = nullptr;
    psPool->m_asTB[iIndex].m_fStart = -1.0F;
    psPool->m_asTB[iIndex].m_fEnd = -1.0F;
    psPool->m_asTB[iIndex].m_iStart = iStart;
    psPool->m_asTB[iIndex].m_iEnd = iEnd;
    psPool->m_asTB[iIndex].m_uiLocal_Index = (TgUINT32)tiTE.m.iI;
    psPool->m_asTB[iIndex].m_bfFlags = 0;

    psPool->m_asTE[iIndex].m_pfnCallback = pfnCallback;
    psPool->m_asTE[iIndex].m_uiParam = uiParam;

    psPool->m_aiKI[iIndex] = tiTE.m_iKI;
    tgAM_WRITE_FENCE();

    tgCM_UTM_AM_ST_Push( &psPool->m_sNew, &psPool->m_asTB[iIndex].m_sHead.tgMP );

    return (tiTE);
}


/* ---- tgEM_TE_FRM_DEL ------------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgEM_TE_FRM_DEL( C_TgEM_TE_FRM_ID tiTE )
{
    C_TgUINT32                          uiIndex = tiTE.m.iI & 0xFFFF;
    C_TgUINT32                          uiPool = (TgUINT32)(tiTE.m.iI >> 16);

    if (TgFAILED( tgEM_TE_FRM_Lock( tiTE, uiPool, uiIndex ) ))
    {
        return (KTgE_FAIL);
    };

    TgPARAM_CHECK_INDEX( uiIndex, g_apsEM_TE_FRM[uiPool]->m_aiKI );

    /* Invalidate the item from further acquires (may have to add a data cache flush) */
    g_apsEM_TE_FRM[uiPool]->m_aiKI[uiIndex] = KTgEM_TE_FRM_ID__INVALID.m_iKI;

    /* Mark it for removal list by the next update */
    g_apsEM_TE_FRM[uiPool]->m_asTB[uiIndex].m_iStart = 0;
    g_apsEM_TE_FRM[uiPool]->m_asTB[uiIndex].m_iEnd = 0;
    tgEM_TB_Set_Paused( g_apsEM_TE_FRM[uiPool]->m_asTB + uiIndex, TgFALSE );

    tgCM_UTM_SN_Signal( &g_asEM_TE_FRM_Data_Lock[uiPool].m_sLock );
    return (KTgS_OK);
}


/* ---- tgEM_TE_FRM_Set_Pause ------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgEM_TE_FRM_Set_Pause( C_TgEM_TE_FRM_ID tiTE, C_TgBOOL bPause )
{
    C_TgUINT32                          uiIndex = tiTE.m.iI & 0xFFFF;
    C_TgUINT32                          uiPool = (TgUINT32)(tiTE.m.iI >> 16);

    if (TgFAILED( tgEM_TE_FRM_Lock( tiTE, uiPool, uiIndex ) ))
    {
        return (KTgE_FAIL);
    };

    tgEM_TB_Set_Paused( g_apsEM_TE_FRM[uiPool]->m_asTB + uiIndex, bPause );
    tgCM_UTM_SN_Signal( &g_asEM_TE_FRM_Data_Lock[uiPool].m_sLock );
    return (KTgS_OK);
}


/* ---- tgEM_TE_FRM_Set_Start_Frame ------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgEM_TE_FRM_Set_Start_Frame( C_TgEM_TE_FRM_ID tiTE, C_TgSINT32 iFrame )
{
    C_TgUINT32                          uiIndex = tiTE.m.iI & 0xFFFF;
    C_TgUINT32                          uiPool = (TgUINT32)(tiTE.m.iI >> 16);

    if (TgFAILED( tgEM_TE_FRM_Lock( tiTE, uiPool, uiIndex ) ))
    {
        return (KTgE_FAIL);
    };

    TgPARAM_CHECK_INDEX( uiIndex, g_apsEM_TE_FRM[uiPool]->m_asTB );

    if (tgEM_TB_Is_Active( g_apsEM_TE_FRM[uiPool]->m_asTB + uiIndex ))
    {
        tgCM_UTM_SN_Signal( &g_asEM_TE_FRM_Data_Lock[uiPool].m_sLock );
        return (KTgE_FAIL);
    }

    g_apsEM_TE_FRM[uiPool]->m_asTB[uiIndex].m_iStart = iFrame;
    tgCM_UTM_SN_Signal( &g_asEM_TE_FRM_Data_Lock[uiPool].m_sLock );
    return (KTgS_OK);
}


/* ---- tgEM_TE_FRM_Set_End_Frame --------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgEM_TE_FRM_Set_End_Frame( C_TgEM_TE_FRM_ID tiTE, C_TgSINT32 iFrame )
{
    C_TgUINT32                          uiIndex = tiTE.m.iI & 0xFFFF;
    C_TgUINT32                          uiPool = (TgUINT32)(tiTE.m.iI >> 16);

    if (TgFAILED( tgEM_TE_FRM_Lock( tiTE, uiPool, uiIndex ) ))
    {
        return (KTgE_FAIL);
    };

    TgPARAM_CHECK_INDEX( uiIndex, g_apsEM_TE_FRM[uiPool]->m_asTB );

    g_apsEM_TE_FRM[uiPool]->m_asTB[uiIndex].m_iEnd = tgCM_MAX_S32( g_apsEM_TE_FRM[uiPool]->m_asTB[uiIndex].m_iStart, iFrame );
    tgCM_UTM_SN_Signal( &g_asEM_TE_FRM_Data_Lock[uiPool].m_sLock );
    return (KTgS_OK);
}


/* ---- tgEM_TE_FRM_Set_Frame_To_Live ----------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgEM_TE_FRM_Set_Frame_To_Live( C_TgEM_TE_FRM_ID tiTE, C_TgSINT32 iFrame )
{
    C_TgUINT32                          uiIndex = tiTE.m.iI & 0xFFFF;
    C_TgUINT32                          uiPool = (TgUINT32)(tiTE.m.iI >> 16);

    if (TgFAILED( tgEM_TE_FRM_Lock( tiTE, uiPool, uiIndex ) ))
    {
        return (KTgE_FAIL);
    };

    TgPARAM_CHECK_INDEX( uiIndex, g_apsEM_TE_FRM[uiPool]->m_asTB );

    g_apsEM_TE_FRM[uiPool]->m_asTB[uiIndex].m_iEnd = tgGB_Query_Total_Frame() + iFrame;
    tgCM_UTM_SN_Signal( &g_asEM_TE_FRM_Data_Lock[uiPool].m_sLock );
    return (KTgS_OK);
}


/* ---- tgEM_TE_FRM_Query_Valid ----------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgBOOL tgEM_TE_FRM_Query_Valid( C_TgEM_TE_FRM_ID tiTE )
{
    C_TgUINT32                          uiIndex = tiTE.m.iI & 0xFFFF;
    C_TgUINT32                          uiPool = (TgUINT32)(tiTE.m.iI >> 16);

    if (TgFAILED( tgEM_TE_FRM_Lock( tiTE, uiPool, uiIndex ) ))
    {
        return (TgFALSE);
    };

    tgCM_UTM_SN_Signal( &g_asEM_TE_FRM_Data_Lock[uiPool].m_sLock );
    return (TgTRUE);
}


/* ---- tgEM_TE_FRM_Query_Paused ---------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgEM_TE_FRM_Query_Paused( PCU_TgBOOL pbPaused, C_TgEM_TE_FRM_ID tiTE )
{
    C_TgUINT32                          uiIndex = tiTE.m.iI & 0xFFFF;
    C_TgUINT32                          uiPool = (TgUINT32)(tiTE.m.iI >> 16);

    TgPARAM_CHECK(nullptr != pbPaused);

    if (TgFAILED( tgEM_TE_FRM_Lock( tiTE, uiPool, uiIndex ) ))
    {
        return (KTgE_FAIL);
    };

    TgPARAM_CHECK_INDEX( uiIndex, g_apsEM_TE_FRM[uiPool]->m_asTB );

    *pbPaused = tgEM_TB_Is_Paused( g_apsEM_TE_FRM[uiPool]->m_asTB + uiIndex );
    tgCM_UTM_SN_Signal( &g_asEM_TE_FRM_Data_Lock[uiPool].m_sLock );
    return (KTgS_OK);
}


/* ---- tgEM_TE_FRM_Query_Start_Frame ----------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgEM_TE_FRM_Query_Start_Frame( PCU_TgSINT32 piFrame, C_TgEM_TE_FRM_ID tiTE )
{
    C_TgUINT32                          uiIndex = tiTE.m.iI & 0xFFFF;
    C_TgUINT32                          uiPool = (TgUINT32)(tiTE.m.iI >> 16);

    TgPARAM_CHECK(nullptr != piFrame);

    if (TgFAILED( tgEM_TE_FRM_Lock( tiTE, uiPool, uiIndex ) ))
    {
        return (KTgE_FAIL);
    };

    TgPARAM_CHECK_INDEX( uiIndex, g_apsEM_TE_FRM[uiPool]->m_asTB );

    *piFrame = g_apsEM_TE_FRM[uiPool]->m_asTB[uiIndex].m_iStart;
    tgCM_UTM_SN_Signal( &g_asEM_TE_FRM_Data_Lock[uiPool].m_sLock );
    return (KTgS_OK);
}


/* ---- tgEM_TE_FRM_Query_End_Frame ------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgEM_TE_FRM_Query_End_Frame( PCU_TgSINT32 piFrame, C_TgEM_TE_FRM_ID tiTE )
{
    C_TgUINT32                          uiIndex = tiTE.m.iI & 0xFFFF;
    C_TgUINT32                          uiPool = (TgUINT32)(tiTE.m.iI >> 16);

    TgPARAM_CHECK(nullptr != piFrame);

    if (TgFAILED( tgEM_TE_FRM_Lock( tiTE, uiPool, uiIndex ) ))
    {
        return (KTgE_FAIL);
    };

    TgPARAM_CHECK_INDEX( uiIndex, g_apsEM_TE_FRM[uiPool]->m_asTB );

    *piFrame = g_apsEM_TE_FRM[uiPool]->m_asTB[uiIndex].m_iEnd;
    tgCM_UTM_SN_Signal( &g_asEM_TE_FRM_Data_Lock[uiPool].m_sLock );
    return (KTgS_OK);
}


/* ---- tgEM_TE_FRM_Query_Frame_To_Live --------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgEM_TE_FRM_Query_Frame_To_Live( PCU_TgSINT32 piFrame, C_TgEM_TE_FRM_ID tiTE )
{
    C_TgUINT32                          uiIndex = tiTE.m.iI & 0xFFFF;
    C_TgUINT32                          uiPool = (TgUINT32)(tiTE.m.iI >> 16);

    TgPARAM_CHECK(nullptr != piFrame);

    if (TgFAILED( tgEM_TE_FRM_Lock( tiTE, uiPool, uiIndex ) ))
    {
        return (KTgE_FAIL);
    };

    TgPARAM_CHECK_INDEX( uiIndex, g_apsEM_TE_FRM[uiPool]->m_asTB );

    *piFrame = tgGB_Query_Total_Frame() - g_apsEM_TE_FRM[uiPool]->m_asTB[uiIndex].m_iEnd;
    tgCM_UTM_SN_Signal( &g_asEM_TE_FRM_Data_Lock[uiPool].m_sLock );
    return (KTgS_OK);
}




/* ---- Time Event - Time ------------------------------------------------------------------------------------------------------------------------------------------------- */

/* ---- tgEM_TE_SEC_NEW ------------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgEM_TE_SEC_ID tgEM_TE_SEC_NEW( TgFCN_EM_CALLBACK pfnCallback, C_TgUINTPTR uiParam, C_TgFLOAT32 fStart, C_TgFLOAT32 fEnd )
{
    TgSINT32                            iPool, iIndex;
    P_STg2_EM_TE_Pool                   psPool;
    TgEM_TE_SEC_ID                      tiTE;

    if (nullptr == pfnCallback)
    {
        return (KTgEM_TE_SEC_ID__INVALID);
    };

    tgCM_UTM_SN_Lock_Spin( &g_sEM_TE_SEC_Lock.m_sLock );

    /* Check to see if we need to allocate a new pool into the pool list */
    if (nullptr == g_psEM_TE_SEC_Free_List)
    {
        /* Find an available pool slot */
        for (iPool = 0; iPool < KTgEM_MAX_TE_SEC_POOL && nullptr != g_apsEM_TE_SEC[iPool]; ++iPool);
        TgCRITICAL( iPool < KTgEM_MAX_TE_SEC_POOL );

        /* Allocate and initialize a new pool */
        psPool = (P_STg2_EM_TE_Pool)TgMALLOC_POOL( sizeof( STg2_EM_TE_Pool ) );
        tgEM_TP_Init( psPool );
        psPool->m_iPool = iPool;
        psPool->m_niUsed = 1;

        tgCM_UTM_SN_Lock_Spin( &g_asEM_TE_SEC_NewDel_Lock[iPool].m_sLock );

        /* Assign the new pool into the array list, and as the free pool */
        g_psEM_TE_SEC_Free_List = psPool;
        g_apsEM_TE_SEC[iPool] = psPool;
    }
    else
    {
        psPool = (P_STg2_EM_TE_Pool)g_psEM_TE_SEC_Free_List;
        iPool = g_psEM_TE_SEC_Free_List->m_iPool;

        tgCM_UTM_SN_Lock_Spin( &g_asEM_TE_SEC_NewDel_Lock[iPool].m_sLock );

        TgERROR(psPool == g_apsEM_TE_SEC[iPool]);
        ++g_psEM_TE_SEC_Free_List->m_niUsed;

        /* Check to see if we have filled this pool (to remove from the free list */
        if (g_psEM_TE_SEC_Free_List->m_niUsed >= KTgEM_NUM_TE_IN_POOL)
        {
            g_psEM_TE_SEC_Free_List = g_psEM_TE_SEC_Free_List->m_psFree_Next;
            g_psEM_TE_SEC_Free_List->m_psFree_Next = nullptr;
        };
    };

    tgCM_UTM_SN_Signal( &g_sEM_TE_SEC_Lock.m_sLock );

    /* Remove the head of the free list for the allocation */
    iIndex = (TgSINT32)(psPool->m_psFree - psPool->m_asTB);
    psPool->m_psFree = psPool->m_psFree->m_sHead.psNext;
    tgCM_UTM_SN_Signal( &g_asEM_TE_SEC_NewDel_Lock[iPool].m_sLock );

    tgInit_EM_TE_SEC_ID( &tiTE, (iPool << 16) | iIndex );

    /* Initialize and acquire the look */
    psPool->m_asTB[iIndex].m_sHead.psNext = nullptr;
    psPool->m_asTB[iIndex].m_fStart = fStart;
    psPool->m_asTB[iIndex].m_fEnd = fEnd;
    psPool->m_asTB[iIndex].m_iStart = -1;
    psPool->m_asTB[iIndex].m_iEnd = -1;
    psPool->m_asTB[iIndex].m_uiLocal_Index = (TgUINT32)tiTE.m.iI;
    psPool->m_asTB[iIndex].m_bfFlags = 0;

    psPool->m_asTE[iIndex].m_pfnCallback = pfnCallback;
    psPool->m_asTE[iIndex].m_uiParam = uiParam;

    psPool->m_aiKI[iIndex] = tiTE.m_iKI;
    tgAM_WRITE_FENCE();

    tgCM_UTM_AM_ST_Push( &psPool->m_sNew, &psPool->m_asTB[iIndex].m_sHead.tgMP );

    return (tiTE);
}


/* ---- tgEM_TE_SEC_DEL ------------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgEM_TE_SEC_DEL( C_TgEM_TE_SEC_ID tiTE )
{
    C_TgUINT32                          uiIndex = tiTE.m.iI & 0xFFFF;
    C_TgUINT32                          uiPool = (TgUINT32)(tiTE.m.iI >> 16);

    if (TgFAILED( tgEM_TE_SEC_Lock( tiTE, uiPool, uiIndex ) ))
    {
        return (KTgE_FAIL);
    };

    TgPARAM_CHECK_INDEX( uiIndex, g_apsEM_TE_SEC[uiPool]->m_aiKI );

    /* Invalidate the item from further acquires (may have to add a data cache flush) */
    g_apsEM_TE_SEC[uiPool]->m_aiKI[uiIndex] = KTgEM_TE_SEC_ID__INVALID.m_iKI;

    /* Mark it for removal list by the next update */
    g_apsEM_TE_SEC[uiPool]->m_asTB[uiIndex].m_fStart = 0.0F;
    g_apsEM_TE_SEC[uiPool]->m_asTB[uiIndex].m_fEnd = 0.0F;
    tgEM_TB_Set_Paused( g_apsEM_TE_SEC[uiPool]->m_asTB + uiIndex, TgFALSE );

    tgCM_UTM_SN_Signal( &g_asEM_TE_SEC_Data_Lock[uiPool].m_sLock );
    return (KTgS_OK);
}


/* ---- tgEM_TE_SEC_Set_Pause ------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgEM_TE_SEC_Set_Pause( C_TgEM_TE_SEC_ID tiTE, C_TgBOOL bPause )
{
    C_TgUINT32                          uiIndex = tiTE.m.iI & 0xFFFF;
    C_TgUINT32                          uiPool = (TgUINT32)(tiTE.m.iI >> 16);

    if (TgFAILED( tgEM_TE_SEC_Lock( tiTE, uiPool, uiIndex ) ))
    {
        return (KTgE_FAIL);
    };

    TgPARAM_CHECK_INDEX( uiIndex, g_apsEM_TE_SEC[uiPool]->m_asTB );

    tgEM_TB_Set_Paused( g_apsEM_TE_SEC[uiPool]->m_asTB + uiIndex, bPause );
    tgCM_UTM_SN_Signal( &g_asEM_TE_SEC_Data_Lock[uiPool].m_sLock );
    return (KTgS_OK);
}


/* ---- tgEM_TE_SEC_Set_Start_Time -------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgEM_TE_SEC_Set_Start_Time( C_TgEM_TE_SEC_ID tiTE, C_TgFLOAT32 fTime )
{
    C_TgUINT32                          uiIndex = tiTE.m.iI & 0xFFFF;
    C_TgUINT32                          uiPool = (TgUINT32)(tiTE.m.iI >> 16);

    if (TgFAILED( tgEM_TE_SEC_Lock( tiTE, uiPool, uiIndex ) ))
    {
        return (KTgE_FAIL);
    };

    TgPARAM_CHECK_INDEX( uiIndex, g_apsEM_TE_SEC[uiPool]->m_asTB );

    if (tgEM_TB_Is_Active( g_apsEM_TE_SEC[uiPool]->m_asTB + uiIndex ))
    {
        tgCM_UTM_SN_Signal( &g_asEM_TE_SEC_Data_Lock[uiPool].m_sLock );
        return (KTgE_FAIL);
    }

    g_apsEM_TE_SEC[uiPool]->m_asTB[uiIndex].m_fStart = fTime;
    tgCM_UTM_SN_Signal( &g_asEM_TE_SEC_Data_Lock[uiPool].m_sLock );
    return (KTgS_OK);
}


/* ---- tgEM_TE_SEC_Set_End_Time ---------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgEM_TE_SEC_Set_End_Time( C_TgEM_TE_SEC_ID tiTE, C_TgFLOAT32 fTime )
{
    C_TgUINT32                          uiIndex = tiTE.m.iI & 0xFFFF;
    C_TgUINT32                          uiPool = (TgUINT32)(tiTE.m.iI >> 16);

    if (TgFAILED( tgEM_TE_SEC_Lock( tiTE, uiPool, uiIndex ) ))
    {
        return (KTgE_FAIL);
    };

    TgPARAM_CHECK_INDEX( uiIndex, g_apsEM_TE_SEC[uiPool]->m_asTB );

    g_apsEM_TE_SEC[uiPool]->m_asTB[uiIndex].m_fEnd = tgCM_MAX_F32( g_apsEM_TE_SEC[uiPool]->m_asTB[uiIndex].m_fStart, fTime );
    tgCM_UTM_SN_Signal( &g_asEM_TE_SEC_Data_Lock[uiPool].m_sLock );
    return (KTgS_OK);
}


/* ---- tgEM_TE_SEC_Set_Time_To_Live ------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgEM_TE_SEC_Set_Time_To_Live( C_TgEM_TE_SEC_ID tiTE, C_TgFLOAT32 fTime )
{
    C_TgUINT32                          uiIndex = tiTE.m.iI & 0xFFFF;
    C_TgUINT32                          uiPool = (TgUINT32)(tiTE.m.iI >> 16);

    if (TgFAILED( tgEM_TE_SEC_Lock( tiTE, uiPool, uiIndex ) ))
    {
        return (KTgE_FAIL);
    };

    TgPARAM_CHECK_INDEX( uiIndex, g_apsEM_TE_SEC[uiPool]->m_asTB );

    g_apsEM_TE_SEC[uiPool]->m_asTB[uiIndex].m_fEnd = tgGB_Query_Total_Time() + fTime;
    tgCM_UTM_SN_Signal( &g_asEM_TE_SEC_Data_Lock[uiPool].m_sLock );
    return (KTgS_OK);
}


/* ---- tgEM_TE_SEC_Query_Valid ----------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgBOOL tgEM_TE_SEC_Query_Valid( C_TgEM_TE_SEC_ID tiTE )
{
    C_TgUINT32                          uiIndex = tiTE.m.iI & 0xFFFF;
    C_TgUINT32                          uiPool = (TgUINT32)(tiTE.m.iI >> 16);

    if (TgFAILED( tgEM_TE_SEC_Lock( tiTE, uiPool, uiIndex ) ))
    {
        return (TgFALSE);
    };

    tgCM_UTM_SN_Signal( &g_asEM_TE_SEC_Data_Lock[uiPool].m_sLock );
    return (TgTRUE);
}


/* ---- tgEM_TE_SEC_Query_Paused ---------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgEM_TE_SEC_Query_Paused( PCU_TgBOOL pbPaused, C_TgEM_TE_SEC_ID tiTE )
{
    C_TgUINT32                          uiIndex = tiTE.m.iI & 0xFFFF;
    C_TgUINT32                          uiPool = (TgUINT32)(tiTE.m.iI >> 16);

    TgPARAM_CHECK(nullptr != pbPaused);

    if (TgFAILED( tgEM_TE_SEC_Lock( tiTE, uiPool, uiIndex ) ))
    {
        return (KTgE_FAIL);
    };

    TgPARAM_CHECK_INDEX( uiIndex, g_apsEM_TE_SEC[uiPool]->m_asTB );

    *pbPaused = tgEM_TB_Is_Paused( g_apsEM_TE_SEC[uiPool]->m_asTB + uiIndex );
    tgCM_UTM_SN_Signal( &g_asEM_TE_SEC_Data_Lock[uiPool].m_sLock );
    return (KTgS_OK);
}


/* ---- tgEM_TE_SEC_Query_Start_Time ------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgEM_TE_SEC_Query_Start_Time( PCU_TgFLOAT32 piTime, C_TgEM_TE_SEC_ID tiTE )
{
    C_TgUINT32                          uiIndex = tiTE.m.iI & 0xFFFF;
    C_TgUINT32                          uiPool = (TgUINT32)(tiTE.m.iI >> 16);

    TgPARAM_CHECK(nullptr != piTime);

    if (TgFAILED( tgEM_TE_SEC_Lock( tiTE, uiPool, uiIndex ) ))
    {
        return (KTgE_FAIL);
    };

    TgPARAM_CHECK_INDEX( uiIndex, g_apsEM_TE_SEC[uiPool]->m_asTB );

    *piTime = g_apsEM_TE_SEC[uiPool]->m_asTB[uiIndex].m_fStart;
    tgCM_UTM_SN_Signal( &g_asEM_TE_SEC_Data_Lock[uiPool].m_sLock );
    return (KTgS_OK);
}


/* ---- tgEM_TE_SEC_Query_End_Time -------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgEM_TE_SEC_Query_End_Time( PCU_TgFLOAT32 piTime, C_TgEM_TE_SEC_ID tiTE )
{
    C_TgUINT32                          uiIndex = tiTE.m.iI & 0xFFFF;
    C_TgUINT32                          uiPool = (TgUINT32)(tiTE.m.iI >> 16);

    TgPARAM_CHECK(nullptr != piTime);

    if (TgFAILED( tgEM_TE_SEC_Lock( tiTE, uiPool, uiIndex ) ))
    {
        return (KTgE_FAIL);
    };

    TgPARAM_CHECK_INDEX( uiIndex, g_apsEM_TE_SEC[uiPool]->m_asTB );

    *piTime = g_apsEM_TE_SEC[uiPool]->m_asTB[uiIndex].m_fEnd;
    tgCM_UTM_SN_Signal( &g_asEM_TE_SEC_Data_Lock[uiPool].m_sLock );
    return (KTgS_OK);
}


/* ---- tgEM_TE_SEC_Query_Time_To_Live ---------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgEM_TE_SEC_Query_Time_To_Live( PCU_TgFLOAT32 piTime, C_TgEM_TE_SEC_ID tiTE )
{
    C_TgUINT32                          uiIndex = tiTE.m.iI & 0xFFFF;
    C_TgUINT32                          uiPool = (TgUINT32)(tiTE.m.iI >> 16);

    TgPARAM_CHECK(nullptr != piTime);

    if (TgFAILED( tgEM_TE_SEC_Lock( tiTE, uiPool, uiIndex ) ))
    {
        return (KTgE_FAIL);
    };

    TgPARAM_CHECK_INDEX( uiIndex, g_apsEM_TE_SEC[uiPool]->m_asTB );

    *piTime = tgGB_Query_Total_Time() - g_apsEM_TE_SEC[uiPool]->m_asTB[uiIndex].m_fEnd;
    tgCM_UTM_SN_Signal( &g_asEM_TE_SEC_Data_Lock[uiPool].m_sLock );
    return (KTgS_OK);
}