tech-userlevel archive

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

Re: patch adding a pidfile-option to script(1)



> Date: Wed, 16 Sep 2026 12:55:43 -0400 (EDT)
> From: Mouse <mouse%Rodents-Montreal.ORG@localhost>
> 
> >> [...] the way the SIGUSR1 handling is coded won't work in general -
> >> signal handlers should only ever call async signal safe functions,
> >> and neither fopen() nor fclose() is that (fflush() I'm not sure
> >> about).
> 
> > This patch can be made safe with a much smaller modification: simply
> > keep SIGUSR1 blocked _except_ during the calls to read() and write()
> > in dooutput(), when there is no risk of interrupting access to the
> > stdio data structures.  Just needs a handful of sigprocmask calls.
> 
> That makes it safe...for one particular implementation.  It is not safe
> in general.  There is no promise that stdio is signal-unsafe only when
> the signal interrupts a stdio call, though that is the way most
> implementations happen to work.

No, it is safe in general for all POSIX-conformant systems:

   In the presence of signals, all functions defined by this volume of
   POSIX.1-2024 shall behave as defined when called from or
   interrupted by a signal-catching function, with the exception that
   when a signal interrupts an unsafe function or function-like macro,
   or equivalent (such as the processing equivalent to exit()
   performed after a return from the initial call to main()), and the
   signal-catching function calls an unsafe function or function-like
   macro, the behavior is undefined.

   POSIX.1-2024, Volume XSH: System Interfaces, Sec. 2.4.3 `Signal
   Actions'
   https://pubs.opengroup.org/onlinepubs/9799919799/functions/V2_chap02.html#tag_16_04_03   

In other words, you can safely call a non-async-signal-safe function
from a signal handler _if_ you can guarantee that it won't interrupt
any non-async-signal-safe function.

In contrast, the async-signal-safe functions are _always_ safe to call
unconditionally, _even if_ they may be interrupted and the signal
handler may call non-async-signal-safe functions (or if they are
called from a signal handler that interrupts a non-async-signal-safe
function):

   The following table defines a set of functions and function-like
   macros that shall be async-signal-safe.  Therefore, applications
   can call them, without restriction, from signal-catching functions.

   POSIX.1-2024, Volume XSH: System Interfaces, Sec. 2.4.3 `Signal
   Actions'
   https://pubs.opengroup.org/onlinepubs/9799919799/functions/V2_chap02.html#tag_16_04_03   

So code like this (pseudo-code, with various irrelevant details elided
for brevity) is safe:

FILE *fp;

on_sigusr1()
{
	int e = errno;		/* make sure to save and restore errno! */
	fclose(fp);
	fp = fopen(path, "a");
	errno = e;
}

main()
{
	...
	sigprocmask(SIG_BLOCK, {SIGUSR1}, NULL);
	signal(SIGUSR1, on_sigusr1);
	...
	for (;;) {
		sigprocmask(SIG_SETMASK, {}, &mask);
		/*
		 * read and write are async-signal-safe, so they can
		 * safely be interrupted by calls to fclose/fopen
		 */
		read(...);
		write(...);
		sigprocmask(SIG_SETMASK, &mask, NULL);
		fwrite(fp, ...);
	}
	...
}


This isn't new; essentially the same language already appears in
POSIX.1-2001, SUSv2 in 1997, and POSIX.1-1990 (all that was added in
the excerpt above is clarification about implied calls to unsafe
functions like exit() on return from main()), and read() and write()
both appear in all the async-signal-safe lists since 1990:

   POSIX.1-2001, Volume XSH: System Interfaces, Sec. 2.4.3 `Signal
   Actions'
   https://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html#tag_02_04_03

   Single Unix Specification, Version 2, Volume XSH: System
   Interfaces, Sec. `sigaction'
   https://pubs.opengroup.org/onlinepubs/7908799/xsh/sigaction.html

   POSIX.1-1990, Part I: System API (C Language), Sec. 3.3.1.3 `Signal
   Actions', pp. 54--55
   https://archive.org/details/posix-1/page/n37/mode/1up


Home | Main Index | Thread Index | Old Index