From: Tomas Hruby Date: Mon, 29 Mar 2010 11:16:37 +0000 (+0000) Subject: Slightly faster IPC X-Git-Tag: v3.1.7~197 X-Git-Url: http://zhaoyanbai.com/repos/man.host.html?a=commitdiff_plain;h=2521cc6bdf872059baaf895e36974b8ce86b609c;p=minix.git Slightly faster IPC - there are cycles wasted in the IPC call due to a fairly compliacted way of copying messages from userland to kernel. Sometimes this complicated way (generic though) is used even for copying within the kernel address space, sometimes it is used for copying in case _no_ copying is necessary. The goal of this patch is to improve this a little bit. - the places where a copy is from user to kernel use the copy_msg_from_user() kernel-kernel copies are turned into assignments and BuildNotifyMessage uses the delivery buffers to avoid copying. - copy_msg_from_user() was introduced when removing the system task and is about 2/3 faster then using the current mechanism (phys_copy). It also avoids the PHYS_COPY_CATCH macro. Assignment is also faster and no copy is the fastest ;-) so perhaps there will be some hardly noticable performance gain besides the clean up. --- diff --git a/kernel/proc.c b/kernel/proc.c index 78edbacd3..65d3125d1 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -77,47 +77,6 @@ FORWARD _PROTOTYPE( void enqueue_head, (struct proc *rp)); break; \ } -/*===========================================================================* - * QueueMess * - *===========================================================================*/ -PRIVATE int QueueMess(endpoint_t ep, vir_bytes msg_lin, struct proc *dst) -{ - int k; - phys_bytes addr; - NOREC_ENTER(queuemess); - /* Queue a message from the src process (in memory) to the dst - * process (using dst process table entry). Do actual copy to - * kernel here; it's an error if the copy fails into kernel. - */ - assert(!(dst->p_misc_flags & MF_DELIVERMSG)); - assert(dst->p_delivermsg_lin); - assert(isokendpt(ep, &k)); - -#if 0 - if(INMEMORY(dst)) { - PHYS_COPY_CATCH(msg_lin, dst->p_delivermsg_lin, - sizeof(message), addr); - if(!addr) { - PHYS_COPY_CATCH(vir2phys(&ep), dst->p_delivermsg_lin, - sizeof(ep), addr); - if(!addr) { - NOREC_RETURN(queuemess, OK); - } - } - } -#endif - - PHYS_COPY_CATCH(msg_lin, vir2phys(&dst->p_delivermsg), sizeof(message), addr); - if(addr) { - NOREC_RETURN(queuemess, EFAULT); - } - - dst->p_delivermsg.m_source = ep; - dst->p_misc_flags |= MF_DELIVERMSG; - - NOREC_RETURN(queuemess, OK); -} - /*===========================================================================* * idle * *===========================================================================*/ @@ -561,26 +520,7 @@ const int flags; */ register struct proc *dst_ptr; register struct proc **xpp; - struct proc *msg_proc_ptr; /* Proc in which the message can be found */ int dst_p; - phys_bytes linaddr; - vir_bytes addr; - int r; - - /* The kernel can send messages on behalf of other processes. In that case - we need to pass a pointer to the kernel, not the caller_ptr, to - umap_local as the kernel contains the message to be sent. */ - if (flags & FROM_KERNEL) { - msg_proc_ptr = proc_addr(KERNEL); - } - else { - msg_proc_ptr = caller_ptr; - } - - if(!(linaddr = umap_local(msg_proc_ptr, D, (vir_bytes) m_ptr, - sizeof(message)))) { - return EFAULT; - } dst_p = _ENDPOINT_P(dst_e); dst_ptr = proc_addr(dst_p); @@ -596,8 +536,15 @@ const int flags; int call; /* Destination is indeed waiting for this message. */ assert(!(dst_ptr->p_misc_flags & MF_DELIVERMSG)); - if((r=QueueMess(caller_ptr->p_endpoint, linaddr, dst_ptr)) != OK) - return r; + + if (!(flags & FROM_KERNEL)) { + if(copy_msg_from_user(caller_ptr, m_ptr, &dst_ptr->p_delivermsg)) + return EFAULT; + } else + dst_ptr->p_delivermsg = *m_ptr; + dst_ptr->p_delivermsg.m_source = caller_ptr->p_endpoint; + dst_ptr->p_misc_flags |= MF_DELIVERMSG; + call = (caller_ptr->p_misc_flags & MF_REPLY_PEND ? SENDREC : (flags & NON_BLOCKING ? SENDNB : SEND)); IPC_STATUS_ADD(dst_ptr, IPC_STATUS_CALL_TO(call)); @@ -613,10 +560,12 @@ const int flags; } /* Destination is not waiting. Block and dequeue caller. */ - PHYS_COPY_CATCH(linaddr, vir2phys(&caller_ptr->p_sendmsg), - sizeof(message), addr); + if (!(flags & FROM_KERNEL)) { + if(copy_msg_from_user(caller_ptr, m_ptr, &caller_ptr->p_sendmsg)) + return EFAULT; + } else + caller_ptr->p_sendmsg = *m_ptr; - if(addr) { return EFAULT; } RTS_SET(caller_ptr, RTS_SENDING); caller_ptr->p_sendto_e = dst_e; @@ -643,7 +592,6 @@ const int flags; * is available block the caller. */ register struct proc **xpp; - message m; sys_map_t *map; bitchunk_t *chunk; int i, r, src_id, src_proc_nr, src_p; @@ -699,15 +647,18 @@ const int flags; *chunk &= ~(1 << i); /* no longer pending */ /* Found a suitable source, deliver the notification message. */ - BuildNotifyMessage(&m, src_proc_nr, caller_ptr); /* assemble message */ hisep = proc_addr(src_proc_nr)->p_endpoint; assert(!(caller_ptr->p_misc_flags & MF_DELIVERMSG)); assert(src_e == ANY || hisep == src_e); - if((r=QueueMess(hisep, vir2phys(&m), caller_ptr)) != OK) { - panic("mini_receive: local QueueMess failed"); - } + + /* assemble message */ + BuildNotifyMessage(&caller_ptr->p_delivermsg, src_proc_nr, caller_ptr); + caller_ptr->p_delivermsg.m_source = hisep; + caller_ptr->p_misc_flags |= MF_DELIVERMSG; + IPC_STATUS_ADD(caller_ptr, IPC_STATUS_CALL_TO(NOTIFY)); - return(OK); /* report success */ + + return(OK); } } @@ -735,13 +686,16 @@ const int flags; /* Found acceptable message. Copy it and update status. */ assert(!(caller_ptr->p_misc_flags & MF_DELIVERMSG)); - QueueMess((*xpp)->p_endpoint, - vir2phys(&(*xpp)->p_sendmsg), caller_ptr); + caller_ptr->p_delivermsg = (*xpp)->p_sendmsg; + caller_ptr->p_delivermsg.m_source = (*xpp)->p_endpoint; + caller_ptr->p_misc_flags |= MF_DELIVERMSG; + RTS_UNSET(*xpp, RTS_SENDING); + call = ((*xpp)->p_misc_flags & MF_REPLY_PEND ? SENDREC : SEND); IPC_STATUS_ADD(caller_ptr, IPC_STATUS_CALL_TO(call)); if ((*xpp)->p_misc_flags & MF_SIG_DELAY) sig_delay_done(*xpp); - RTS_UNSET(*xpp, RTS_SENDING); + *xpp = (*xpp)->p_q_link; /* remove from queue */ return(OK); /* report success */ } @@ -776,8 +730,6 @@ PUBLIC int mini_notify( { register struct proc *dst_ptr; int src_id; /* source id for late delivery */ - message m; /* the notification message */ - int r; int dst_p; if (!isokendpt(dst_e, &dst_p)) { @@ -797,13 +749,15 @@ PUBLIC int mini_notify( * message and deliver it. Copy from pseudo-source HARDWARE, since the * message is in the kernel's address space. */ - BuildNotifyMessage(&m, proc_nr(caller_ptr), dst_ptr); assert(!(dst_ptr->p_misc_flags & MF_DELIVERMSG)); - if((r=QueueMess(caller_ptr->p_endpoint, vir2phys(&m), dst_ptr)) != OK) { - panic("mini_notify: local QueueMess failed"); - } + + BuildNotifyMessage(&dst_ptr->p_delivermsg, proc_nr(caller_ptr), dst_ptr); + dst_ptr->p_delivermsg.m_source = caller_ptr->p_endpoint; + dst_ptr->p_misc_flags |= MF_DELIVERMSG; + IPC_STATUS_ADD(dst_ptr, IPC_STATUS_CALL_TO(NOTIFY)); RTS_UNSET(dst_ptr, RTS_RECEIVING); + return(OK); } @@ -850,7 +804,6 @@ PRIVATE int mini_senda(struct proc *caller_ptr, asynmsg_t *table, size_t size) struct priv *privp; asynmsg_t tabent; const vir_bytes table_v = (vir_bytes) table; - vir_bytes linaddr; privp= priv(caller_ptr); if (!(privp->s_flags & SYS_PROC)) @@ -870,13 +823,6 @@ PRIVATE int mini_senda(struct proc *caller_ptr, asynmsg_t *table, size_t size) return OK; } - if(!(linaddr = umap_local(caller_ptr, D, (vir_bytes) table, - size * sizeof(*table)))) { - printf("mini_senda: umap_local failed; 0x%lx len 0x%lx\n", - table, size * sizeof(*table)); - return EFAULT; - } - /* Limit size to something reasonable. An arbitrary choice is 16 * times the number of process table entries. * @@ -985,13 +931,16 @@ PRIVATE int mini_senda(struct proc *caller_ptr, asynmsg_t *table, size_t size) { /* Destination is indeed waiting for this message. */ /* Copy message from sender. */ - tabent.result= QueueMess(caller_ptr->p_endpoint, - linaddr + (vir_bytes) &table[i].msg - - (vir_bytes) table, dst_ptr); - if(tabent.result == OK) { + if(copy_msg_from_user(caller_ptr, &table[i].msg, + &dst_ptr->p_delivermsg)) + tabent.result = EFAULT; + else { + dst_ptr->p_delivermsg.m_source = caller_ptr->p_endpoint; + dst_ptr->p_misc_flags |= MF_DELIVERMSG; IPC_STATUS_ADD(dst_ptr, IPC_STATUS_CALL_TO(SENDA)); RTS_UNSET(dst_ptr, RTS_RECEIVING); + tabent.result = OK; } A_INSERT(i, result); @@ -1067,7 +1016,6 @@ PRIVATE int try_one(struct proc *src_ptr, struct proc *dst_ptr, int *postponed) asynmsg_t tabent; vir_bytes table_v; struct proc *caller_ptr; - int r; privp= priv(src_ptr); @@ -1139,10 +1087,11 @@ PRIVATE int try_one(struct proc *src_ptr, struct proc *dst_ptr, int *postponed) /* Deliver message */ A_RETRIEVE(i, msg); - r = QueueMess(src_ptr->p_endpoint, vir2phys(&tabent.msg), - dst_ptr); + dst_ptr->p_delivermsg = tabent.msg; + dst_ptr->p_delivermsg.m_source = src_ptr->p_endpoint; + dst_ptr->p_misc_flags |= MF_DELIVERMSG; - tabent.result= r; + tabent.result = OK; A_INSERT(i, result); tabent.flags= flags | AMF_DONE; A_INSERT(i, flags);