Kernel: try_async/try_one fixes

- skip processes that are not asynsending to the target
- do not clear whole asynsend table upon IPC permission error
- be more accepting when one table entry is bogus later on
This commit is contained in:
David van Moolenbroek 2011-04-18 22:56:34 +00:00
parent afb8067c4f
commit 46cee00ad8

View file

@ -1186,12 +1186,18 @@ struct proc *caller_ptr;
int r; int r;
struct priv *privp; struct priv *privp;
struct proc *src_ptr; struct proc *src_ptr;
sys_map_t *map;
map = &priv(caller_ptr)->s_asyn_pending;
/* Try all privilege structures */ /* Try all privilege structures */
for (privp = BEG_PRIV_ADDR; privp < END_PRIV_ADDR; ++privp) { for (privp = BEG_PRIV_ADDR; privp < END_PRIV_ADDR; ++privp) {
if (privp->s_proc_nr == NONE) if (privp->s_proc_nr == NONE)
continue; continue;
if (!get_sys_bit(*map, privp->s_id))
continue;
src_ptr = proc_addr(privp->s_proc_nr); src_ptr = proc_addr(privp->s_proc_nr);
assert(!(caller_ptr->p_misc_flags & MF_DELIVERMSG)); assert(!(caller_ptr->p_misc_flags & MF_DELIVERMSG));
@ -1224,8 +1230,6 @@ PRIVATE int try_one(struct proc *src_ptr, struct proc *dst_ptr)
table_v = privp->s_asyntab; table_v = privp->s_asyntab;
/* Clear table pending message flag. We're done unless we're not. */ /* 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); unset_sys_bit(priv(dst_ptr)->s_asyn_pending, privp->s_id);
if (size == 0) return(EAGAIN); if (size == 0) return(EAGAIN);
@ -1234,13 +1238,13 @@ PRIVATE int try_one(struct proc *src_ptr, struct proc *dst_ptr)
caller_ptr = src_ptr; /* Needed for A_ macros later on */ caller_ptr = src_ptr; /* Needed for A_ macros later on */
/* Scan the table */ /* Scan the table */
do_notify = FALSE; /* XXX: this doesn't do anything? */ do_notify = FALSE;
done = TRUE; done = TRUE;
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
/* Process each entry in the table and store the result in the table. /* Process each entry in the table and store the result in the table.
* If we're done handling a message, copy the result to the sender. * If we're done handling a message, copy the result to the sender.
* Some checks done in mini_senda are duplicated here, as the sender * Some checks done in mini_senda are duplicated here, as the sender
* could've altered the contents of the table in the mean time. * could've altered the contents of the table in the meantime.
*/ */
/* Copy message to kernel */ /* Copy message to kernel */
@ -1257,9 +1261,6 @@ PRIVATE int try_one(struct proc *src_ptr, struct proc *dst_ptr)
r = EINVAL; r = EINVAL;
else if (flags & AMF_DONE) continue; /* Already done processing */ else if (flags & AMF_DONE) continue; /* Already done processing */
if (r == EINVAL)
goto store_result;
/* Clear done flag. The sender is done sending when all messages in the /* Clear done flag. The sender is done sending when all messages in the
* table are marked done or empty. However, we will know that only * table are marked done or empty. However, we will know that only
* the next time we enter this function or when the sender decides to * the next time we enter this function or when the sender decides to
@ -1268,6 +1269,9 @@ PRIVATE int try_one(struct proc *src_ptr, struct proc *dst_ptr)
*/ */
done = FALSE; done = FALSE;
if (r == EINVAL)
goto store_result;
/* Message must be directed at receiving end */ /* Message must be directed at receiving end */
if (dst != dst_ptr->p_endpoint) continue; if (dst != dst_ptr->p_endpoint) continue;
@ -1298,10 +1302,11 @@ store_result:
if (do_notify) if (do_notify)
mini_notify(proc_addr(ASYNCM), src_ptr->p_endpoint); mini_notify(proc_addr(ASYNCM), src_ptr->p_endpoint);
if (!done) { if (done) {
privp->s_asyntab = table_v; privp->s_asyntab = -1;
privp->s_asynsize = size; privp->s_asynsize = 0;
set_sys_bit(priv(dst_ptr)->s_asyn_pending, privp->s_id); } else {
set_sys_bit(priv(dst_ptr)->s_asyn_pending, privp->s_id);
} }
return(r); return(r);