📄 rendezvous.c
字号:
/* *---------------------------------------------------------------------- * micro T-Kernel * * Copyright (C) 2006-2007 by Ken Sakamura. All rights reserved. * micro T-Kernel is distributed under the micro T-License. *---------------------------------------------------------------------- * * Version: 1.00.00 * Released by T-Engine Forum(http://www.t-engine.org) at 2007/03/26. * *---------------------------------------------------------------------- *//* * rendezvous.c * Rendezvous *//** [BEGIN Common Definitions] */#include "kernel.h"#include "task.h"#include "wait.h"#include "check.h"#include "rendezvous.h"/** [END Common Definitions] */#if CFN_MAX_PORID > 0#ifdef USE_FUNC_PORCB_TABLENoinit(EXPORT PORCB knl_porcb_table[NUM_PORID]); /* Rendezvous port control block */Noinit(EXPORT QUEUE knl_free_porcb); /* FreeQue */#endif /* USE_FUNC_PORCB_TABLE */#ifdef USE_FUNC_RENDEZVOUS_INITIALIZE/* * Initialization of port control block */EXPORT ER knl_rendezvous_initialize( void ){ PORCB *porcb, *end; /* Get system information */ if ( NUM_PORID < 1 ) { return E_SYS; } /* Register all control blocks onto FreeQue */ QueInit(&knl_free_porcb); end = knl_porcb_table + NUM_PORID; for ( porcb = knl_porcb_table; porcb < end; porcb++ ) { porcb->porid = 0; QueInsert(&porcb->call_queue, &knl_free_porcb); } return E_OK;}#endif /* USE_FUNC_RENDEZVOUS_INITIALIZE */#ifdef USE_FUNC_WSPEC_CAL/* * Processing if the priority of send wait task changes */LOCAL void cal_chg_pri( TCB *tcb, INT oldpri ){ PORCB *porcb; porcb = get_porcb(tcb->wid); knl_gcb_change_priority((GCB*)porcb, tcb);}/* * Definition of rendezvous wait specification */EXPORT WSPEC knl_wspec_cal_tfifo = { TTW_CAL, NULL, NULL };EXPORT WSPEC knl_wspec_cal_tpri = { TTW_CAL, cal_chg_pri, NULL };#endif /* USE_FUNC_WSPEC_CAL */#ifdef USE_FUNC_WSPEC_RDVEXPORT WSPEC knl_wspec_rdv = { TTW_RDV, NULL, NULL };#endif /* USE_FUNC_WSPEC_RDV */#ifdef USE_FUNC_TK_CRE_POR/* * Create rendezvous port */SYSCALL ID tk_cre_por_impl( T_CPOR *pk_cpor ){ const ATR VALID_PORATR = { TA_TPRI#if USE_OBJECT_NAME |TA_DSNAME#endif }; PORCB *porcb; ID porid; ER ercd; CHECK_RSATR(pk_cpor->poratr, VALID_PORATR); CHECK_PAR(pk_cpor->maxcmsz >= 0); CHECK_PAR(pk_cpor->maxrmsz >= 0); CHECK_INTSK(); BEGIN_CRITICAL_SECTION; /* Get control block from FreeQue */ porcb = (PORCB*)QueRemoveNext(&knl_free_porcb); if ( porcb == NULL ) { ercd = E_LIMIT; } else { porid = ID_POR(porcb - knl_porcb_table); /* Initialize control block */ QueInit(&porcb->call_queue); porcb->porid = porid; porcb->exinf = pk_cpor->exinf; porcb->poratr = pk_cpor->poratr; QueInit(&porcb->accept_queue); porcb->maxcmsz = pk_cpor->maxcmsz; porcb->maxrmsz = pk_cpor->maxrmsz;#if USE_OBJECT_NAME if ( (pk_cpor->poratr & TA_DSNAME) != 0 ) { strncpy((char*)porcb->name, (char*)pk_cpor->dsname, OBJECT_NAME_LENGTH); }#endif ercd = porid; } END_CRITICAL_SECTION; return ercd;}#endif /* USE_FUNC_TK_CRE_POR */#ifdef USE_FUNC_TK_DEL_POR/* * Delete rendezvous port */SYSCALL ER tk_del_por_impl( ID porid ){ PORCB *porcb; ER ercd = E_OK; CHECK_PORID(porid); CHECK_INTSK(); porcb = get_porcb(porid); BEGIN_CRITICAL_SECTION; if ( porcb->porid == 0 ) { ercd = E_NOEXS; } else { /* Release wait state of task (E_DLT) */ knl_wait_delete(&porcb->call_queue); knl_wait_delete(&porcb->accept_queue); /* Return to FreeQue */ QueInsert(&porcb->call_queue, &knl_free_porcb); porcb->porid = 0; } END_CRITICAL_SECTION; return ercd;}#endif /* USE_FUNC_TK_DEL_POR */#ifdef USE_FUNC_TK_CAL_POR/* * 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;}#endif /* USE_FUNC_TK_CAL_POR */#ifdef USE_FUNC_TK_ACP_PORLOCAL WSPEC knl_wspec_acp = { TTW_ACP, NULL, NULL };/* * 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;}#endif /* USE_FUNC_TK_ACP_POR */#ifdef USE_FUNC_TK_FWD_POR/* * Forward Rendezvous to Other Port */SYSCALL ER tk_fwd_por_impl( ID porid, UINT calptn, RNO rdvno, VP msg, INT cmsgsz ){ PORCB *porcb; TCB *caltcb, *tcb; QUEUE *queue; RNO new_rdvno; ER ercd = E_OK; CHECK_PORID(porid); CHECK_PAR(calptn != 0); CHECK_RDVNO(rdvno); CHECK_PAR(cmsgsz >= 0); CHECK_INTSK(); porcb = get_porcb(porid); caltcb = get_tcb(knl_get_tskid_rdvno(rdvno)); 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 if ( (caltcb->state & TS_WAIT) == 0 || caltcb->wspec != &knl_wspec_rdv || rdvno != caltcb->winfo.rdv.rdvno ) { ercd = E_OBJ; goto error_exit; } if ( porcb->maxrmsz > caltcb->winfo.rdv.maxrmsz ) { ercd = E_OBJ; goto error_exit; }#if CHK_PAR if ( cmsgsz > caltcb->winfo.rdv.maxrmsz ) { 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 */ new_rdvno = knl_gen_rdvno(caltcb); if ( cmsgsz > 0 ) { memcpy(tcb->winfo.acp.msg, msg, (UINT)cmsgsz); } *tcb->winfo.acp.p_rdvno = new_rdvno; *tcb->winfo.acp.p_cmsgsz = cmsgsz; knl_wait_release_ok(tcb); /* Change rendezvous end wait of the other task */ caltcb->winfo.rdv.rdvno = new_rdvno; caltcb->winfo.rdv.msg = caltcb->winfo.cal.msg; caltcb->winfo.rdv.maxrmsz = porcb->maxrmsz; caltcb->winfo.rdv.p_rmsgsz = caltcb->winfo.cal.p_rmsgsz; goto error_exit; } /* Change the other task to rendezvous call wait */ caltcb->wspec = ( (porcb->poratr & TA_TPRI) != 0 )? &knl_wspec_cal_tpri: &knl_wspec_cal_tfifo; caltcb->wid = porid; caltcb->winfo.cal.calptn = calptn; caltcb->winfo.cal.msg = caltcb->winfo.rdv.msg; caltcb->winfo.cal.cmsgsz = cmsgsz; caltcb->winfo.cal.p_rmsgsz = caltcb->winfo.rdv.p_rmsgsz; knl_timer_insert(&caltcb->wtmeb, TMO_FEVR, (CBACK)knl_wait_release_tmout, caltcb); QueInsert(&caltcb->tskque, &porcb->call_queue); if ( cmsgsz > 0 ) { memcpy(caltcb->winfo.cal.msg, msg, (UINT)cmsgsz); } error_exit: END_CRITICAL_SECTION; return ercd;}#endif /* USE_FUNC_TK_FWD_POR */#ifdef USE_FUNC_TK_RPL_RDV/* * Reply rendezvous */SYSCALL ER tk_rpl_rdv_impl( RNO rdvno, VP msg, INT rmsgsz ){ TCB *caltcb; ER ercd = E_OK; CHECK_RDVNO(rdvno); CHECK_PAR(rmsgsz >= 0); CHECK_INTSK(); caltcb = get_tcb(knl_get_tskid_rdvno(rdvno)); BEGIN_CRITICAL_SECTION; if ( (caltcb->state & TS_WAIT) == 0 || caltcb->wspec != &knl_wspec_rdv || rdvno != caltcb->winfo.rdv.rdvno ) { ercd = E_OBJ; goto error_exit; }#if CHK_PAR if ( rmsgsz > caltcb->winfo.rdv.maxrmsz ) { ercd = E_PAR; goto error_exit; }#endif /* Send message */ if ( rmsgsz > 0 ) { memcpy(caltcb->winfo.rdv.msg, msg, (UINT)rmsgsz); } *caltcb->winfo.rdv.p_rmsgsz = rmsgsz; knl_wait_release_ok(caltcb); error_exit: END_CRITICAL_SECTION; return ercd;}#endif /* USE_FUNC_TK_RPL_RDV */#ifdef USE_FUNC_TK_REF_POR/* * Refer rendezvous port */SYSCALL ER tk_ref_por_impl( ID porid, T_RPOR *pk_rpor ){ PORCB *porcb; ER ercd = E_OK; CHECK_PORID(porid); porcb = get_porcb(porid); BEGIN_CRITICAL_SECTION; if ( porcb->porid == 0 ) { ercd = E_NOEXS; } else { pk_rpor->exinf = porcb->exinf; pk_rpor->wtsk = knl_wait_tskid(&porcb->call_queue); pk_rpor->atsk = knl_wait_tskid(&porcb->accept_queue); pk_rpor->maxcmsz = porcb->maxcmsz; pk_rpor->maxrmsz = porcb->maxrmsz; } END_CRITICAL_SECTION; return ercd;}#endif /* USE_FUNC_TK_REF_POR *//* ------------------------------------------------------------------------ *//* * Debugger support function */#if USE_DBGSPT#ifdef USE_FUNC_RENDEZVOUS_GETNAME#if USE_OBJECT_NAME/* * Get object name from control block */EXPORT ER knl_rendezvous_getname(ID id, UB **name){ PORCB *porcb; ER ercd = E_OK; CHECK_PORID(id); BEGIN_DISABLE_INTERRUPT; porcb = get_porcb(id); if ( porcb->porid == 0 ) { ercd = E_NOEXS; goto error_exit; } if ( (porcb->poratr & TA_DSNAME) == 0 ) { ercd = E_OBJ; goto error_exit; } *name = porcb->name; error_exit: END_DISABLE_INTERRUPT; return ercd;}#endif /* USE_OBJECT_NAME */#endif /* USE_FUNC_RENDEZVOUS_GETNAME */#ifdef USE_FUNC_TD_LST_POR/* * Refer rendezvous port usage state */SYSCALL INT td_lst_por_impl( ID list[], INT nent ){ PORCB *porcb, *end; INT n = 0; BEGIN_DISABLE_INTERRUPT; end = knl_porcb_table + NUM_PORID; for ( porcb = knl_porcb_table; porcb < end; porcb++ ) { if ( porcb->porid == 0 ) { continue; } if ( n++ < nent ) { *list++ = porcb->porid; } } END_DISABLE_INTERRUPT; return n;}#endif /* USE_FUNC_TD_LST_POR */#ifdef USE_FUNC_TD_REF_POR/* * Refer rendezvous port */SYSCALL ER td_ref_por_impl( ID porid, TD_RPOR *pk_rpor ){ PORCB *porcb; ER ercd = E_OK; CHECK_PORID(porid); porcb = get_porcb(porid); BEGIN_DISABLE_INTERRUPT; if ( porcb->porid == 0 ) { ercd = E_NOEXS; } else { pk_rpor->exinf = porcb->exinf; pk_rpor->wtsk = knl_wait_tskid(&porcb->call_queue); pk_rpor->atsk = knl_wait_tskid(&porcb->accept_queue); pk_rpor->maxcmsz = porcb->maxcmsz; pk_rpor->maxrmsz = porcb->maxrmsz; } END_DISABLE_INTERRUPT; return ercd;}#endif /* USE_FUNC_TD_REF_POR */#ifdef USE_FUNC_TD_CAL_QUE/* * Refer rendezvous call wait queue */SYSCALL INT td_cal_que_impl( ID porid, ID list[], INT nent ){ PORCB *porcb; QUEUE *q; ER ercd = E_OK; CHECK_PORID(porid); porcb = get_porcb(porid); BEGIN_DISABLE_INTERRUPT; if ( porcb->porid == 0 ) { ercd = E_NOEXS; } else { INT n = 0; for ( q = porcb->call_queue.next; q != &porcb->call_queue; q = q->next ) { if ( n++ < nent ) { *list++ = ((TCB*)q)->tskid; } } ercd = n; } END_DISABLE_INTERRUPT; return ercd;}#endif /* USE_FUNC_TD_CAL_QUE */#ifdef USE_FUNC_TD_ACP_QUE/* * Refer rendezvous accept wait queue */SYSCALL INT td_acp_que_impl( ID porid, ID list[], INT nent ){ PORCB *porcb; QUEUE *q; ER ercd = E_OK; CHECK_PORID(porid); porcb = get_porcb(porid); BEGIN_DISABLE_INTERRUPT; if ( porcb->porid == 0 ) { ercd = E_NOEXS; } else { INT n = 0; for ( q = porcb->accept_queue.next; q != &porcb->accept_queue; q = q->next ) { if ( n++ < nent ) { *list++ = ((TCB*)q)->tskid; } } ercd = n; } END_DISABLE_INTERRUPT; return ercd;}#endif /* USE_FUNC_TD_ACP_QUE */#endif /* USE_DBGSPT */#endif /* CFN_MAX_PORID */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -