[comp.os.minix] Fixes to the MINIX deadlocks

ast@cs.vu.nl (Andy Tanenbaum) (03/10/88)

While working on the Atari port, Johan Stevenson found and fixed the
deadlocks in MINIX that have been reported here repeatedly.  The same
problems occurred on both the PC and ST.  Below are diff listings to 
apply to the original V1.2 sources to generate the fixed files.  For
example, do
    fix pipe.c pipe.diff >pipe.new
to make a new version of pipe.  The 7 files included here are:
  h/com.h
  fs/device.c
  fs/pipe.c
  fs/putc.c
  kernel/proc.c
  kernel/system.c
  lib/syslib.c

If any problems appear with these fixes, please post them.

These fixes make the ASYNC task that Jim Paradis put into his tty
driver unnecessary.  This is a much better solution to the problem and
is the one that will be used in both Atari MINIX and 1.3 for the PC.

Andy Tanenbaum


: This is a shar archive.  Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
: --------------------------- cut here --------------------------
PATH=/bin:/usr/bin:/usr/ucb
echo Extracting 'com.diff'
sed 's/^X//' > 'com.diff' << '+ END-OF-FILE ''com.diff'
X20d19
X< #	define SYS_KILL   11	/* fcn code for sys_kill(proc, sig) */
X37c36
X< #	define DISKINT     1	/* fcn code for disk interrupt */
X---
X> #	define DISKINT     1	/* fcn code for disk interupt */
X51,57d49
X< #define ETHERNET 	  -9	/* Ethernet I/O class */
X< #	define ETHER_ARRIV 1	/* fcn code for packet arrival */
X< #	define ETHER_SENT  2	/* fcn code for LANCE interrupt on send */
X< #	define ETHER_READ  3	/* fcn code for reading from Ethernet */
X< #	define ETHER_WRITE 4	/* fcn code for writing to Ethernet */
X< #	define ETHER_IOCTL 5	/* fcn code for ioctl */
X< 
X95c87
X< #define CHILD_STIME    m4_l4	/* sys time consumed by process' children */
X---
X> #define CHILD_STIME    m4_l4	/* system time consumed by proces children */
+ END-OF-FILE com.diff
chmod 'u=rw,g=rw,o=rw' 'com.diff'
set `wc -c 'com.diff'`
count=$1
case $count in
729)	:;;
*)	echo 'Bad character count in ''com.diff' >&2
		echo 'Count should be 729' >&2
esac
echo Extracting 'device.diff'
sed 's/^X//' > 'device.diff' << '+ END-OF-FILE ''device.diff'
X153c153,154
X<   int proc_nr;
X---
X>   int r;
X>   message m;
X155,160c156,159
X<   proc_nr = mess_ptr->PROC_NR;
X< 
X<   if (sendrec(task_nr, mess_ptr) != OK) panic("rw_dev: can't send", NO_NUM);
X<   while (mess_ptr->REP_PROC_NR != proc_nr) {
X< 	/* Instead of the reply to this request, we got a message for an
X< 	 * earlier request.  Handle it and go receive again.
X---
X>   while ((r = sendrec(task_nr, mess_ptr)) == E_LOCKED) {
X> 	/* sendrec() failed to avoid deadlock. The task 'task_nr' is
X> 	 * trying to send a REVIVE message for an earlier request.
X> 	 * Handle it and go try again.
X162,163c161,162
X< 	revive(mess_ptr->REP_PROC_NR, mess_ptr->REP_STATUS);
X< 	receive(task_nr, mess_ptr);
X---
X> 	if (receive(task_nr, &m) != OK) panic("rw_dev: can't receive", NO_NUM);
X> 	revive(m.REP_PROC_NR, m.REP_STATUS);
X164a164
X>   if (r != OK) panic("rw_dev: can't send", NO_NUM);
X175c175
X< /* This routine is only called for one device, namely /dev/tty.  It's job
X---
X> /* This routine is only called for one device, namely /dev/tty.  Its job
+ END-OF-FILE device.diff
chmod 'u=rw,g=rw,o=rw' 'device.diff'
set `wc -c 'device.diff'`
count=$1
case $count in
1031)	:;;
*)	echo 'Bad character count in ''device.diff' >&2
		echo 'Count should be 1031' >&2
esac
echo Extracting 'pipe.diff'
sed 's/^X//' > 'pipe.diff' << '+ END-OF-FILE ''pipe.diff'
X116,120c116,117
X< 		/* Tell MM to generate a SIGPIPE signal. */
X< 		mess.m_type = KSIG;
X< 		mess.PROC1 = fp - fproc;
X< 		mess.SIG_MAP = 1 << (SIGPIPE - 1);
X< 		send(MM_PROC_NR, &mess);
X---
X> 		/* Tell kernel to generate a SIGPIPE signal. */
X> 		sys_kill((int)(fp - fproc), SIGPIPE);
X251,255c248
X< 	if (sendrec(task, &mess) != OK) panic("unpause err 3", NO_NUM);
X< 	while (mess.REP_PROC_NR != proc_nr) {
X< 		revive(mess.REP_PROC_NR, mess.REP_STATUS);
X< 		if (receive(task, &m) != OK) panic("unpause err 4", NO_NUM);
X< 	}
X---
X> 	rw_dev(task, &mess);
+ END-OF-FILE pipe.diff
chmod 'u=rw,g=rw,o=rw' 'pipe.diff'
set `wc -c 'pipe.diff'`
count=$1
case $count in
548)	:;;
*)	echo 'Bad character count in ''pipe.diff' >&2
		echo 'Count should be 548' >&2
esac
echo Extracting 'proc.diff'
sed 's/^X//' > 'proc.diff' << '+ END-OF-FILE ''proc.diff'
X153a154,163
X>   /* Check for deadlock by 'caller' and 'dest' sending to each other. */
X>   if (dest_ptr->p_flags & SENDING) {
X> 	next_ptr = caller_ptr->p_callerq;
X> 	while (next_ptr) {
X> 		if (next_ptr == dest_ptr)
X> 			return(E_LOCKED);
X> 		next_ptr = next_ptr->p_sendlink;
X> 	}
X>   }
X> 
X155,156c165,166
X<   if ( (dest_ptr->p_flags & RECEIVING) &&
X< 		(dest_ptr->p_getfrom == ANY || dest_ptr->p_getfrom == caller) ) {
X---
X>   if ( (dest_ptr->p_flags & RECEIVING) && (dest_ptr->p_flags & SENDING) == 0 &&
X> 		(dest_ptr->p_getfrom == ANY || dest_ptr->p_getfrom == caller)){
X205c215,216
X<   while (sender_ptr != NIL_PROC) {
X---
X>   if ((caller_ptr->p_flags & SENDING) == 0) {
X>      while (sender_ptr != NIL_PROC) {
X220a232
X>      }
X253c265
X<    * deposit the registers when a interrupt occurs on an idle machine.
X---
X>    * deposit the registers when an interrupt occurs on an idle machine.
X256c268
X<    * clock task is running, 'cur_proc' = CLOCKTASK. In addition, set 'bill_ptr'
X---
X>    * clock task is running, 'cur_proc' = CLOCKTASK.) In addition, set 'bill_ptr'
+ END-OF-FILE proc.diff
chmod 'u=rw,g=rw,o=rw' 'proc.diff'
set `wc -c 'proc.diff'`
count=$1
case $count in
1067)	:;;
*)	echo 'Bad character count in ''proc.diff' >&2
		echo 'Count should be 1067' >&2
esac
echo Extracting 'putc.diff'
sed 's/^X//' > 'putc.diff' << '+ END-OF-FILE ''putc.diff'
X49c49
X<   sendrec(TTY, &putchmsg);
X---
X>   rw_dev(TTY, &putchmsg);
+ END-OF-FILE putc.diff
chmod 'u=rw,g=rw,o=rw' 'putc.diff'
set `wc -c 'putc.diff'`
count=$1
case $count in
67)	:;;
*)	echo 'Bad character count in ''putc.diff' >&2
		echo 'Count should be 67' >&2
esac
echo Extracting 'syslib.diff'
sed 's/^X//' > 'syslib.diff' << '+ END-OF-FILE ''syslib.diff'
X132a133,145
X> 
X> 
X> PUBLIC sys_kill(proc, sig)
X> int proc;			/* which proc has exited */
X> int sig;			/* signal number: 1 - 16 */
X> {
X> /* A proc has to be signaled via MM.  Tell the kernel. */
X> 
X>   M.m6_i1 = proc;
X>   M.m6_i2 = sig;
X>   callx(SYSTASK, SYS_KILL);
X> }
X> 	
+ END-OF-FILE syslib.diff
chmod 'u=rw,g=rw,o=rw' 'syslib.diff'
set `wc -c 'syslib.diff'`
count=$1
case $count in
274)	:;;
*)	echo 'Bad character count in ''syslib.diff' >&2
		echo 'Count should be 274' >&2
esac
echo Extracting 'system.diff'
sed 's/^X//' > 'system.diff' << '+ END-OF-FILE ''system.diff'
X15a16
X>  *   SYS_KILL	 cause a signal to be sent via MM
X42a44,45
X>  * | SYS_KILL   | proc_nr  |  sig    |         |         |
X>  * ------------------------------------------------------
X95a99
X> 	    case SYS_KILL:	r = do_kill(&m);	break;
X372a377,395
X>  *				do_kill					     * 
X>  *===========================================================================*/
X> PRIVATE int do_kill(m_ptr)
X> message *m_ptr;			/* pointer to request message */
X> {
X> /* Handle sys_kill(). Cause a signal to be sent to a process via MM. */
X> 
X>   int proc_nr;			/* process number */
X>   int sig;			/* signal number 1-16 */
X> 
X>   proc_nr = m_ptr->PR;		/* process being signalled */
X>   sig = m_ptr->SIGNUM;		/* signal number, 1 to 16 */
X>   if (proc_nr < LOW_USER || proc_nr >= NR_PROCS) return(E_BAD_PROC);
X>   cause_sig(proc_nr, sig);
X>   return(OK);
X> }
X> 
X> 
X> /*===========================================================================*
X504c527
X<   seg_base = seg_base << CLICK_SHIFT;	/* segment orgin in bytes */
X---
X>   seg_base = seg_base << CLICK_SHIFT;	/* segment origin in bytes */
+ END-OF-FILE system.diff
chmod 'u=rw,g=rw,o=rw' 'system.diff'
set `wc -c 'system.diff'`
count=$1
case $count in
1075)	:;;
*)	echo 'Bad character count in ''system.diff' >&2
		echo 'Count should be 1075' >&2
esac
exit 0