help-make
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Make does not clean up the target when stderr is piped. Why?


From: Kaz Kylheku (gmake)
Subject: Re: Make does not clean up the target when stderr is piped. Why?
Date: Fri, 04 Jun 2021 14:17:23 -0700
User-agent: Roundcube Webmail/0.9.2

On 2021-06-04 05:57, Paul Smith wrote:
On Fri, 2021-06-04 at 12:31 +0900, Masahiro Yamada wrote:
GNU Make cleans up partially updated targets if the user interrupts
before the build rules complete.

If GNU Make does not do this, they will not be updated in the next
run of 'make' because their timestamps are new while the contents are
incomplete.

This issue was asked in the Linux kernel ML [1], but I can reproduce
it in simple test code.  Please see the following case.

It's pretty easy to see what's happening if you use strace.

The thing to remember is that when you use ^C you're sending the signal
to the entire process group.  That means that not only does make get a
SIGINT, but also your "cat" program gets a SIGINT, and dies.

When the SIGINT signal handler is called in GNU make, it tries to clean
up IN THE SIGNAL HANDLER.  This is a long-standing problem, since the
very first version of GNU make as far as I know: it does all kinds of
things in its signal handler which are not really valid in a signal
handler context.

The applicable standards like POSIX may say so as a blanket general
statement. For instance of a signal goes off while we are executing
free() and we call malloc() in the handler, that is obviously bad.

But if we block the signal, and only unblock it in safe situations
(like around long I/O operations, or invocations of external programs),
then we are actually okay.

I have a partial solution to fix it, but it's actually extremely
difficult due to the really crappy signal handling model that POSIX
provides and my current solution still suffers from race conditions
that need to be resolved before it can be used.  I haven't had time to
get back to this.

Oh, the model will sit up and beg if you give it the right milk bones.

I've written Lisp code that uses a lambda function as a signal handler
to detect its own stack overrun, executing on a sigaltstack. :)

I think your main difficulty is working in in a widely portable and
fundamental GNU program. There are still some VMS ifdefs in this thing
and such. I.e. that GNU Make perhaps still has to run on systems
which have broken POSIX signal handling.

Any changes in this area have to build everywhere and at least not
break anything, even if the interruption problem is not solved
everywhere.

Anyway: one of the things make will do in its signal handler is try to
write error messages to stderr.  If you are piping the output of stderr
to a program, and that program has died, then writing to it will
generate a SIGPIPE.

Because the write is inside the SIGINT signal handler, make is no
longer catching signals like SIGPIPE, so when it receives that SIGPIPE
it will simply exit immediately.

In this situation, when that handler is running, it might make sense
to block SIGPIPE. POSIX has the wherewithal to arrange that.

Using sigaction you can use sa_mask to specify which signals are
blocked when that handler is running.

POSIX has a cool sigsetjmp/siglongjmp feature: you can jump out of
signal handlers such that the signal mask is restored to the sigsetjmp
context. That could be used. The handler could do no clean-up itself
but just siglongjmp to some handling code up in main() or wherever.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]