Clean and support for asynchronous sends.
This commit is contained in:
parent
47233bdf30
commit
c59b23859e
1 changed files with 482 additions and 66 deletions
508
kernel/proc.c
508
kernel/proc.c
|
@ -42,6 +42,7 @@
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
#include "proc.h"
|
#include "proc.h"
|
||||||
|
#include <stddef.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <minix/portio.h>
|
#include <minix/portio.h>
|
||||||
|
|
||||||
|
@ -54,8 +55,12 @@ FORWARD _PROTOTYPE( int mini_send, (struct proc *caller_ptr, int dst_e,
|
||||||
FORWARD _PROTOTYPE( int mini_receive, (struct proc *caller_ptr, int src,
|
FORWARD _PROTOTYPE( int mini_receive, (struct proc *caller_ptr, int src,
|
||||||
message *m_ptr, unsigned flags));
|
message *m_ptr, unsigned flags));
|
||||||
FORWARD _PROTOTYPE( int mini_notify, (struct proc *caller_ptr, int dst));
|
FORWARD _PROTOTYPE( int mini_notify, (struct proc *caller_ptr, int dst));
|
||||||
|
FORWARD _PROTOTYPE( int mini_senda, (struct proc *caller_ptr,
|
||||||
|
asynmsg_t *table, size_t size));
|
||||||
FORWARD _PROTOTYPE( int deadlock, (int function,
|
FORWARD _PROTOTYPE( int deadlock, (int function,
|
||||||
register struct proc *caller, int src_dst));
|
register struct proc *caller, int src_dst));
|
||||||
|
FORWARD _PROTOTYPE( int try_async, (struct proc *caller_ptr));
|
||||||
|
FORWARD _PROTOTYPE( int try_one, (struct proc *src_ptr, struct proc *dst_ptr));
|
||||||
FORWARD _PROTOTYPE( void enqueue, (struct proc *rp));
|
FORWARD _PROTOTYPE( void enqueue, (struct proc *rp));
|
||||||
FORWARD _PROTOTYPE( void dequeue, (struct proc *rp));
|
FORWARD _PROTOTYPE( void dequeue, (struct proc *rp));
|
||||||
FORWARD _PROTOTYPE( void sched, (struct proc *rp, int *queue, int *front));
|
FORWARD _PROTOTYPE( void sched, (struct proc *rp, int *queue, int *front));
|
||||||
|
@ -95,12 +100,10 @@ long bit_map; /* notification event set or flags */
|
||||||
* (or both). The caller is always given by 'proc_ptr'.
|
* (or both). The caller is always given by 'proc_ptr'.
|
||||||
*/
|
*/
|
||||||
register struct proc *caller_ptr = proc_ptr; /* get pointer to caller */
|
register struct proc *caller_ptr = proc_ptr; /* get pointer to caller */
|
||||||
int function = call_nr & SYSCALL_FUNC; /* get system call function */
|
|
||||||
unsigned flags = call_nr & SYSCALL_FLAGS; /* get flags */
|
|
||||||
int mask_entry; /* bit to check in send mask */
|
int mask_entry; /* bit to check in send mask */
|
||||||
int group_size; /* used for deadlock check */
|
int group_size; /* used for deadlock check */
|
||||||
int result; /* the system call's result */
|
int result; /* the system call's result */
|
||||||
int src_dst;
|
int src_dst_p; /* Process slot number */
|
||||||
vir_clicks vlo, vhi; /* virtual clicks containing message to send */
|
vir_clicks vlo, vhi; /* virtual clicks containing message to send */
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
|
@ -111,69 +114,132 @@ long bit_map; /* notification event set or flags */
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Require a valid source and/ or destination process, unless echoing. */
|
/* Check destination. SENDA is special because its argument is a table and
|
||||||
if (src_dst_e != ANY && function != ECHO) {
|
* not a single destination. RECEIVE is the only call that accepts ANY (in
|
||||||
if(!isokendpt(src_dst_e, &src_dst)) {
|
* addition to a real endpoint). The other calls (SEND, SENDNB, SENDREC,
|
||||||
|
* and NOTIFY) require an endpoint to corresponds to a process. In addition,
|
||||||
|
* it is necessary to check whether a process is allow to send to a given
|
||||||
|
* destination. For SENDREC we check s_ipc_sendrec, and for SEND, SENDNB,
|
||||||
|
* and NOTIFY we check s_ipc_to.
|
||||||
|
*/
|
||||||
|
if (call_nr == SENDA)
|
||||||
|
{
|
||||||
|
/* No destination argument */
|
||||||
|
}
|
||||||
|
else if (src_dst_e == ANY)
|
||||||
|
{
|
||||||
|
if (call_nr != RECEIVE)
|
||||||
|
{
|
||||||
#if DEBUG_ENABLE_IPC_WARNINGS
|
#if DEBUG_ENABLE_IPC_WARNINGS
|
||||||
kprintf("sys_call: trap %d by %d with bad endpoint %d\n",
|
kprintf("sys_call: trap %d by %d with bad endpoint %d\n",
|
||||||
function, proc_nr(caller_ptr), src_dst_e);
|
call_nr, proc_nr(caller_ptr), src_dst_e);
|
||||||
|
#endif
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
src_dst_p = src_dst_e;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Require a valid source and/or destination process. */
|
||||||
|
if(!isokendpt(src_dst_e, &src_dst_p)) {
|
||||||
|
if (src_dst_e == 0) panic("sys_call: no PM", NO_NUM);
|
||||||
|
#if DEBUG_ENABLE_IPC_WARNINGS
|
||||||
|
kprintf("sys_call: trap %d by %d with bad endpoint %d\n",
|
||||||
|
call_nr, proc_nr(caller_ptr), src_dst_e);
|
||||||
#endif
|
#endif
|
||||||
return EDEADSRCDST;
|
return EDEADSRCDST;
|
||||||
}
|
}
|
||||||
} else src_dst = src_dst_e;
|
|
||||||
|
/* If the call is to send to a process, i.e., for SEND, SENDNB,
|
||||||
|
* SENDREC or NOTIFY, verify that the caller is allowed to send to
|
||||||
|
* the given destination.
|
||||||
|
*/
|
||||||
|
if (call_nr == SENDREC)
|
||||||
|
{
|
||||||
|
if (! get_sys_bit(priv(caller_ptr)->s_ipc_sendrec,
|
||||||
|
nr_to_id(src_dst_p))) {
|
||||||
|
#if DEBUG_ENABLE_IPC_WARNINGS
|
||||||
|
kprintf(
|
||||||
|
"sys_call: ipc sendrec mask denied trap %d from %d to %d\n",
|
||||||
|
call_nr, proc_nr(caller_ptr), src_dst_p);
|
||||||
|
#endif
|
||||||
|
return(ECALLDENIED); /* call denied by ipc mask */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (call_nr == SEND || call_nr == SENDNB || call_nr == NOTIFY)
|
||||||
|
{
|
||||||
|
if (! get_sys_bit(priv(caller_ptr)->s_ipc_to,
|
||||||
|
nr_to_id(src_dst_p))) {
|
||||||
|
#if DEBUG_ENABLE_IPC_WARNINGS
|
||||||
|
kprintf(
|
||||||
|
"sys_call: ipc mask denied trap %d from %d to %d\n",
|
||||||
|
call_nr, proc_nr(caller_ptr), src_dst_p);
|
||||||
|
#endif
|
||||||
|
return(ECALLDENIED); /* call denied by ipc mask */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only allow non-negative call_nr values less than 32 */
|
||||||
|
if (call_nr < 0 || call_nr >= 32)
|
||||||
|
{
|
||||||
|
#if DEBUG_ENABLE_IPC_WARNINGS
|
||||||
|
kprintf("sys_call: trap %d not allowed, caller %d, src_dst %d\n",
|
||||||
|
call_nr, proc_nr(caller_ptr), src_dst_p);
|
||||||
|
#endif
|
||||||
|
return(ETRAPDENIED); /* trap denied by mask or kernel */
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if the process has privileges for the requested call. Calls to the
|
/* Check if the process has privileges for the requested call. Calls to the
|
||||||
* kernel may only be SENDREC, because tasks always reply and may not block
|
* kernel may only be SENDREC, because tasks always reply and may not block
|
||||||
* if the caller doesn't do receive().
|
* if the caller doesn't do receive().
|
||||||
*/
|
*/
|
||||||
if (! (priv(caller_ptr)->s_trap_mask & (1 << function)) ||
|
if (!(priv(caller_ptr)->s_trap_mask & (1 << call_nr))) {
|
||||||
(iskerneln(src_dst) && function != SENDREC
|
#if DEBUG_ENABLE_IPC_WARNINGS
|
||||||
&& function != RECEIVE)) {
|
kprintf("sys_call: trap %d not allowed, caller %d, src_dst %d\n",
|
||||||
|
call_nr, proc_nr(caller_ptr), src_dst_p);
|
||||||
|
#endif
|
||||||
|
return(ETRAPDENIED); /* trap denied by mask or kernel */
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if ((iskerneln(src_dst_p) && _function != SENDREC
|
||||||
|
&& _function != RECEIVE)) {
|
||||||
#if DEBUG_ENABLE_IPC_WARNINGS
|
#if DEBUG_ENABLE_IPC_WARNINGS
|
||||||
kprintf("sys_call: trap %d not allowed, caller %d, src_dst %d\n",
|
kprintf("sys_call: trap %d not allowed, caller %d, src_dst %d\n",
|
||||||
function, proc_nr(caller_ptr), src_dst);
|
function, proc_nr(caller_ptr), src_dst);
|
||||||
#endif
|
#endif
|
||||||
return(ETRAPDENIED); /* trap denied by mask or kernel */
|
return(ETRAPDENIED); /* trap denied by mask or kernel */
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* If the call involves a message buffer, i.e., for SEND, RECEIVE, SENDREC,
|
/* If the call involves a message buffer, i.e., for SEND, SENDNB, SENDREC,
|
||||||
* or ECHO, check the message pointer. This check allows a message to be
|
* or RECEIVE, check the message pointer. This check allows a message to be
|
||||||
* anywhere in data or stack or gap. It will have to be made more elaborate
|
* anywhere in data or stack or gap. It will have to be made more elaborate
|
||||||
* for machines which don't have the gap mapped.
|
* for machines which don't have the gap mapped.
|
||||||
*/
|
*/
|
||||||
if (function & CHECK_PTR) {
|
if (call_nr == SEND || call_nr == SENDNB || call_nr == SENDREC ||
|
||||||
|
call_nr == RECEIVE) {
|
||||||
vlo = (vir_bytes) m_ptr >> CLICK_SHIFT;
|
vlo = (vir_bytes) m_ptr >> CLICK_SHIFT;
|
||||||
vhi = ((vir_bytes) m_ptr + MESS_SIZE - 1) >> CLICK_SHIFT;
|
vhi = ((vir_bytes) m_ptr + MESS_SIZE - 1) >> CLICK_SHIFT;
|
||||||
if (vlo < caller_ptr->p_memmap[D].mem_vir || vlo > vhi ||
|
if (vlo < caller_ptr->p_memmap[D].mem_vir || vlo > vhi ||
|
||||||
vhi >= caller_ptr->p_memmap[S].mem_vir +
|
vhi >= caller_ptr->p_memmap[S].mem_vir +
|
||||||
caller_ptr->p_memmap[S].mem_len) {
|
caller_ptr->p_memmap[S].mem_len) {
|
||||||
#if DEBUG_ENABLE_IPC_WARNINGS
|
#if DEBUG_ENABLE_IPC_WARNINGS
|
||||||
kprintf("sys_call: invalid message pointer, trap %d, caller %d\n",
|
kprintf(
|
||||||
function, proc_nr(caller_ptr));
|
"sys_call: invalid message pointer, trap %d, caller %d\n",
|
||||||
|
call_nr, proc_nr(caller_ptr));
|
||||||
#endif
|
#endif
|
||||||
return(EFAULT); /* invalid message pointer */
|
return(EFAULT); /* invalid message pointer */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the call is to send to a process, i.e., for SEND, SENDREC or NOTIFY,
|
|
||||||
* verify that the caller is allowed to send to the given destination.
|
|
||||||
*/
|
|
||||||
if (function & CHECK_DST) {
|
|
||||||
if (! get_sys_bit(priv(caller_ptr)->s_ipc_to, nr_to_id(src_dst))) {
|
|
||||||
#if DEBUG_ENABLE_IPC_WARNINGS
|
|
||||||
kprintf("sys_call: ipc mask denied trap %d from %d to %d\n",
|
|
||||||
function, proc_nr(caller_ptr), src_dst);
|
|
||||||
#endif
|
|
||||||
return(ECALLDENIED); /* call denied by ipc mask */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check for a possible deadlock for blocking SEND(REC) and RECEIVE. */
|
/* Check for a possible deadlock for blocking SEND(REC) and RECEIVE. */
|
||||||
if (function & CHECK_DEADLOCK) {
|
if (call_nr == SEND || call_nr == SENDREC || call_nr == RECEIVE) {
|
||||||
if (group_size = deadlock(function, caller_ptr, src_dst)) {
|
if (group_size = deadlock(call_nr, caller_ptr, src_dst_p)) {
|
||||||
#if DEBUG_ENABLE_IPC_WARNINGS
|
#if DEBUG_ENABLE_IPC_WARNINGS
|
||||||
kprintf("sys_call: trap %d from %d to %d deadlocked, group size %d\n",
|
kprintf("sys_call: trap %d from %d to %d deadlocked, group size %d\n",
|
||||||
function, proc_nr(caller_ptr), src_dst, group_size);
|
call_nr, proc_nr(caller_ptr), src_dst_p, group_size);
|
||||||
#endif
|
#endif
|
||||||
return(ELOCKED);
|
return(ELOCKED);
|
||||||
}
|
}
|
||||||
|
@ -184,30 +250,33 @@ long bit_map; /* notification event set or flags */
|
||||||
* - SENDREC: combines SEND and RECEIVE in a single system call
|
* - SENDREC: combines SEND and RECEIVE in a single system call
|
||||||
* - SEND: sender blocks until its message has been delivered
|
* - SEND: sender blocks until its message has been delivered
|
||||||
* - RECEIVE: receiver blocks until an acceptable message has arrived
|
* - RECEIVE: receiver blocks until an acceptable message has arrived
|
||||||
* - NOTIFY: nonblocking call; deliver notification or mark pending
|
* - NOTIFY: asynchronous call; deliver notification or mark pending
|
||||||
* - ECHO: nonblocking call; directly echo back the message
|
* - SENDNB: nonblocking send
|
||||||
|
* - SENDA: list of asynchronous send requests
|
||||||
*/
|
*/
|
||||||
switch(function) {
|
switch(call_nr) {
|
||||||
case SENDREC:
|
case SENDREC:
|
||||||
/* A flag is set so that notifications cannot interrupt SENDREC. */
|
/* A flag is set so that notifications cannot interrupt SENDREC. */
|
||||||
caller_ptr->p_misc_flags |= REPLY_PENDING;
|
caller_ptr->p_misc_flags |= REPLY_PENDING;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case SEND:
|
case SEND:
|
||||||
result = mini_send(caller_ptr, src_dst_e, m_ptr, flags);
|
result = mini_send(caller_ptr, src_dst_e, m_ptr, 0 /*flags*/);
|
||||||
if (function == SEND || result != OK) {
|
if (call_nr == SEND || result != OK)
|
||||||
break; /* done, or SEND failed */
|
break; /* done, or SEND failed */
|
||||||
} /* fall through for SENDREC */
|
/* fall through for SENDREC */
|
||||||
case RECEIVE:
|
case RECEIVE:
|
||||||
if (function == RECEIVE)
|
if (call_nr == RECEIVE)
|
||||||
caller_ptr->p_misc_flags &= ~REPLY_PENDING;
|
caller_ptr->p_misc_flags &= ~REPLY_PENDING;
|
||||||
result = mini_receive(caller_ptr, src_dst_e, m_ptr, flags);
|
result = mini_receive(caller_ptr, src_dst_e, m_ptr, 0 /*flags*/);
|
||||||
break;
|
break;
|
||||||
case NOTIFY:
|
case NOTIFY:
|
||||||
result = mini_notify(caller_ptr, src_dst);
|
result = mini_notify(caller_ptr, src_dst_p);
|
||||||
break;
|
break;
|
||||||
case ECHO:
|
case SENDNB:
|
||||||
CopyMess(caller_ptr->p_nr, caller_ptr, m_ptr, caller_ptr, m_ptr);
|
result = mini_send(caller_ptr, src_dst_e, m_ptr, NON_BLOCKING);
|
||||||
result = OK;
|
break;
|
||||||
|
case SENDA:
|
||||||
|
result = mini_senda(caller_ptr, (asynmsg_t *)m_ptr, (size_t)src_dst_e);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
result = EBADCALL; /* illegal system call */
|
result = EBADCALL; /* illegal system call */
|
||||||
|
@ -269,6 +338,7 @@ int src_dst; /* src or dst process */
|
||||||
return(0); /* not a deadlock */
|
return(0); /* not a deadlock */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* mini_send *
|
* mini_send *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -337,7 +407,7 @@ unsigned flags; /* system call flags */
|
||||||
int bit_nr;
|
int bit_nr;
|
||||||
sys_map_t *map;
|
sys_map_t *map;
|
||||||
bitchunk_t *chunk;
|
bitchunk_t *chunk;
|
||||||
int i, src_id, src_proc_nr, src_p;
|
int i, r, src_id, src_proc_nr, src_p;
|
||||||
|
|
||||||
if(src_e == ANY) src_p = ANY;
|
if(src_e == ANY) src_p = ANY;
|
||||||
else
|
else
|
||||||
|
@ -400,6 +470,24 @@ unsigned flags; /* system call flags */
|
||||||
}
|
}
|
||||||
xpp = &(*xpp)->p_q_link; /* proceed to next */
|
xpp = &(*xpp)->p_q_link; /* proceed to next */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (caller_ptr->p_misc_flags & MF_ASYNMSG)
|
||||||
|
{
|
||||||
|
if (src_e != ANY)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
kprintf("mini_receive: should try async from %d\n", src_e);
|
||||||
|
#endif
|
||||||
|
r= EAGAIN;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
caller_ptr->p_messbuf = m_ptr;
|
||||||
|
r= try_async(caller_ptr);
|
||||||
|
}
|
||||||
|
if (r == OK)
|
||||||
|
return OK; /* Got a message */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No suitable message is available or the caller couldn't send in SENDREC.
|
/* No suitable message is available or the caller couldn't send in SENDREC.
|
||||||
|
@ -454,6 +542,335 @@ int dst; /* which process to notify */
|
||||||
return(OK);
|
return(OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* mini_senda *
|
||||||
|
*===========================================================================*/
|
||||||
|
PRIVATE int mini_senda(caller_ptr, table, size)
|
||||||
|
struct proc *caller_ptr;
|
||||||
|
asynmsg_t *table;
|
||||||
|
size_t size;
|
||||||
|
{
|
||||||
|
int i, dst_p, done, do_notify;
|
||||||
|
unsigned flags;
|
||||||
|
phys_bytes tab_phys;
|
||||||
|
struct proc *dst_ptr;
|
||||||
|
struct priv *privp;
|
||||||
|
message *m_ptr;
|
||||||
|
asynmsg_t tabent;
|
||||||
|
|
||||||
|
privp= priv(caller_ptr);
|
||||||
|
if (!(privp->s_flags & SYS_PROC))
|
||||||
|
{
|
||||||
|
kprintf(
|
||||||
|
"mini_senda: warning caller has no privilege structure\n");
|
||||||
|
return EPERM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear table */
|
||||||
|
privp->s_asyntab= -1;
|
||||||
|
privp->s_asynsize= 0;
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
/* Nothing to do, just return */
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Limit size to something reasonable. An arbitrary choice is 16
|
||||||
|
* times the number of process table entries.
|
||||||
|
*/
|
||||||
|
if (size > 16*(NR_TASKS + NR_PROCS))
|
||||||
|
return EDOM;
|
||||||
|
|
||||||
|
/* Map table */
|
||||||
|
tab_phys= umap_local(caller_ptr, D, (vir_bytes)table,
|
||||||
|
size*sizeof(table[0]));
|
||||||
|
if (tab_phys == 0)
|
||||||
|
{
|
||||||
|
kprintf("mini_senda: got bad table pointer/size\n");
|
||||||
|
return EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scan the table */
|
||||||
|
do_notify= FALSE;
|
||||||
|
done= TRUE;
|
||||||
|
for (i= 0; i<size; i++)
|
||||||
|
{
|
||||||
|
/* Read status word */
|
||||||
|
phys_copy(tab_phys + i*sizeof(table[0]) +
|
||||||
|
offsetof(struct asynmsg, flags),
|
||||||
|
vir2phys(&tabent.flags), sizeof(tabent.flags));
|
||||||
|
flags= tabent.flags;
|
||||||
|
|
||||||
|
/* Skip empty entries */
|
||||||
|
if (flags == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Check for reserved bits in the flags field */
|
||||||
|
if (flags & ~(AMF_VALID|AMF_DONE|AMF_NOTIFY) ||
|
||||||
|
!(flags & AMF_VALID))
|
||||||
|
{
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip entry is AMF_DONE is already set */
|
||||||
|
if (flags & AMF_DONE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Get destination */
|
||||||
|
phys_copy(tab_phys + i*sizeof(table[0]) +
|
||||||
|
offsetof(struct asynmsg, dst),
|
||||||
|
vir2phys(&tabent.dst), sizeof(tabent.dst));
|
||||||
|
|
||||||
|
if (!isokendpt(tabent.dst, &dst_p))
|
||||||
|
{
|
||||||
|
/* Bad destination, report the error */
|
||||||
|
tabent.result= EDEADSRCDST;
|
||||||
|
phys_copy(vir2phys(&tabent.result),
|
||||||
|
tab_phys + i*sizeof(table[0]) +
|
||||||
|
offsetof(struct asynmsg, result),
|
||||||
|
sizeof(tabent.result));
|
||||||
|
tabent.flags= flags | AMF_DONE;
|
||||||
|
phys_copy(vir2phys(&tabent.flags),
|
||||||
|
tab_phys + i*sizeof(table[0]) +
|
||||||
|
offsetof(struct asynmsg, flags),
|
||||||
|
sizeof(tabent.flags));
|
||||||
|
|
||||||
|
if (flags & AMF_NOTIFY)
|
||||||
|
do_notify= 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
kprintf("mini_senda: entry[%d]: flags 0x%x dst %d/%d\n",
|
||||||
|
i, tabent.flags, tabent.dst, dst_p);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
dst_ptr = proc_addr(dst_p);
|
||||||
|
|
||||||
|
/* NO_ENDPOINT should be removed */
|
||||||
|
if (dst_ptr->p_rts_flags & NO_ENDPOINT)
|
||||||
|
{
|
||||||
|
tabent.result= EDSTDIED;
|
||||||
|
phys_copy(vir2phys(&tabent.result),
|
||||||
|
tab_phys + i*sizeof(table[0]) +
|
||||||
|
offsetof(struct asynmsg, result),
|
||||||
|
sizeof(tabent.result));
|
||||||
|
tabent.flags= flags | AMF_DONE;
|
||||||
|
phys_copy(vir2phys(&tabent.flags),
|
||||||
|
tab_phys + i*sizeof(table[0]) +
|
||||||
|
offsetof(struct asynmsg, flags),
|
||||||
|
sizeof(tabent.flags));
|
||||||
|
|
||||||
|
if (flags & AMF_NOTIFY)
|
||||||
|
do_notify= TRUE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if 'dst' is blocked waiting for this message. The
|
||||||
|
* destination's SENDING flag may be set when its SENDREC call
|
||||||
|
* blocked while sending.
|
||||||
|
*/
|
||||||
|
if ( (dst_ptr->p_rts_flags & (RECEIVING | SENDING)) ==
|
||||||
|
RECEIVING &&
|
||||||
|
(dst_ptr->p_getfrom_e == ANY ||
|
||||||
|
dst_ptr->p_getfrom_e == caller_ptr->p_endpoint))
|
||||||
|
{
|
||||||
|
/* Destination is indeed waiting for this message. */
|
||||||
|
m_ptr= &table[i].msg; /* Note: pointer in the
|
||||||
|
* caller's address space.
|
||||||
|
*/
|
||||||
|
CopyMess(caller_ptr->p_nr, caller_ptr, m_ptr, dst_ptr,
|
||||||
|
dst_ptr->p_messbuf);
|
||||||
|
|
||||||
|
if ((dst_ptr->p_rts_flags &= ~RECEIVING) == 0)
|
||||||
|
enqueue(dst_ptr);
|
||||||
|
|
||||||
|
tabent.result= OK;
|
||||||
|
phys_copy(vir2phys(&tabent.result),
|
||||||
|
tab_phys + i*sizeof(table[0]) +
|
||||||
|
offsetof(struct asynmsg, result),
|
||||||
|
sizeof(tabent.result));
|
||||||
|
tabent.flags= flags | AMF_DONE;
|
||||||
|
phys_copy(vir2phys(&tabent.flags),
|
||||||
|
tab_phys + i*sizeof(table[0]) +
|
||||||
|
offsetof(struct asynmsg, flags),
|
||||||
|
sizeof(tabent.flags));
|
||||||
|
|
||||||
|
if (flags & AMF_NOTIFY)
|
||||||
|
do_notify= 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Should inform receiver that something is pending */
|
||||||
|
dst_ptr->p_misc_flags |= MF_ASYNMSG;
|
||||||
|
done= FALSE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (do_notify)
|
||||||
|
kprintf("mini_senda: should notifiy caller\n");
|
||||||
|
if (!done)
|
||||||
|
{
|
||||||
|
privp->s_asyntab= (vir_bytes)table;
|
||||||
|
privp->s_asynsize= size;
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* try_async *
|
||||||
|
*===========================================================================*/
|
||||||
|
PRIVATE int try_async(caller_ptr)
|
||||||
|
struct proc *caller_ptr;
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
struct priv *privp;
|
||||||
|
struct proc *src_ptr;
|
||||||
|
|
||||||
|
/* Try all privilege structures */
|
||||||
|
for (privp = BEG_PRIV_ADDR; privp < END_PRIV_ADDR; ++privp)
|
||||||
|
{
|
||||||
|
if (privp->s_proc_nr == NONE || privp->s_id == USER_PRIV_ID)
|
||||||
|
continue;
|
||||||
|
if (privp->s_asynsize == 0)
|
||||||
|
continue;
|
||||||
|
#if 0
|
||||||
|
kprintf("try_async: found asyntable for proc %d\n",
|
||||||
|
privp->s_proc_nr);
|
||||||
|
#endif
|
||||||
|
src_ptr= proc_addr(privp->s_proc_nr);
|
||||||
|
r= try_one(src_ptr, caller_ptr);
|
||||||
|
if (r == OK)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Nothing found, clear MF_ASYNMSG */
|
||||||
|
caller_ptr->p_misc_flags &= ~MF_ASYNMSG;
|
||||||
|
|
||||||
|
return ESRCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* try_one *
|
||||||
|
*===========================================================================*/
|
||||||
|
PRIVATE int try_one(src_ptr, dst_ptr)
|
||||||
|
struct proc *src_ptr;
|
||||||
|
struct proc *dst_ptr;
|
||||||
|
{
|
||||||
|
int i, do_notify, done;
|
||||||
|
unsigned flags;
|
||||||
|
size_t size;
|
||||||
|
endpoint_t dst_e;
|
||||||
|
phys_bytes tab_phys;
|
||||||
|
asynmsg_t *table_ptr;
|
||||||
|
message *m_ptr;
|
||||||
|
struct priv *privp;
|
||||||
|
asynmsg_t tabent;
|
||||||
|
|
||||||
|
privp= priv(src_ptr);
|
||||||
|
size= privp->s_asynsize;
|
||||||
|
|
||||||
|
dst_e= dst_ptr->p_endpoint;
|
||||||
|
|
||||||
|
/* Map table */
|
||||||
|
tab_phys= umap_local(src_ptr, D, privp->s_asyntab,
|
||||||
|
size*sizeof(tabent));
|
||||||
|
if (tab_phys == 0)
|
||||||
|
{
|
||||||
|
kprintf("try_one: got bad table pointer/size\n");
|
||||||
|
privp->s_asynsize= 0;
|
||||||
|
return EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scan the table */
|
||||||
|
do_notify= FALSE;
|
||||||
|
done= TRUE;
|
||||||
|
for (i= 0; i<size; i++)
|
||||||
|
{
|
||||||
|
/* Read status word */
|
||||||
|
phys_copy(tab_phys + i*sizeof(tabent) +
|
||||||
|
offsetof(struct asynmsg, flags),
|
||||||
|
vir2phys(&tabent.flags), sizeof(tabent.flags));
|
||||||
|
flags= tabent.flags;
|
||||||
|
|
||||||
|
/* Skip empty entries */
|
||||||
|
if (flags == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for reserved bits in the flags field */
|
||||||
|
if (flags & ~(AMF_VALID|AMF_DONE|AMF_NOTIFY) ||
|
||||||
|
!(flags & AMF_VALID))
|
||||||
|
{
|
||||||
|
kprintf("try_one: bad bits in table\n");
|
||||||
|
privp->s_asynsize= 0;
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip entry is AMF_DONE is already set */
|
||||||
|
if (flags & AMF_DONE)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear done. We are done when all entries are either empty
|
||||||
|
* or done at the start of the call.
|
||||||
|
*/
|
||||||
|
done= FALSE;
|
||||||
|
|
||||||
|
/* Get destination */
|
||||||
|
phys_copy(tab_phys + i*sizeof(tabent) +
|
||||||
|
offsetof(struct asynmsg, dst),
|
||||||
|
vir2phys(&tabent.dst), sizeof(tabent.dst));
|
||||||
|
|
||||||
|
if (tabent.dst != dst_e)
|
||||||
|
{
|
||||||
|
kprintf("try_one: wrong dst %d, looking for %d\n",
|
||||||
|
tabent.dst, dst_e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
kprintf("try_one: entry[%d]: flags 0x%x dst %d\n",
|
||||||
|
i, tabent.flags, tabent.dst);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Deliver message */
|
||||||
|
table_ptr= (asynmsg_t *)privp->s_asyntab;
|
||||||
|
m_ptr= &table_ptr[i].msg; /* Note: pointer in the
|
||||||
|
* caller's address space.
|
||||||
|
*/
|
||||||
|
CopyMess(src_ptr->p_nr, src_ptr, m_ptr, dst_ptr,
|
||||||
|
dst_ptr->p_messbuf);
|
||||||
|
|
||||||
|
tabent.result= OK;
|
||||||
|
phys_copy(vir2phys(&tabent.result),
|
||||||
|
tab_phys + i*sizeof(tabent) +
|
||||||
|
offsetof(struct asynmsg, result),
|
||||||
|
sizeof(tabent.result));
|
||||||
|
tabent.flags= flags | AMF_DONE;
|
||||||
|
phys_copy(vir2phys(&tabent.flags),
|
||||||
|
tab_phys + i*sizeof(tabent) +
|
||||||
|
offsetof(struct asynmsg, flags),
|
||||||
|
sizeof(tabent.flags));
|
||||||
|
|
||||||
|
if (flags & AMF_NOTIFY)
|
||||||
|
{
|
||||||
|
kprintf("try_one: should notify caller\n");
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
if (done)
|
||||||
|
privp->s_asynsize= 0;
|
||||||
|
return EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* lock_notify *
|
* lock_notify *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -785,4 +1202,3 @@ int *p, fatalflag;
|
||||||
}
|
}
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue