On Tue, Mar 24, 2026 at 4:18 AM alain williams <[email protected]> wrote:
> On Tue, Mar 24, 2026 at 12:01:23AM -0400, Jeffrey Walton wrote:
>
> > You have to be careful of what you do in a signal handler. If the
> > editor is trying to log messages to a log file like, "Received SIGTERM
> > on 03/23/2026 22:00:00", then things could get very tricky. That's
> > because any system call made must be AS-Safe a/k/a Asynchronous Signal
> > Safe. If the call is not AS-Safe, then that is Undefined Behavior
> > (UB) and you should expect nasal demons.
>
> I am well aware of that. The signal handler code is careful to not use
> stdio -
> so thus open()/close()/write(); things like localtime() not used.
>
My bad for a second post...
write() _IS_ AS-Signal safe. That is what you should be using.
But _NO_ memory allocations, like could happen with printf(), sprintf() and
friends. Below is some code I wrote to log a signal in a signal handler.
It uses write(). I had to switch from printf() to write() because printf()
was causing hangs on occasion, like during shutdown.
> It does use strsignal() & strerror() which I am a bit dubious about.
>
> It does use sprintf() (%ld) which I think should be safe.
And for completeness, the other email said do not use strsignal(),
strerror() and sprintf() in a signal handler because they are _NOT_
AS-Signal safe.
----- Code -----
/* No printf in the signal handler. Use write(2) directly */
static void signal_callback(int sig)
{
int save_errno = errno;
/* Add a \n for ^C in terminal */
if (sig == SIGINT)
write(STDOUT_FILENO, "\n", 1);
if (log_level_guard(LOG_DEBUG))
write(STDOUT_FILENO, "signal_callback\n", 16);
g_sigval = sig;
if (log_level_guard(LOG_INFO))
{
const char* sigName = signal_to_string(sig);
size_t len=0;
for (; sigName[len] != '\0'; ++len) {}
write(STDOUT_FILENO, "Info: received signal ", 22);
write(STDOUT_FILENO, sigName, len);
write(STDOUT_FILENO, "\n", 1);
}
g_continue = 0;
errno = save_errno;
}
const char* signal_to_string(int sig)
{
switch (sig)
{
case SIGABRT:
return "SIGABRT";
case SIGHUP:
return "SIGHUP";
case SIGINT:
return "SIGINT";
case SIGKILL:
return "SIGKILL";
case SIGCONT:
return "SIGCONT";
case SIGPWR:
return "SIGPWR";
case SIGQUIT:
return "SIGQUIT";
case SIGSTOP:
return "SIGSTOP";
case SIGTERM:
return "SIGTERM";
case SIGUSR1:
return "SIGUSR1";
case SIGUSR2:
return "SIGUSR2";
default:
;;
}
return "UNKNOWN";
}
----- End Code -----
Jeff