Use a bitmap for pending asynchronous messages instead of a global flag.

That way it works similar to pending notifications.
This commit is contained in:
Thomas Veerman 2011-04-08 15:03:33 +00:00
parent 9db2311b22
commit 16e0e9370e
3 changed files with 68 additions and 58 deletions

View file

@ -38,6 +38,7 @@ struct priv {
endpoint_t s_sig_mgr; /* signal manager for system signals */ endpoint_t s_sig_mgr; /* signal manager for system signals */
endpoint_t s_bak_sig_mgr; /* backup 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_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 */ irq_id_t s_int_pending; /* pending hardware interrupts */
sigset_t s_sig_pending; /* pending signals */ sigset_t s_sig_pending; /* pending signals */

View file

@ -54,6 +54,7 @@ FORWARD _PROTOTYPE( void idle, (void));
FORWARD _PROTOTYPE( int mini_send, (struct proc *caller_ptr, endpoint_t dst_e, FORWARD _PROTOTYPE( int mini_send, (struct proc *caller_ptr, endpoint_t dst_e,
message *m_ptr, int flags)); 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, FORWARD _PROTOTYPE( int mini_receive, (struct proc *caller_ptr, endpoint_t src,
message *m_ptr, int flags)); message *m_ptr, int flags));
FORWARD _PROTOTYPE( int mini_senda, (struct proc *caller_ptr, 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, FORWARD _PROTOTYPE( int deadlock, (int function,
register struct proc *caller, endpoint_t src_dst_e)); register struct proc *caller, endpoint_t src_dst_e));
FORWARD _PROTOTYPE( int try_async, (struct proc *caller_ptr)); FORWARD _PROTOTYPE( int try_async, (struct proc *caller_ptr));
FORWARD _PROTOTYPE( int try_one, (struct proc *src_ptr, struct proc *dst_ptr, FORWARD _PROTOTYPE( int try_one, (struct proc *src_ptr, struct proc *dst_ptr));
int *postponed));
FORWARD _PROTOTYPE( struct proc * pick_proc, (void)); FORWARD _PROTOTYPE( struct proc * pick_proc, (void));
FORWARD _PROTOTYPE( void enqueue_head, (struct proc *rp)); 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 */ 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 * * mini_send *
*===========================================================================*/ *===========================================================================*/
@ -799,7 +834,7 @@ PRIVATE int mini_receive(struct proc * caller_ptr,
*/ */
register struct proc **xpp; register struct proc **xpp;
sys_map_t *map; 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)); 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)) { if (! (caller_ptr->p_misc_flags & MF_REPLY_PEND)) {
map = &priv(caller_ptr)->s_notify_pending; map = &priv(caller_ptr)->s_notify_pending;
/* Either check a specific bit in the pending notifications mask, or /* Check for pending notifications */
* find the first bit set in it (if any), depending on whether the if ((src_id = has_pending(map, src_p)) != NULL_PRIV_ID) {
* 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) {
endpoint_t hisep; endpoint_t hisep;
src_proc_nr = id_to_nr(src_id); /* get source proc */ 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(). */ /* Check for pending asynchronous messages */
if (caller_ptr->p_misc_flags & MF_ASYNMSG) { map = &priv(caller_ptr)->s_asyn_pending;
if (src_e != ANY)
r = try_one(proc_addr(src_p), caller_ptr, NULL); if (has_pending(map, src_p) != NULL_PRIV_ID) {
else if (src_p != ANY)
r = try_async(caller_ptr); r = try_one(proc_addr(src_p), caller_ptr);
else
r = try_async(caller_ptr);
if (r == OK) { if (r == OK) {
IPC_STATUS_ADD_CALL(caller_ptr, SENDA); IPC_STATUS_ADD_CALL(caller_ptr, SENDA);
goto receive_done; goto receive_done;
} }
} }
/* Check caller queue. Use pointer pointers to keep code simple. */ /* 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) 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; unsigned flags;
endpoint_t dst; endpoint_t dst;
struct proc *dst_ptr; 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); IPC_STATUS_ADD_CALL(dst_ptr, SENDA);
RTS_UNSET(dst_ptr, RTS_RECEIVING); RTS_UNSET(dst_ptr, RTS_RECEIVING);
} else if (r == OK) { } else if (r == OK) {
/* Should inform receiver that something is pending */ /* Inform receiver that something is pending */
dst_ptr->p_misc_flags |= MF_ASYNMSG; set_sys_bit(priv(dst_ptr)->s_asyn_pending,
priv(caller_ptr)->s_id);
pending_recv = TRUE; pending_recv = TRUE;
} }
@ -1164,7 +1184,6 @@ struct proc *caller_ptr;
int r; int r;
struct priv *privp; struct priv *privp;
struct proc *src_ptr; struct proc *src_ptr;
int postponed = FALSE;
/* 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) {
@ -1174,15 +1193,10 @@ struct proc *caller_ptr;
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));
r = try_one(src_ptr, caller_ptr, &postponed); if ((r = try_one(src_ptr, caller_ptr)) == OK)
if (r == OK)
return(r); return(r);
} }
/* Nothing found, clear MF_ASYNMSG unless messages were postponed */
if (postponed == FALSE)
caller_ptr->p_misc_flags &= ~MF_ASYNMSG;
return(ESRCH); return(ESRCH);
} }
@ -1190,10 +1204,11 @@ struct proc *caller_ptr;
/*===========================================================================* /*===========================================================================*
* try_one * * 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; /* Try to receive an asynchronous message from 'src_ptr' */
unsigned flags; int r = EAGAIN, done, do_notify, pending_recv = FALSE;
unsigned int flags, i;
size_t size; size_t size;
endpoint_t dst; endpoint_t dst;
struct proc *caller_ptr; 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; size = privp->s_asynsize;
table_v = privp->s_asyntab; 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_asyntab = -1;
privp->s_asynsize = 0; privp->s_asynsize = 0;
unset_sys_bit(priv(dst_ptr)->s_asyn_pending, privp->s_id);
if (size == 0) return(EAGAIN); if (size == 0) return(EAGAIN);
if (!may_send_to(src_ptr, proc_nr(dst_ptr))) 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 and thus should not satisfy the receiving part of the
* SENDREC. This message is to be delivered later. * SENDREC. This message is to be delivered later.
*/ */
if ((flags & AMF_NOREPLY) && (dst_ptr->p_misc_flags & MF_REPLY_PEND)) { if ((flags & AMF_NOREPLY) && (dst_ptr->p_misc_flags & MF_REPLY_PEND))
if (postponed != NULL)
*postponed = TRUE;
continue; continue;
}
/* Destination is ready to receive the message; deliver it */ /* Destination is ready to receive the message; deliver it */
dst_ptr->p_delivermsg = tabent.msg; 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) { if (!done) {
privp->s_asyntab = table_v; privp->s_asyntab = table_v;
privp->s_asynsize = size; privp->s_asynsize = size;
set_sys_bit(priv(dst_ptr)->s_asyn_pending, privp->s_id);
} }
return(r); return(r);

View file

@ -599,12 +599,8 @@ int caller_ret; /* code to return on callers */
/* Unset pending notification bits. */ /* Unset pending notification bits. */
unset_sys_bit(priv(rp)->s_notify_pending, priv(rc)->s_id); 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 /* Unset pending asynchronous messages */
* done in a realistic way, we need a better implementation of senda unset_sys_bit(priv(rp)->s_asyn_pending, priv(rc)->s_id);
* 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.
*/
/* Check if process depends on given process. */ /* Check if process depends on given process. */
if (P_BLOCKEDON(rp) == rc->p_endpoint) { if (P_BLOCKEDON(rp) == rc->p_endpoint) {