GNU bug report logs -
#8938
make timeout and CTRL-C
Previous Next
Reported by: shay shimony <shayshim <at> gmail.com>
Date: Sun, 26 Jun 2011 21:48:01 UTC
Severity: normal
Fixed in version 8.13
Done: Pádraig Brady <P <at> draigBrady.com>
Bug is archived. No further changes may be made.
To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 8938 in the body.
You can then email your comments to 8938 AT debbugs.gnu.org in the normal way.
Toggle the display of automated, internal messages from the tracker.
Report forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Sun, 26 Jun 2011 21:48:01 GMT)
Full text and
rfc822 format available.
Acknowledgement sent
to
shay shimony <shayshim <at> gmail.com>
:
New bug report received and forwarded. Copy sent to
bug-coreutils <at> gnu.org
.
(Sun, 26 Jun 2011 21:48:01 GMT)
Full text and
rfc822 format available.
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Hello coreutils team,
I found that if you run timeout inside make file then CTRL-C doesn't work.
Really frustrating because I use timeout to terminate deadlocked tests, but
can't stop them with CTRL-C as I used to.
To reproduce copy the following into file named Makefile:
all:
timeout 12 sleep 10
Note there is a tab before "timeout 12 sleep 10".
Then run at same directory where the file is located "make" and try to press
CTRL-C.
Notes:
CTRL-Z works.
When executing timeout without make CTRL-C works.
When executing make without timeout CTRL-C works.
Thanks,
Shay
[Message part 2 (text/html, inline)]
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Mon, 27 Jun 2011 12:04:02 GMT)
Full text and
rfc822 format available.
Message #8 received at 8938 <at> debbugs.gnu.org (full text, mbox):
On 26/06/11 20:20, shay shimony wrote:
> Hello coreutils team,
>
> I found that if you run timeout inside make file then CTRL-C doesn't work.
> Really frustrating because I use timeout to terminate deadlocked tests, but
> can't stop them with CTRL-C as I used to.
>
> To reproduce copy the following into file named Makefile:
>
> all:
> timeout 12 sleep 10
>
> Note there is a tab before "timeout 12 sleep 10".
> Then run at same directory where the file is located "make" and try to press
> CTRL-C.
>
> Notes:
> CTRL-Z works.
> When executing timeout without make CTRL-C works.
> When executing make without timeout CTRL-C works.
Drats,
That because SIGINT is sent by the terminal to the foreground group.
The issue is that `make` and `timeout` use much the same method
to control their jobs. I.E. they create their own process group
so they can terminate all sub-processes.
So in your case, make creates its own program group and is in the foreground.
Because timeout does too, it will not get SIGINT from the terminal.
Really `make` should propagate the SIGINT down, though I
suppose the same thing could be said for `timeout`.
I.E. the following demonstrates the same issue and times out after 10s
and is also unresponsive to CTRL-C:
timeout 5 timeout 10 sleep 20
Note a handy way to see the process structure of timeout and make is:
ps -C make -C timeout -o ppid,pgid,pgrp,pid,tty,sess,comm
So what to do.
The cascaded timeouts could be handled by timeout sending a signal
to the child process as well as the process group.
But that won't fix the make case as `make` would have to do
something similar. Maybe I could add an option to not create
a separate group. I'll need to think a bit about this.
cheers,
Pádraig.
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Mon, 27 Jun 2011 20:13:03 GMT)
Full text and
rfc822 format available.
Message #11 received at 8938 <at> debbugs.gnu.org (full text, mbox):
=?UTF-8?Q?P=C3=A1draig?= Brady writes:
>
> On 26/06/11 20:20, shay shimony wrote:
> > all:
> > timeout 12 sleep 10
> >
> > Note there is a tab before "timeout 12 sleep 10".
> > Then run at same directory where the file is located "make" and try to press
> > CTRL-C.
> >
> > Notes:
> > CTRL-Z works.
> > When executing timeout without make CTRL-C works.
> > When executing make without timeout CTRL-C works.
>
> Drats,
>
> That because SIGINT is sent by the terminal to the foreground group.
> The issue is that `make` and `timeout` use much the same method
> to control their jobs. I.E. they create their own process group
> so they can terminate all sub-processes.
Are you sure? I see no evidence of that. When I run make with the above
makefile, the processes look like this:
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
1 1451 1451 1451 6 16407 S 1000 0:06 -zsh
1451 16407 16407 1451 6 16407 S 1000 0:00 make
16407 16408 16408 1451 6 16407 S 1000 0:00 timeout 60 sleep 30
16408 16409 16408 1451 6 16407 S 1000 0:00 sleep 30
The first PGID is the login shell. The second PGID is make, which was put
into its own process group by the shell because the shell has job control
enabled. The last PGID is timeout, which put itself into a process group.
make never noticed any of them.
In the source for GNU make 3.82 there are no calls to setpgrp or setpgid
(unless obfuscated from grep). There is the following comment:
/* A termination signal won't be sent to the entire
process group, but it means we want to kill the children. */
That's above the handling of SIGTERM, which iterates over child processes and
passes along the SIGTERM to them.
After that is the handling of SIGINT, which doesn't kill child processes
(unless they're "remote", which is... news to me that make does remote
things) but just waits for them.
What seems to be happening is that make *doesn't* create a process group,
therefore assumes that when it gets a SIGINT, its children have already
gotten it too, and it just waits for them to die. A child that puts itself
into a new process group screws this up (as would kill -2 `pidof make`).
I think the answer is that timeout should put itself into the foreground.
That way it would get the SIGINT. make wouldn't get it, but wouldn't need to.
timeout would exit quickly after SIGINT and make would proceed or abort
according to the exit code.
--
Alan Curry
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Mon, 27 Jun 2011 22:24:02 GMT)
Full text and
rfc822 format available.
Message #14 received at 8938 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
On 27/06/11 21:12, Alan Curry wrote:
> =?UTF-8?Q?P=C3=A1draig?= Brady writes:
>>
>> On 26/06/11 20:20, shay shimony wrote:
>>> all:
>>> timeout 12 sleep 10
>>>
>>> Note there is a tab before "timeout 12 sleep 10".
>>> Then run at same directory where the file is located "make" and try to press
>>> CTRL-C.
>>>
>>> Notes:
>>> CTRL-Z works.
>>> When executing timeout without make CTRL-C works.
>>> When executing make without timeout CTRL-C works.
>>
>> Drats,
>>
>> That because SIGINT is sent by the terminal to the foreground group.
>> The issue is that `make` and `timeout` use much the same method
>> to control their jobs. I.E. they create their own process group
>> so they can terminate all sub-processes.
>
> Are you sure? I see no evidence of that. When I run make with the above
> makefile, the processes look like this:
>
> PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
> 1 1451 1451 1451 6 16407 S 1000 0:06 -zsh
> 1451 16407 16407 1451 6 16407 S 1000 0:00 make
> 16407 16408 16408 1451 6 16407 S 1000 0:00 timeout 60 sleep 30
> 16408 16409 16408 1451 6 16407 S 1000 0:00 sleep 30
>
> The first PGID is the login shell. The second PGID is make, which was put
> into its own process group by the shell because the shell has job control
> enabled. The last PGID is timeout, which put itself into a process group.
> make never noticed any of them.
>
> In the source for GNU make 3.82 there are no calls to setpgrp or setpgid
> (unless obfuscated from grep). There is the following comment:
>
> /* A termination signal won't be sent to the entire
> process group, but it means we want to kill the children. */
>
> That's above the handling of SIGTERM, which iterates over child processes and
> passes along the SIGTERM to them.
>
> After that is the handling of SIGINT, which doesn't kill child processes
> (unless they're "remote", which is... news to me that make does remote
> things) but just waits for them.
>
> What seems to be happening is that make *doesn't* create a process group,
> therefore assumes that when it gets a SIGINT, its children have already
> gotten it too, and it just waits for them to die. A child that puts itself
> into a new process group screws this up (as would kill -2 `pidof make`).
Thanks for the analysis Alan.
Yes you're right I think.
In any case the important point is that timeout sets itself as group leader,
and is not the foreground group.
>
> I think the answer is that timeout should put itself into the foreground.
> That way it would get the SIGINT. make wouldn't get it, but wouldn't need to.
> timeout would exit quickly after SIGINT and make would proceed or abort
> according to the exit code.
I've a version locally here actually that calls tcsetpgrp() but I discounted
that as it's not timeout's place to call that I think.
timeout sets itself as group leader so that it can kill everything it starts,
but it shouldn't need to grab the foreground group as the shell (or make)
may be starting it in the background etc.
So really `make` should not assume children stay in the same group,
and propagate signals down (like it does for TERM).
It might be appropriate for `make` to call tcsetpgrp() before exec..()
but given remote & parallel jobs etc. signal propagation might be best.
I've fixed up `timeout` itself not assume children stay in
the same group, and pass signals on, in the attached patch.
cheers,
Pádraig.
[timeout-timeout.diff (text/x-patch, attachment)]
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Mon, 27 Jun 2011 22:56:01 GMT)
Full text and
rfc822 format available.
Message #17 received at 8938 <at> debbugs.gnu.org (full text, mbox):
=?UTF-8?Q?P=C3=A1draig?= Brady writes:
>
> This is a multi-part message in MIME format.
> --------------000003030307000505070101
> Content-Type: text/plain; charset=ISO-8859-1
> Content-Transfer-Encoding: 8bit
>
> On 27/06/11 21:12, Alan Curry wrote:
> >
> > What seems to be happening is that make *doesn't* create a process group,
> > therefore assumes that when it gets a SIGINT, its children have already
> > gotten it too, and it just waits for them to die. A child that puts itself
> > into a new process group screws this up (as would kill -2 `pidof make`).
>
> Thanks for the analysis Alan.
> Yes you're right I think.
> In any case the important point is that timeout sets itself as group leader,
> and is not the foreground group.
Right, we have a tree of process groups that goes roughly
shell->make->timeout and the one in the middle of the tree is the
foreground, receiving tty-based signals.
>
> >
> > I think the answer is that timeout should put itself into the foreground.
> > That way it would get the SIGINT. make wouldn't get it, but wouldn't need to.
> > timeout would exit quickly after SIGINT and make would proceed or abort
> > according to the exit code.
>
> I've a version locally here actually that calls tcsetpgrp() but I discounted
> that as it's not timeout's place to call that I think.
> timeout sets itself as group leader so that it can kill everything it starts,
> but it shouldn't need to grab the foreground group as the shell (or make)
> may be starting it in the background etc.
It seems like this is a misuse of process groups, using them as if they
were a handle for killing a whole tree of processes. That's not what
they're for. Process groups were invented to support job control, which
means the only program that was supposed to mess with them was csh. Only
the lack of a "kill process tree" primitive (and the fact that you can't
even query the process tree easily) tempts us into using process groups
as a shortcut.
Any non-job-control-aware parent process will have a problem with
timeout's behavior. We've already seen what GNU make does. pmake simply
dies of the SIGINT and leaves the child processes lingering (it probably
also assumes they got the SIGINT, and doesn't bother waiting for them).
In an interactive shell with job control disabled (set +m in most
Bourne-ish shells), the behavior is not good there either. dash, bash,
and posh all act like GNU make, appearing to ignore the SIGINT. zsh acts
more like pmake, printing a new prompt but leaving the timeout and its
child running.
timeout's pgrp behavior only appears harmless when the parent process is
a shell with job control, which expects its children to be in separate
process groups. But in that case, timeout doesn't need to put itself in
a new process group because the shell has already done so.
So I suggest that if you create a process group, you take on the
responsibility of behaving like a job control shell in other ways,
including managing the foreground group. (An important piece of that is
remembering the original value and restoring it before you exit).
--
Alan Curry
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Tue, 28 Jun 2011 18:20:03 GMT)
Full text and
rfc822 format available.
Message #20 received at 8938 <at> debbugs.gnu.org (full text, mbox):
I'd like to have an option to 'timeout' so that
it merely calls alarm(2) and then execs COMMAND.
This would be simple and fast would avoid the problem
in question. This approach has its own issues, but
when it works it works great, and it'd be a nice option.
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Tue, 28 Jun 2011 18:43:02 GMT)
Full text and
rfc822 format available.
Message #23 received at 8938 <at> debbugs.gnu.org (full text, mbox):
On 28/06/11 19:19, Paul Eggert wrote:
> I'd like to have an option to 'timeout' so that
> it merely calls alarm(2) and then execs COMMAND.
> This would be simple and fast would avoid the problem
> in question. This approach has its own issues, but
> when it works it works great, and it'd be a nice option.
The main problem with that is would only
send the signal to the first process, and
any processes it started would keep running.
I think we should be able to figure out something more general.
cheers,
Pádraig.
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Tue, 28 Jun 2011 18:46:02 GMT)
Full text and
rfc822 format available.
Message #26 received at 8938 <at> debbugs.gnu.org (full text, mbox):
On 06/28/11 11:41, Pádraig Brady wrote:
> The main problem with that is would only
> send the signal to the first process, and
> any processes it started would keep running.
Yes, that's the main issue with it. Still,
it's handy for programs where you either know
it doesn't use subprocesses, or you *want* to
kill just the main program and not its subprocesses.
I don't think it should be the default option,
but it'd be nice to have it as an option.
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Tue, 28 Jun 2011 18:51:02 GMT)
Full text and
rfc822 format available.
Message #29 received at 8938 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
On 27/06/11 23:55, Alan Curry wrote:
> =?UTF-8?Q?P=C3=A1draig?= Brady writes:
>>
>> This is a multi-part message in MIME format.
>> --------------000003030307000505070101
>> Content-Type: text/plain; charset=ISO-8859-1
>> Content-Transfer-Encoding: 8bit
>>
>> On 27/06/11 21:12, Alan Curry wrote:
>>>
>>> What seems to be happening is that make *doesn't* create a process group,
>>> therefore assumes that when it gets a SIGINT, its children have already
>>> gotten it too, and it just waits for them to die. A child that puts itself
>>> into a new process group screws this up (as would kill -2 `pidof make`).
>>
>> Thanks for the analysis Alan.
>> Yes you're right I think.
>> In any case the important point is that timeout sets itself as group leader,
>> and is not the foreground group.
>
> Right, we have a tree of process groups that goes roughly
> shell->make->timeout and the one in the middle of the tree is the
> foreground, receiving tty-based signals.
>
>>
>>>
>>> I think the answer is that timeout should put itself into the foreground.
>>> That way it would get the SIGINT. make wouldn't get it, but wouldn't need to.
>>> timeout would exit quickly after SIGINT and make would proceed or abort
>>> according to the exit code.
>>
>> I've a version locally here actually that calls tcsetpgrp() but I discounted
>> that as it's not timeout's place to call that I think.
>> timeout sets itself as group leader so that it can kill everything it starts,
>> but it shouldn't need to grab the foreground group as the shell (or make)
>> may be starting it in the background etc.
>
> It seems like this is a misuse of process groups, using them as if they
> were a handle for killing a whole tree of processes. That's not what
> they're for. Process groups were invented to support job control, which
> means the only program that was supposed to mess with them was csh. Only
> the lack of a "kill process tree" primitive (and the fact that you can't
> even query the process tree easily) tempts us into using process groups
> as a shortcut.
>
> Any non-job-control-aware parent process will have a problem with
> timeout's behavior. We've already seen what GNU make does. pmake simply
> dies of the SIGINT and leaves the child processes lingering (it probably
> also assumes they got the SIGINT, and doesn't bother waiting for them).
>
> In an interactive shell with job control disabled (set +m in most
> Bourne-ish shells), the behavior is not good there either. dash, bash,
> and posh all act like GNU make, appearing to ignore the SIGINT. zsh acts
> more like pmake, printing a new prompt but leaving the timeout and its
> child running.
>
> timeout's pgrp behavior only appears harmless when the parent process is
> a shell with job control, which expects its children to be in separate
> process groups. But in that case, timeout doesn't need to put itself in
> a new process group because the shell has already done so.
>
> So I suggest that if you create a process group, you take on the
> responsibility of behaving like a job control shell in other ways,
> including managing the foreground group. (An important piece of that is
> remembering the original value and restoring it before you exit).
I'm still not convinced we need to be messing with tcsetpgrp()
but you're right in that the disconnect between the timeout
process group and that of whatever starts `timeout` should be bridged.
I'm testing the attached patch at the moment (which I'll split into 2).
It only creates a separate group for the child that `timeout` execs,
leaving the timeout process in the original group to propagate signals down.
I'll need to do lots of testing with this before I commit.
cheers,
Pádraig.
[timeout-groups.diff (text/x-patch, attachment)]
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Tue, 28 Jun 2011 19:07:02 GMT)
Full text and
rfc822 format available.
Message #32 received at 8938 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Thanks for taking care for this! Interesting stuff as well.
2011/6/28 Pádraig Brady <P <at> draigbrady.com>
> On 27/06/11 21:12, Alan Curry wrote:
> > =?UTF-8?Q?P=C3=A1draig?= Brady writes:
> >>
> >> On 26/06/11 20:20, shay shimony wrote:
> >>> all:
> >>> timeout 12 sleep 10
> >>>
> >>> Note there is a tab before "timeout 12 sleep 10".
> >>> Then run at same directory where the file is located "make" and try to
> press
> >>> CTRL-C.
> >>>
> >>> Notes:
> >>> CTRL-Z works.
> >>> When executing timeout without make CTRL-C works.
> >>> When executing make without timeout CTRL-C works.
> >>
> >> Drats,
> >>
> >> That because SIGINT is sent by the terminal to the foreground group.
> >> The issue is that `make` and `timeout` use much the same method
> >> to control their jobs. I.E. they create their own process group
> >> so they can terminate all sub-processes.
> >
> > Are you sure? I see no evidence of that. When I run make with the above
> > makefile, the processes look like this:
> >
> > PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
> > 1 1451 1451 1451 6 16407 S 1000 0:06 -zsh
> > 1451 16407 16407 1451 6 16407 S 1000 0:00 make
> > 16407 16408 16408 1451 6 16407 S 1000 0:00 timeout 60 sleep 30
> > 16408 16409 16408 1451 6 16407 S 1000 0:00 sleep 30
> >
> > The first PGID is the login shell. The second PGID is make, which was put
> > into its own process group by the shell because the shell has job control
> > enabled. The last PGID is timeout, which put itself into a process group.
> > make never noticed any of them.
> >
> > In the source for GNU make 3.82 there are no calls to setpgrp or setpgid
> > (unless obfuscated from grep). There is the following comment:
> >
> > /* A termination signal won't be sent to the entire
> > process group, but it means we want to kill the children. */
> >
> > That's above the handling of SIGTERM, which iterates over child processes
> and
> > passes along the SIGTERM to them.
> >
> > After that is the handling of SIGINT, which doesn't kill child processes
> > (unless they're "remote", which is... news to me that make does remote
> > things) but just waits for them.
> >
> > What seems to be happening is that make *doesn't* create a process group,
> > therefore assumes that when it gets a SIGINT, its children have already
> > gotten it too, and it just waits for them to die. A child that puts
> itself
> > into a new process group screws this up (as would kill -2 `pidof make`).
>
> Thanks for the analysis Alan.
> Yes you're right I think.
> In any case the important point is that timeout sets itself as group
> leader,
> and is not the foreground group.
>
> >
> > I think the answer is that timeout should put itself into the foreground.
> > That way it would get the SIGINT. make wouldn't get it, but wouldn't need
> to.
> > timeout would exit quickly after SIGINT and make would proceed or abort
> > according to the exit code.
>
> I've a version locally here actually that calls tcsetpgrp() but I
> discounted
> that as it's not timeout's place to call that I think.
> timeout sets itself as group leader so that it can kill everything it
> starts,
> but it shouldn't need to grab the foreground group as the shell (or make)
> may be starting it in the background etc.
>
> So really `make` should not assume children stay in the same group,
> and propagate signals down (like it does for TERM).
> It might be appropriate for `make` to call tcsetpgrp() before exec..()
> but given remote & parallel jobs etc. signal propagation might be best.
>
> I've fixed up `timeout` itself not assume children stay in
> the same group, and pass signals on, in the attached patch.
>
> cheers,
> Pádraig.
>
[Message part 2 (text/html, inline)]
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Tue, 28 Jun 2011 19:11:02 GMT)
Full text and
rfc822 format available.
Message #35 received at 8938 <at> debbugs.gnu.org (full text, mbox):
=?ISO-8859-1?Q?P=E1draig_Brady?= writes:
>
> I'm still not convinced we need to be messing with tcsetpgrp()
> but you're right in that the disconnect between the timeout
> process group and that of whatever starts `timeout` should be bridged.
>
> I'm testing the attached patch at the moment (which I'll split into 2).
> It only creates a separate group for the child that `timeout` execs,
> leaving the timeout process in the original group to propagate signals down.
>
> I'll need to do lots of testing with this before I commit.
With this patch the child is guaranteed to not be in the foreground (as far
as the tty knows) so it will be getting SIGTTIN and possibly SIGTTOU on tty
operations.
I don't think there's anything that will make every scenario happy. (Except
for a recursive-kill that doesn't use pgrps!).
--
Alan Curry
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Tue, 28 Jun 2011 20:28:01 GMT)
Full text and
rfc822 format available.
Message #38 received at 8938 <at> debbugs.gnu.org (full text, mbox):
Pádraig Brady wrote:
> Paul Eggert wrote:
> > I'd like to have an option to 'timeout' so that
> > it merely calls alarm(2) and then execs COMMAND.
> > This would be simple and fast would avoid the problem
> > in question. This approach has its own issues, but
> > when it works it works great, and it'd be a nice option.
I agree. It is nice and simple and well understood.
> The main problem with that is would only send the signal to the
> first process, and any processes it started would keep running.
Then that is a problem for that parent process to keep track of its
own children. It is a recursive situation. If all processes are well
behaved then it works okay. And if you ask about processes that are
not well behaved then my response would be to fix them so that they
are better behaved.
Bob
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Tue, 28 Jun 2011 20:33:02 GMT)
Full text and
rfc822 format available.
Message #41 received at 8938 <at> debbugs.gnu.org (full text, mbox):
Bob Proulx writes:
>
> P=E1draig Brady wrote:
> > Paul Eggert wrote:
> > > I'd like to have an option to 'timeout' so that
> > > it merely calls alarm(2) and then execs COMMAND.
> > > This would be simple and fast would avoid the problem
> > > in question. This approach has its own issues, but
> > > when it works it works great, and it'd be a nice option.
>
> I agree. It is nice and simple and well understood.
>
> > The main problem with that is would only send the signal to the
> > first process, and any processes it started would keep running.
>
> Then that is a problem for that parent process to keep track of its
> own children. It is a recursive situation. If all processes are well
> behaved then it works okay. And if you ask about processes that are
> not well behaved then my response would be to fix them so that they
> are better behaved.
That sounds reasonable, but then if something is about to be killed by
timeout, there's reason to believe it's not behaving well at the moment.
--
Alan Curry
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Tue, 28 Jun 2011 20:44:02 GMT)
Full text and
rfc822 format available.
Message #44 received at 8938 <at> debbugs.gnu.org (full text, mbox):
Alan Curry wrote:
> That sounds reasonable, but then if something is about to be killed by
> timeout, there's reason to believe it's not behaving well at the moment.
Not necessarily. For example many things depend upon something across
the network. If the network wire is unplugged then they might never
complete and therefore need a timeout. But that doesn't mean that
they are not well behaved otherwise.
Bob
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Tue, 28 Jun 2011 21:17:02 GMT)
Full text and
rfc822 format available.
Message #47 received at 8938 <at> debbugs.gnu.org (full text, mbox):
On 28/06/11 21:32, Alan Curry wrote:
> Bob Proulx writes:
>>
>> P=E1draig Brady wrote:
>>> Paul Eggert wrote:
>>>> I'd like to have an option to 'timeout' so that
>>>> it merely calls alarm(2) and then execs COMMAND.
>>>> This would be simple and fast would avoid the problem
>>>> in question. This approach has its own issues, but
>>>> when it works it works great, and it'd be a nice option.
>>
>> I agree. It is nice and simple and well understood.
>>
>>> The main problem with that is would only send the signal to the
>>> first process, and any processes it started would keep running.
>>
>> Then that is a problem for that parent process to keep track of its
>> own children. It is a recursive situation. If all processes are well
>> behaved then it works okay. And if you ask about processes that are
>> not well behaved then my response would be to fix them so that they
>> are better behaved.
>
> That sounds reasonable, but then if something is about to be killed by
> timeout, there's reason to believe it's not behaving well at the moment.
>
Well think of a shell script that has started lots of processes.
Many (most) will rely on signal propagation to the group
to clean things up.
cheers,
Pâdraig.
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Wed, 29 Jun 2011 09:57:01 GMT)
Full text and
rfc822 format available.
Message #50 received at 8938 <at> debbugs.gnu.org (full text, mbox):
On 28/06/11 20:10, Alan Curry wrote:
> =?ISO-8859-1?Q?P=E1draig_Brady?= writes:
>>
>> I'm still not convinced we need to be messing with tcsetpgrp()
>> but you're right in that the disconnect between the timeout
>> process group and that of whatever starts `timeout` should be bridged.
>>
>> I'm testing the attached patch at the moment (which I'll split into 2).
>> It only creates a separate group for the child that `timeout` execs,
>> leaving the timeout process in the original group to propagate signals down.
>>
>> I'll need to do lots of testing with this before I commit.
>
> With this patch the child is guaranteed to not be in the foreground (as far
> as the tty knows) so it will be getting SIGTTIN and possibly SIGTTOU on tty
> operations.
Oh right. This will immediately put dd in sTop state:
timeout 10 dd
That was one of the main reasons I didn't split the groups
in the first place. I should read my own comments :)
I'm very wary of changing the foreground group (with tcsetpgrp),
which would fix this, but in turn may cause other issues.
> I don't think there's anything that will make every scenario happy. (Except
> for a recursive-kill that doesn't use pgrps!).
Yes, an ideal solution is elusive.
Maybe `make` needs to handle things differently?
If you put the following in a Makefile, how should make respond to Ctrl-C?
all:
setsid sleep 10
cheers,
Pádraig.
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Sat, 02 Jul 2011 18:38:03 GMT)
Full text and
rfc822 format available.
Message #53 received at 8938 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
> With this patch the child is guaranteed to not be in the foreground (as far
> as the tty knows) so it will be getting SIGTTIN and possibly SIGTTOU on tty
> operations.
You may need to correct me. In practice we see that the "timeouted" program
perform successfully writes to the terminal, though it belongs to a
different group then the foreground (in my case "make"'s group is in the
foreground and timeout+compiler/test group is in the background, and all
output of the compiler and test seem to appear correctly on the terminal).
And regarding read, I think it makes sense enough that users will not use
timeout for interactive programs that wait for input from the user.
So maybe the fact that the timeouted program will not be able to get SIGTTIN
and SIGTTOU is not such a disaster?
[Message part 2 (text/html, inline)]
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Sat, 02 Jul 2011 20:15:02 GMT)
Full text and
rfc822 format available.
Message #56 received at 8938 <at> debbugs.gnu.org (full text, mbox):
shay shimony writes:
>
> > With this patch the child is guaranteed to not be in the foreground (as far
> > as the tty knows) so it will be getting SIGTTIN and possibly SIGTTOU on tty
> > operations.
>
> You may need to correct me. In practice we see that the "timeouted" program
> perform successfully writes to the terminal, though it belongs to a
> different group then the foreground (in my case "make"'s group is in the
> foreground and timeout+compiler/test group is in the background, and all
> output of the compiler and test seem to appear correctly on the terminal).
> And regarding read, I think it makes sense enough that users will not use
> timeout for interactive programs that wait for input from the user.
> So maybe the fact that the timeouted program will not be able to get SIGTTIN
> and SIGTTOU is not such a disaster?
>
Notice that I wrote "possibly" before SIGTTOU. There was a reason for that.
A background process that writes to the tty will get SIGTTOU if "stty tostop"
is in effect. This is a user preference thing. You can set it if you get
annoyed by processes writing to the terminal after you backgrounded them
expecting them to be quiet. It's not enabled by default.
If the process ignores SIGTTOU, the write will proceed, overriding the user's
expressed preference.
SIGTTIN is more forceful. There's no stty flag to turn it off, and ignoring
it results in EIO. Keyboard input always belongs exclusively to the
foreground job.
For completeness I'll also mention that SIGTTOU will also be sent to a
background process that attempts to change the tty settings, even if tostop
is not enabled.
--
Alan Curry
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Sat, 02 Jul 2011 21:12:01 GMT)
Full text and
rfc822 format available.
Message #59 received at 8938 <at> debbugs.gnu.org (full text, mbox):
On 02/07/11 19:36, shay shimony wrote:
>> With this patch the child is guaranteed to not be in the foreground (as far
>> as the tty knows) so it will be getting SIGTTIN and possibly SIGTTOU on tty
>> operations.
>
> You may need to correct me. In practice we see that the "timeouted"
> program perform successfully writes to the terminal, though it belongs
> to a different group then the foreground (in my case "make"'s group is
> in the foreground and timeout+compiler/test group is in the background,
> and all output of the compiler and test seem to appear correctly on the
> terminal). And regarding read, I think it makes sense enough that users
> will not use timeout for interactive programs that wait for input from
> the user.
> So maybe the fact that the timeouted program will not be able to get
> SIGTTIN and SIGTTOU is not such a disaster?
Whether output in a background group triggers SIGTTOU is configurable.
Also, in general a long running job might need input from the terminal at the start.
So I think it would be too restrictive to disallow programs that
read from tty from being timed out.
cheers,
Pádraig.
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Sat, 02 Jul 2011 21:26:01 GMT)
Full text and
rfc822 format available.
Message #62 received at 8938 <at> debbugs.gnu.org (full text, mbox):
On 29/06/11 10:55, Pádraig Brady wrote:
> On 28/06/11 20:10, Alan Curry wrote:
>> =?ISO-8859-1?Q?P=E1draig_Brady?= writes:
>>>
>>> I'm still not convinced we need to be messing with tcsetpgrp()
>>> but you're right in that the disconnect between the timeout
>>> process group and that of whatever starts `timeout` should be bridged.
>>>
>>> I'm testing the attached patch at the moment (which I'll split into 2).
>>> It only creates a separate group for the child that `timeout` execs,
>>> leaving the timeout process in the original group to propagate signals down.
>>>
>>> I'll need to do lots of testing with this before I commit.
>>
>> With this patch the child is guaranteed to not be in the foreground (as far
>> as the tty knows) so it will be getting SIGTTIN and possibly SIGTTOU on tty
>> operations.
>
> Oh right. This will immediately put dd in sTop state:
> timeout 10 dd
> That was one of the main reasons I didn't split the groups
> in the first place. I should read my own comments :)
> I'm very wary of changing the foreground group (with tcsetpgrp),
> which would fix this, but in turn may cause other issues.
>
>> I don't think there's anything that will make every scenario happy. (Except
>> for a recursive-kill that doesn't use pgrps!).
>
> Yes, an ideal solution is elusive.
> Maybe `make` needs to handle things differently?
> If you put the following in a Makefile, how should make respond to Ctrl-C?
>
> all:
> setsid sleep 10
I've been doing a quick test here with a version of timeout that
calls tcsetpgrp() in the child background group, and it
works for these cases. However I still don't think we should be
grabbing the foreground group, and instead this
responsibility should be passed down?
Given the above setsid make example (which hangs for 10s
ignoring Ctrl-C, I'm leaning towards `make` needing to
be more shell like, or at least forward the SIGINT etc.
to the job, and not assume jobs run in the foreground group).
There is also the suggestion from Paul Eggert, to add
an option to timeout, so that it doesn't create a separate group,
and so only times out the exec'd process and nothing beneath that.
We might call this --single (process/group).
cheers,
Pádraig.
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Sat, 02 Jul 2011 21:39:01 GMT)
Full text and
rfc822 format available.
Message #65 received at 8938 <at> debbugs.gnu.org (full text, mbox):
=?ISO-8859-1?Q?P=E1draig_Brady?= writes:
>
> Given the above setsid make example (which hangs for 10s
> ignoring Ctrl-C, I'm leaning towards `make` needing to
> be more shell like, or at least forward the SIGINT etc.
> to the job, and not assume jobs run in the foreground group).
I'm a little worried that you're focusing too much on make, which is just one
way to demonstrate the problems of process group abuse.
This simple shell script:
#!/bin/sh
timeout 12 sleep 10
is also nonresponsive to ^C for the same reason as the original makefile.
Are you going to argue that the shell is doing something wrong there too?
--
Alan Curry
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Sat, 02 Jul 2011 23:40:02 GMT)
Full text and
rfc822 format available.
Message #68 received at 8938 <at> debbugs.gnu.org (full text, mbox):
On 02/07/11 22:38, Alan Curry wrote:
> =?ISO-8859-1?Q?P=E1draig_Brady?= writes:
>>
>> Given the above setsid make example (which hangs for 10s
>> ignoring Ctrl-C, I'm leaning towards `make` needing to
>> be more shell like, or at least forward the SIGINT etc.
>> to the job, and not assume jobs run in the foreground group).
>
> I'm a little worried that you're focusing too much on make, which is just one
> way to demonstrate the problems of process group abuse.
>
> This simple shell script:
>
> #!/bin/sh
> timeout 12 sleep 10
>
> is also nonresponsive to ^C for the same reason as the original makefile.
>
> Are you going to argue that the shell is doing something wrong there too?
Oh good point.
The shell script above becomes the foreground group,
rather than the timeout command as is the case when started directly.
I guess there are good reasons for the shell not
to propagate signals down to its children.
So we're left with Paul's "--single" option
to support this, with the tradeoff that it
only signals the child but nothing below that.
cheers,
Pádraig.
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Wed, 06 Jul 2011 22:39:01 GMT)
Full text and
rfc822 format available.
Message #71 received at 8938 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
On 28/06/11 19:45, Paul Eggert wrote:
> On 06/28/11 11:41, Pádraig Brady wrote:
>> The main problem with that is would only
>> send the signal to the first process, and
>> any processes it started would keep running.
>
> Yes, that's the main issue with it. Still,
> it's handy for programs where you either know
> it doesn't use subprocesses, or you *want* to
> kill just the main program and not its subprocesses.
>
> I don't think it should be the default option,
> but it'd be nice to have it as an option.
OK I've added --foreground to support this.
Note it still maintains a separate timeout
monitor process to return 124 on timeout etc.
cheers,
Pádraig.
[timeout--foreground.diff (text/x-patch, attachment)]
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Thu, 07 Jul 2011 10:07:02 GMT)
Full text and
rfc822 format available.
Message #74 received at 8938 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
On 06/07/11 23:37, Pádraig Brady wrote:
> OK I've added --foreground to support this.
> Note it still maintains a separate timeout
> monitor process to return 124 on timeout etc.
Updated wording and NEWS entry now included.
I'll push this later today.
cheers,
Pádraig.
[timeout--foreground.diff (text/x-patch, attachment)]
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Thu, 07 Jul 2011 10:16:01 GMT)
Full text and
rfc822 format available.
Message #77 received at 8938 <at> debbugs.gnu.org (full text, mbox):
On 07/07/11 11:05, Pádraig Brady wrote:
> On 06/07/11 23:37, Pádraig Brady wrote:
>> OK I've added --foreground to support this.
>> Note it still maintains a separate timeout
>> monitor process to return 124 on timeout etc.
>
> Updated wording and NEWS entry now included.
> I'll push this later today.
I'm also thinking of pushing this as a separate patch,
which will set WIFSIGNALED for the timeout process itself.
This will make timeout more transparent and when doing
Ctrl-C from make for example, printing "[target] Interrupt"
rather than "[target] Error 130".
diff --git a/src/timeout.c b/src/timeout.c
index a686225..ea4af18 100644
--- a/src/timeout.c
+++ b/src/timeout.c
@@ -341,7 +361,19 @@ main (int argc, char **argv)
if (WIFEXITED (status))
status = WEXITSTATUS (status);
else if (WIFSIGNALED (status))
- status = WTERMSIG (status) + 128; /* what sh does at least. */
+ {
+ int sig = WTERMSIG (status);
+ if (!timed_out)
+ {
+ /* exit with the signal flag set, but avoid core files. */
+ if (setrlimit (RLIMIT_CORE, &(struct rlimit) {0,0}) == 0)
+ {
+ signal (sig, SIG_DFL);
+ raise (sig);
+ }
+ }
+ status = sig + 128; /* what sh returns for signaled processes. */
+ }
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Thu, 07 Jul 2011 10:56:01 GMT)
Full text and
rfc822 format available.
Message #80 received at 8938 <at> debbugs.gnu.org (full text, mbox):
Pádraig Brady wrote:
> On 06/07/11 23:37, Pádraig Brady wrote:
>> OK I've added --foreground to support this.
>> Note it still maintains a separate timeout
>> monitor process to return 124 on timeout etc.
>
> Updated wording and NEWS entry now included.
> I'll push this later today.
Thanks! This looks good.
> Subject: [PATCH] timeout: add --foreground to support interactive commands
...
> diff --git a/doc/coreutils.texi b/doc/coreutils.texi
> index c59af2f..e04806d 100644
> --- a/doc/coreutils.texi
> +++ b/doc/coreutils.texi
> @@ -15651,6 +15651,23 @@ The program accepts the following options. Also see @ref{Common options}.
> Options must precede operands.
>
> @table @samp
> +@itemx --foreground
> +@opindex --foreground
> +Don't create a separate background program group, so that
> +the managed @var{COMMAND} can use the foreground TTY normally.
"make check" dings that:
./coreutils.texi:15659:the managed @var{COMMAND} can use the foreground TTY normally.
doc/Makefile: do not use upper case in @var{...}
make[2]: *** [sc-lower-case-var] Error 1
You probably have a test case, but just forgot to include it.
This is subtle enough that it deserves one, if it's not too much work.
> +This is needed to support timing out commands not started
> +directly from an interactive shell, in two situations.
> +@enumerate
> +@item
> +@var{command} is interactive and needs to read from the terminal for example
> +@item
> +the user wants to support sending signals directly to @var{command}
> +from the terminal (like Ctrl-C for example)
> +@end enumerate
> +
> +Note in this mode of operation, any children of @var{command}
> +will not be timed out.
> +
> @item -k @var{duration}
> @itemx --kill-after=@var{duration}
> @opindex -k
> diff --git a/src/timeout.c b/src/timeout.c
> index a686225..8f0980b 100644
> --- a/src/timeout.c
> +++ b/src/timeout.c
> @@ -67,11 +67,19 @@ static int term_signal = SIGTERM; /* same default as kill command. */
> static int monitored_pid;
> static int sigs_to_ignore[NSIG]; /* so monitor can ignore sigs it resends. */
> static unsigned long kill_after;
> +static bool foreground; /* whether to use another program group. */
The comment is worth more if it says e.g.,
/* If true, don't create a separate process group. */
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Thu, 07 Jul 2011 11:14:02 GMT)
Full text and
rfc822 format available.
Message #83 received at 8938 <at> debbugs.gnu.org (full text, mbox):
Pádraig Brady wrote:
> On 07/07/11 11:05, Pádraig Brady wrote:
>> On 06/07/11 23:37, Pádraig Brady wrote:
>>> OK I've added --foreground to support this.
>>> Note it still maintains a separate timeout
>>> monitor process to return 124 on timeout etc.
>>
>> Updated wording and NEWS entry now included.
>> I'll push this later today.
>
> I'm also thinking of pushing this as a separate patch,
> which will set WIFSIGNALED for the timeout process itself.
> This will make timeout more transparent and when doing
> Ctrl-C from make for example, printing "[target] Interrupt"
> rather than "[target] Error 130".
>
> diff --git a/src/timeout.c b/src/timeout.c
> index a686225..ea4af18 100644
> --- a/src/timeout.c
> +++ b/src/timeout.c
> @@ -341,7 +361,19 @@ main (int argc, char **argv)
> if (WIFEXITED (status))
> status = WEXITSTATUS (status);
> else if (WIFSIGNALED (status))
> - status = WTERMSIG (status) + 128; /* what sh does at least. */
> + {
> + int sig = WTERMSIG (status);
> + if (!timed_out)
> + {
> + /* exit with the signal flag set, but avoid core files. */
> + if (setrlimit (RLIMIT_CORE, &(struct rlimit) {0,0}) == 0)
> + {
> + signal (sig, SIG_DFL);
> + raise (sig);
> + }
> + }
> + status = sig + 128; /* what sh returns for signaled processes. */
I like the idea.
Note that setrlimit is not available on mingw or Beos, according to
gnulib's doc/posix-functions/setrlimit.texi, so you might want to test
for its existence. Otherwise, this change would induce link failure on
those systems.
At first I was worried that this improvement would be dependent on
setrlimit success, but it appears that it cannot fail for the arguments
used here. I wonder if it's better to assert that non-failure -- or
maybe just issue a warning, so that if it happens we'll be more likely
to get a bug report about it, rather than have users endure a subtle
difference in behavior.
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Fri, 08 Jul 2011 10:52:01 GMT)
Full text and
rfc822 format available.
Message #86 received at 8938 <at> debbugs.gnu.org (full text, mbox):
On 07/07/11 11:55, Jim Meyering wrote:
> You probably have a test case, but just forgot to include it.
> This is subtle enough that it deserves one, if it's not too much work.
The test is a bit awkward, but worth adding.
Applying now...
cheers,
Pádraig.
Information forwarded
to
owner <at> debbugs.gnu.org, bug-coreutils <at> gnu.org
:
bug#8938
; Package
coreutils
.
(Fri, 08 Jul 2011 10:57:02 GMT)
Full text and
rfc822 format available.
Message #89 received at 8938 <at> debbugs.gnu.org (full text, mbox):
On 07/07/11 12:13, Jim Meyering wrote:
> Pádraig Brady wrote:
>
>> On 07/07/11 11:05, Pádraig Brady wrote:
>>> On 06/07/11 23:37, Pádraig Brady wrote:
>>>> OK I've added --foreground to support this.
>>>> Note it still maintains a separate timeout
>>>> monitor process to return 124 on timeout etc.
>>>
>>> Updated wording and NEWS entry now included.
>>> I'll push this later today.
>>
>> I'm also thinking of pushing this as a separate patch,
>> which will set WIFSIGNALED for the timeout process itself.
>> This will make timeout more transparent and when doing
>> Ctrl-C from make for example, printing "[target] Interrupt"
>> rather than "[target] Error 130".
>>
>> diff --git a/src/timeout.c b/src/timeout.c
>> index a686225..ea4af18 100644
>> --- a/src/timeout.c
>> +++ b/src/timeout.c
>> @@ -341,7 +361,19 @@ main (int argc, char **argv)
>> if (WIFEXITED (status))
>> status = WEXITSTATUS (status);
>> else if (WIFSIGNALED (status))
>> - status = WTERMSIG (status) + 128; /* what sh does at least. */
>> + {
>> + int sig = WTERMSIG (status);
>> + if (!timed_out)
>> + {
>> + /* exit with the signal flag set, but avoid core files. */
>> + if (setrlimit (RLIMIT_CORE, &(struct rlimit) {0,0}) == 0)
>> + {
>> + signal (sig, SIG_DFL);
>> + raise (sig);
>> + }
>> + }
>> + status = sig + 128; /* what sh returns for signaled processes. */
>
> I like the idea.
> Note that setrlimit is not available on mingw or Beos, according to
> gnulib's doc/posix-functions/setrlimit.texi, so you might want to test
> for its existence. Otherwise, this change would induce link failure on
> those systems.
Good catch. I'll wrap in
#if HAVE_SETRLIMIT && defined RLIMIT_CORE
#endif
> At first I was worried that this improvement would be dependent on
> setrlimit success, but it appears that it cannot fail for the arguments
> used here. I wonder if it's better to assert that non-failure -- or
> maybe just issue a warning, so that if it happens we'll be more likely
> to get a bug report about it, rather than have users endure a subtle
> difference in behavior.
I'll issue a warning.
cheers,
Pádraig.
bug marked as fixed in version 8.13, send any further explanations to
8938 <at> debbugs.gnu.org and shay shimony <shayshim <at> gmail.com>
Request was from
Pádraig Brady <P <at> draigBrady.com>
to
control <at> debbugs.gnu.org
.
(Sun, 17 Jul 2011 12:03:01 GMT)
Full text and
rfc822 format available.
bug archived.
Request was from
Debbugs Internal Request <help-debbugs <at> gnu.org>
to
internal_control <at> debbugs.gnu.org
.
(Mon, 15 Aug 2011 11:24:03 GMT)
Full text and
rfc822 format available.
This bug report was last modified 14 years and 25 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.