Enable sending a notification when sending of an asynchronous message was
completed (successfully or not). AMF_NOTIFY_ERR can be used if the sender only wishes to be notified in case of an error (e.g., EDEADSRCDST). A new endpoint ASYNCM will be the sender of the notification.
This commit is contained in:
parent
16e0e9370e
commit
7457cbe62f
6 changed files with 130 additions and 25 deletions
|
@ -54,6 +54,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Kernel tasks. These all run in the same address space. */
|
/* Kernel tasks. These all run in the same address space. */
|
||||||
|
#define ASYNCM ((endpoint_t) -5) /* notifies about finished async sends */
|
||||||
#define IDLE ((endpoint_t) -4) /* runs when no one else can run */
|
#define IDLE ((endpoint_t) -4) /* runs when no one else can run */
|
||||||
#define CLOCK ((endpoint_t) -3) /* alarms and other clock functions */
|
#define CLOCK ((endpoint_t) -3) /* alarms and other clock functions */
|
||||||
#define SYSTEM ((endpoint_t) -2) /* request system functionality */
|
#define SYSTEM ((endpoint_t) -2) /* request system functionality */
|
||||||
|
@ -62,7 +63,7 @@
|
||||||
|
|
||||||
/* Number of tasks. Note that NR_PROCS is defined in <minix/config.h>. */
|
/* Number of tasks. Note that NR_PROCS is defined in <minix/config.h>. */
|
||||||
#define MAX_NR_TASKS 1023
|
#define MAX_NR_TASKS 1023
|
||||||
#define NR_TASKS 4
|
#define NR_TASKS 5
|
||||||
|
|
||||||
/* User-space processes, that is, device drivers, servers, and INIT. */
|
/* User-space processes, that is, device drivers, servers, and INIT. */
|
||||||
#define PM_PROC_NR ((endpoint_t) 0) /* process manager */
|
#define PM_PROC_NR ((endpoint_t) 0) /* process manager */
|
||||||
|
|
|
@ -132,13 +132,15 @@ typedef struct asynmsg
|
||||||
} asynmsg_t;
|
} asynmsg_t;
|
||||||
|
|
||||||
/* Defines for flags field */
|
/* Defines for flags field */
|
||||||
#define AMF_EMPTY 0 /* slot is not inuse */
|
#define AMF_EMPTY 000 /* slot is not inuse */
|
||||||
#define AMF_VALID 1 /* slot contains message */
|
#define AMF_VALID 001 /* slot contains message */
|
||||||
#define AMF_DONE 2 /* Kernel has processed the message. The
|
#define AMF_DONE 002 /* Kernel has processed the message. The
|
||||||
* result is stored in 'result'
|
* result is stored in 'result'
|
||||||
*/
|
*/
|
||||||
#define AMF_NOTIFY 4 /* Send a notification when AMF_DONE is set */
|
#define AMF_NOTIFY 004 /* Send a notification when AMF_DONE is set */
|
||||||
#define AMF_NOREPLY 8 /* Not a reply message for a SENDREC */
|
#define AMF_NOREPLY 010 /* Not a reply message for a SENDREC */
|
||||||
|
#define AMF_NOTIFY_ERR 020 /* Send a notification when AMF_DONE is set and
|
||||||
|
* delivery of the message failed */
|
||||||
|
|
||||||
/* Hide names to avoid name space pollution. */
|
/* Hide names to avoid name space pollution. */
|
||||||
#define echo _echo
|
#define echo _echo
|
||||||
|
|
127
kernel/proc.c
127
kernel/proc.c
|
@ -54,14 +54,13 @@ 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,
|
||||||
asynmsg_t *table, size_t size));
|
asynmsg_t *table, size_t size));
|
||||||
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));
|
||||||
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));
|
||||||
|
@ -691,7 +690,7 @@ endpoint_t src_dst_e; /* src or dst process */
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* has_pending *
|
* has_pending *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
PRIVATE int has_pending(sys_map_t *map, int src_p)
|
PUBLIC int has_pending(sys_map_t *map, int src_p)
|
||||||
{
|
{
|
||||||
/* Check to see if there is a pending message from the desired source
|
/* Check to see if there is a pending message from the desired source
|
||||||
* available.
|
* available.
|
||||||
|
@ -1098,7 +1097,7 @@ PRIVATE int mini_senda(struct proc *caller_ptr, asynmsg_t *table, size_t size)
|
||||||
if (size > 16*(NR_TASKS + NR_PROCS)) return(EDOM);
|
if (size > 16*(NR_TASKS + NR_PROCS)) return(EDOM);
|
||||||
|
|
||||||
/* 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.
|
||||||
|
@ -1113,7 +1112,7 @@ PRIVATE int mini_senda(struct proc *caller_ptr, asynmsg_t *table, size_t size)
|
||||||
if (flags == 0) continue; /* Skip empty entries */
|
if (flags == 0) continue; /* Skip empty entries */
|
||||||
|
|
||||||
/* 'flags' field must contain only valid bits */
|
/* 'flags' field must contain only valid bits */
|
||||||
if (flags & ~(AMF_VALID|AMF_DONE|AMF_NOTIFY|AMF_NOREPLY))
|
if(flags & ~(AMF_VALID|AMF_DONE|AMF_NOTIFY|AMF_NOREPLY|AMF_NOTIFY_ERR))
|
||||||
return(EINVAL);
|
return(EINVAL);
|
||||||
if (!(flags & AMF_VALID)) return(EINVAL); /* Must contain message */
|
if (!(flags & AMF_VALID)) return(EINVAL); /* Must contain message */
|
||||||
if (flags & AMF_DONE) continue; /* Already done processing */
|
if (flags & AMF_DONE) continue; /* Already done processing */
|
||||||
|
@ -1157,14 +1156,17 @@ PRIVATE int mini_senda(struct proc *caller_ptr, asynmsg_t *table, size_t size)
|
||||||
tabent.result = r;
|
tabent.result = r;
|
||||||
tabent.flags = flags;
|
tabent.flags = flags;
|
||||||
if (flags & AMF_DONE) {
|
if (flags & AMF_DONE) {
|
||||||
if (r != EDEADSRCDST && (flags & AMF_NOTIFY))
|
if (flags & AMF_NOTIFY)
|
||||||
do_notify = TRUE; /* XXX: ? */
|
do_notify = TRUE;
|
||||||
|
else if (r != OK && (flags & AMF_NOTIFY_ERR))
|
||||||
|
do_notify = TRUE;
|
||||||
A_INSRT(i); /* Copy results to caller */
|
A_INSRT(i); /* Copy results to caller */
|
||||||
} else
|
} else
|
||||||
done = FALSE;
|
done = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (do_notify) printf("mini_senda: should notify caller\n"); /* XXX: ? */
|
if (do_notify)
|
||||||
|
mini_notify(proc_addr(ASYNCM), caller_ptr->p_endpoint);
|
||||||
|
|
||||||
if (!done) {
|
if (!done) {
|
||||||
privp->s_asyntab = (vir_bytes) table;
|
privp->s_asyntab = (vir_bytes) table;
|
||||||
|
@ -1227,9 +1229,9 @@ PRIVATE int try_one(struct proc *src_ptr, struct proc *dst_ptr)
|
||||||
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);
|
||||||
if (!may_send_to(src_ptr, proc_nr(dst_ptr))) return(EAGAIN);
|
if (!may_send_to(src_ptr, proc_nr(dst_ptr))) return(ECALLDENIED);
|
||||||
|
|
||||||
caller_ptr = src_ptr;
|
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; /* XXX: this doesn't do anything? */
|
||||||
|
@ -1249,10 +1251,14 @@ PRIVATE int try_one(struct proc *src_ptr, struct proc *dst_ptr)
|
||||||
if (flags == 0) continue; /* Skip empty entries */
|
if (flags == 0) continue; /* Skip empty entries */
|
||||||
|
|
||||||
/* 'flags' field must contain only valid bits */
|
/* 'flags' field must contain only valid bits */
|
||||||
if (flags & ~(AMF_VALID|AMF_DONE|AMF_NOTIFY|AMF_NOREPLY))
|
if(flags & ~(AMF_VALID|AMF_DONE|AMF_NOTIFY|AMF_NOREPLY|AMF_NOTIFY_ERR))
|
||||||
return(EINVAL);
|
r = EINVAL;
|
||||||
if (!(flags & AMF_VALID)) return(EINVAL); /* Must contain message */
|
else if (!(flags & AMF_VALID)) /* Must contain message */
|
||||||
if (flags & AMF_DONE) continue; /* Already done processing */
|
r = EINVAL;
|
||||||
|
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
|
||||||
|
@ -1273,21 +1279,24 @@ PRIVATE int try_one(struct proc *src_ptr, struct proc *dst_ptr)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Destination is ready to receive the message; deliver it */
|
/* Destination is ready to receive the message; deliver it */
|
||||||
|
r = OK;
|
||||||
dst_ptr->p_delivermsg = tabent.msg;
|
dst_ptr->p_delivermsg = tabent.msg;
|
||||||
dst_ptr->p_delivermsg.m_source = src_ptr->p_endpoint;
|
dst_ptr->p_delivermsg.m_source = src_ptr->p_endpoint;
|
||||||
dst_ptr->p_misc_flags |= MF_DELIVERMSG;
|
dst_ptr->p_misc_flags |= MF_DELIVERMSG;
|
||||||
|
|
||||||
|
store_result:
|
||||||
/* Store results for sender */
|
/* Store results for sender */
|
||||||
tabent.result = OK;
|
tabent.result = r;
|
||||||
tabent.flags = flags | AMF_DONE;
|
tabent.flags = flags | AMF_DONE;
|
||||||
if (flags & AMF_NOTIFY) do_notify = TRUE; /* XXX: ? */
|
if (flags & AMF_NOTIFY) do_notify = TRUE;
|
||||||
|
else if (r != OK && (flags & AMF_NOTIFY_ERR)) do_notify = TRUE;
|
||||||
A_INSRT(i); /* Copy results to sender */
|
A_INSRT(i); /* Copy results to sender */
|
||||||
|
|
||||||
r = OK;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (do_notify) printf("mini_senda: should notify caller\n"); /* XXX: ? */
|
if (do_notify)
|
||||||
|
mini_notify(proc_addr(ASYNCM), src_ptr->p_endpoint);
|
||||||
|
|
||||||
if (!done) {
|
if (!done) {
|
||||||
privp->s_asyntab = table_v;
|
privp->s_asyntab = table_v;
|
||||||
|
@ -1298,6 +1307,88 @@ PRIVATE int try_one(struct proc *src_ptr, struct proc *dst_ptr)
|
||||||
return(r);
|
return(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* cancel_async *
|
||||||
|
*===========================================================================*/
|
||||||
|
PUBLIC int cancel_async(struct proc *src_ptr, struct proc *dst_ptr)
|
||||||
|
{
|
||||||
|
/* Cancel asynchronous messages from src to dst, because dst is not interested
|
||||||
|
* in them (e.g., dst has been restarted) */
|
||||||
|
int done, do_notify, pending_recv = FALSE;
|
||||||
|
unsigned int flags, i;
|
||||||
|
size_t size;
|
||||||
|
endpoint_t dst;
|
||||||
|
struct proc *caller_ptr;
|
||||||
|
struct priv *privp;
|
||||||
|
asynmsg_t tabent;
|
||||||
|
vir_bytes table_v;
|
||||||
|
|
||||||
|
privp = priv(src_ptr);
|
||||||
|
if (!(privp->s_flags & SYS_PROC)) return(EPERM);
|
||||||
|
size = privp->s_asynsize;
|
||||||
|
table_v = privp->s_asyntab;
|
||||||
|
|
||||||
|
/* 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(ECALLDENIED);
|
||||||
|
|
||||||
|
caller_ptr = src_ptr; /* Needed for A_ macros later on */
|
||||||
|
|
||||||
|
/* Scan the table */
|
||||||
|
do_notify = FALSE;
|
||||||
|
done = TRUE;
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
/* 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.
|
||||||
|
* Some checks done in mini_senda are duplicated here, as the sender
|
||||||
|
* could've altered the contents of the table in the mean time.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int r = EDEADSRCDST; /* Cancel delivery due to dead dst */
|
||||||
|
|
||||||
|
/* Copy message to kernel */
|
||||||
|
A_RETR(i);
|
||||||
|
flags = tabent.flags;
|
||||||
|
dst = tabent.dst;
|
||||||
|
|
||||||
|
if (flags == 0) continue; /* Skip empty entries */
|
||||||
|
|
||||||
|
/* 'flags' field must contain only valid bits */
|
||||||
|
if(flags & ~(AMF_VALID|AMF_DONE|AMF_NOTIFY|AMF_NOREPLY|AMF_NOTIFY_ERR))
|
||||||
|
r = EINVAL;
|
||||||
|
else if (!(flags & AMF_VALID)) /* Must contain message */
|
||||||
|
r = EINVAL;
|
||||||
|
else if (flags & AMF_DONE) continue; /* Already done processing */
|
||||||
|
|
||||||
|
/* Message must be directed at receiving end */
|
||||||
|
if (dst != dst_ptr->p_endpoint) {
|
||||||
|
done = FALSE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store results for sender */
|
||||||
|
tabent.result = r;
|
||||||
|
tabent.flags = flags | AMF_DONE;
|
||||||
|
if (flags & AMF_NOTIFY) do_notify = TRUE;
|
||||||
|
else if (r != OK && (flags & AMF_NOTIFY_ERR)) do_notify = TRUE;
|
||||||
|
A_INSRT(i); /* Copy results to sender */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (do_notify)
|
||||||
|
mini_notify(proc_addr(ASYNCM), src_ptr->p_endpoint);
|
||||||
|
|
||||||
|
if (!done) {
|
||||||
|
privp->s_asyntab = table_v;
|
||||||
|
privp->s_asynsize = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(OK);
|
||||||
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* enqueue *
|
* enqueue *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
|
|
@ -47,6 +47,8 @@ _PROTOTYPE( void bsp_finish_booting, (void) );
|
||||||
|
|
||||||
_PROTOTYPE( int do_ipc, (reg_t r1, reg_t r2, reg_t r3) );
|
_PROTOTYPE( int do_ipc, (reg_t r1, reg_t r2, reg_t r3) );
|
||||||
_PROTOTYPE( void proc_init, (void) );
|
_PROTOTYPE( void proc_init, (void) );
|
||||||
|
_PROTOTYPE( int has_pending, (sys_map_t *map, int src_p) );
|
||||||
|
_PROTOTYPE( int cancel_async, (struct proc *src, struct proc *dst) );
|
||||||
_PROTOTYPE( int mini_notify, (const struct proc *src, endpoint_t dst) );
|
_PROTOTYPE( int mini_notify, (const struct proc *src, endpoint_t dst) );
|
||||||
_PROTOTYPE( void enqueue, (struct proc *rp) );
|
_PROTOTYPE( void enqueue, (struct proc *rp) );
|
||||||
_PROTOTYPE( void dequeue, (struct proc *rp) );
|
_PROTOTYPE( void dequeue, (struct proc *rp) );
|
||||||
|
|
|
@ -591,6 +591,14 @@ int caller_ret; /* code to return on callers */
|
||||||
{
|
{
|
||||||
/* Clear IPC references for a given process slot. */
|
/* Clear IPC references for a given process slot. */
|
||||||
struct proc *rp; /* iterate over process table */
|
struct proc *rp; /* iterate over process table */
|
||||||
|
int src_id;
|
||||||
|
sys_map_t *map;
|
||||||
|
|
||||||
|
/* Tell processes that sent asynchronous messages to 'rc' they are not
|
||||||
|
* going to be delivered */
|
||||||
|
map = &priv(rc)->s_asyn_pending;
|
||||||
|
while ((src_id = has_pending(map, ANY)) != NULL_PRIV_ID)
|
||||||
|
cancel_async(proc_addr(id_to_nr(src_id)), rc);
|
||||||
|
|
||||||
for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; rp++) {
|
for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; rp++) {
|
||||||
if(isemptyp(rp))
|
if(isemptyp(rp))
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
|
|
||||||
PUBLIC struct boot_image image[] = {
|
PUBLIC struct boot_image image[] = {
|
||||||
/* process nr, flags, name */
|
/* process nr, flags, name */
|
||||||
|
{ASYNCM, 0, "asyncm"},
|
||||||
{IDLE, 0, "idle" },
|
{IDLE, 0, "idle" },
|
||||||
{CLOCK, 0, "clock" },
|
{CLOCK, 0, "clock" },
|
||||||
{SYSTEM, 0, "system"},
|
{SYSTEM, 0, "system"},
|
||||||
|
@ -66,7 +67,7 @@ PUBLIC struct boot_image image[] = {
|
||||||
|
|
||||||
{PM_PROC_NR, OVM_F, "pm" },
|
{PM_PROC_NR, OVM_F, "pm" },
|
||||||
{SCHED_PROC_NR,OVM_F, "sched" },
|
{SCHED_PROC_NR,OVM_F, "sched" },
|
||||||
{VFS_PROC_NR, OVM_F, "vfs" },
|
{VFS_PROC_NR, BVM_F, "vfs" },
|
||||||
{MEM_PROC_NR, BVM_F, "memory"},
|
{MEM_PROC_NR, BVM_F, "memory"},
|
||||||
{LOG_PROC_NR, BVM_F, "log" },
|
{LOG_PROC_NR, BVM_F, "log" },
|
||||||
{TTY_PROC_NR, BVM_F, "tty" },
|
{TTY_PROC_NR, BVM_F, "tty" },
|
||||||
|
|
Loading…
Reference in a new issue