/* * Free mutex when task is terminated * Free all mutexes which the task holds. * Do not need to handle mutex list and priority of terminated task. * */ EXPORT void signal_all_mutex( TCB *tcb ) { MTXCB *mtxcb, *next_mtxcb; TCB *next_tcb; next_mtxcb = tcb->mtxlist; while ( (mtxcb = next_mtxcb) != NULL ) { next_mtxcb = mtxcb->mtxlist; if ( mtx_waited(mtxcb) ) { next_tcb = (TCB*)mtxcb->wait_queue.next; /* Wake wait task */ wait_release_ok(next_tcb); /* Change mutex get task */ mtxcb->mtxtsk = next_tcb; mtxcb->mtxlist = next_tcb->mtxlist; next_tcb->mtxlist = mtxcb; if ( (mtxcb->mtxatr & TA_CEILING) == TA_CEILING ) { if ( next_tcb->priority > mtxcb->ceilpri ) { /* Raise the priority for the task that got lock to the highest priority limit */ change_task_priority(next_tcb, mtxcb->ceilpri); } } } else { /* No wait task */ mtxcb->mtxtsk = NULL; } } }
/* * Unlock mutex */ SYSCALL ER _tk_unl_mtx( ID mtxid ) { MTXCB *mtxcb; TCB *tcb; ER ercd = E_OK; CHECK_MTXID(mtxid); CHECK_INTSK(); mtxcb = get_mtxcb(mtxid); BEGIN_CRITICAL_SECTION; if ( mtxcb->mtxid == 0 ) { ercd = E_NOEXS; goto error_exit; } if ( mtxcb->mtxtsk != ctxtsk ) { ercd = E_ILUSE; /* This is not locked by its own task */ goto error_exit; } /* Delete the mutex from the list, and adjust its own task priority if necessary. */ release_mutex(ctxtsk, mtxcb); if ( mtx_waited(mtxcb) ) { tcb = (TCB*)mtxcb->wait_queue.next; /* Release wait */ wait_release_ok(tcb); /* Change mutex get task */ mtxcb->mtxtsk = tcb; mtxcb->mtxlist = tcb->mtxlist; tcb->mtxlist = mtxcb; if ( (mtxcb->mtxatr & TA_CEILING) == TA_CEILING ) { if ( tcb->priority > mtxcb->ceilpri ) { /* Raise the priority of the task that got lock to the highest priority limit */ change_task_priority(tcb, mtxcb->ceilpri); } } } else { /* No wait task */ mtxcb->mtxtsk = NULL; } error_exit: END_CRITICAL_SECTION; return ercd; }
/* * Change task priority */ SYSCALL ER _tk_chg_pri( ID tskid, PRI tskpri ) { TCB *tcb; INT priority; ER ercd; CHECK_TSKID_SELF(tskid); CHECK_PRI_INI(tskpri); tcb = get_tcb_self(tskid); BEGIN_CRITICAL_SECTION; if ( tcb->state == TS_NONEXIST ) { ercd = E_NOEXS; goto error_exit; } /* Conversion priority to internal expression */ if ( tskpri == TPRI_INI ) { priority = tcb->ipriority; } else { priority = int_priority(tskpri); } #ifdef NUM_MTXID /* Mutex priority change limit */ ercd = chg_pri_mutex(tcb, priority); if ( ercd < E_OK ) { goto error_exit; } tcb->bpriority = (UB)priority; priority = ercd; #else tcb->bpriority = priority; #endif /* Change priority */ change_task_priority(tcb, priority); ercd = E_OK; error_exit: END_CRITICAL_SECTION; return ercd; }
/* * Release the lock and delete it from list, and then adjust the * priority of task. * Set the highest priority between listed below: * (A) The highest priority in all mutexes in which 'tcb' task locks. * (B) The base priority of 'tcb' task. */ LOCAL void release_mutex( TCB *tcb, MTXCB *relmtxcb ) { MTXCB *mtxcb, **prev; INT newpri, pri; /* (B) The base priority of task */ newpri = tcb->bpriority; /* (A) The highest priority in mutex which is locked */ pri = newpri; prev = &tcb->mtxlist; while ( (mtxcb = *prev) != NULL ) { if ( mtxcb == relmtxcb ) { /* Delete from list */ *prev = mtxcb->mtxlist; continue; } switch ( mtxcb->mtxatr & TA_CEILING ) { case TA_CEILING: pri = mtxcb->ceilpri; break; case TA_INHERIT: if ( mtx_waited(mtxcb) ) { pri = mtx_head_pri(mtxcb); } break; default: /* TA_TFIFO, TA_TPRI */ /* nothing to do */ break; } if ( newpri > pri ) { newpri = pri; } prev = &mtxcb->mtxlist; } if ( newpri != tcb->priority ) { /* Change priority of lock get task */ change_task_priority(tcb, newpri); } }
/* * Processing if the priority of wait task changes */ LOCAL void mtx_chg_pri( TCB *tcb, INT oldpri ) { MTXCB *mtxcb; TCB *mtxtsk; mtxcb = get_mtxcb(tcb->wid); gcb_change_priority((GCB*)mtxcb, tcb); if ( (mtxcb->mtxatr & TA_CEILING) == TA_INHERIT ) { mtxtsk = mtxcb->mtxtsk; if ( mtxtsk->priority > tcb->priority ) { /* Since the highest priority of the lock wait task became higher, raise the lock get task priority higher */ change_task_priority(mtxtsk, tcb->priority); } else if ( mtxtsk->priority == oldpri ) { /* Since the highest priority of the lock wait task might become lower, adjust this priority */ reset_priority(mtxtsk); } } }
SYSCALL ER _tk_loc_mtx_u( ID mtxid, TMO_U tmout ) { MTXCB *mtxcb; TCB *mtxtsk; ATR mtxatr; ER ercd = E_OK; CHECK_MTXID(mtxid); CHECK_TMOUT(tmout); CHECK_DISPATCH(); mtxcb = get_mtxcb(mtxid); BEGIN_CRITICAL_SECTION; if ( mtxcb->mtxid == 0 ) { ercd = E_NOEXS; goto error_exit; } if ( mtxcb->mtxtsk == ctxtsk ) { ercd = E_ILUSE; /* Multiplexed lock */ goto error_exit; } mtxatr = mtxcb->mtxatr & TA_CEILING; if ( mtxatr == TA_CEILING ) { if ( ctxtsk->bpriority < mtxcb->ceilpri ) { /* Violation of highest priority limit */ ercd = E_ILUSE; goto error_exit; } } /* Check wait disable */ if ( is_diswai((GCB*)mtxcb, ctxtsk, TTW_MTX) ) { ercd = E_DISWAI; goto error_exit; } mtxtsk = mtxcb->mtxtsk; if ( mtxtsk == NULL ) { /* Get lock */ mtxcb->mtxtsk = ctxtsk; mtxcb->mtxlist = ctxtsk->mtxlist; ctxtsk->mtxlist = mtxcb; if ( mtxatr == TA_CEILING ) { if ( ctxtsk->priority > mtxcb->ceilpri ) { /* Raise its own task to the highest priority limit */ change_task_priority(ctxtsk, mtxcb->ceilpri); } } } else { ercd = E_TMOUT; if ( tmout == TMO_POL ) { goto error_exit; } if ( mtxatr == TA_INHERIT ) { if ( mtxtsk->priority > ctxtsk->priority ) { /* Raise the priority of task during locking to the same priority as its own task */ change_task_priority(mtxtsk, ctxtsk->priority); } } /* Ready for wait */ ctxtsk->wspec = ( mtxatr == TA_TFIFO )? &wspec_mtx_tfifo: ( mtxatr == TA_INHERIT )? &wspec_mtx_inherit: &wspec_mtx_tpri; ctxtsk->wercd = &ercd; ctxtsk->wid = mtxcb->mtxid; make_wait(tmout, mtxcb->mtxatr); if ( mtxatr == TA_TFIFO ) { QueInsert(&ctxtsk->tskque, &mtxcb->wait_queue); } else { queue_insert_tpri(ctxtsk, &mtxcb->wait_queue); } } error_exit: END_CRITICAL_SECTION; return ercd; }