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 "$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 #include 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 #include 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 . # 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 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