/*
 * vxworks_partition.c
 */
#include <stdlib.h>
#include <assert.h>

#include <taskLib.h>
#include <taskHookLib.h>

#include "private.h"

static lub_vxworks_partition_t *first_partition;

/*-------------------------------------------------------- */
static void
lub_vxworks_partition_task_delete_hook(WIND_TCB *pTcb)
{
    lub_vxworks_partition_t **ptr;
    int                       tid = (int)pTcb;
    
    /* iterate the list of partitions */
    taskLock();
    for(ptr = &first_partition;
        *ptr;
         ptr = &(*ptr)->m_next_partition)
    {
        int val = taskVarGet(tid,(int*)&(*ptr)->m_local_heap);
        if(ERROR != val)
        {
            /* destroy this local heap */
            lub_partition_destroy_local_heap(&(*ptr)->m_base,(void*)val);

            /* and remove the task variable */
            taskVarDelete(tid,(int*)&(*ptr)->m_local_heap);
        }
    }
    taskUnlock();
}
/*-------------------------------------------------------- */
lub_partition_t *
lub_partition_create(const lub_partition_spec_t *spec)
{
    lub_vxworks_partition_t *this;
    this = calloc(sizeof(lub_vxworks_partition_t),1);
    if(this)
    {
        /* initialise the global mutex */
        if(ERROR == semMInit(&this->m_sem,SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE))
        {
            assert(NULL == "semMInit() failed!");
        }
        
        lub_partition_lock(&this->m_base);
        /* initialise the local task variable system */
        taskVarInit();
        
        /* initialise the base class */
        lub_partition_init(&this->m_base,spec);
        
        /* add to the list of partitions */
        this->m_next_partition = first_partition;
        first_partition        = this;

        if(this == first_partition)
        {
            /* register a task deletion hook */
            taskDeleteHookAdd((FUNCPTR)lub_vxworks_partition_task_delete_hook);
        }
        lub_partition_unlock(&this->m_base);
    }
    return this ? &this->m_base : 0;
}
/*-------------------------------------------------------- */
void
lub_partition_destroy(lub_partition_t *instance)
{
    lub_vxworks_partition_t  *this = (void*)instance;
    lub_vxworks_partition_t **ptr;

    /* finalise the base class */
    lub_partition_fini(&this->m_base);
    
    lub_partition_lock(&this->m_base);
    /* remove from the list of partitions */
    for(ptr = &first_partition;
        *ptr;
        ptr = &(*ptr)->m_next_partition)
    {
        if(&(*ptr)->m_base == instance)
        {
            /* remove from list */
            *ptr = (*ptr)->m_next_partition;
            break;
        }
    }
    if(!first_partition)
    {
        /* deregister delete hook */
        taskDeleteHookDelete((FUNCPTR)lub_vxworks_partition_task_delete_hook);
    }
    lub_partition_unlock(&this->m_base);
    free(this);
}
/*-------------------------------------------------------- */
lub_heap_t *
lub_partition__get_local_heap(lub_partition_t *instance) 
{
    lub_vxworks_partition_t *this = (void*)instance;

    return this->m_local_heap;
}
/*-------------------------------------------------------- */
void
lub_partition__set_local_heap(lub_partition_t *instance,
                              lub_heap_t      *heap) 
{
    lub_vxworks_partition_t *this = (void*)instance;

    if(this->m_local_heap)
    {
        assert(NULL == "Local heap already exists!");
    }
    /* add this memory to the local task */
    taskVarAdd(0,(int*)&this->m_local_heap);

    /* add set the value */
    this->m_local_heap = heap;
}
/*-------------------------------------------------------- */
void
lub_partition_lock(lub_partition_t *instance) 
{
    lub_vxworks_partition_t *this = (void*)instance;
    
    if(ERROR == semTake(&this->m_sem,WAIT_FOREVER))
    {
        assert(NULL == "semTake() failed!");
    }
}
/*-------------------------------------------------------- */
void
lub_partition_unlock(lub_partition_t *instance) 
{
    lub_vxworks_partition_t *this = (void*)instance;
    
    if(ERROR == semGive(&this->m_sem))
    {
        assert(NULL == "semGive() failed!");
    }
}
/*-------------------------------------------------------- */