Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.2 9/18/84; site calgary.UUCP Path: utzoo!watmath!clyde!cbosgd!ihnp4!alberta!calgary!radford From: radford@calgary.UUCP (Radford Neal) Newsgroups: net.unix-wizards,net.sources Subject: Re: When does ( alarm(1) == alarm(INFINITY) ) ? Message-ID: <312@calgary.UUCP> Date: Wed, 31-Dec-69 18:59:59 EST Article-I.D.: calgary.312 Posted: Wed Dec 31 18:59:59 1969 Date-Received: Tue, 19-Mar-85 08:04:56 EST References: <132@heurikon.UUCP> <1094@calgary.UUCP> <1095@calgary.UUCP> <1097@calgary.UUCP> <178@encore.UUCP> <179@encore.UUCP> <6358@boring.UUCP> Organization: University of Calgary, Calgary, Alberta Lines: 112 Xref: watmath net.unix-wizards:12484 net.sources:2726 > >As I read the manual (I didn't read the code) pause will only return when a > >signal is "caught". If the semantics were that it would also return > >(immediately) if there were no signal handlers active (since they revert > >when caught), the race condition would also disappear. > > This sounds nice at first, but gives rise to some even weirder > situations... [e.g. multiple interrupt handlers] I think the thing to do if you want to go this route is to have a flag in the process table entry which is set to one whenever a signal routine is activated and cleared to zero by pause(). If pause is called when it is one, it returns immediately (after clearing the flag). This works as long as people have not been doing things like: alarm(1); pause(); but have instead been doing: alarm_caught = 0; alarm(1); while (!alarm_caught) pause(); /* alarm_caught set in signal routine */ They should have been doing this anyway, or their code will break if there are other signal handlers active. BTW, the routine I posted for avoiding the race (on a VAX) has a slight bug. Here it is again, with bug noted: ---------------------------------------------------------------------- /* PAUSE_FUDGE - Fudge routines to fix up pause race problem */ /* This module allows someone to wait until some condition has been made true by an interrupt routine without wasting cp time in a polling loop. The Unix 'pause' system call will suspend a process until an interrupt (i.e. signal) is received. This is not directly usable in a wait loop however, since between a check for a condition and a call of pause an interrupt may occur which would have made the condition true. So the following wait loop may hang up: while (!condition) pause(); The following wait loop is to be used instead: for (;;) { jk_set_up_pause(); if (condition) break; jk_maybe_do_pause(); } The way this works is that jk_set_up_pause creates a routine which will perform a pause system call. jk_maybe_do_pause will execute this routine. The interrupt routine should be written to call the routine jk_disable_pause, which changes the routine created by jk_set_up_pause to do nothing instead of a pause. This is done by a change of a single Vax machine instruction to nop's. */ static char pause_routine[5]; /* Pause system call or nop's */ /* Set up a routine to do a "pause" system call. */ jk_set_up_pause() { register char *p; p = &pause_routine[2]; *p++ = 0274; *p++ = 035; /* chmk $pause */ /* BUG BUG BUG BUG BUG */ *p++ = 04; /* ret */ } /* Execute routine to do pause system call, unless it has been nop'ed out. */ jk_maybe_do_pause() { (*(void (*)())pause_routine)(); } /* Disable pause call by replacing system call with nop's */ jk_disable_pause() { register char *p; p = &pause_routine[2]; *p++ = 01; *p++ = 01; /* nop; nop */ } ---------------------------------------------------------------------- The problem is that the signal may arrive between the *p++ = 0274; and the *p++ = 035; which would lead to the final routine called by maybe_do_pause having *half* a chmk instruction (anything might happen then, I haven't looked to see what instruction has op-code 035). This can be fixed by storing BOTH bytes of the chmk $pause instruction with a single assignment, though that depends on the compiler really generating a 16-bit move rather than two 8-bit moves (it almost certainly will). I think the moral of all this is: - Don't use signal handlers if you can avoid it, especially for anything other than printing an error message and exiting. - If you have to use signal handlers, you better think REALLY carefully about what could happen, or you may write a program which fails inexplicably once every few weeks. Radford Neal The University of Calgary