]> Zhao Yanbai Git Server - minix.git/commitdiff
New deadlock check at proc.c.
authorJorrit Herder <jnherder@minix3.org>
Wed, 12 Oct 2005 15:08:23 +0000 (15:08 +0000)
committerJorrit Herder <jnherder@minix3.org>
Wed, 12 Oct 2005 15:08:23 +0000 (15:08 +0000)
New exit checks (stop IPC).

kernel/ipc.h
kernel/proc.c
kernel/system/do_exit.c
kernel/table.c

index c8442f54d8b5584a71cee8621485b7e181e080fa..4cef03e256a4a347e17fc585e3a34e7accba0770 100644 (file)
@@ -25,5 +25,6 @@
 #define CHECK_PTR       0x0B   /* 1 0 1 1 : validate message buffer */
 #define CHECK_DST       0x05   /* 0 1 0 1 : validate message destination */
 #define CHECK_SRC       0x02   /* 0 0 1 0 : validate message source */
+#define CHECK_DEADLOCK  0x03   /* 0 0 1 1 : check for deadlock */
 
 #endif /* IPC_H */
index e54a512150934e9ad05ad8d7211890411c6c870d..11e1b01f86485b59e0791fb86193696ec7b828a9 100755 (executable)
  * interrupts to prevent race conditions. 
  */
 FORWARD _PROTOTYPE( int mini_send, (struct proc *caller_ptr, int dst,
-               message *m_ptr, unsigned flags) );
+               message *m_ptr, unsigned flags));
 FORWARD _PROTOTYPE( int mini_receive, (struct proc *caller_ptr, int src,
-               message *m_ptr, unsigned flags) );
-FORWARD _PROTOTYPE( int mini_notify, (struct proc *caller_ptr, int dst) );
-
-FORWARD _PROTOTYPE( void enqueue, (struct proc *rp) );
-FORWARD _PROTOTYPE( void dequeue, (struct proc *rp) );
-FORWARD _PROTOTYPE( void sched, (struct proc *rp, int *queue, int *front) );
-FORWARD _PROTOTYPE( void pick_proc, (void) );
+               message *m_ptr, unsigned flags));
+FORWARD _PROTOTYPE( int mini_notify, (struct proc *caller_ptr, int dst));
+FORWARD _PROTOTYPE( int deadlock, (int function,
+               register struct proc *caller, int src_dst));
+FORWARD _PROTOTYPE( void enqueue, (struct proc *rp));
+FORWARD _PROTOTYPE( void dequeue, (struct proc *rp));
+FORWARD _PROTOTYPE( void sched, (struct proc *rp, int *queue, int *front));
+FORWARD _PROTOTYPE( void pick_proc, (void));
 
 #define BuildMess(m_ptr, src, dst_ptr) \
        (m_ptr)->m_source = (src);                                      \
@@ -99,6 +100,7 @@ message *m_ptr;                      /* pointer to message in the caller's space */
   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 group_size;                              /* used for deadlock check */
   int result;                                  /* the system call's result */
   vir_clicks vlo, vhi;         /* virtual clicks containing message to send */
 
@@ -150,12 +152,21 @@ message *m_ptr;                   /* pointer to message in the caller's space */
    */
   if (function & CHECK_DST) {  
       if (! get_sys_bit(priv(caller_ptr)->s_ipc_to, nr_to_id(src_dst))) {
-          kprintf("sys_call: ipc mask denied %d sending to %d\n",
-               proc_nr(caller_ptr), src_dst);
+          kprintf("sys_call: ipc mask denied trap %d from %d to %d\n",
+               function, proc_nr(caller_ptr), src_dst);
           return(ECALLDENIED);         /* call denied by ipc mask */
       }
   }
 
+  /* Check for a possible deadlock for blocking SEND(REC) and RECEIVE. */
+  if (function & CHECK_DEADLOCK) {
+      if (group_size = deadlock(function, caller_ptr, src_dst)) {
+          kprintf("sys_call: trap %d from %d to %d deadlocked, group size %d\n",
+              function, proc_nr(caller_ptr), src_dst, group_size);
+          return(ELOCKED);
+      }
+  }
+
   /* Now check if the call is known and try to perform the request. The only
    * system calls that exist in MINIX are sending and receiving messages.
    *   - SENDREC: combines SEND and RECEIVE in a single system call
@@ -194,6 +205,56 @@ message *m_ptr;                    /* pointer to message in the caller's space */
   return(result);
 }
 
+/*===========================================================================*
+ *                             deadlock                                     * 
+ *===========================================================================*/
+PRIVATE int deadlock(function, cp, src_dst) 
+int function;                                  /* trap number */
+register struct proc *cp;                      /* pointer to caller */
+register int src_dst;                          /* src or dst process */
+{
+/* Check for deadlock. This can happen if 'caller_ptr' and 'src_dst' have
+ * a cyclic dependency of blocking send and receive calls. The only cyclic 
+ * depency that is not fatal is if the caller and target directly SEND(REC)
+ * and RECEIVE to each other. If a deadlock is found, the group size is 
+ * returned. Otherwise zero is returned. 
+ */
+  register struct proc *xp;                    /* process pointer */
+  int group_size = 1;                          /* start with only caller */
+  int trap_flags;
+
+  while (src_dst != ANY) {                     /* check while process nr */
+      xp = proc_addr(src_dst);                 /* follow chain of processes */
+      group_size ++;                           /* extra process in group */
+
+      /* Check whether the last process in the chain has a depency. If it 
+       * has not, the cycle cannot be closed and we are done.
+       */
+      if (xp->p_rts_flags & RECEIVING) {       /* xp has dependency */
+          src_dst = xp->p_getfrom;             /* get xp's source */
+      } else if (xp->p_rts_flags & SENDING) {  /* xp has dependency */
+          src_dst = xp->p_sendto;              /* get xp's destination */
+      } else {
+         return(0);                            /* not a deadlock */
+      }
+
+      /* Now check if there is a cyclic dependency. For group sizes of two,  
+       * a combination of SEND(REC) and RECEIVE is not fatal. Larger groups
+       * or other combinations indicate a deadlock.  
+       */
+      if (src_dst == proc_nr(cp)) {            /* possible deadlock */
+         if (group_size == 2) {                /* caller and src_dst */
+             /* The function number is magically converted to flags. */
+             if ((xp->p_rts_flags ^ (function << 2)) & SENDING) { 
+                 return(0);                    /* not a deadlock */
+             }
+         }
+          return(group_size);                  /* deadlock found */
+      }
+  }
+  return(0);                                   /* not a deadlock */
+}
+
 /*===========================================================================*
  *                             mini_send                                    * 
  *===========================================================================*/
@@ -209,14 +270,6 @@ unsigned flags;                            /* system call flags */
  */
   register struct proc *dst_ptr = proc_addr(dst);
   register struct proc **xpp;
-  register struct proc *xp;
-
-  /* Check for deadlock by 'caller_ptr' and 'dst' sending to each other. */
-  xp = dst_ptr;
-  while (xp->p_rts_flags & SENDING) {          /* check while sending */
-       xp = proc_addr(xp->p_sendto);           /* get xp's destination */
-       if (xp == caller_ptr) return(ELOCKED);  /* deadlock if cyclic */
-  }
 
   /* Check if 'dst' is blocked waiting for this message. The destination's 
    * SENDING flag may be set when its SENDREC call blocked while sending.  
index 85278adeb7c77536cf162f4af02382eb6cbcca32..67fb1d18da14d4e382017902e267a9a76425a9ce 100644 (file)
@@ -65,7 +65,9 @@ register struct proc *rc;             /* slot of process to clean up */
       while (*xpp != NIL_PROC) {               /* check entire queue */
           if (*xpp == rc) {                    /* process is on the queue */
               *xpp = (*xpp)->p_q_link;         /* replace by next process */
-              break;                           /* done, can only send one */
+             kprintf("Proc %d removed from queue at %d\n",
+                 proc_nr(rc), rc->p_sendto);
+              break;                           /* can only be queued once */
           }
           xpp = &(*xpp)->p_q_link;             /* proceed to next queued */
       }
@@ -81,11 +83,13 @@ register struct proc *rc;           /* slot of process to clean up */
       if ((rp->p_rts_flags & RECEIVING) && rp->p_getfrom == proc_nr(rc)) {
           rp->p_reg.retreg = EDEADSRCDST;      /* report source died */
          rp->p_rts_flags &= ~RECEIVING;        /* no longer receiving */
+         kprintf("Proc %d receive dead src %d\n", proc_nr(rp), proc_nr(rc));
          lock_enqueue(rp);                     /* let process run again */
       } 
       else if ((rp->p_rts_flags & SENDING) && rp->p_sendto == proc_nr(rc)) {
           rp->p_reg.retreg = EDEADSRCDST;      /* report destination died */
          rp->p_rts_flags &= ~SENDING;          /* no longer sending */
+         kprintf("Proc %d send dead dst %d\n", proc_nr(rp), proc_nr(rc));
          lock_enqueue(rp);                     /* let process run again */
       } 
   }
index 5cfd1bfe1a647bde35044706ae00311b0d1a4723..066ea77df72e27fbccfa3bf64d1d1cf78fb31c10 100755 (executable)
@@ -107,10 +107,7 @@ PUBLIC struct boot_image image[] = {
  { MEM_PROC_NR,   0, SRV_F,  4,      2, 0,     SRV_T, DRV_M, MEM_C, "memory"},
  { LOG_PROC_NR,   0, SRV_F,  4,      2, 0,     SRV_T, SYS_M, DRV_C, "log"   },
  { DRVR_PROC_NR,  0, SRV_F,  4,      2, 0,     SRV_T, SYS_M, DRV_C, "driver"},
-#if DEAD_CODE
-  ... WARNING: replace ~0 with USR_T / USR_M
-#endif
- { INIT_PROC_NR,  0, USR_F,  8, USER_Q, 0,     ~0, ~0,     0, "init"  },
+ { INIT_PROC_NR,  0, USR_F,  8, USER_Q, 0,     USR_T, USR_M,     0, "init"  },
 };
 
 /* Verify the size of the system image table at compile time. Also verify that