/* * Refer mutex wait queue */ SYSCALL INT _td_mtx_que( ID mtxid, ID list[], INT nent ) { MTXCB *mtxcb; QUEUE *q; ER ercd = E_OK; CHECK_MTXID(mtxid); mtxcb = get_mtxcb(mtxid); BEGIN_DISABLE_INTERRUPT; if ( mtxcb->mtxid == 0 ) { ercd = E_NOEXS; } else { INT n = 0; for ( q = mtxcb->wait_queue.next; q != &mtxcb->wait_queue; q = q->next ) { if ( n++ < nent ) { *list++ = ((TCB*)q)->tskid; } } ercd = n; } END_DISABLE_INTERRUPT; return ercd; }
/* * Delete mutex */ SYSCALL ER _tk_del_mtx( ID mtxid ) { MTXCB *mtxcb; ER ercd = E_OK; CHECK_MTXID(mtxid); mtxcb = get_mtxcb(mtxid); BEGIN_CRITICAL_SECTION; if ( mtxcb->mtxid == 0 ) { ercd = E_NOEXS; } else { /* If there is a task that holds mutex to delete, * delete the mutex from the list * and adjust the task priority if necessary. */ if ( mtxcb->mtxtsk != NULL ) { release_mutex(mtxcb->mtxtsk, mtxcb); } /* Free wait state of task (E_DLT) */ wait_delete(&mtxcb->wait_queue); /* Return to FreeQue */ QueInsert(&mtxcb->wait_queue, &free_mtxcb); mtxcb->mtxid = 0; } END_CRITICAL_SECTION; return ercd; }
ER ini_mtx(ID mtxid) { MTXCB *p_mtxcb; TCB *p_loctsk; bool_t dspreq; ER ercd; LOG_INI_MTX_ENTER(mtxid); CHECK_TSKCTX_UNL(); CHECK_MTXID(mtxid); p_mtxcb = get_mtxcb(mtxid); t_lock_cpu(); dspreq = init_wait_queue(&(p_mtxcb->wait_queue)); p_loctsk = p_mtxcb->p_loctsk; if (p_loctsk != NULL) { queue_delete(&(p_mtxcb->mutex_queue)); p_mtxcb->p_loctsk = NULL; if (MTX_CEILING(p_mtxcb)) { if (mutex_drop_priority(p_loctsk, p_mtxcb->p_mtxinib->ceilpri)) { dspreq = true; } } } if (dspreq) { dispatch(); } ercd = E_OK; t_unlock_cpu(); error_exit: LOG_INI_MTX_LEAVE(ercd); return(ercd); }
/* * 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; }
ER tloc_mtx(ID mtxid, TMO tmout) { MTXCB *p_mtxcb; WINFO_MTX winfo_mtx; TMEVTB tmevtb; ER ercd; LOG_TLOC_MTX_ENTER(mtxid, tmout); CHECK_DISPATCH(); CHECK_MTXID(mtxid); CHECK_TMOUT(tmout); p_mtxcb = get_mtxcb(mtxid); t_lock_cpu(); if (MTX_CEILING(p_mtxcb) && p_runtsk->bpriority < p_mtxcb->p_mtxinib->ceilpri) { ercd = E_ILUSE; } else if (p_mtxcb->p_loctsk == NULL) { (void) mutex_acquire(p_runtsk, p_mtxcb); /* * 優先度上限ミューテックスをロックした場合,p_runtskの優先度 * が上がる可能性があるが,ディスパッチが必要になることはない. */ assert(!(p_runtsk != p_schedtsk && dspflg)); ercd = E_OK; } else if (p_mtxcb->p_loctsk == p_runtsk) { ercd = E_OBJ; } else if (tmout == TMO_POL) { ercd = E_TMOUT; } else { p_runtsk->tstat = (TS_WAITING | TS_WAIT_MTX); wobj_make_wait_tmout((WOBJCB *) p_mtxcb, (WINFO_WOBJ *) &winfo_mtx, &tmevtb, tmout); dispatch(); ercd = winfo_mtx.winfo.wercd; } t_unlock_cpu(); error_exit: LOG_TLOC_MTX_LEAVE(ercd); return(ercd); }
/* * Refer mutex state */ SYSCALL ER _td_ref_mtx( ID mtxid, TD_RMTX *pk_rmtx ) { MTXCB *mtxcb; ER ercd = E_OK; CHECK_MTXID(mtxid); mtxcb = get_mtxcb(mtxid); BEGIN_DISABLE_INTERRUPT; if ( mtxcb->mtxid == 0 ) { ercd = E_NOEXS; } else { pk_rmtx->exinf = mtxcb->exinf; pk_rmtx->htsk = ( mtxcb->mtxtsk != NULL )? mtxcb->mtxtsk->tskid: 0; pk_rmtx->wtsk = wait_tskid(&mtxcb->wait_queue); } END_DISABLE_INTERRUPT; return ercd; }
/* * Refer mutex state */ SYSCALL ER _tk_ref_mtx( ID mtxid, T_RMTX *pk_rmtx ) { MTXCB *mtxcb; ER ercd = E_OK; CHECK_MTXID(mtxid); mtxcb = get_mtxcb(mtxid); BEGIN_CRITICAL_SECTION; if ( mtxcb->mtxid == 0 ) { ercd = E_NOEXS; } else { pk_rmtx->exinf = mtxcb->exinf; pk_rmtx->htsk = ( mtxcb->mtxtsk != NULL )? mtxcb->mtxtsk->tskid: 0; pk_rmtx->wtsk = wait_tskid(&mtxcb->wait_queue); } END_CRITICAL_SECTION; return ercd; }
ER ref_mtx(ID mtxid, T_RMTX *pk_rmtx) { MTXCB *p_mtxcb; ER ercd; LOG_REF_MTX_ENTER(mtxid, pk_rmtx); CHECK_TSKCTX_UNL(); CHECK_MTXID(mtxid); p_mtxcb = get_mtxcb(mtxid); t_lock_cpu(); pk_rmtx->htskid = (p_mtxcb->p_loctsk != NULL) ? TSKID(p_mtxcb->p_loctsk) : TSK_NONE; pk_rmtx->wtskid = wait_tskid(&(p_mtxcb->wait_queue)); ercd = E_OK; t_unlock_cpu(); error_exit: LOG_REF_MTX_LEAVE(ercd, pk_rmtx); return(ercd); }
ER unl_mtx(ID mtxid) { MTXCB *p_mtxcb; bool_t dspreq = false; ER ercd; LOG_UNL_MTX_ENTER(mtxid); CHECK_TSKCTX_UNL(); CHECK_MTXID(mtxid); p_mtxcb = get_mtxcb(mtxid); t_lock_cpu(); if (p_mtxcb->p_loctsk != p_runtsk) { ercd = E_OBJ; } else { queue_delete(&(p_mtxcb->mutex_queue)); if (MTX_CEILING(p_mtxcb)) { if (mutex_drop_priority(p_runtsk, p_mtxcb->p_mtxinib->ceilpri)) { dspreq = true; } } if (mutex_release(p_mtxcb)) { dspreq = true; } if (dspreq) { dispatch(); } ercd = E_OK; } t_unlock_cpu(); error_exit: LOG_UNL_MTX_LEAVE(ercd); return(ercd); }
ER ploc_mtx(ID mtxid) { MTXCB *p_mtxcb; ER ercd; LOG_PLOC_MTX_ENTER(mtxid); CHECK_TSKCTX_UNL(); CHECK_MTXID(mtxid); p_mtxcb = get_mtxcb(mtxid); t_lock_cpu(); if (MTX_CEILING(p_mtxcb) && p_runtsk->bpriority < p_mtxcb->p_mtxinib->ceilpri) { ercd = E_ILUSE; } else if (p_mtxcb->p_loctsk == NULL) { (void) mutex_acquire(p_runtsk, p_mtxcb); /* * 優先度上限ミューテックスをロックした場合,p_runtskの優先度 * が上がる可能性があるが,ディスパッチが必要になることはない. */ assert(!(p_runtsk != p_schedtsk && dspflg)); ercd = E_OK; } else if (p_mtxcb->p_loctsk == p_runtsk) { ercd = E_OBJ; } else { ercd = E_TMOUT; } t_unlock_cpu(); error_exit: LOG_PLOC_MTX_LEAVE(ercd); return(ercd); }
EXPORT ER mutex_getname(ID id, UB **name) { MTXCB *mtxcb; ER ercd = E_OK; CHECK_MTXID(id); BEGIN_DISABLE_INTERRUPT; mtxcb = get_mtxcb(id); if ( mtxcb->mtxid == 0 ) { ercd = E_NOEXS; goto error_exit; } if ( (mtxcb->mtxatr & TA_DSNAME) == 0 ) { ercd = E_OBJ; goto error_exit; } *name = mtxcb->name; error_exit: END_DISABLE_INTERRUPT; return ercd; }
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; }