Subject: kern/1186: can't interrupt process hung on audio output
To: None <gnats-admin@sun-lamp.pc.cs.cmu.edu>
From: John Kohl <jtk@kolvir.blrc.ma.us>
List: netbsd-bugs
Date: 07/02/1995 15:50:06
>Number:         1186
>Category:       kern
>Synopsis:       processes interrupted from writing to audio cannot be reinterrupted during exit
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Jul  2 15:50:05 1995
>Originator:     John Kohl
>Organization:
NetBSD Kernel Hackers `R` Us
>Release:        -current, June 30
>Environment:
	
System: NetBSD kolvir 1.0A NetBSD 1.0A (KOLVIR) #559: Sun Jul 2 14:50:32 EDT 1995 jtk@kolvir:/u1/NetBSD-current/src/sys/arch/i386/compile/KOLVIR i386


>Description:
If you have a buggy sound driver, and a process is stuck inside
audio_write, you can interrupt it and it will then start cleaning up/exiting.
While it's exiting, it has all signals masked and it cannot be
interrupted when it tries to drain the audio output.

>How-To-Repeat:
Get a buggy driver.  Interrupt a process writing to the sound card, and
try to interrupt it while it's exiting.

>Fix:
Make the audio_drain routine time out after some period of time.  In the
patch below, I set it to 60 seconds.

===================================================================
RCS file: RCS/audio.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 audio.c
--- audio.c	1995/06/06 03:53:56	1.1.1.1
+++ audio.c	1995/07/02 19:18:25
@@ -76,12 +76,13 @@
 #include <sys/proc.h>
 #include <sys/systm.h>
 #include <sys/syslog.h>
+#include <sys/kernel.h>
 
 #include <sys/audioio.h>
 #include <dev/audiovar.h>
 #include <dev/audio_if.h>
 
 #ifdef DEBUG
 #include <machine/stdarg.h>
 #ifndef TOLOG
 #define TOLOG	0x04
@@ -451,9 +452,10 @@
 }
 
 static inline int
-audio_sleep(chan, label)
+audio_sleep_timo(chan, label, timo)
 	int *chan;
 	char *label;
+	int timo;
 {
 	int st;
 
@@ -461,11 +463,22 @@
 		label = "audio";
 	
 	*chan = 1;
-	st = (tsleep(chan, PWAIT | PCATCH, label, 0));
+	st = (tsleep(chan, PWAIT | PCATCH, label, timo));
 	*chan = 0;
+	if (st != 0) {
+	    DPRINTF(("audio_sleep: %d\n", st));
+	}
 	return (st);
 }
 
+static inline int
+audio_sleep(chan, label)
+	int *chan;
+	char *label;
+{
+    return audio_sleep_timo(chan, label, 0);
+}
+
 static inline void
 audio_wakeup(chan)
 	int *chan;
@@ -602,7 +615,8 @@
 	int s = splaudio();
 
 	sc->sc_mode |= 1<<AUMODE_RECORD;
-	if (sc->hw_if->speaker_ctl)
+	if (sc->hw_if->speaker_ctl &&
+	    (!sc->hw_if->full_duplex || (sc->sc_mode & 1<<AUMODE_PLAY) == 0))
 		sc->hw_if->speaker_ctl(sc->hw_hdl, SPKR_OFF);
 	splx(s);
 }
@@ -631,7 +645,13 @@
 
 	while (sc->pr.nblk > 0) {
 		DPRINTF(("audio_drain: nblk=%d\n", sc->pr.nblk));
-		error = audio_sleep(&sc->sc_wchan, "aud dr");
+		/*
+		 * XXX
+		 * When the process is exiting, it ignores all signals and
+		 * we can't interrupt this sleep, so we set a 1-minute
+		 * timeout.
+		 */
+		error = audio_sleep_timo(&sc->sc_wchan, "aud dr", 60*hz);
 		if (error != 0)
 			return (error);
 	}
>Audit-Trail:
>Unformatted: