]> Zhao Yanbai Git Server - minix.git/commitdiff
Enable sending a notification when sending of an asynchronous message was
authorThomas Veerman <thomas@minix3.org>
Fri, 8 Apr 2011 15:14:48 +0000 (15:14 +0000)
committerThomas Veerman <thomas@minix3.org>
Fri, 8 Apr 2011 15:14:48 +0000 (15:14 +0000)
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.

common/include/minix/com.h
common/include/minix/ipc.h
kernel/proc.c
kernel/proto.h
kernel/system.c
kernel/table.c

index 97f5b3ff06e0a6b4f05d64f4493dd31124c96f8d..b5557835cbfd6fa73c5f06760a69b091c24de744 100644 (file)
@@ -54,6 +54,7 @@
  */
 
 /* 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 CLOCK          ((endpoint_t) -3) /* alarms and other clock functions */
 #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>. */
 #define MAX_NR_TASKS   1023
-#define NR_TASKS         4 
+#define NR_TASKS         5 
 
 /* User-space processes, that is, device drivers, servers, and INIT. */
 #define PM_PROC_NR   ((endpoint_t) 0)  /* process manager */
index b53af790dc1a5d81c5f6865eb372d365f6cc98d8..8ce24a47964a04a941588c9c862df98703aa1fc1 100644 (file)
@@ -132,13 +132,15 @@ typedef struct asynmsg
 } asynmsg_t;
 
 /* Defines for flags field */
-#define AMF_EMPTY      0       /* slot is not inuse */
-#define AMF_VALID      1       /* slot contains message */
-#define AMF_DONE       2       /* Kernel has processed the message. The
+#define AMF_EMPTY      000     /* slot is not inuse */
+#define AMF_VALID      001     /* slot contains message */
+#define AMF_DONE       002     /* Kernel has processed the message. The
                                 * result is stored in 'result'
                                 */
-#define AMF_NOTIFY     4       /* Send a notification when AMF_DONE is set */
-#define AMF_NOREPLY    8       /* Not a reply message for a SENDREC */
+#define AMF_NOTIFY     004     /* Send a notification when AMF_DONE is set */
+#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. */
 #define echo           _echo
index 1cbb307c5f372695a3b525fab83e6b157f3e7b5a..f91ff75554844aeeba7fa0b25e317929ec573f49 100644 (file)
@@ -54,14 +54,13 @@ 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,
        asynmsg_t *table, size_t size));
 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_async, (struct proc *caller_ptr)           );
 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));
@@ -691,7 +690,7 @@ endpoint_t src_dst_e;                               /* src or dst process */
 /*===========================================================================*
  *                             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
  * 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);
        
   /* Scan the table */
-  do_notify = FALSE;   /* XXX: this doesn't do anything? */
+  do_notify = FALSE;
   done = TRUE;
   for (i = 0; i < size; i++) {
        /* 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 */
 
        /* '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);
        if (!(flags & AMF_VALID)) return(EINVAL); /* Must contain message */
        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.flags = flags;
        if (flags & AMF_DONE) {
-               if (r != EDEADSRCDST && (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 caller */
        } else
                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) {
        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);
 
   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 */
   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 */
 
        /* 'flags' field must contain only valid bits */
-       if (flags & ~(AMF_VALID|AMF_DONE|AMF_NOTIFY|AMF_NOREPLY))
-               return(EINVAL);
-       if (!(flags & AMF_VALID)) return(EINVAL); /* Must contain message */
-       if (flags & AMF_DONE) continue; /* Already done processing */
+       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 */
+
+       if (r == EINVAL)
+               goto store_result;
 
        /* 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
@@ -1273,21 +1279,24 @@ PRIVATE int try_one(struct proc *src_ptr, struct proc *dst_ptr)
                continue;
 
        /* Destination is ready to receive the message; deliver it */
+       r = OK;
        dst_ptr->p_delivermsg = tabent.msg;
        dst_ptr->p_delivermsg.m_source = src_ptr->p_endpoint;
        dst_ptr->p_misc_flags |= MF_DELIVERMSG;
 
+store_result:
        /* Store results for sender */
-       tabent.result = OK;
+       tabent.result = r;
        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 */
 
-       r = OK;
        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) {
        privp->s_asyntab = table_v;
@@ -1298,6 +1307,88 @@ PRIVATE int try_one(struct proc *src_ptr, struct proc *dst_ptr)
   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                                      * 
  *===========================================================================*/
index b26d7d4564fab06dff3677dac96bec25e295e880..79683763fadd5470945a1ef33d8f9c77afd1187e 100644 (file)
@@ -47,6 +47,8 @@ _PROTOTYPE( void bsp_finish_booting, (void)                           );
 
 _PROTOTYPE( int do_ipc, (reg_t r1, reg_t r2, reg_t r3)                 );
 _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( void enqueue, (struct proc *rp)                            );
 _PROTOTYPE( void dequeue, (struct proc *rp)                            );
index 71bdf53609bbaf58a06d828eedad824e568dd550..fd34336c84aa186b194bd550184c7103bca4e32a 100644 (file)
@@ -591,6 +591,14 @@ int caller_ret;                            /* code to return on callers */
 {
 /* Clear IPC references for a given process slot. */
   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++) {
       if(isemptyp(rp))
index cde0614112bc8e74e29c44d459258196e8080865..d65a9dc796b1deb2f3b355ec446179e6dd2afad9 100644 (file)
@@ -56,6 +56,7 @@
 
 PUBLIC struct boot_image image[] = {
 /* process nr, flags, name */
+{ASYNCM,           0, "asyncm"},
 {IDLE,             0, "idle"  },
 {CLOCK,            0, "clock" },
 {SYSTEM,           0, "system"},
@@ -66,7 +67,7 @@ PUBLIC struct boot_image image[] = {
                       
 {PM_PROC_NR,   OVM_F, "pm"    },
 {SCHED_PROC_NR,OVM_F, "sched" },
-{VFS_PROC_NR,  OVM_F, "vfs"   },
+{VFS_PROC_NR,  BVM_F, "vfs"   },
 {MEM_PROC_NR,  BVM_F, "memory"},
 {LOG_PROC_NR,  BVM_F, "log"   },
 {TTY_PROC_NR,  BVM_F, "tty"   },