]> Zhao Yanbai Git Server - minix.git/commitdiff
Use a bitmap for pending asynchronous messages instead of a global flag.
authorThomas Veerman <thomas@minix3.org>
Fri, 8 Apr 2011 15:03:33 +0000 (15:03 +0000)
committerThomas Veerman <thomas@minix3.org>
Fri, 8 Apr 2011 15:03:33 +0000 (15:03 +0000)
That way it works similar to pending notifications.

kernel/priv.h
kernel/proc.c
kernel/system.c

index 424d6c0afad7e9453361678becfa918963d65985..f9304423c87489e3afcdb35a828dc824b9b044e0 100644 (file)
@@ -38,6 +38,7 @@ struct priv {
   endpoint_t s_sig_mgr;                /* 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_asyn_pending;    /* bit map with pending asyn messages */
   irq_id_t s_int_pending;      /* pending hardware interrupts */
   sigset_t s_sig_pending;      /* pending signals */
 
index badb72f706c6865bfa2af0a9af2f021e1dcdc488..1cbb307c5f372695a3b525fab83e6b157f3e7b5a 100644 (file)
@@ -54,6 +54,7 @@ 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,
@@ -61,8 +62,7 @@ FORWARD _PROTOTYPE( int mini_senda, (struct proc *caller_ptr,
 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_one, (struct proc *src_ptr, struct proc *dst_ptr,
-               int *postponed));
+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));
 
@@ -688,6 +688,41 @@ endpoint_t src_dst_e;                              /* src or dst process */
   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                                    * 
  *===========================================================================*/
@@ -799,7 +834,7 @@ PRIVATE int mini_receive(struct proc * caller_ptr,
  */
   register struct proc **xpp;
   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));
 
@@ -827,27 +862,8 @@ PRIVATE int mini_receive(struct proc * caller_ptr,
     if (! (caller_ptr->p_misc_flags & MF_REPLY_PEND)) {
         map = &priv(caller_ptr)->s_notify_pending;
 
-        /* Either check a specific bit in the pending notifications mask, 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);
-
-            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) {
+       /* Check for pending notifications */
+        if ((src_id = has_pending(map, src_p)) != NULL_PRIV_ID) {
             endpoint_t hisep;
 
             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(). */
-    if (caller_ptr->p_misc_flags & MF_ASYNMSG) {
-       if (src_e != ANY)
-               r = try_one(proc_addr(src_p), caller_ptr, NULL);
-       else
-               r = try_async(caller_ptr);
+    /* Check for pending asynchronous messages */
+    map = &priv(caller_ptr)->s_asyn_pending;
+
+    if (has_pending(map, src_p) != NULL_PRIV_ID) {
+        if (src_p != ANY)
+               r = try_one(proc_addr(src_p), caller_ptr);
+        else
+               r = try_async(caller_ptr);
 
        if (r == OK) {
-               IPC_STATUS_ADD_CALL(caller_ptr, SENDA);
-               goto receive_done;
-       }
+            IPC_STATUS_ADD_CALL(caller_ptr, SENDA);
+            goto receive_done;
+        }
     }
 
     /* 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)
 {
-  int r = OK, i, dst_p, done, do_notify;
+  int r = OK, dst_p, done, do_notify;
+  unsigned int i;
   unsigned flags;
   endpoint_t dst;
   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);
                RTS_UNSET(dst_ptr, RTS_RECEIVING);
        } else if (r == OK) {
-               /* Should inform receiver that something is pending */
-               dst_ptr->p_misc_flags |= MF_ASYNMSG;
+               /* Inform receiver that something is pending */
+               set_sys_bit(priv(dst_ptr)->s_asyn_pending, 
+                           priv(caller_ptr)->s_id); 
                pending_recv = TRUE;
        } 
 
@@ -1164,7 +1184,6 @@ struct proc *caller_ptr;
   int r;
   struct priv *privp;
   struct proc *src_ptr;
-  int postponed = FALSE;
 
   /* Try all privilege structures */
   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);
 
        assert(!(caller_ptr->p_misc_flags & MF_DELIVERMSG));
-       r = try_one(src_ptr, caller_ptr, &postponed);
-       if (r == OK)
+       if ((r = try_one(src_ptr, caller_ptr)) == OK)
                return(r);
   }
 
-  /* Nothing found, clear MF_ASYNMSG unless messages were postponed */
-  if (postponed == FALSE)
-       caller_ptr->p_misc_flags &= ~MF_ASYNMSG;
-
   return(ESRCH);
 }
 
@@ -1190,10 +1204,11 @@ struct proc *caller_ptr;
 /*===========================================================================*
  *                             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;
-  unsigned flags;
+/* Try to receive an asynchronous message from 'src_ptr' */
+  int r = EAGAIN, done, do_notify, pending_recv = FALSE;
+  unsigned int flags, i;
   size_t size;
   endpoint_t dst;
   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;
   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_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(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. This message is to be delivered later.
         */
-       if ((flags & AMF_NOREPLY) && (dst_ptr->p_misc_flags & MF_REPLY_PEND)) {
-               if (postponed != NULL)
-                       *postponed = TRUE;
-
+       if ((flags & AMF_NOREPLY) && (dst_ptr->p_misc_flags & MF_REPLY_PEND)) 
                continue;
-       }
 
        /* Destination is ready to receive the message; deliver it */
        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) {
        privp->s_asyntab = table_v;
        privp->s_asynsize = size;
+       set_sys_bit(priv(dst_ptr)->s_asyn_pending, privp->s_id);
   }
 
   return(r);
index 029738b7efb190c16c1b6c7c100ccb1049b36795..71bdf53609bbaf58a06d828eedad824e568dd550 100644 (file)
@@ -599,12 +599,8 @@ int caller_ret;                            /* code to return on callers */
       /* Unset pending notification bits. */
       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
-       * done in a realistic way, we need a better implementation of senda
-       * 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.
-       */
+      /* Unset pending asynchronous messages */
+      unset_sys_bit(priv(rp)->s_asyn_pending, priv(rc)->s_id);
 
       /* Check if process depends on given process. */
       if (P_BLOCKEDON(rp) == rc->p_endpoint) {