From 16e0e9370e8c3a30892d0890572b2cb8700ac5a1 Mon Sep 17 00:00:00 2001 From: Thomas Veerman Date: Fri, 8 Apr 2011 15:03:33 +0000 Subject: [PATCH] Use a bitmap for pending asynchronous messages instead of a global flag. That way it works similar to pending notifications. --- kernel/priv.h | 1 + kernel/proc.c | 117 +++++++++++++++++++++++++++--------------------- kernel/system.c | 8 +--- 3 files changed, 68 insertions(+), 58 deletions(-) diff --git a/kernel/priv.h b/kernel/priv.h index 424d6c0af..f9304423c 100644 --- a/kernel/priv.h +++ b/kernel/priv.h @@ -38,6 +38,7 @@ struct priv { endpoint_t s_sig_mgr; /* signal manager for system signals */ endpoint_t s_bak_sig_mgr; /* backup signal manager for system signals */ sys_map_t s_notify_pending; /* bit map with pending notifications */ + sys_map_t s_asyn_pending; /* bit map with pending asyn messages */ irq_id_t s_int_pending; /* pending hardware interrupts */ sigset_t s_sig_pending; /* pending signals */ diff --git a/kernel/proc.c b/kernel/proc.c index badb72f70..1cbb307c5 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -54,6 +54,7 @@ FORWARD _PROTOTYPE( void idle, (void)); FORWARD _PROTOTYPE( int mini_send, (struct proc *caller_ptr, endpoint_t dst_e, message *m_ptr, int flags)); */ +FORWARD _PROTOTYPE( int has_pending, (sys_map_t *map, int src_p) ); FORWARD _PROTOTYPE( int mini_receive, (struct proc *caller_ptr, endpoint_t src, message *m_ptr, int flags)); FORWARD _PROTOTYPE( int mini_senda, (struct proc *caller_ptr, @@ -61,8 +62,7 @@ FORWARD _PROTOTYPE( int mini_senda, (struct proc *caller_ptr, FORWARD _PROTOTYPE( int deadlock, (int function, register struct proc *caller, endpoint_t src_dst_e)); FORWARD _PROTOTYPE( int try_async, (struct proc *caller_ptr)); -FORWARD _PROTOTYPE( int try_one, (struct proc *src_ptr, struct proc *dst_ptr, - int *postponed)); +FORWARD _PROTOTYPE( int try_one, (struct proc *src_ptr, struct proc *dst_ptr)); FORWARD _PROTOTYPE( struct proc * pick_proc, (void)); FORWARD _PROTOTYPE( void enqueue_head, (struct proc *rp)); @@ -688,6 +688,41 @@ endpoint_t src_dst_e; /* src or dst process */ return(0); /* not a deadlock */ } +/*===========================================================================* + * has_pending * + *===========================================================================*/ +PRIVATE int has_pending(sys_map_t *map, int src_p) +{ +/* Check to see if there is a pending message from the desired source + * available. + */ + + int src_id; + sys_id_t id = NULL_PRIV_ID; + + /* Either check a specific bit in the mask map, or find the first bit set in + * it (if any), depending on whether the receive was called on a specific + * source endpoint. + */ + if (src_p != ANY) { + src_id = nr_to_id(src_p); + if (get_sys_bit(*map, src_id)) + id = src_id; + } else { + /* Find a source with a pending message */ + for (src_id = 0; src_id < NR_SYS_PROCS; src_id += BITCHUNK_BITS) { + if (get_sys_bits(*map, src_id) != 0) { + while(!get_sys_bit(*map, src_id)) src_id++; + break; + } + } + if (src_id < NR_SYS_PROCS) /* Found one */ + id = src_id; + } + + return(id); +} + /*===========================================================================* * mini_send * *===========================================================================*/ @@ -799,7 +834,7 @@ PRIVATE int mini_receive(struct proc * caller_ptr, */ register struct proc **xpp; sys_map_t *map; - int i, r, src_id, found, src_proc_nr, src_p; + int i, r, src_id, src_proc_nr, src_p; assert(!(caller_ptr->p_misc_flags & MF_DELIVERMSG)); @@ -827,27 +862,8 @@ PRIVATE int mini_receive(struct proc * caller_ptr, if (! (caller_ptr->p_misc_flags & MF_REPLY_PEND)) { map = &priv(caller_ptr)->s_notify_pending; - /* Either check a specific bit in the pending notifications mask, or - * find the first bit set in it (if any), depending on whether the - * receive was called on a specific source endpoint. - */ - if (src_p != ANY) { - src_id = nr_to_id(src_p); - - found = get_sys_bit(*map, src_id); - } else { - for (src_id = 0; src_id < NR_SYS_PROCS; src_id += BITCHUNK_BITS) { - if (get_sys_bits(*map, src_id) != 0) { - while (!get_sys_bit(*map, src_id)) src_id++; - - break; - } - } - - found = (src_id < NR_SYS_PROCS); - } - - if (found) { + /* Check for pending notifications */ + if ((src_id = has_pending(map, src_p)) != NULL_PRIV_ID) { endpoint_t hisep; src_proc_nr = id_to_nr(src_id); /* get source proc */ @@ -874,17 +890,19 @@ PRIVATE int mini_receive(struct proc * caller_ptr, } } - /* Check if there are pending senda(). */ - if (caller_ptr->p_misc_flags & MF_ASYNMSG) { - if (src_e != ANY) - r = try_one(proc_addr(src_p), caller_ptr, NULL); - else - r = try_async(caller_ptr); + /* Check for pending asynchronous messages */ + map = &priv(caller_ptr)->s_asyn_pending; + + if (has_pending(map, src_p) != NULL_PRIV_ID) { + if (src_p != ANY) + r = try_one(proc_addr(src_p), caller_ptr); + else + r = try_async(caller_ptr); if (r == OK) { - IPC_STATUS_ADD_CALL(caller_ptr, SENDA); - goto receive_done; - } + IPC_STATUS_ADD_CALL(caller_ptr, SENDA); + goto receive_done; + } } /* Check caller queue. Use pointer pointers to keep code simple. */ @@ -1050,7 +1068,8 @@ field, caller->p_name, entry, priv(caller)->s_asynsize, priv(caller)->s_asyntab) *===========================================================================*/ PRIVATE int mini_senda(struct proc *caller_ptr, asynmsg_t *table, size_t size) { - int r = OK, i, dst_p, done, do_notify; + int r = OK, dst_p, done, do_notify; + unsigned int i; unsigned flags; endpoint_t dst; struct proc *dst_ptr; @@ -1126,8 +1145,9 @@ PRIVATE int mini_senda(struct proc *caller_ptr, asynmsg_t *table, size_t size) IPC_STATUS_ADD_CALL(dst_ptr, SENDA); RTS_UNSET(dst_ptr, RTS_RECEIVING); } else if (r == OK) { - /* Should inform receiver that something is pending */ - dst_ptr->p_misc_flags |= MF_ASYNMSG; + /* Inform receiver that something is pending */ + set_sys_bit(priv(dst_ptr)->s_asyn_pending, + priv(caller_ptr)->s_id); pending_recv = TRUE; } @@ -1164,7 +1184,6 @@ struct proc *caller_ptr; int r; struct priv *privp; struct proc *src_ptr; - int postponed = FALSE; /* Try all privilege structures */ for (privp = BEG_PRIV_ADDR; privp < END_PRIV_ADDR; ++privp) { @@ -1174,15 +1193,10 @@ struct proc *caller_ptr; src_ptr = proc_addr(privp->s_proc_nr); assert(!(caller_ptr->p_misc_flags & MF_DELIVERMSG)); - r = try_one(src_ptr, caller_ptr, &postponed); - if (r == OK) + if ((r = try_one(src_ptr, caller_ptr)) == OK) return(r); } - /* Nothing found, clear MF_ASYNMSG unless messages were postponed */ - if (postponed == FALSE) - caller_ptr->p_misc_flags &= ~MF_ASYNMSG; - return(ESRCH); } @@ -1190,10 +1204,11 @@ struct proc *caller_ptr; /*===========================================================================* * try_one * *===========================================================================*/ -PRIVATE int try_one(struct proc *src_ptr, struct proc *dst_ptr, int *postponed) +PRIVATE int try_one(struct proc *src_ptr, struct proc *dst_ptr) { - int r = EAGAIN, i, done, do_notify, pending_recv = FALSE; - unsigned flags; +/* Try to receive an asynchronous message from 'src_ptr' */ + int r = EAGAIN, done, do_notify, pending_recv = FALSE; + unsigned int flags, i; size_t size; endpoint_t dst; struct proc *caller_ptr; @@ -1206,9 +1221,10 @@ PRIVATE int try_one(struct proc *src_ptr, struct proc *dst_ptr, int *postponed) size = privp->s_asynsize; table_v = privp->s_asyntab; - /* Clear table */ + /* Clear table pending message flag. We're done unless we're not. */ privp->s_asyntab = -1; privp->s_asynsize = 0; + unset_sys_bit(priv(dst_ptr)->s_asyn_pending, privp->s_id); if (size == 0) return(EAGAIN); if (!may_send_to(src_ptr, proc_nr(dst_ptr))) return(EAGAIN); @@ -1253,12 +1269,8 @@ PRIVATE int try_one(struct proc *src_ptr, struct proc *dst_ptr, int *postponed) * SENDREC and thus should not satisfy the receiving part of the * SENDREC. This message is to be delivered later. */ - if ((flags & AMF_NOREPLY) && (dst_ptr->p_misc_flags & MF_REPLY_PEND)) { - if (postponed != NULL) - *postponed = TRUE; - + if ((flags & AMF_NOREPLY) && (dst_ptr->p_misc_flags & MF_REPLY_PEND)) continue; - } /* Destination is ready to receive the message; deliver it */ dst_ptr->p_delivermsg = tabent.msg; @@ -1280,6 +1292,7 @@ PRIVATE int try_one(struct proc *src_ptr, struct proc *dst_ptr, int *postponed) if (!done) { privp->s_asyntab = table_v; privp->s_asynsize = size; + set_sys_bit(priv(dst_ptr)->s_asyn_pending, privp->s_id); } return(r); diff --git a/kernel/system.c b/kernel/system.c index 029738b7e..71bdf5360 100644 --- a/kernel/system.c +++ b/kernel/system.c @@ -599,12 +599,8 @@ int caller_ret; /* code to return on callers */ /* Unset pending notification bits. */ unset_sys_bit(priv(rp)->s_notify_pending, priv(rc)->s_id); - /* XXX FIXME: Cleanup should be done for senda() as well. For this to be - * done in a realistic way, we need a better implementation of senda - * with a bitmap similar to s_notify_pending for notify() rather than - * a single global MF_ASYNMSG flag. The current arrangement exposes - * several performance issues. - */ + /* Unset pending asynchronous messages */ + unset_sys_bit(priv(rp)->s_asyn_pending, priv(rc)->s_id); /* Check if process depends on given process. */ if (P_BLOCKEDON(rp) == rc->p_endpoint) {