Subject: sigpending(2) bug, sigwait(2), tsleep added, much more (#426 1 of 2)
Index:	sys/kern_sig.c,kern_synch.c,many others 2.11BSD

Description:
	1) Program which use sigpending(2) would erroneously see SIGCONT
	   set if the program was stopped and continued.

	2) sigwait(2) is missing.

	3) send(2), recv(2), sendto(2), recvfrom(2) do not restart after
	   signals as do read(2) and write(2).

	4) connect(2) and open(2) be restarted after signals instead 
	   of returning EINTR.

	5) open(2) when using the O_EXLOCK or O_SHLOCK flag would leave
	   resources allocated if the open() were interrupted by a signal.

	6) ino_lock() (used by the kernel to handle flock(2) and open(2) 
	   when O_EXLOCK/O_SHLOCK are specified in the flags) would sleep
	   using an odd (lower order bit set) wait channel.   

	7) Determining if a system call should be restarted or reported as
	   interrupted used two "global" (u_eosys and u_error) locations instead
	   just one.  

	8) The adb script used to print out 'struct u' entries was broken.

	9) The select(2) manpage failed to document the limitation on the 
	   maximum value of timeout that can be used.

Repeat-By:
	1) Write a program which uses sigpending(2).  Stop the program (^Z in 
	   csh) then bring the program back into the foreground.  Note that 
	   the SIGCONT signal will be present in the mask returned from 
	   sigpending(2).  This is an error and does not happen on other 
	   BSD systems).

	2) Observation.

	3) Observation and experience.  Programs such as 'rwhod', 'comsat' 
	   use recv(2) and timers and have checks for 'EINTR'.  Unless the 
	   program specifically requests that a signal interrupt a system
	   call (read, write, recv, send) the kernel should restart the
	   system call if no data has been transferred.  It was an oversight
	   in 4.3BSD to not restart recv() and send() after signals.

	4) It is not correct to automatically restart certain system calls and
	   4.4BSD derived systems return EINTR if open(2) and connect(2) are
	   interrupted by signals.

	5) Due to the way 2.11BSD used longjmp (global 'goto') it was possible
	   for the part of the open(2) processing which allocated file struct-
	   ures to be done and then have a signal interrupt the acquisition of
	   a lock.  The kernel would 'goto' the top level system call handling
	   to restart the system call but NOT give the open() processing a
	   chance to free the allocated resources.   After a while a process
	   would be unable to open any more files.

	6) Observation.  Odd wait channels are reserved for the networking code
	   and the kernel jumps into supervisor mode when it sees an odd wait
	   channel during wakeup() processing. 

	7) This was noticed while fixing up the rest of the problems.  It seemed
	   redundant (and needlessly complex) to set u_eosys with a "restart",
	   "interrupt", "do nothing"  status _and_ make sure u_error was 
	   cleared/set/ignored.

	8) Try using adb's "$<u" command to dump out a proc structure.

	9) Use a timeout more than about 9 minutes long with select(2).

Fix:

	This is update #426 and is part 1 of 2.  Make sure you have the 2nd
	part (#427) before continuing on.   These instructions only appear in
	this part.

	These are the files modified by updates #426 and 427:

/usr/include/syscall.h
/usr/src/sys/sys/kern_synch.c
/usr/src/sys/sys/kern_exit.c
/usr/src/sys/sys/kern_sig.c
/usr/src/sys/sys/sys_generic.c
/usr/src/sys/sys/sys_inode.c
/usr/src/sys/sys/sys_process.c
/usr/src/sys/sys/kern_descrip.c
/usr/src/sys/sys/ufs_syscalls.c
/usr/src/sys/sys/kern_sig2.c
/usr/src/sys/sys/syscalls.c
/usr/src/sys/sys/init_sysent.c
/usr/src/sys/sys/kern_exec.c
/usr/src/sys/sys/vm_sched.c
/usr/src/sys/sys/vfs_vnops.c
/usr/src/sys/sys/uipc_syscalls.c
/usr/src/sys/h/proc.h
/usr/src/sys/h/param.h
/usr/src/sys/h/signalvar.h
/usr/src/sys/h/errno.h
/usr/src/sys/h/user.h
/usr/src/sys/pdp/trap.c
/usr/src/sys/pdp/machdep.c
/usr/src/libexec/comsat/comsat.c
/usr/src/lib/libc/pdp/sys/Makefile
/usr/src/man/man2/select.2
/usr/src/man/man2/Makefile
/usr/src/new/crash/crashsubs.c
/usr/src/share/adb/u
/usr/src/share/lint/llib-lc
/usr/src/usr.sbin/rwhod/rwhod.c
/usr/src/usr.sbin/pstat/pstat.c
/VERSION

	There is one file added (the sigwait(2) manpage):

/usr/src/man/man2/sigwait.2

	Now it is time to improve my typing skills and give a somewhat 
	detailed narrative of what the changes are and why they are so
	extensive.

	1.
	---

	It all started one evening a month or two ago when a test program
	(included below) began reporting bit 19 (SIGCONT) being on in the
	return from sigpending() when the program was stopped and then brought 
	back into the foreground.  SIGCONT is supposed to be cleared before 
	the program is resumed.  Further experimentation on other systems
	implementing sigpending() showed that 2.11BSD clearly had a bug
	in the signal handling part of the kernel.

	The problem was indeed that 'SIGCONT' was not being cleared from the
	mask of pending signals.   It should have been cleared.  This comment
	in kern_sig.c:

                  * XXX - 2.11BSD has to leave the SIGCONT bit in the
                  * mask so that the call to issig() will clear p_cursig.
                  * We could clear p_cursig here but since issig() will
                  * get called anyway when the process wakes up why not
                  * leave it something to do?  Besides clearing p_cursig
                  * here felt like a kluge.

	was added when the 4.4BSD signal handling was ported over.  Even at that
	time there were indications that oddities were being kluged around.  
	NOW it is known exactly what those oddities were:  the dual use of
	'p_cursig'.  The p_cursig member (which has been renamed to more 
	accurately reflect its use) is part of the parent/child "process trace"
	protocol - a parent process (debugger) would set a value in p_cursig
	if it wanted the child process to see the signal.  'p_cursig' should NOT
	have been used outside of the 'ptrace' protocol but it was.   P

	The checks for pending signals to a process used BOTH p_cursig (even
	if no 'ptrace' processing was going on) and p_sig.  Clearing a signal
	from p_sig but leaving it set in p_cursig would cause a kernel crash
	(at worst) or a program crash (at best).  Clearing p_cursig but leaving
	the bit set in p_sig would also cause abnormal behaviour.  What a kluge.

	Clearly the test for pending signals needed to be cleanly and plainly
	broken out from the 'ptrace' handling.  The first step was to rename
	p_cursig to p_ptracesig.  The next step was much larger - issig(),
	psig(), postsig() were rewritten/modified and ISSIG() replace by the
	4.4BSD CURSIG() macro.  SEVERAL extraneous p_cursig references were 
	removed because they were not needed.  At this time the comment above
	was also removed because the proper way to deal with pending signals
	had finally been implemented.

	Signal handling of course is involved with the kernel "sleep()" routine
	because signals must be checked before and after a process is suspended.
	Since changes were required why not finally implement the 4.4BSD
	'tsleep' routine which allows the caller to specify if a sleep can be
	interrupted or not.  The tsleep() routine proved to be extremely
	valuable during the remainder of the changes.  The select() syscall
	routine for example was greatly simplified by use of 'tsleep' instead
	of 'setjmp'+'longjmp'.

	sleep() was rewritten to use tsleep().  There is ONE BIG change now
	that kernel hackers need to be away of:

	    the interruptibility of a sleep() is NOT solely based on the
	    "priority" being greater than PZERO!  If tsleep() is called without
	    PCATCH or'd in to the priority it is possible for a process to
	    be non-interruptible no matter what the priority is.

	    sleep() emulates the earlier behaviour (non-interruptible if the
	    priority is <=PZERO, interruptible if >PZERO) by setting PCATCH
	    if the priority is >PZERO.

	By this time a pattern should be emerging: every time another area
	of the signal handling code was looked at the more apparent the 
	"neglect" became.  When new functionality had been added in the past
	it was done with an eye towards changing as little as possible outside
	a specific feature's needs.  That worked fine for a number of years but
	the resulting code was beginning to become unwieldy and causing 
	problems.  

	One of the things which needed cleaning up was the issue of restarting
	system calls (or reporting them interrupted).  Previously sleep() would
	simply longjmp() back to the top level system call handler after
	setting 'u_eosys' and clearing u_error.  Yet another 4.4BSD idea to
	the rescue - set the error indicator (u_error) to a special value
	and remove u_eosys altogether.  Works very nicely and simplified  a
	number of routines (in pdp/trap.c and several other places).   This
	is NOT a complete solution - the IDEAL solution would be to not use
	u_error at all but that was not feasible at this time (it would require
	a function by function walkthru of the kernel to propagate return 
	values).  A project for the future.

	Along the way several of the 'process flags' were renamed and now
	use the 4.4BSD names (P_TRACED instead of STRC for example).  This makes
	the logic flow easier to follow when comparing the sources.

	2.
	---
	sigwait() was missing - an oversight that was easily corrected.  It was
	even simpler than expected due to 'tlseep()' being available now.

	3.
	---
	The networking send/recv syscalls not being restarted after signals
	(and no data transfer) was an oversight from 4.3BSD.  The fix was
	to put a 'setjmp' in for sleep() to use and then check the residual
	byte count.

	4.
	---
	If open(2) or connect(2) is interrupted by a signal always return EINTR
	and do not restart the system call.  This was made much easier by the
	new sleep() routine (which is actually tlseep() in compatibility mode).

	5.
	---
	open("xxx", O_EXLOCK, 0) could leave a 'u_ofile' and 'struct file'
	allocated.  The fix was actually in ino_lock()'s use of tsleep()
	and returning an error to copen() so that the open logic could 
	deallocate the resources and return an error.  The error, since a 
	signal has happened, is EINTR (see #4 above).

	6.
	---
	ino_lock() rewritten to always sleep on the even wait channel.  This
	works because there are different flag bits specifying which lock
	(exclusive or shared) is desired.  It is possible now that an extra
	wakeup/sleep event may occur due to shared and exclusive lock requestors
	using the same wait channel but it's unlikely to be a problem since 
	there are rarely more than two processes waiting for a lock at a time.

	7.
	---
	Fairly well described in the verbose narrative that started the Fix:
	section :).  One more 'global' (u area) variable has gone away.

	8.
	---
	Over time as the kernel structures changed the adb scripts were not
	updated accordingly.  The 'u' area script was badly broken.

	9.
	---
	The kernel uses the 'timeout' table for the select() system call. The
	timeout struct has a signed int available for the number of ticks a
	process can be suspended.  This normally is perfectly ok because no
	kernel timeout is more than about 9 minutes.  For select() used from
	user programs the lower limit could catch some applications by surprise.
	It wasn't possible to change how select in the kernel does the timeout
	but at least the manpage can be updated with a warning for the users.

	Misc.
	----
	A couple of applications (rwhod and comsat) were updated to not bother
	checking for EINTR after recv(2).  There are other applications that
	could have the same modifications made but they have not been updated
	at this time.  As long as siginterrupt(2) is not called to request that
	signals interrupt system calls the kernel will take care of restarting
	recv() automatically.

	The C lint library was updated to reflect the addtion of sigwait(2)
	to the system.

	pstat(8) was updated to take into account the renamed process flags
	and the removal (actually renaming so as to preserve alignment) of
	u_eosys from the u structure.

	The crashsubs program was edited to reflect the changes in system
	include files.  The program didn't compile before and nothing was done
	to change that (another project for the proverbial rainy day ;))

	Oh, the test program that started all of this.  Out of tiny acorns... ;)

-----------sig1.c----------
#include <stdio.h>
#include <signal.h>

	sig_t	catch();
	int	caught = 0;
	struct	sigaction sa;
	sigset_t sigt, pend;

main()
	{
	int	status;
	
	alarm(60);
	sigemptyset(&pend);
	sigemptyset(&sigt);
	sigaddset(&sigt, SIGQUIT);
	sigprocmask(SIG_BLOCK, &sigt, NULL);

	sa.sa_handler = (sig_t)catch;
	sa.sa_mask = 0;
	sa.sa_flags = 0;;

	if	(sigaction(SIGINT, &sa, (struct sigaction *)NULL) == -1)
		err(1, "sigaction");

	while	(1)
		{
		status = sigsuspend(&sigt);
		if	(caught)
			{
			fprintf(stderr, "caught a SIGINT - pend = %lx\n", pend);
			sigemptyset(&pend);
			caught = 0;
			}
		else
			{
			fprintf(stderr, "sigsuspend ret, 'caught' = 0\n");
			}
		}

	exit(0);
	}

sig_t
catch(sig, code, scp)
	int sig, code;
	register struct sigcontext *scp;
	{
	sigset_t set;

	caught = 1;
	sigpending(&set);
	printf("catch: pend %lx\n", set);
	return;
	}

------------------

	It's simple minded.  Compile it "cc -O sig1.c", run it as ./a.out.
	Hit a ^C (to generate a SIGINT) and it'll print out the current
	pending signals - should be 0.  Then hit a ^\ (to generate a SIGQUIT)
	and then a ^C and you should see that a SIGQUIT is pending (because it
	is blocked).  Next ^Z and then 'fg' and if you see anything other than
	0 you have the bug that started this whole mess.  After 60 seconds
	the program exits.

	To see how sigwait(2) can be used here's a modification of the above
	program.  Again, simple minded so as to be a good example.

----------sig2.c--------
#include <stdio.h>
#include <signal.h>

	sig_t	catch();
	int	caught = 0;
	struct	sigaction sa;
	sigset_t sigt, pend;
	char	stack[MINSIGSTKSZ + 512];
	struct	sigaltstack ss;

main()
	{
	int	status;
	
	alarm(60);
	sigemptyset(&pend);
	sigemptyset(&sigt);
	sigaddset(&sigt, SIGQUIT);
	sigprocmask(SIG_BLOCK, &sigt, NULL);

	sa.sa_handler = (sig_t)catch;
	sa.sa_mask = 0;
	sa.sa_flags = SA_ONSTACK;

	ss.ss_base = stack;
	ss.ss_size = sizeof (stack);
	ss.ss_flags = 0;
	if	(sigaltstack(&ss, (struct sigaltstack *)NULL) == -1)
		err(1, "sigaltstack");

	if	(sigaction(SIGINT, &sa, (struct sigaction *)NULL) == -1)
		err(1, "sigaction");

	while	(1)
		{
		status = sigsuspend(&sigt);
		if	(caught)
			{
			fprintf(stderr, "caught a SIGINT - pend = %lx\n", pend);
			sigemptyset(&pend);
			caught = 0;
			}
		else
			{
			fprintf(stderr, "sigsuspend ret, 'caught' = 0\n");
			}
		}

	exit(0);
	}

sig_t
catch(sig, code, scp)
	int sig, code;
	register struct sigcontext *scp;
	{
	sigset_t set;

	caught = 1;
	sigpending(&set);
	printf("catch: pend %lx\n", set);
	if	(sigismember(&set, SIGQUIT))
		{
		sigemptyset(&set);
		sigaddset(&set, SIGQUIT);
		if	(sigwait(&set, &sig) < 0)
			err(1, "sigwait");
		printf("sigwait: %d\n", sig);
		}
	return;
	}
---------------------

	Obviously you can't link that program until after sigwait(2) has
	been added to both the kernel and libc.a :)

	And with that it's time to get on with the directions how to upgrade
	the system.

	First make sure you have both parts of this update (#426 and 427).
	Save each to a tmp file (/tmp/426 and /tmp/427) and cut where 
	indicated.  Then:

		cd /tmp
		sh 426
		sh 426.shar
		patch -p0 < 426.patch
		patch -p0 < 427.patch

	At this point BEFORE compiling _anything_ it would be a good idea to
	make a bootable backup of the system.  At the least have a spare
	kernel (perhaps /genunix) in /.   While nothing _should_ go wrong
	a little bit of paranoia is often wise when changes of this magnitude
	are being made.

	All set?  Ok, first the C library is updated, the new manpage is 
	installed and the C lint library rebuilt.   There are two ways to do
	the C library rebuild - one takes about an hour and recompiles the
	entire library, the second method is faster but involves issuing
	multiple commands manually:

		#1
		___
		cd /usr/src/lib/libc
		make clean
		make
		make install
		make clean
	OR
		#2
		---
		cd /usr/src/lib/libc/pdp/sys
		make
		ar rv /lib/libc.a *.o
		cd profiled
		ar rv /usr/lib/libc_p.a *.o
		ranlib /lib/libc.a /usr/lib/libc_p.a
		cd ..
		make clean

	Next:
		cd /usr/src/man/man2
		/usr/man/manroff select.2 > /usr/man/cat2/select.0
		/usr/man/manroff sigwait.2 > /usr/man/cat2/sigwait.0
		chmod 444 /usr/man/cat2/sigwait.0

	The lint library:

	   cd /usr/src/share/lint
	   make install
	   cd /usr/share/lint
	   /lib/cpp -C -Dlint llib-lc | /usr/libexec/lint/lint1 -v > llib-lc.ln
	   chmod a+r *.ln

	Ok so far?  There's still time to do a backup of the system before
	starting the kernel compiles...

	Now the kernel is done.  

	NOTE:  many of the object modules change size.  It is likely that you
	       will need to adjust the overlay arrangement if the linker
	       gives a "unix.o too big" error.   Do NOT ignore any errors
	       produced during the build of the kernel - the resulting images
	       are not useable.
		
		cd /sys/YOUR_KERNEL
		make clean
		make
		mv /unix /ounix
		mv /netnix /onetnix
		mv unix /unix
		mv netnix /netnix
		chmod 744 /unix /netnix

	NOTE: omit the references to '/netnix' if you are not building a 
	      networking kernel.

	And now the system is rebooted ("shutdown -r now").  When the system
	comes back up there are a couple of applications that are recompiled
	but the hard part is done.

	System all back up?  Great!

		cd /usr/src/usr.sbin/rwhod
		make 
		make install
		make clean
		cd /usr/src/usr.sbin/pstat
		make 
		make install
		make clean
		cd /usr/src/libexec/comsat
		make 
		make install
		make clean

	Hooray - you're all done.  Enjoy the new and improved signal handling,
	the new system call and the improved internal kernel 'sleep' mechanism.

	At your leisure you should recompile the GENERIC kernel and install
	it into /genunix (this is a good way to keep a spare kernel around):

		cd /sys/GENERIC
		make clean
		make
		mv unix /genunix

	As always this and previous updates to 2.11BSD are available via
	anonymous FTP to either FTP.GD-ISO.COM or MOE.2BSD.COM in the
	directory /pub/2.11BSD.

----------------------------cut here-----------------
#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.2).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Made on 1999-09-23 19:57 PDT by <sms@moe.2bsd.com>.
# Source directory was `/users/sms/KIT'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
# This format requires very little intelligence at unshar time.
# "if test", "echo", "mkdir", and "sed" may be needed.
#
# This shar contains:
# length mode       name
# ------ ---------- ------------------------------------------
#   1866 -rw-r--r-- 426.shar
#  42932 -rw-r--r-- 426.patch
#
echo=echo
if mkdir _sh07598; then
  $echo 'x -' 'creating lock directory'
else
  $echo 'failed to create lock directory'
  exit 1
fi
# ============= 426.shar ==============
if test -f '426.shar' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING '426.shar' '(file already exists)'
else
  $echo 'x -' extracting '426.shar' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > '426.shar' &&
X#! /bin/sh
X# This is a shell archive, meaning:
X# 1. Remove everything above the #! /bin/sh line.
X# 2. Save the resulting text in a file.
X# 3. Execute the file with /bin/sh (not csh) to create:
X#	/usr/src/man/man2/sigwait.2
X# This archive created: Mon Sep 20 20:34:17 1999
Xexport PATH; PATH=/bin:/usr/bin:$PATH
Xif test -f '/usr/src/man/man2/sigwait.2'
Xthen
X	echo shar: "will not over-write existing file '/usr/src/man/man2/sigwait.2'"
Xelse
Xsed 's/^Z//' << \SHAR_EOF > '/usr/src/man/man2/sigwait.2'
XZ.\"	@(#)sigwait.2 1.0 (2.11BSD) 1999/9/10
XZ.\"
XZ.TH SIGACTION 2 "September 10, 1999"
XZ.UC 7
XZ.SH NAME
XZ\fBsigwait\fP \- wait for a signal
XZ.SH SYNOPSIS
XZ.B #include <signal.h>
XZ.sp
XZint
XZ\fBsigwait\fP(set, sig)
XZ.br
XZ.I sigset_t *set;
XZ.br
XZ.I int *sig;
XZ.SH DESCRIPTION
XZ.B Sigwait
XZchecks for a pending signal in 
XZ.IR set ,
XZclears it from the set of pending signals and returns the signal number
XZin the location referenced by
XZ.IR sig .
XZIf more than one of the signals contained in
XZ.I set
XZis pending then
XZ.B sigwait
XZselects only one and acts upon it.
XZIf no signal contained in
XZ.I set
XZis pending, then
XZ.B sigwait
XZwaits for a signal to arrive.
XZAll of the signals contained in
XZ.I set
XZshould be blocked or unpredictable results may occur.
XZ.SH RETURN VALUES
XZThe
XZ.B sigwait
XZfunction returns 0 if successful and the signal number is stored in the
XZlocation referenced by
XZ.IR sig .
XZ.SH ERRORS
XZThe
XZ.B sigwait
XZfunction may return one of the following errors:
XZ.TP 20
XZEINVAL
XZThe
XZ.I set
XZargument contains an invalid or unsupported signal number.
XZ.TP 20
XZEFAULT
XZ.I Sig
XZpoints to memory that is not a valid part of the process address space.
XZ.SH SEE ALSO
XZsigprocmask(2)
XZ.SH STANDARDS
XZThe
XZ.B sigwait
XZfunction call
XZconforms to
XZIEEE Std1003.1-1998 (``POSIX'').
XSHAR_EOF
Xchmod 644 '/usr/src/man/man2/sigwait.2'
Xfi
Xexit 0
X#	End of shell archive
SHAR_EOF
  : || $echo 'restore of' '426.shar' 'failed'
fi
# ============= 426.patch ==============
if test -f '426.patch' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING '426.patch' '(file already exists)'
else
  $echo 'x -' extracting '426.patch' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > '426.patch' &&
X*** /usr/include/syscall.h.old	Fri Feb 26 20:09:41 1999
X--- /usr/include/syscall.h	Fri Sep 10 20:39:37 1999
X***************
X*** 3,9 ****
X   * All rights reserved.  The Berkeley software License Agreement
X   * specifies the terms and conditions for redistribution.
X   *
X!  *	@(#)syscall.h	5.4.9 (2.11BSD) 1999/2/19
X   */
X  
X  /*
X--- 3,9 ----
X   * All rights reserved.  The Berkeley software License Agreement
X   * specifies the terms and conditions for redistribution.
X   *
X!  *	@(#)syscall.h	5.4.10 (2.11BSD) 1999/9/10
X   */
X  
X  /*
X***************
X*** 66,72 ****
X  #define	SYS_lock	53
X  #define	SYS_ioctl	54
X  #define	SYS_reboot	55
X! 				/* 56 is old: mpxchan */
X  #define	SYS_symlink	57
X  #define	SYS_readlink	58
X  #define	SYS_execve	59
X--- 66,72 ----
X  #define	SYS_lock	53
X  #define	SYS_ioctl	54
X  #define	SYS_reboot	55
X! #define	SYS_sigwait	56
X  #define	SYS_symlink	57
X  #define	SYS_readlink	58
X  #define	SYS_execve	59
X*** /usr/src/sys/sys/kern_synch.c.old	Fri Aug 29 13:04:11 1997
X--- /usr/src/sys/sys/kern_synch.c	Wed Sep 15 19:19:46 1999
X***************
X*** 3,9 ****
X   * All rights reserved.  The Berkeley software License Agreement
X   * specifies the terms and conditions for redistribution.
X   *
X!  *	@(#)kern_synch.c	1.4 (2.11BSD GTE) 1997/8/29
X   */
X  
X  #include "param.h"
X--- 3,9 ----
X   * All rights reserved.  The Berkeley software License Agreement
X   * specifies the terms and conditions for redistribution.
X   *
X!  *	@(#)kern_synch.c	1.5 (2.11BSD) 1999/9/13
X   */
X  
X  #include "param.h"
X***************
X*** 13,18 ****
X--- 13,19 ----
X  #include "proc.h"
X  #include "buf.h"
X  #include "signal.h"
X+ #include "signalvar.h"
X  #include "vm.h"
X  #include "kernel.h"
X  #include "systm.h"
X***************
X*** 91,185 ****
X  }
X  
X  /*
X!  * Give up the processor till a wakeup occurs
X!  * on chan, at which time the process
X!  * enters the scheduling queue at priority pri.
X!  * The most important effect of pri is that when
X!  * pri<=PZERO a signal cannot disturb the sleep;
X!  * if pri>PZERO signals will be processed.
X!  * Callers of this routine must be prepared for
X!  * premature return, and check that the reason for
X!  * sleeping has gone away.
X!  */
X! sleep(chan, pri)
X! 	caddr_t chan;
X! 	int pri;
X! {
X! 	register struct proc *rp;
X  	register struct proc **qp;
X! 	register s;
X  
X- 	rp = u.u_procp;
X  	s = splhigh();
X! 	if (panicstr) {
X! 		/*
X! 		 * After a panic, just give interrupts a chance, then just
X! 		 * return; don't run any other procs or panic below, in
X! 		 * case this is the idle process and already asleep.  The
X! 		 * splnet should be spl0 if the network was being used
X! 		 * by the filesystem, but for now avoid network interrupts
X! 		 * that might cause another panic.
X! 		 */
X! 		(void) _splnet();
X  		noop();
X  		splx(s);
X  		return;
X- 	}
X- 	if (!chan || rp->p_stat != SRUN)
X- 		panic("sleep");
X- 	rp->p_wchan = chan;
X- 	rp->p_slptime = 0;
X- 	rp->p_pri = pri;
X- 	qp = &slpque[HASH(chan)];
X- 	rp->p_link = *qp;
X- 	*qp = rp;
X- 	if (pri > PZERO) {
X- 		/*
X- 		 * If we stop in issig(), wakeup may already have happened
X- 		 * when we return (rp->p_wchan will then be 0).
X- 		 */
X- 		if (ISSIG(rp)) {
X- 			if (rp->p_wchan)
X- 				unsleep(rp);
X- 			rp->p_stat = SRUN;
X- 			(void) _spl0();
X- 			goto psig;
X  		}
X! 		if (rp->p_wchan == 0)
X! 			goto out;
X! 		rp->p_stat = SSLEEP;
X! 		(void) _spl0();
X! 		/*
X! 		 * maybe a very small core memory, give swapped out
X! 		 * processes a chance.
X! 		 */
X! 		if (runin != 0) {
X! 			runin = 0;
X! 			wakeup((caddr_t)&runin);
X  		}
X! 		u.u_ru.ru_nvcsw++;
X! 		swtch();
X! 		if (ISSIG(rp))
X! 			goto psig;
X! 	} else {
X! 		rp->p_stat = SSLEEP;
X! 		(void) _spl0();
X! 		u.u_ru.ru_nvcsw++;
X! 		swtch();
X  	}
X! out:
X  	splx(s);
X! 	return;
X  
X! 	/*
X! 	 * If priority was low (>PZERO) and there has been a signal,
X! 	 * execute non-local goto through u.u_qsave, aborting the
X! 	 * system call in progress (see trap.c)
X! 	 */
X! psig:
X  	longjmp(u.u_procp->p_addr, &u.u_qsave);
X  	/*NOTREACHED*/
X! }
X  
X  /*
X   * Remove a process from its wait queue
X--- 92,263 ----
X  }
X  
X  /*
X!  * General sleep call "borrowed" from 4.4BSD - the 'wmesg' parameter was
X!  * removed due to data space concerns.  Sleeps at most timo/hz seconds
X!  * 0 means no timeout). NOTE: timeouts in 2.11BSD use a signed int and 
X!  * thus can be at most 32767 'ticks' or about 540 seconds in the US with 
X!  * 60hz power (~650 seconds if 50hz power is being used).
X!  *
X!  * If 'pri' includes the PCATCH flag signals are checked before and after
X!  * sleeping otherwise  signals are not checked.   Returns 0 if a wakeup was
X!  * done, EWOULDBLOCK if the timeout expired, ERESTART if the current system
X!  * call should be restarted, and EINTR if the system call should be
X!  * interrupted and EINTR returned to the user process.
X! */
X! 
X! int
X! tsleep(ident, priority, timo)
X! 	caddr_t	ident;
X! 	int	priority;
X! 	u_short	timo;
X! 	{
X! 	register struct proc *p = u.u_procp;
X  	register struct proc **qp;
X! 	int	s;
X! 	int	sig, catch = priority & PCATCH;
X! 	void	endtsleep();
X  
X  	s = splhigh();
X! 	if	(panicstr)
X! 		{
X! /*
X!  * After a panic just give interrupts a chance then just return.  Don't
X!  * run any other procs (or panic again below) in case this is the idle
X!  * process and already asleep.  The splnet should be spl0 if the network
X!  * was being used but for now avoid network interrupts that might cause
X!  * another panic.
X! */
X! 		(void)_splnet();
X  		noop();
X  		splx(s);
X  		return;
X  		}
X! #ifdef	DIAGNOSTIC
X! 	if	(ident == NULL || p->p_stat != SRUN)
X! 		panic("tsleep");
X! #endif
X! 	p->p_wchan = ident;
X! 	p->p_slptime = 0;
X! 	p->p_pri = priority & PRIMASK;
X! 	qp = &slpque[HASH(ident)];
X! 	p->p_link = *qp;
X! 	*qp =p;
X! 	if	(timo)
X! 		timeout(endtsleep, (caddr_t)p, timo);
X! /*
X!  * We put outselves on the sleep queue and start the timeout before calling
X!  * CURSIG as we could stop there and a wakeup or a SIGCONT (or both) could
X!  * occur while we were stopped.  A SIGCONT would cause us to be marked SSLEEP
X!  * without resuming us thus we must be ready for sleep when CURSIG is called.
X!  * If the wakeup happens while we're stopped p->p_wchan will be 0 upon 
X!  * return from CURSIG.
X! */
X! 	if	(catch)
X! 		{
X! 		p->p_flag |= P_SINTR;
X! 		if	(sig = CURSIG(p))
X! 			{
X! 			if	(p->p_wchan)
X! 				unsleep(p);
X! 			p->p_stat = SRUN;
X! 			goto resume;
X! 			}
X! 		if	(p->p_wchan == 0)
X! 			{
X! 			catch = 0;
X! 			goto resume;
X! 			}
X  		}
X! 	else
X! 		sig = 0;
X! 	p->p_stat = SSLEEP;
X! 	u.u_ru.ru_nvcsw++;
X! 	swtch();
X! resume:
X! 	splx(s);
X! 	p->p_flag &= ~P_SINTR;
X! 	if	(p->p_flag & P_TIMEOUT)
X! 		{
X! 		p->p_flag &= ~P_TIMEOUT;
X! 		if	(sig == 0)
X! 			return(EWOULDBLOCK);
X! 		}
X! 	else if (timo)
X! 		untimeout(endtsleep, (caddr_t)p);
X! 	if	(catch && (sig != 0 || (sig = CURSIG(p))))
X! 		{
X! 		if	(u.u_sigintr & sigmask(sig))
X! 			return(EINTR);
X! 		return(ERESTART);
X! 		}
X! 	return(0);
X  	}
X! 
X! /*
X!  * Implement timeout for tsleep above.  If process hasn't been awakened
X!  * (p_wchan non zero) then set timeout flag and undo the sleep.  If proc
X!  * is stopped just unsleep so it will remain stopped.
X! */
X! 
X! void
X! endtsleep(p)
X! 	register struct proc *p;
X! 	{
X! 	register int	s;
X! 
X! 	s = splhigh();
X! 	if	(p->p_wchan)
X! 		{
X! 		if	(p->p_stat == SSLEEP)
X! 			setrun(p);
X! 		else
X! 			unsleep(p);
X! 		p->p_flag |= P_TIMEOUT;
X! 		}
X  	splx(s);
X! 	}
X  
X! /*
X!  * Give up the processor till a wakeup occurs on chan, at which time the 
X!  * process enters the scheduling queue at priority pri.
X!  *
X!  * This routine was rewritten to use 'tsleep'.  The  old behaviour of sleep
X!  * being interruptible (if 'pri>PZERO') is emulated by setting PCATCH and
X!  * then performing the 'longjmp' if the return value of 'tsleep' is 
X!  * ERESTART.
X!  * 
X!  * Callers of this routine must be prepared for premature return, and check 
X!  * that the reason for sleeping has gone away.
X!  */
X! sleep(chan, pri)
X! 	caddr_t chan;
X! 	int pri;
X! 	{
X! 	register int priority = pri;
X! 	
X! 	if	(pri > PZERO)
X! 		priority |= PCATCH;
X! 
X! 	u.u_error = tsleep(chan, priority, 0);
X! /*
X!  * sleep does not return anything.  If it was a non-interruptible sleep _or_ 
X!  * a successful/normal sleep (one for which a wakeup was done) then return.
X! */
X! 	if	((priority & PCATCH) == 0 || (u.u_error == 0))
X! 		return;
X! /*
X!  * XXX - compatibility uglyness.
X!  *
X!  * The tsleep() above will leave one of the following in u_error:
X!  *
X!  * 0 - a wakeup was done, this is handled above
X!  * EWOULDBLOCK - since no timeout was passed to tsleep we will not see this
X!  * EINTR - put into u_error for trap.c to find (interrupted syscall)
X!  * ERESTART - system call to be restared
X! */
X  	longjmp(u.u_procp->p_addr, &u.u_qsave);
X  	/*NOTREACHED*/
X! 	}
X  
X  /*
X   * Remove a process from its wait queue
X*** /usr/src/sys/sys/kern_exit.c.old	Fri Aug 13 18:55:30 1999
X--- /usr/src/sys/sys/kern_exit.c	Mon Sep 13 20:44:23 1999
X***************
X*** 3,9 ****
X   * All rights reserved.  The Berkeley software License Agreement
X   * specifies the terms and conditions for redistribution.
X   *
X!  *	@(#)kern_exit.c	2.4 (2.11BSD) 1999/8/11
X   */
X  
X  #include "param.h"
X--- 3,9 ----
X   * All rights reserved.  The Berkeley software License Agreement
X   * specifies the terms and conditions for redistribution.
X   *
X!  *	@(#)kern_exit.c	2.5 (2.11BSD) 1999/9/13
X   */
X  
X  #include "param.h"
X***************
X*** 52,58 ****
X  	struct	proc **pp;
X  
X  	p = u.u_procp;
X! 	p->p_flag &= ~(STRC|SULOCK);
X  	p->p_sigignore = ~0;
X  	p->p_sig = 0;
X  	/*
X--- 52,58 ----
X  	struct	proc **pp;
X  
X  	p = u.u_procp;
X! 	p->p_flag &= ~(P_TRACED|SULOCK);
X  	p->p_sigignore = ~0;
X  	p->p_sig = 0;
X  	/*
X***************
X*** 135,142 ****
X  				q->p_pptr = &proc[1];
X  				q->p_ppid = 1;
X  				wakeup((caddr_t)&proc[1]);
X! 				if (q->p_flag&STRC) {
X! 					q->p_flag &= ~STRC;
X  					psignal(q, SIGKILL);
X  				} else if (q->p_stat == SSTOP) {
X  					psignal(q, SIGHUP);
X--- 135,142 ----
X  				q->p_pptr = &proc[1];
X  				q->p_ppid = 1;
X  				wakeup((caddr_t)&proc[1]);
X! 				if (q->p_flag& P_TRACED) {
X! 					q->p_flag &= ~P_TRACED;
X  					psignal(q, SIGKILL);
X  				} else if (q->p_stat == SSTOP) {
X  					psignal(q, SIGHUP);
X***************
X*** 258,264 ****
X  		p->p_pgrp = 0;
X  		p->p_flag = 0;
X  		p->p_wchan = 0;
X- 		p->p_cursig = 0;
X  		return (0);
X  	}
X  	for (p = allproc; p;p = p->p_nxt) {
X--- 258,263 ----
X***************
X*** 268,282 ****
X  		    p->p_pid != uap->pid && p->p_pgrp != -uap->pid)
X  			continue;
X  		++nfound;
X! 		if (p->p_stat == SSTOP && (p->p_flag&SWTED)==0 &&
X! 		    (p->p_flag&STRC || uap->options&WUNTRACED)) {
X! 			p->p_flag |= SWTED;
X  			retval[0] = p->p_pid;
X  			error = 0;
X  			if (uap->compat)
X! 				retval[1] = W_STOPCODE(p->p_cursig);
X  			else if (uap->status) {
X! 				status = W_STOPCODE(p->p_cursig);
X  				error = copyout(&status, uap->status,
X  						sizeof (status));
X  			}
X--- 267,281 ----
X  		    p->p_pid != uap->pid && p->p_pgrp != -uap->pid)
X  			continue;
X  		++nfound;
X! 		if (p->p_stat == SSTOP && (p->p_flag& P_WAITED)==0 &&
X! 		    (p->p_flag&P_TRACED || uap->options&WUNTRACED)) {
X! 			p->p_flag |= P_WAITED;
X  			retval[0] = p->p_pid;
X  			error = 0;
X  			if (uap->compat)
X! 				retval[1] = W_STOPCODE(p->p_ptracesig);
X  			else if (uap->status) {
X! 				status = W_STOPCODE(p->p_ptracesig);
X  				error = copyout(&status, uap->status,
X  						sizeof (status));
X  			}
X***************
X*** 289,302 ****
X  		retval[0] = 0;
X  		return (0);
X  	}
X! 	if (setjmp(&u.u_qsave)) {
X! 		if ((u.u_sigintr & sigmask(q->p_cursig)) != 0)
X! 			return(EINTR);
X! 		u.u_eosys = RESTARTSYS;
X! 		return (0);
X! 	}
X! 	sleep((caddr_t)q, PWAIT);
X! 	goto loop;
X  }
X  
X  /*
X--- 288,297 ----
X  		retval[0] = 0;
X  		return (0);
X  	}
X! 	error = tsleep(q, PWAIT|PCATCH, 0);
X! 	if	(error == 0)
X! 		goto loop;
X! 	return(error);
X  }
X  
X  /*
X*** /usr/src/sys/sys/kern_sig.c.old	Wed Aug 11 19:38:29 1999
X--- /usr/src/sys/sys/kern_sig.c	Thu Sep  9 21:15:29 1999
X***************
X*** 3,9 ****
X   * All rights reserved.  The Berkeley software License Agreement
X   * specifies the terms and conditions for redistribution.
X   *
X!  *	@(#)kern_sig.c	1.10 (2.11BSD) 1999/8/10
X   */
X  
X  #include "param.h"
X--- 3,9 ----
X   * All rights reserved.  The Berkeley software License Agreement
X   * specifies the terms and conditions for redistribution.
X   *
X!  *	@(#)kern_sig.c	1.11 (2.11BSD) 1999/9/9
X   */
X  
X  #include "param.h"
X***************
X*** 149,158 ****
X   * 4.3 Compatibility
X  */
X  sigpause()
X! {
X  	struct a {
X  		long	mask;
X! 	} *uap = (struct a *)u.u_ap;
X  	register struct proc *p = u.u_procp;
X  
X  	/*
X--- 149,158 ----
X   * 4.3 Compatibility
X  */
X  sigpause()
X! 	{
X  	struct a {
X  		long	mask;
X! 		} *uap = (struct a *)u.u_ap;
X  	register struct proc *p = u.u_procp;
X  
X  	/*
X***************
X*** 165,174 ****
X  	u.u_oldmask = p->p_sigmask;
X  	u.u_psflags |= SAS_OLDMASK;
X  	p->p_sigmask = uap->mask &~ sigcantmask;
X! 	for (;;)
X! 		sleep((caddr_t)&u, PSLEP);
X! 	/*NOTREACHED*/
X! }
X  
X  /*
X   * 4.3 Compatibility
X--- 165,175 ----
X  	u.u_oldmask = p->p_sigmask;
X  	u.u_psflags |= SAS_OLDMASK;
X  	p->p_sigmask = uap->mask &~ sigcantmask;
X! 	while	(tsleep((caddr_t)&u, PPAUSE|PCATCH, 0) == 0)
X! 		;
X! 	/* always return EINTR rather than ERESTART */
X! 	return(u.u_error = EINTR);	/* XXX */
X! 	}
X  
X  /*
X   * 4.3 Compatibility
X***************
X*** 337,343 ****
X  	/*
X  	 * If proc is traced, always give parent a chance.
X  	 */
X! 	if (p->p_flag & STRC)
X  		action = SIG_DFL;
X  	else {
X  		/*
X--- 338,344 ----
X  	/*
X  	 * If proc is traced, always give parent a chance.
X  	 */
X! 	if (p->p_flag & P_TRACED)
X  		action = SIG_DFL;
X  	else {
X  		/*
X***************
X*** 355,361 ****
X  	}
X  
X  	if (p->p_nice > NZERO && action == SIG_DFL && (prop & SA_KILL) &&
X! 	    (p->p_flag & STRC) == 0)
X  		p->p_nice = NZERO;
X  
X  	if (prop & SA_CONT)
X--- 356,362 ----
X  	}
X  
X  	if (p->p_nice > NZERO && action == SIG_DFL && (prop & SA_KILL) &&
X! 	    (p->p_flag & P_TRACED) == 0)
X  		p->p_nice = NZERO;
X  
X  	if (prop & SA_CONT)
X***************
X*** 385,403 ****
X  
X  	case SSLEEP:
X  		/*
X! 		 * If process is sleeping at negative priority
X! 		 * we can't interrupt the sleep... the signal will
X! 		 * be noticed when the process returns through
X! 		 * trap() or syscall().
X  		 */
X! 		if (p->p_pri <= PZERO)
X  			goto out;
X  		/*
X  		 * Process is sleeping and traced... make it runnable
X! 		 * so it can discover the signal in issig() and stop
X  		 * for the parent.
X  		 */
X! 		if (p->p_flag&STRC)
X  			goto run;
X  
X  		/*
X--- 386,403 ----
X  
X  	case SSLEEP:
X  		/*
X! 		 * If process is sleeping uninterruptibly we can not
X! 		 * interrupt the sleep... the signal will be noticed 
X! 		 * when the process returns through trap() or syscall().
X  		 */
X! 		if	((p->p_flag & P_SINTR) == 0)
X  			goto out;
X  		/*
X  		 * Process is sleeping and traced... make it runnable
X! 		 * so it can discover the signal in issignal() and stop
X  		 * for the parent.
X  		 */
X! 		if	(p->p_flag& P_TRACED)
X  			goto run;
X  
X  		/*
X***************
X*** 425,431 ****
X  			if (p->p_flag & SVFORK)
X  				goto out;
X  			p->p_sig &= ~mask;
X! 			p->p_cursig = sig;
X  			if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0)
X  				psignal(p->p_pptr, SIGCHLD);
X  			stop(p);
X--- 425,431 ----
X  			if (p->p_flag & SVFORK)
X  				goto out;
X  			p->p_sig &= ~mask;
X! 			p->p_ptracesig = sig;
X  			if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0)
X  				psignal(p->p_pptr, SIGCHLD);
X  			stop(p);
X***************
X*** 438,444 ****
X  		 * If traced process is already stopped,
X  		 * then no further action is necessary.
X  		 */
X! 		if (p->p_flag&STRC)
X  			goto out;
X  		if (sig == SIGKILL)
X  			goto run;
X--- 438,444 ----
X  		 * If traced process is already stopped,
X  		 * then no further action is necessary.
X  		 */
X! 		if (p->p_flag & P_TRACED)
X  			goto out;
X  		if (sig == SIGKILL)
X  			goto run;
X***************
X*** 445,469 ****
X  		if (prop & SA_CONT) {
X  			/*
X  			 * If SIGCONT is default (or ignored), we continue the
X! 			 * process but don't leave the signal in p_siglist, as
X  			 * it has no further action.  If SIGCONT is held, we
X  			 * continue the process and leave the signal in
X! 			 * p_siglist.  If the process catches SIGCONT, let it
X  			 * handle the signal itself.  If it isn't waiting on
X  			 * an event, then it goes back to run state.
X  			 * Otherwise, process goes back to sleep state.
X- 			 *
X- 			 * XXX - 2.11BSD has to leave the SIGCONT bit in the
X- 			 * mask so that the call to issig() will clear p_cursig.
X- 			 * We could clear p_cursig here but since issig() will 
X- 			 * get called anyway when the process wakes up why not 
X- 			 * leave it something to do?  Besides clearing p_cursig
X- 			 * here felt like a kluge.
X  			 */
X- #ifndef pdp11
X  			if (action == SIG_DFL)
X  				p->p_sig &= ~mask;
X- #endif
X  			if (action == SIG_CATCH || p->p_wchan == 0)
X  				goto run;
X  			p->p_stat = SSLEEP;
X--- 445,460 ----
X  		if (prop & SA_CONT) {
X  			/*
X  			 * If SIGCONT is default (or ignored), we continue the
X! 			 * process but don't leave the signal in p_sig, as
X  			 * it has no further action.  If SIGCONT is held, we
X  			 * continue the process and leave the signal in
X! 			 * p_sig.  If the process catches SIGCONT, let it
X  			 * handle the signal itself.  If it isn't waiting on
X  			 * an event, then it goes back to run state.
X  			 * Otherwise, process goes back to sleep state.
X  			 */
X  			if (action == SIG_DFL)
X  				p->p_sig &= ~mask;
X  			if (action == SIG_CATCH || p->p_wchan == 0)
X  				goto run;
X  			p->p_stat = SSLEEP;
X***************
X*** 485,491 ****
X  		 * runnable and can look at the signal.  But don't make
X  		 * the process runnable, leave it stopped.
X  		 */
X! 		if (p->p_wchan && p->p_pri > PZERO)
X  			unsleep(p);
X  		goto out;
X  		/*NOTREACHED*/
X--- 476,482 ----
X  		 * runnable and can look at the signal.  But don't make
X  		 * the process runnable, leave it stopped.
X  		 */
X! 		if (p->p_wchan && (p->p_flag & P_SINTR))
X  			unsleep(p);
X  		goto out;
X  		/*NOTREACHED*/
X***************
X*** 511,555 ****
X  }
X  
X  /*
X!  * Returns true if the current
X!  * process has a signal to process.
X!  * The signal to process is put in p_cursig.
X!  * This is asked at least once each time a process enters the
X!  * system (though this can usually be done without actually
X!  * calling issig by checking the pending signal masks.)
X!  * A signal does not do anything
X!  * directly to a process; it sets
X!  * a flag that asks the process to
X!  * do something to itself.
X   */
X! issig()
X! {
X  	register struct proc *p;
X  	register int sig;
X  	long mask;
X  	int prop;
X  
X- 	p = u.u_procp;
X  	for (;;) {
X  		mask = p->p_sig & ~p->p_sigmask;
X  		if (p->p_flag&SVFORK)
X  			mask &= ~stopsigmask;
X! 		if (mask == 0) {
X! 			p->p_cursig = 0;	/* XXX - no current signal */
X  			return(0);		/* No signals to send */
X- 		}
X  		sig = ffs(mask);
X  		mask = sigmask(sig);
X  		prop = sigprop[sig];
X  		/*
X  		 * We should see pending but ignored signals
X! 		 * only if STRC was on when they were posted.
X  		*/
X! 		if (mask & p->p_sigignore && (p->p_flag&STRC) == 0) {
X  			p->p_sig &= ~mask;
X  			continue;
X  		}
X! 		if (p->p_flag&STRC && (p->p_flag & SVFORK) == 0) {
X  			/*
X  			 * If traced, always stop, and stay
X  			 * stopped until released by the parent.
X--- 502,543 ----
X  }
X  
X  /*
X!  * If the current process has received a signal (should be caught
X!  * or cause termination, should interrupt current syscall) return the
X!  * signal number.  Stop signals with default action are processed
X!  * immediately then cleared; they are not returned.  This is checked
X!  * after each entry into the kernel for a syscall of trap (though this 
X!  * can usually be done without calling issignal by checking the pending
X!  * signals masks in CURSIG)/  The normal sequence is:
X!  *
X!  *	while (signum = CURSIG(u.u_procp))
X!  *		postsig(signum);
X   */
X! issignal(p)
X  	register struct proc *p;
X+ {
X  	register int sig;
X  	long mask;
X  	int prop;
X  
X  	for (;;) {
X  		mask = p->p_sig & ~p->p_sigmask;
X  		if (p->p_flag&SVFORK)
X  			mask &= ~stopsigmask;
X! 		if (mask == 0)
X  			return(0);		/* No signals to send */
X  		sig = ffs(mask);
X  		mask = sigmask(sig);
X  		prop = sigprop[sig];
X  		/*
X  		 * We should see pending but ignored signals
X! 		 * only if P_TRACED was on when they were posted.
X  		*/
X! 		if (mask & p->p_sigignore && (p->p_flag& P_TRACED) == 0) {
X  			p->p_sig &= ~mask;
X  			continue;
X  		}
X! 		if (p->p_flag & P_TRACED && (p->p_flag & SVFORK) == 0) {
X  			/*
X  			 * If traced, always stop, and stay
X  			 * stopped until released by the parent.
X***************
X*** 563,581 ****
X  			 * the initial request.
X  			 */
X  			p->p_sig &= ~mask;
X! 			p->p_cursig = sig;
X  			psignal(p->p_pptr, SIGCHLD);
X  			do {
X  				stop(p);
X  				swtch();
X! 			} while (!procxmt() && p->p_flag&STRC);
X  
X  			/*
X  			 * If parent wants us to take the signal,
X! 			 * then it will leave it in p->p_cursig;
X  			 * otherwise we just look for signals again.
X  			 */
X! 			sig = p->p_cursig;
X  			if (sig == 0)
X  				continue;
X  
X--- 551,569 ----
X  			 * the initial request.
X  			 */
X  			p->p_sig &= ~mask;
X! 			p->p_ptracesig = sig;
X  			psignal(p->p_pptr, SIGCHLD);
X  			do {
X  				stop(p);
X  				swtch();
X! 			} while (!procxmt() && p->p_flag & P_TRACED);
X  
X  			/*
X  			 * If parent wants us to take the signal,
X! 			 * then it will leave it in p->p_ptracesig;
X  			 * otherwise we just look for signals again.
X  			 */
X! 			sig = p->p_ptracesig;
X  			if (sig == 0)
X  				continue;
X  
X***************
X*** 593,599 ****
X  			 * to the top to rescan signals.  This ensures
X  			 * that p_sig* and u_signal are consistent.
X  			 */
X! 			if ((p->p_flag&STRC) == 0)
X  				continue;
X  			prop = sigprop[sig];
X  		}
X--- 581,587 ----
X  			 * to the top to rescan signals.  This ensures
X  			 * that p_sig* and u_signal are consistent.
X  			 */
X! 			if ((p->p_flag& P_TRACED) == 0)
X  				continue;
X  			prop = sigprop[sig];
X  		}
X***************
X*** 623,633 ****
X  			 * process group, ignore tty stop signals.
X  			 */
X  			if (prop & SA_STOP) {
X! 				if (p->p_flag & STRC ||
X  		    		    (p->p_pptr == &proc[1] &&
X  				    prop & SA_TTYSTOP))
X  					break;	/* == ignore */
X! 				p->p_cursig = sig;
X  				if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0)
X  					psignal(p->p_pptr, SIGCHLD);
X  				stop(p);
X--- 611,621 ----
X  			 * process group, ignore tty stop signals.
X  			 */
X  			if (prop & SA_STOP) {
X! 				if (p->p_flag & P_TRACED ||
X  		    		    (p->p_pptr == &proc[1] &&
X  				    prop & SA_TTYSTOP))
X  					break;	/* == ignore */
X! 				p->p_ptracesig = sig;
X  				if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0)
X  					psignal(p->p_pptr, SIGCHLD);
X  				stop(p);
X***************
X*** 639,648 ****
X  				 * Default action is to ignore; drop it.
X  				 */
X  				break;		/* == ignore */
X! 			} else {
X! 				p->p_cursig = sig;	/* XXX */
X  				return(sig);
X- 			}
X  			/*NOTREACHED*/
X  
X  		case SIG_IGN:
X--- 627,634 ----
X  				 * Default action is to ignore; drop it.
X  				 */
X  				break;		/* == ignore */
X! 			} else
X  				return(sig);
X  			/*NOTREACHED*/
X  
X  		case SIG_IGN:
X***************
X*** 652,670 ****
X  			 * or ignored signal, unless process is traced.
X  			 */
X  			if ((prop & SA_CONT) == 0 &&
X! 				(p->p_flag&STRC) == 0)
X  				printf("issig\n");
X  			break;			/* == ignore */
X  
X  		default:
X  			/*
X! 			 * This signal has an action, put signal in cursig
X! 			 * for postsig to process it.
X  			 */
X- 			p->p_cursig = sig;	/* XXX */
X  			return(sig);
X  		}
X! 		p->p_sig &= ~mask;		/* take the signal! */
X  	}
X  	/* NOTREACHED */
X  }
X--- 638,654 ----
X  			 * or ignored signal, unless process is traced.
X  			 */
X  			if ((prop & SA_CONT) == 0 &&
X! 				(p->p_flag & P_TRACED) == 0)
X  				printf("issig\n");
X  			break;			/* == ignore */
X  
X  		default:
X  			/*
X! 			 * This signal has an action, let postsig process it.
X  			 */
X  			return(sig);
X  		}
X! 		p->p_sig &= ~mask;		/* take the signal away! */
X  	}
X  	/* NOTREACHED */
X  }
X***************
X*** 679,708 ****
X  {
X  
X  	p->p_stat = SSTOP;
X! 	p->p_flag &= ~SWTED;
X  	wakeup((caddr_t)p->p_pptr);
X  }
X  
X  /*
X!  * Perform the action specified by
X!  * the current signal.
X!  * The usual sequence is:
X!  *	if (issig())
X!  *		postsig();
X!  * The signal bit has not already been cleared by issig so that needs to be
X!  * done here.  The current signal number stored in p->p_cursig.
X!  *
X!  * Actually the sequence is:
X!  *	if (p->p_cursig || ISSIG())
X!  * Thus not clearing p_cursig below when returning 0 causes repeated delivery of
X!  * the signal.  The sequence probably _should_ be simply ISSIG() but who knows
X!  * what doing that would break.  Sigh.
X   */
X  
X! postsig()
X  {
X  	register struct proc *p = u.u_procp;
X- 	register int sig = p->p_cursig;
X  	long mask = sigmask(sig), returnmask;
X  	register int (*action)();
X  
X--- 663,681 ----
X  {
X  
X  	p->p_stat = SSTOP;
X! 	p->p_flag &= ~P_WAITED;
X  	wakeup((caddr_t)p->p_pptr);
X  }
X  
X  /*
X!  * Take the action for the specified signal
X!  * from the current set of pending signals.
X   */
X  
X! postsig(sig)
X! 	int sig;
X  {
X  	register struct proc *p = u.u_procp;
X  	long mask = sigmask(sig), returnmask;
X  	register int (*action)();
X  
X***************
X*** 719,725 ****
X  		if (action == SIG_IGN || (p->p_sigmask & mask))
X  			panic("postsig action");
X  #endif
X! 		u.u_error = 0;
X  		/*
X  		 * Set the new mask value and also defer further
X  		 * occurences of this signal.
X--- 692,698 ----
X  		if (action == SIG_IGN || (p->p_sigmask & mask))
X  			panic("postsig action");
X  #endif
X! 		u.u_error = 0;	/* XXX - why? */
X  		/*
X  		 * Set the new mask value and also defer further
X  		 * occurences of this signal.
X***************
X*** 739,745 ****
X  		(void) _spl0();
X  		u.u_ru.ru_nsignals++;
X  		sendsig(action, sig, returnmask);
X- 		p->p_cursig = 0;
X  		return;
X  	}
X  	u.u_acflag |= AXSIG;
X--- 712,717 ----
X*** /usr/src/sys/sys/sys_generic.c.old	Fri Feb 14 22:03:46 1997
X--- /usr/src/sys/sys/sys_generic.c	Mon Sep 13 20:38:18 1999
X***************
X*** 3,9 ****
X   * All rights reserved.  The Berkeley software License Agreement
X   * specifies the terms and conditions for redistribution.
X   *
X!  *	@(#)sys_generic.c	1.6 (2.11BSD GTE) 1997/2/14
X   */
X  
X  #include "param.h"
X--- 3,9 ----
X   * All rights reserved.  The Berkeley software License Agreement
X   * specifies the terms and conditions for redistribution.
X   *
X!  *	@(#)sys_generic.c	1.7 (2.11BSD) 1999/9/10
X   */
X  
X  #include "param.h"
X***************
X*** 11,16 ****
X--- 11,17 ----
X  
X  #include "user.h"
X  #include "proc.h"
X+ #include "signalvar.h"
X  #include "inode.h"
X  #include "file.h"
X  #include "ioctl.h"
X***************
X*** 142,180 ****
X  	total =(off_t)0;
X  	uio->uio_resid = 0;
X  	uio->uio_segflg = UIO_USERSPACE;
X! 	iov = uio->uio_iov;
X! 	for (i = 0; i < uio->uio_iovcnt; i++) {
X! #ifdef	pdp11
X  		total += iov->iov_len;
X! #else
X! 		if (iov->iov_len < 0) {
X! 			u.u_error = EINVAL;
X! 			return;
X! 		}
X! 		uio->uio_resid += iov->iov_len;
X! 		if (uio->uio_resid < 0) {
X! 			u.u_error = EINVAL;
X! 			return;
X! 		}
X! #endif
X! 		iov++;
X! 	}
X! #ifdef	pdp11
X  	uio->uio_resid = total;
X! 	if (uio->uio_resid != total) {	/* check wraparound */
X! 		u.u_error = EINVAL;
X! 		return;
X! 	}
X! #endif
X  	count = uio->uio_resid;
X! 	if (setjmp(&u.u_qsave)) {
X! 		if (uio->uio_resid == count) {
X! 			if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
X! 				u.u_error = EINTR;
X! 			else
X! 				u.u_eosys = RESTARTSYS;
X  		}
X! 	} else
X  		u.u_error = (*Fops[fp->f_type]->fo_rw)(fp, uio);
X  	u.u_r.r_val1 = count - uio->uio_resid;
X  }
X--- 143,171 ----
X  	total =(off_t)0;
X  	uio->uio_resid = 0;
X  	uio->uio_segflg = UIO_USERSPACE;
X! 	for	(iov = uio->uio_iov, i = 0; i < uio->uio_iovcnt; i++, iov++)
X  		total += iov->iov_len;
X! 
X  	uio->uio_resid = total;
X! 	if	(uio->uio_resid != total)	/* check wraparound */
X! 		return(u.u_error = EINVAL);
X! 
X  	count = uio->uio_resid;
X! 	if	(setjmp(&u.u_qsave))
X! 		{
X! /*
X!  * The ONLY way we can get here is via the longjump in sleep.  Thus signals
X!  * have been checked and u_error set accordingly.  If no bytes have been 
X!  * transferred then all that needs to be done now is 'return'; the system 
X!  * call will either be restarted or reported as interrupted.  If bytes have 
X!  * been transferred then we need to calculate the number of bytes transferred.
X! */
X! 		if	(uio->uio_resid == count)
X! 			return;
X! 		else
X! 			u.u_error = 0;
X  		}
X! 	else
X  		u.u_error = (*Fops[fp->f_type]->fo_rw)(fp, uio);
X  	u.u_r.r_val1 = count - uio->uio_resid;
X  }
X***************
X*** 277,283 ****
X  			u.u_error = copyout(data, uap->cmarg, size);
X  }
X  
X- int	unselect();
X  int	nselcoll;
X  
X  /*
X--- 268,273 ----
X***************
X*** 284,300 ****
X   * Select system call.
X   */
X  select()
X! {
X! 	register struct uap  {
X  		int	nd;
X  		fd_set	*in, *ou, *ex;
X  		struct	timeval *tv;
X! 	} *uap = (struct uap *)u.u_ap;
X  	fd_set ibits[3], obits[3];
X  	struct timeval atv;
X! 	register int s, ni;
X! 	int ncoll;
X! 	label_t lqsave;
X  
X  	bzero((caddr_t)ibits, sizeof(ibits));
X  	bzero((caddr_t)obits, sizeof(obits));
X--- 274,291 ----
X   * Select system call.
X   */
X  select()
X! 	{
X! 	register struct uap
X! 		{
X  		int	nd;
X  		fd_set	*in, *ou, *ex;
X  		struct	timeval *tv;
X! 		} *uap = (struct uap *)u.u_ap;
X  	fd_set ibits[3], obits[3];
X  	struct timeval atv;
X! 	unsigned int timo = 0;
X! 	register int error, ni;
X! 	int ncoll, s;
X  
X  	bzero((caddr_t)ibits, sizeof(ibits));
X  	bzero((caddr_t)obits, sizeof(obits));
X***************
X*** 304,312 ****
X  
X  #define	getbits(name, x) \
X  	if (uap->name) { \
X! 		u.u_error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
X  		    (unsigned)(ni * sizeof(fd_mask))); \
X! 		if (u.u_error) \
X  			goto done; \
X  	}
X  	getbits(in, 0);
X--- 295,303 ----
X  
X  #define	getbits(name, x) \
X  	if (uap->name) { \
X! 		error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
X  		    (unsigned)(ni * sizeof(fd_mask))); \
X! 		if (error) \
X  			goto done; \
X  	}
X  	getbits(in, 0);
X***************
X*** 314,412 ****
X  	getbits(ex, 2);
X  #undef	getbits
X  
X! 	if (uap->tv) {
X! 		u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
X! 			sizeof (atv));
X! 		if (u.u_error)
X  			goto done;
X! 		if (itimerfix(&atv)) {
X! 			u.u_error = EINVAL;
X  			goto done;
X! 		}
X  		s = splhigh();
X  		time.tv_usec = lbolt * mshz;
X  		timevaladd(&atv, &time);
X  		splx(s);
X! 	}
X  retry:
X  	ncoll = nselcoll;
X! 	u.u_procp->p_flag |= SSEL;
X! 	u.u_r.r_val1 = selscan(ibits, obits, uap->nd);
X! 	if (u.u_error || u.u_r.r_val1)
X  		goto done;
X  	s = splhigh();
X! 	/* this should be timercmp(&time, &atv, >=) */
X! 	if (uap->tv && (time.tv_sec > atv.tv_sec || (time.tv_sec == atv.tv_sec
X! 	    && lbolt * mshz >= atv.tv_usec))) {
X! 		splx(s);
X! 		goto done;
X! 	}
X! 	if ((u.u_procp->p_flag & SSEL) == 0 || nselcoll != ncoll) {
X! 		u.u_procp->p_flag &= ~SSEL;
X! 		splx(s);
X! 		goto retry;
X! 	}
X! 	u.u_procp->p_flag &= ~SSEL;
X! 	if (uap->tv) {
X! 		lqsave = u.u_qsave;
X! 		if (setjmp(&u.u_qsave)) {
X! 			untimeout(unselect, (caddr_t)u.u_procp);
X! 			u.u_error = EINTR;
X  			splx(s);
X  			goto done;
X  		}
X! 		timeout(unselect, (caddr_t)u.u_procp, hzto(&atv));
X! 	}
X! 	sleep((caddr_t)&selwait, PZERO+1);
X! 	if (uap->tv) {
X! 		u.u_qsave = lqsave;
X! 		untimeout(unselect, (caddr_t)u.u_procp);
X! 	}
X  	splx(s);
X! 	goto retry;
X  done:
X  #define	putbits(name, x) \
X! 	if (uap->name) { \
X! 		int error = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
X! 		    (unsigned)(ni * sizeof(fd_mask))); \
X! 		if (error) \
X! 			u.u_error = error; \
X! 	}
X! 	if (u.u_error == 0) {
X  		putbits(in, 0);
X  		putbits(ou, 1);
X  		putbits(ex, 2);
X  #undef putbits
X  	}
X- }
X  
X! unselect(p)
X! 	register struct proc *p;
X! {
X! 	register int s = splhigh();
X! 
X! 	switch (p->p_stat) {
X! 
X! 	case SSLEEP:
X! 		setrun(p);
X! 		break;
X! 
X! 	case SSTOP:
X! 		unsleep(p);
X! 		break;
X! 	}
X! 	splx(s);
X! }
X! 
X! selscan(ibits, obits, nfd)
X  	fd_set *ibits, *obits;
X! 	int nfd;
X  {
X! 	register int i, j;
X  	fd_mask bits;
X- 	register int which, flag;
X  	struct file *fp;
X! 	int n = 0;
X  
X  	for (which = 0; which < 3; which++) {
X  		switch (which) {
X--- 305,388 ----
X  	getbits(ex, 2);
X  #undef	getbits
X  
X! 	if	(uap->tv)
X! 		{
X! 		error = copyin((caddr_t)uap->tv, (caddr_t)&atv, sizeof (atv));
X! 		if	(error)
X  			goto done;
X! 		if	(itimerfix(&atv))
X! 			{
X! 			error = EINVAL;
X  			goto done;
X! 			}
X  		s = splhigh();
X  		time.tv_usec = lbolt * mshz;
X  		timevaladd(&atv, &time);
X  		splx(s);
X! 		}
X  retry:
X  	ncoll = nselcoll;
X! 	u.u_procp->p_flag |= P_SELECT;
X! 	error = selscan(ibits, obits, uap->nd, &u.u_r.r_val1);
X! 	if	(error || u.u_r.r_val1)
X  		goto done;
X  	s = splhigh();
X! 	if	(uap->tv)
X! 		{
X! 		/* this should be timercmp(&time, &atv, >=) */
X! 		if	((time.tv_sec > atv.tv_sec || (time.tv_sec == atv.tv_sec
X! 	    			&& lbolt * mshz >= atv.tv_usec)))
X! 			{
X  			splx(s);
X  			goto done;
X+ 			}
X+ 		timo = hzto(&atv);
X+ 		if	(timo == 0)
X+ 			timo = 1;
X  		}
X! 	if	((u.u_procp->p_flag & P_SELECT) == 0 || nselcoll != ncoll)
X! 		{
X! 		u.u_procp->p_flag &= ~P_SELECT;
X! 		splx(s);
X! 		goto retry;
X! 		}
X! 	u.u_procp->p_flag &= ~P_SELECT;
X! 	error = tsleep(&selwait, PSOCK | PCATCH, timo);
X  	splx(s);
X! 	if	(error == 0)
X! 		goto retry;
X  done:
X+ 	u.u_procp->p_flag &= ~P_SELECT;
X+ 	/* select is not restarted after signals... */
X+ 	if	(error == ERESTART)
X+ 		error = EINTR;
X+ 	if	(error == EWOULDBLOCK)
X+ 		error = 0;
X  #define	putbits(name, x) \
X! 	if (uap->name && \
X! 		(error2 = copyout(&obits[x],uap->name,(ni*sizeof(fd_mask))))) \
X! 			error = error2;
X! 
X! 	if	(error == 0)
X! 		{
X! 		int error2;
X! 
X  		putbits(in, 0);
X  		putbits(ou, 1);
X  		putbits(ex, 2);
X  #undef putbits
X+ 		}
X+ 	return(u.u_error = error);
X  	}
X  
X! selscan(ibits, obits, nfd, retval)
X  	fd_set *ibits, *obits;
X! 	int nfd, *retval;
X  {
X! 	register int i, j, flag;
X  	fd_mask bits;
X  	struct file *fp;
X! 	int	which, n = 0;
X  
X  	for (which = 0; which < 3; which++) {
X  		switch (which) {
X***************
X*** 425,434 ****
X  			while ((j = ffs(bits)) && i + --j < nfd) {
X  				bits &= ~(1L << j);
X  				fp = u.u_ofile[i + j];
X! 				if (fp == NULL) {
X! 					u.u_error = EBADF;
X! 					break;
X! 				}
X  				if ((*Fops[fp->f_type]->fo_select)(fp,flag)) {
X  					FD_SET(i + j, &obits[which]);
X  					n++;
X--- 401,408 ----
X  			while ((j = ffs(bits)) && i + --j < nfd) {
X  				bits &= ~(1L << j);
X  				fp = u.u_ofile[i + j];
X! 				if (fp == NULL)
X! 					return(EBADF);
X  				if ((*Fops[fp->f_type]->fo_select)(fp,flag)) {
X  					FD_SET(i + j, &obits[which]);
X  					n++;
X***************
X*** 436,442 ****
X  			}
X  		}
X  	}
X! 	return (n);
X  }
X  
X  /*ARGSUSED*/
X--- 410,417 ----
X  			}
X  		}
X  	}
X! 	*retval = n;
X! 	return(0);
X  }
X  
X  /*ARGSUSED*/
X***************
X*** 466,473 ****
X  				setrun(p);
X  			else
X  				unsleep(p);
X! 		} else if (p->p_flag & SSEL)
X! 			p->p_flag &= ~SSEL;
X  		splx(s);
X  	}
X  	restormap(map);
X--- 441,448 ----
X  				setrun(p);
X  			else
X  				unsleep(p);
X! 		} else if (p->p_flag & P_SELECT)
X! 			p->p_flag &= ~P_SELECT;
X  		splx(s);
X  	}
X  	restormap(map);
X*** /usr/src/sys/sys/sys_inode.c.old	Thu Jul  3 19:46:01 1997
X--- /usr/src/sys/sys/sys_inode.c	Mon Sep 13 20:35:59 1999
X***************
X*** 3,9 ****
X   * All rights reserved.  The Berkeley software License Agreement
X   * specifies the terms and conditions for redistribution.
X   *
X!  *	@(#)sys_inode.c	1.10 (2.11BSD GTE) 1997/7/3
X   */
X  
X  #include "param.h"
X--- 3,9 ----
X   * All rights reserved.  The Berkeley software License Agreement
X   * specifies the terms and conditions for redistribution.
X   *
X!  *	@(#)sys_inode.c	1.11 (2.11BSD) 1999/9/10
X   */
X  
X  #include "param.h"
X***************
X*** 11,16 ****
X--- 11,17 ----
X  
X  #include "user.h"
X  #include "proc.h"
X+ #include "signalvar.h"
X  #include "inode.h"
X  #include "buf.h"
X  #include "fs.h"
X***************
X*** 121,129 ****
X  	type = ip->i_mode&IFMT;
X  /*
X   * The write case below checks that i/o is done synchronously to directories
X!  * and that i/o to append only files takes place at the end of file.  The
X!  * 'log()' statements below should be ifdef'd.  Also, we do not panic on 
X!  * non-sync directory i/o - the sync bit is forced on.
X  */
X  	if (uio->uio_rw == UIO_READ)
X  		{
X--- 122,129 ----
X  	type = ip->i_mode&IFMT;
X  /*
X   * The write case below checks that i/o is done synchronously to directories
X!  * and that i/o to append only files takes place at the end of file.
X!  * We do not panic on non-sync directory i/o - the sync bit is forced on.
X  */
X  	if (uio->uio_rw == UIO_READ)
X  		{
X***************
X*** 142,151 ****
X  		    break;
X  		case IFDIR:
X  		    if  ((ioflag & IO_SYNC) == 0)
X- 			{
X- 			log(LOG_ERR, "rwip sync\n");
X  			ioflag |= IO_SYNC;
X- 			}
X  		    break;
X  		case IFLNK:
X  		case IFBLK:
X--- 142,148 ----
X***************
X*** 152,158 ****
X  		case IFCHR:
X  		    break;
X  		default:
X- 		    log(LOG_ERR, "rwip: %d\n", type);
X  		    return(EFTYPE);
X  		}
X  	   }
X--- 149,154 ----
X***************
X*** 357,368 ****
X  	case IFCHR:
X  		dev = ip->i_rdev;
X  		u.u_r.r_val1 = 0;
X! 		if (setjmp(&u.u_qsave)) {
X! 			if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
X! 				return(EINTR);
X! 			u.u_eosys = RESTARTSYS;
X! 			return (0);
X! 		}
X  		return((*cdevsw[major(dev)].d_ioctl)(dev,com,data,fp->f_flag));
X  	}
X  }
X--- 353,365 ----
X  	case IFCHR:
X  		dev = ip->i_rdev;
X  		u.u_r.r_val1 = 0;
X! 		if	(setjmp(&u.u_qsave))
X! /*
X!  * The ONLY way we can get here is via the longjump in sleep.  Signals have
X!  * been checked for and u_error set accordingly.  All that remains to do 
X!  * is 'return'.
X! */
X! 			return(u.u_error);
X  		return((*cdevsw[major(dev)].d_ioctl)(dev,com,data,fp->f_flag));
X  	}
X  }
X***************
X*** 524,529 ****
X--- 521,528 ----
X  
X  /*
X   * Place an advisory lock on an inode.
X+  * NOTE: callers of this routine must be prepared to deal with the pseudo
X+  *       error return ERESTART.
X   */
X  ino_lock(fp, cmd)
X  	register struct file *fp;
X***************
X*** 531,550 ****
X  {
X  	register int priority = PLOCK;
X  	register struct inode *ip = (struct inode *)fp->f_data;
X  
X  	if ((cmd & LOCK_EX) == 0)
X  		priority += 4;
X! 	if (setjmp(&u.u_qsave)) {
X! 		if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
X! 			return(EINTR);
X! 		u.u_eosys = RESTARTSYS;
X! 		return (0);
X! 	}
X! 	/*
X! 	 * If there's a exclusive lock currently applied
X! 	 * to the file, then we've gotta wait for the
X! 	 * lock with everyone else.
X! 	 */
X  again:
X  	while (ip->i_flag & IEXLOCK) {
X  		/*
X--- 530,550 ----
X  {
X  	register int priority = PLOCK;
X  	register struct inode *ip = (struct inode *)fp->f_data;
X+ 	int error;
X  
X  	if ((cmd & LOCK_EX) == 0)
X  		priority += 4;
X! /*
X!  * If there's a exclusive lock currently applied to the file then we've 
X!  * gotta wait for the lock with everyone else.
X!  *
X!  * NOTE:  We can NOT sleep on i_exlockc because it is on an odd byte boundary
X!  *	  and the low (oddness) bit is reserved for networking/supervisor mode
X!  *	  sleep channels.  Thus we always sleep on i_shlockc and simply check
X!  *	  the proper bits to see if the lock we want is granted.  This may 
X!  *	  mean an extra wakeup/sleep event is done once in a while but 
X!  *	  everything will work correctly.
X! */
X  again:
X  	while (ip->i_flag & IEXLOCK) {
X  		/*
X***************
X*** 558,564 ****
X  		if (cmd & LOCK_NB)
X  			return (EWOULDBLOCK);
X  		ip->i_flag |= ILWAIT;
X! 		sleep((caddr_t)&ip->i_exlockc, priority);
X  	}
X  	if ((cmd & LOCK_EX) && (ip->i_flag & ISHLOCK)) {
X  		/*
X--- 558,566 ----
X  		if (cmd & LOCK_NB)
X  			return (EWOULDBLOCK);
X  		ip->i_flag |= ILWAIT;
X! 		error = tsleep((caddr_t)&ip->i_shlockc, priority | PCATCH, 0);
X! 		if	(error)
X! 			return(error);
X  	}
X  	if ((cmd & LOCK_EX) && (ip->i_flag & ISHLOCK)) {
X  		/*
X***************
X*** 575,581 ****
X  		if (cmd & LOCK_NB)
X  			return (EWOULDBLOCK);
X  		ip->i_flag |= ILWAIT;
X! 		sleep((caddr_t)&ip->i_shlockc, PLOCK);
X  		goto again;
X  	}
X  	if (cmd & LOCK_EX) {
X--- 577,585 ----
X  		if (cmd & LOCK_NB)
X  			return (EWOULDBLOCK);
X  		ip->i_flag |= ILWAIT;
X! 		error = tsleep((caddr_t)&ip->i_shlockc, PLOCK | PCATCH, 0);
X! 		if	(error)
X! 			return(error);
X  		goto again;
X  	}
X  	if (cmd & LOCK_EX) {
X***************
X*** 618,624 ****
X  		if (--ip->i_exlockc == 0) {
X  			ip->i_flag &= ~(IEXLOCK|ILWAIT);
X  			if (flags & ILWAIT)
X! 				wakeup((caddr_t)&ip->i_exlockc);
X  		}
X  		fp->f_flag &= ~FEXLOCK;
X  	}
X--- 622,628 ----
X  		if (--ip->i_exlockc == 0) {
X  			ip->i_flag &= ~(IEXLOCK|ILWAIT);
X  			if (flags & ILWAIT)
X! 				wakeup((caddr_t)&ip->i_shlockc);
X  		}
X  		fp->f_flag &= ~FEXLOCK;
X  	}
X*** /usr/src/sys/sys/sys_process.c.old	Tue Jul  5 16:18:50 1988
X--- /usr/src/sys/sys/sys_process.c	Mon Sep  6 10:50:37 1999
X***************
X*** 3,9 ****
X   * All rights reserved.  The Berkeley software License Agreement
X   * specifies the terms and conditions for redistribution.
X   *
X!  *	@(#)sys_process.c	1.1 (2.10BSD Berkeley) 6/12/88
X   */
X  
X  #include "param.h"
X--- 3,9 ----
X   * All rights reserved.  The Berkeley software License Agreement
X   * specifies the terms and conditions for redistribution.
X   *
X!  *	@(#)sys_process.c	1.2 (2.11BSD) 1999/9/5
X   */
X  
X  #include "param.h"
X***************
X*** 20,30 ****
X  #include "ptrace.h"
X  
X  /*
X-  * Priority for tracing
X-  */
X- #define	IPCPRI	PZERO
X- 
X- /*
X   * Tracing variables.
X   * Used to pass trace command from
X   * parent to child being traced.
X--- 20,25 ----
X***************
X*** 55,79 ****
X  
X  	uap = (struct a *)u.u_ap;
X  	if (uap->req <= 0) {
X! 		u.u_procp->p_flag |= STRC;
X  		return;
X  	}
X  	p = pfind(uap->pid);
X  	if (p == 0 || p->p_stat != SSTOP || p->p_ppid != u.u_procp->p_pid ||
X! 	    !(p->p_flag & STRC)) {
X  		u.u_error = ESRCH;
X  		return;
X  	}
X  	while (ipc.ip_lock)
X! 		sleep((caddr_t)&ipc, IPCPRI);
X  	ipc.ip_lock = p->p_pid;
X  	ipc.ip_data = uap->data;
X  	ipc.ip_addr = uap->addr;
X  	ipc.ip_req = uap->req;
X! 	p->p_flag &= ~SWTED;
X  	setrun(p);
X  	while (ipc.ip_req > 0)
X! 		sleep((caddr_t)&ipc, IPCPRI);
X  	u.u_r.r_val1 = (short)ipc.ip_data;
X  	if (ipc.ip_req < 0)
X  		u.u_error = EIO;
X--- 50,74 ----
X  
X  	uap = (struct a *)u.u_ap;
X  	if (uap->req <= 0) {
X! 		u.u_procp->p_flag |= P_TRACED;
X  		return;
X  	}
X  	p = pfind(uap->pid);
X  	if (p == 0 || p->p_stat != SSTOP || p->p_ppid != u.u_procp->p_pid ||
X! 	    !(p->p_flag & P_TRACED)) {
X  		u.u_error = ESRCH;
X  		return;
X  	}
X  	while (ipc.ip_lock)
X! 		sleep((caddr_t)&ipc, PZERO);
X  	ipc.ip_lock = p->p_pid;
X  	ipc.ip_data = uap->data;
X  	ipc.ip_addr = uap->addr;
X  	ipc.ip_req = uap->req;
X! 	p->p_flag &= ~P_WAITED;
X  	setrun(p);
X  	while (ipc.ip_req > 0)
X! 		sleep((caddr_t)&ipc, PZERO);
X  	u.u_r.r_val1 = (short)ipc.ip_data;
X  	if (ipc.ip_req < 0)
X  		u.u_error = EIO;
X***************
X*** 188,199 ****
X  			u.u_ar0[PC] = (int)ipc.ip_addr;
X  		if (ipc.ip_data > NSIG)
X  			goto error;
X! 		u.u_procp->p_cursig = ipc.ip_data;
X  		return(1);
X  
X  	/* force exit */
X  	case PT_KILL:
X! 		exit(u.u_procp->p_cursig);
X  		/*NOTREACHED*/
X  
X  	default:
X--- 183,194 ----
X  			u.u_ar0[PC] = (int)ipc.ip_addr;
X  		if (ipc.ip_data > NSIG)
X  			goto error;
X! 		u.u_procp->p_ptracesig = ipc.ip_data;
X  		return(1);
X  
X  	/* force exit */
X  	case PT_KILL:
X! 		exit(u.u_procp->p_ptracesig);
X  		/*NOTREACHED*/
X  
X  	default:
SHAR_EOF
  : || $echo 'restore of' '426.patch' 'failed'
fi
rm -fr _sh07598
exit 0
