StatusType SleepTask ( TickType Timeout ) { StatusType ercd = E_OK; OS_CHECK_EXT(!in_indp(),E_OS_CALLEVEL); OS_CHECK_EXT(isQueEmpty(&knl_ctxtsk->resque),E_OS_RESOURCE); BEGIN_CRITICAL_SECTION; if ( knl_ctxtsk->wupcnt > 0 ) { knl_ctxtsk->wupcnt--; } else { ercd = E_OS_TMOUT; if ( Timeout != 0 ) { knl_ctxtsk->wspec = &knl_wspec_slp; knl_ctxtsk->wid = 0; knl_ctxtsk->wercd = &ercd; knl_make_wait(Timeout); QueInit(&knl_ctxtsk->tskque); } } END_CRITICAL_SECTION; Error_Exit: return ercd; }
/* * Change the active task state to wait state and connect to the timer wait * queue and the object wait queue. Also set 'wid' in 'knl_ctxtsk'. */ EXPORT void knl_gcb_make_wait( GCB *gcb, TMO tmout ) { *knl_ctxtsk->wercd = E_TMOUT; if ( tmout != TMO_POL ) { knl_ctxtsk->wid = gcb->objid; knl_make_wait(tmout, gcb->objatr); if ( (gcb->objatr & TA_TPRI) != 0 ) { knl_queue_insert_tpri(knl_ctxtsk, &gcb->wait_queue); } else { QueInsert(&knl_ctxtsk->tskque, &gcb->wait_queue); } } }
/* * Accept rendezvous */ SYSCALL INT tk_acp_por_impl( ID porid, UINT acpptn, RNO *p_rdvno, VP msg, TMO tmout ) { PORCB *porcb; TCB *tcb; QUEUE *queue; RNO rdvno; INT cmsgsz; ER ercd = E_OK; CHECK_PORID(porid); CHECK_PAR(acpptn != 0); CHECK_TMOUT(tmout); CHECK_DISPATCH(); porcb = get_porcb(porid); BEGIN_CRITICAL_SECTION; if ( porcb->porid == 0 ) { ercd = E_NOEXS; goto error_exit; } /* Search call wait task */ queue = porcb->call_queue.next; while ( queue != &porcb->call_queue ) { tcb = (TCB*)queue; queue = queue->next; if ( (acpptn & tcb->winfo.cal.calptn) == 0 ) { continue; } /* Receive message */ *p_rdvno = rdvno = knl_gen_rdvno(tcb); cmsgsz = tcb->winfo.cal.cmsgsz; if ( cmsgsz > 0 ) { memcpy(msg, tcb->winfo.cal.msg, (UINT)cmsgsz); } knl_wait_cancel(tcb); /* Make the other task at rendezvous end wait state */ tcb->wspec = &knl_wspec_rdv; tcb->wid = 0; tcb->winfo.rdv.rdvno = rdvno; tcb->winfo.rdv.msg = tcb->winfo.cal.msg; tcb->winfo.rdv.maxrmsz = porcb->maxrmsz; tcb->winfo.rdv.p_rmsgsz = tcb->winfo.cal.p_rmsgsz; knl_timer_insert(&tcb->wtmeb, TMO_FEVR, (CBACK)knl_wait_release_tmout, tcb); QueInit(&tcb->tskque); goto error_exit; } ercd = E_TMOUT; if ( tmout != TMO_POL ) { /* Ready for rendezvous accept wait */ knl_ctxtsk->wspec = &knl_wspec_acp; knl_ctxtsk->wid = porid; knl_ctxtsk->wercd = &ercd; knl_ctxtsk->winfo.acp.acpptn = acpptn; knl_ctxtsk->winfo.acp.msg = msg; knl_ctxtsk->winfo.acp.p_rdvno = p_rdvno; knl_ctxtsk->winfo.acp.p_cmsgsz = &cmsgsz; knl_make_wait(tmout, porcb->poratr); QueInsert(&knl_ctxtsk->tskque, &porcb->accept_queue); } error_exit: END_CRITICAL_SECTION; return ( ercd < E_OK )? ercd: cmsgsz; }
/* * Call rendezvous */ SYSCALL INT tk_cal_por_impl( ID porid, UINT calptn, VP msg, INT cmsgsz, TMO tmout ) { PORCB *porcb; TCB *tcb; QUEUE *queue; RNO rdvno; INT rmsgsz; ER ercd = E_OK; CHECK_PORID(porid); CHECK_PAR(calptn != 0); CHECK_PAR(cmsgsz >= 0); CHECK_TMOUT(tmout); CHECK_DISPATCH(); porcb = get_porcb(porid); BEGIN_CRITICAL_SECTION; if ( porcb->porid == 0 ) { ercd = E_NOEXS; goto error_exit; } #if CHK_PAR if ( cmsgsz > porcb->maxcmsz ) { ercd = E_PAR; goto error_exit; } #endif /* Search accept wait task */ queue = porcb->accept_queue.next; while ( queue != &porcb->accept_queue ) { tcb = (TCB*)queue; queue = queue->next; if ( (calptn & tcb->winfo.acp.acpptn) == 0 ) { continue; } /* Send message */ rdvno = knl_gen_rdvno(knl_ctxtsk); if ( cmsgsz > 0 ) { memcpy(tcb->winfo.acp.msg, msg, (UINT)cmsgsz); } *tcb->winfo.acp.p_rdvno = rdvno; *tcb->winfo.acp.p_cmsgsz = cmsgsz; knl_wait_release_ok(tcb); /* Ready for rendezvous end wait */ ercd = E_TMOUT; knl_ctxtsk->wspec = &knl_wspec_rdv; knl_ctxtsk->wid = 0; knl_ctxtsk->wercd = &ercd; knl_ctxtsk->winfo.rdv.rdvno = rdvno; knl_ctxtsk->winfo.rdv.msg = msg; knl_ctxtsk->winfo.rdv.maxrmsz = porcb->maxrmsz; knl_ctxtsk->winfo.rdv.p_rmsgsz = &rmsgsz; knl_make_wait(TMO_FEVR, porcb->poratr); QueInit(&knl_ctxtsk->tskque); goto error_exit; } /* Ready for rendezvous call wait */ knl_ctxtsk->wspec = ( (porcb->poratr & TA_TPRI) != 0 )? &knl_wspec_cal_tpri: &knl_wspec_cal_tfifo; knl_ctxtsk->wercd = &ercd; knl_ctxtsk->winfo.cal.calptn = calptn; knl_ctxtsk->winfo.cal.msg = msg; knl_ctxtsk->winfo.cal.cmsgsz = cmsgsz; knl_ctxtsk->winfo.cal.p_rmsgsz = &rmsgsz; knl_gcb_make_wait((GCB*)porcb, tmout); error_exit: END_CRITICAL_SECTION; return ( ercd < E_OK )? ercd: rmsgsz; }
/* * Lock mutex */ SYSCALL ER tk_loc_mtx_impl( ID mtxid, TMO 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 == knl_ctxtsk ) { ercd = E_ILUSE; /* Multiplexed lock */ goto error_exit; } mtxatr = mtxcb->mtxatr & TA_CEILING; if ( mtxatr == TA_CEILING ) { if ( knl_ctxtsk->bpriority < mtxcb->ceilpri ) { /* Violation of highest priority limit */ ercd = E_ILUSE; goto error_exit; } } mtxtsk = mtxcb->mtxtsk; if ( mtxtsk == NULL ) { /* Get lock */ mtxcb->mtxtsk = knl_ctxtsk; mtxcb->mtxlist = knl_ctxtsk->mtxlist; knl_ctxtsk->mtxlist = mtxcb; if ( mtxatr == TA_CEILING ) { if ( knl_ctxtsk->priority > mtxcb->ceilpri ) { /* Raise its own task to the highest priority limit */ knl_change_task_priority(knl_ctxtsk, mtxcb->ceilpri); } } } else { ercd = E_TMOUT; if ( tmout == TMO_POL ) { goto error_exit; } if ( mtxatr == TA_INHERIT ) { if ( mtxtsk->priority > knl_ctxtsk->priority ) { /* Raise the priority of task during locking to the same priority as its own task */ knl_change_task_priority(mtxtsk, knl_ctxtsk->priority); } } /* Ready for wait */ knl_ctxtsk->wspec = ( mtxatr == TA_TFIFO )? &knl_wspec_mtx_tfifo: ( mtxatr == TA_INHERIT )? &knl_wspec_mtx_inherit: &knl_wspec_mtx_tpri; knl_ctxtsk->wercd = &ercd; knl_ctxtsk->wid = mtxcb->mtxid; knl_make_wait(tmout, mtxcb->mtxatr); if ( mtxatr == TA_TFIFO ) { QueInsert(&knl_ctxtsk->tskque, &mtxcb->wait_queue); } else { knl_queue_insert_tpri(knl_ctxtsk, &mtxcb->wait_queue); } } error_exit: END_CRITICAL_SECTION; return ercd; }