예제 #1
0
/*
 *  ======== SemaphoreMP_pend ========
 */
Bool SemaphoreMP_pend(SemaphoreMP_Object *obj)
{
    UInt tskKey;
    SemaphoreMP_PendElem *elem;
    IArg gateMPKey;

    /* Check for correct calling context */
    Assert_isTrue((BIOS_getThreadType() == BIOS_ThreadType_Task),
                    SemaphoreMP_A_badContext);

    elem = ThreadLocal_getspecific(SemaphoreMP_pendElemKey);
    if (elem == NULL) {
        /* 
         * Choose region zero (instead of the region that contains the 
         * SemaphoreMP) since region zero is always accessible by all cores
         */
        elem = Memory_alloc(SharedRegion_getHeap(0), 
                sizeof(SemaphoreMP_PendElem), 0, NULL);
        ThreadLocal_setspecific(SemaphoreMP_pendElemKey, elem);
    }
    
    /* Enter the gate */
    gateMPKey = GateMP_enter((GateMP_Handle)obj->gate);

    if (obj->cacheEnabled) {
        Cache_inv(obj->attrs, sizeof(SemaphoreMP_Attrs), Cache_Type_ALL, TRUE);
    }
    
    /* check semaphore count */
    if (obj->attrs->count == 0) {
        /* lock task scheduler */
        tskKey = Task_disable();

        /* get task handle and block tsk */
        elem->task = (Bits32)Task_self();
        elem->procId = MultiProc_self();
        
        Task_block((Task_Handle)elem->task);
        
        if (obj->cacheEnabled) {
            Cache_wbInv(elem, sizeof(SemaphoreMP_PendElem), Cache_Type_ALL, TRUE);
        }

        /* add it to pendQ */
        ListMP_putTail((ListMP_Handle)obj->pendQ, (ListMP_Elem *)elem);

        /* Leave the gate */
        GateMP_leave((GateMP_Handle)obj->gate, gateMPKey);

        Task_restore(tskKey);/* the calling task will switch out here */

        return (TRUE);
    }
    else {
        obj->attrs->count--;
        if (obj->cacheEnabled) {
            Cache_wbInv(obj->attrs, sizeof(SemaphoreMP_Attrs), Cache_Type_ALL, 
                    TRUE);
        }

        /* Leave the gate */
        GateMP_leave((GateMP_Handle)obj->gate, gateMPKey);

        return (TRUE);
    }
}
예제 #2
0
/*
 *  ======== GateMutexPri_Gate ========
 *  Returns FIRST_ENTER when it gets the gate, returns NESTED_ENTER
 *  on nested calls.
 */
IArg GateMutexPri_enter(GateMutexPri_Object *obj)
{
    Task_Handle tsk;
    UInt tskKey;
    Int tskPri;
    Task_PendElem elem;
    Queue_Handle pendQ;

    /* make sure we're not calling from Hwi or Swi context */
    Assert_isTrue(((BIOS_getThreadType() == BIOS_ThreadType_Task) ||
                   (BIOS_getThreadType() == BIOS_ThreadType_Main)),
                   GateMutexPri_A_badContext);

    pendQ = GateMutexPri_Instance_State_pendQ(obj);
    
    tsk = Task_self();

    /* 
     * Prior to tasks starting, Task_self() will return NULL.
     * Simply return NESTED_ENTER here as, by definition, there is
     * is only one thread running at this time.
     */
    if (tsk == NULL) {
        return (NESTED_ENTER);
    }

    tskPri = Task_getPri(tsk);
    
    /* 
     * Gate may only be called from task context, so Task_disable is sufficient
     * protection.
     */
    tskKey = Task_disable();
    
    /* If the gate is free, take it. */
    if (obj->mutexCnt == 1) {
        obj->mutexCnt = 0;
        obj->owner = tsk;
        obj->ownerOrigPri = tskPri;
   
        Task_restore(tskKey);
        return (FIRST_ENTER);
    }
   
    /* At this point, the gate is already held by someone. */
    
    /* If this is a nested call to gate... */
    if (obj->owner == tsk) {
        Task_restore(tskKey);
        return (NESTED_ENTER);
    }
    
    /*
     * Donate priority if necessary. The owner is guaranteed to have the
     * highest priority of anyone waiting on the gate, so just compare this
     * task's priority against the owner's. 
     */        
    if (tskPri > Task_getPri(obj->owner)) {
        Task_setPri(obj->owner, tskPri);
    }

    /* Remove tsk from ready list. */
    Task_block(tsk);

    elem.task = tsk;
    elem.clock = NULL;
    /* leave a pointer for Task_delete() */
    tsk->pendElem = &elem;

    /* Insert tsk in wait queue in order by priority (high pri at head) */
    GateMutexPri_insertPri(pendQ, (Queue_Elem *)&elem, tskPri);

    /* Task_restore will call the scheduler and this task will block. */
    Task_restore(tskKey);
    
    tsk->pendElem = NULL;

    /* 
     * At this point, tsk has the gate. Initialization of the gate is handled
     * by the previous owner's call to leave. 
     */
    return (FIRST_ENTER);
}