[comp.unix.wizards] Device driver timeout question ...

roger@mips.UUCP (Roger March) (08/05/87)

	  A friend (yeah, sure), no really, a friend of mine is trying
	to patch up this device driver and foolishly came to me for help,
	so now I'm asking you. It is a block device and locks up when the
	cable isn't connected or people chew on the power cords, well at
	least when the cable isn't connected. I suspect that the lack of
	a cable means the DMA never starts and most certainly the device
	driver will never get an interrupt from the controller. It seemed
	to me that a possible solution was:

	1)	Enter the "strategy" routine and set up the DMA. Also set
		a "timeout" for N minutes. Wait for 2) or 3).

	2)	On a timeout, print a horrible error message and try to
		clean things up.

	3)	On a DMA complete interrupt, indicate that when the timeout
		occurs you were just kidding and everything is really okay.

	The above does some nasty stuff now when the cable is connected.
	Since the "timeout" is for N minutes, and requests to the device can
	be much quicker than this, it looks like I can expect to have several
	outstanding "timeout"s working; one of which may be valid.
	  So (finally) my question is: is there a way to kill outstanding an
	"timeout" when realize it is no longer neccessary? If not, is there
	a limit to how many "timeout"s can be issued before some buffer in
	the kernal fills? Or, is my algorithm totally brain damaged and I
	should go back to writting AI programs for microprocessor controlled
	toasters? Thanks.
-- 
-Rogue Monster
UUCP: {decvax,ucbvax,ihnp4}!decwrl!mips!roger  OR  roger@mips.com
USPS: MIPS Computer Systems, 930 Arques, Sunnyvale, CA 94086, (408) 991-0220

nawaf@muffy.UUCP (08/18/87)

In article <570@obiwan.UUCP>, roger@mips.UUCP (Roger March) writes:
> 	  So (finally) my question is: is there a way to kill outstanding an
> 	"timeout" when realize it is no longer neccessary?

My understanding is that you can call:

	untimeout(fun, arg)
	int (*fun)();
	caddr_t arg;

to remove a function timeout call from the callout structure queue.

> If not, is there a limit to how many "timeout"s can be issued before
> some buffer in the kernal fills?

A number of callout structures are allocated, 16 + MAXUSERS I believe.
No free ones results in a "timeout table overflow" panic.  Look in
sys/kern_clock.c conf/param.c and h/callout.h for details.

-- 
Nawaf Bitar
uucp:	 ...{harvard,decvax}!elrond!nawaf or nawaf@elrond.CalComp.COM
usps:    CalComp (A Lockheed Company), Display Products Division,
	 Mail Stop PTP2-2D01, CS 908, Hudson NH 03051 (603) 885 8135

jvs@micas.UUCP (08/19/87)

in article <570@obiwan.UUCP>, roger@mips.UUCP (Roger March) says:
>  ...  So (finally) my question is: is there a way to kill outstanding an
> 	"timeout" when realize it is no longer neccessary? If not, is there
> 	a limit to how many "timeout"s can be issued before some buffer in
> 	the kernal fills? Or, is my algorithm totally brain damaged and I
> 	should go back to writting AI programs for microprocessor controlled
> 	toasters? Thanks.

I have been writting drivers for the Sun to do various things where it is
possible for interrupts to time out. Under Sun Unix 3.2 there is a timeout
routine AND an untimeout routine to cancel a previous timeout. I don't
remember seeing any mention of untimeout in the 3.0 release manuals so maybe
it is a Sun specific addition and "real" 4.[23] BSD doesn't have it. Anyone
know the truth?

Jo. Stockley. (jvs@micas.uucp or ...!mcvax!ukc!micas!jvs)

Nodecrest Computer Systems Ltd
Byfleet, UK.

Phone: +44 09323 40555

djg@nscpdc.NSC.COM (Derek J. Godfrey) (08/20/87)

In article <666@muffy.CalComp.COM>, nawaf@muffy.CalComp.COM (Nawaf K. Bitar) writes:
 > In article <570@obiwan.UUCP>, roger@mips.UUCP (Roger March) writes:
 > > 	  So (finally) my question is: is there a way to kill outstanding an
 > > 	"timeout" when realize it is no longer neccessary?
 > 
 > My understanding is that you can call:
 > 
 > 	untimeout(fun, arg)
 > 	int (*fun)();
 > 	caddr_t arg;
 > 
For UNIX V.x the calls should be
	int t;
	t = timeout( fun, arg, time );
	untimeout( t );

ed@mtxinu.UUCP (Ed Gould) (08/22/87)

>I don't
>remember seeing any mention of untimeout in the 3.0 release manuals so maybe
>it is a Sun specific addition and "real" 4.[23] BSD doesn't have it. Anyone
>know the truth?

untimeout() has been part of BSD-derived systems since at least 4.2BSD;
I don't remember for sure if it was in 4.1, but I imagine that it was.

-- 
Ed Gould                    mt Xinu, 2560 Ninth St., Berkeley, CA  94710  USA
{ucbvax,decvax}!mtxinu!ed   +1 415 644 0146

"A man of quality is not threatened by a woman of equality."

chris@mimsy.UUCP (Chris Torek) (08/23/87)

In article <474@mtxinu.UUCP> ed@mtxinu.UUCP (Ed Gould) writes:
>untimeout() has been part of BSD-derived systems since at least 4.2BSD;
>I don't remember for sure if it was in 4.1, but I imagine that it was.

As I recall, we had to install untimeout() when we installed CMU
IPC.

Anyway, as to watchdog timers, untimeout() seems unnecessary:

	fooopen(dev, flag)
		dev_t dev;
		int flag;
	{
		...
		s = spl5();
		/* start the watchdog timer, if necessary */
		foostate = FOO_OPEN;
		if (foowstart == 0) {
			timeout(foowatch, (caddr_t)0, hz);
			foowstart++;
		}
		splx(s);
		...
	}

	fooclose(dev)
		dev_t dev;
	{

		foostate = FOO_CLOSED;
		...
	}

	/* check on the foo once a second */
	foowatch()
	{

		/* stop timing if we have closed down the foo */
		if (foostate == FOO_CLOSED) {
			foowstart = 0;	/* and remember to restart */
			return;
		}
		timeout(foowatch, (caddr_t)0, hz);
		...
	}

Or, as I do in my UDA50 driver, let the timer run always.  (Someday
I may move the timer to uba.c.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
Domain:	chris@mimsy.umd.edu	Path:	seismo!mimsy!chris

iv@hal6000.UUCP (08/24/87)

----
| The above does some nasty stuff now when the cable is connected.
| Since the "timeout" is for N minutes, and requests to the device can
| be much quicker than this, it looks like I can expect to have several
| outstanding "timeout"s working; one of which may be valid.
[ . . . ]
| -Rogue Monster
| -- 
| UUCP: {decvax,ucbvax,ihnp4}!decwrl!mips!roger  OR  roger@mips.com
| USPS: MIPS Computer Systems, 930 Arques, Sunnyvale, CA 94086, (408) 991-0220
---- 

Another solution that we've used is to have ONE timeout that gets
started by the stragedy, uh, strategy routine and that requeues itself.
This way, you only use at most two timeout table slots.

It can look something like this [please note that however much this may
resemble real kernel code, it is really pseudo-code intended to show the
general idea]:

io_poll()
{
	register int	p;
	static int	running = 0;

	/* This way we can just call io_poll() to prime the polling.
	 * You can just call it from the stragedy routine each time,
	 * or make "running" a global that stragedy() can look at.
	 */
	if (running)	/* Is another copy of me running already? */
		return;

	/* "driver_running" should be a flag maintained by your stragedy
	 * and interrupt routines which indicates whether there is work
	 * to do.  It is possible in most drivers to catch them at a
	 * time where there is no I/O outstanding, yet there is work in
	 * the queue.  The idea is, we don't want to tie up system
	 * resources polling for an idle driver.
	 */

	p = SPL();		/* Protect against interrupt races */

	if (!driver_running) {
		running = 0;
		splx(s);
		return;
	}

	/* "io_in_progress" should be a flag maintained by your driver
	 * start routine and interrupt routine to indicate that there
	 * is an I/O operation in progress we need to watch and
	 * potentially timeout */
	if (!io_in_progress)
		goto out;

	/* Okay.  Now here we need to have the start routine leave
	 * enough information around to be able to decide if the
	 * current I/O operation has gone on too long.  Here we assume
	 * that the start routine put the start time of the operation
	 * in "started_time" and that the I/O is overdue after 2 secs.
	 * Notice that interrupts are still disabled.
	/*/
	if (started_time + (2 * HZ) < time)
		goto out;

	/* Here, of course, you abort your overdue I/O operation */

	/* Oh, oh...  No word from planet DMA! */
	printf("Shut her down, Scotty, she's sucking DMA again...\n");
	abort_IO_stuff();


    out:
	/* On and on... I just keep on timing,
	 * and after a while I feel like cryyyying
	 * on and on, on and on, on aaaaand on...
	 */
	timeout(io_poll, (caddr_t)0, LaterTime);
	splx(s);
}

Anyway.   I hope this helps.
----
IV  (aka John Elliott IV)	 Domain: iv@hal6000.Tandy.COM
1300 Two Tandy Center		   UUCP: ...!ihnp4!sys1!hal6000!iv
Tandy Systems Software		     or: ...!decvax!microsoft!trsvax!hal6000!iv
Fort Worth, TX 76102		  Phone: 817/390-2701; 9:30am-6:00pm CST

[This information was provided by an individual and is not  nor  should
 be  construed  as  being provided by Radio Shack or Tandy Corporation.
 Radio Shack and/or Tandy Corporation have no obligation to support the
 information  provided.    The  author will, however, cheerfully accept
 mail.  This note will self-destruct in 5 seconds.  Good luck, %s.]