How to make a function async-signal-safe?
Asked Answered
S

3

9

I have the following sigaction handler function

void signal_term_handler(int sig)
{
    printf("EXIT :TERM signal Received!\n");
    int rc = flock(pid_file, LOCK_UN | LOCK_NB);
    if(rc) {
        char *piderr = "PID file unlock failed!";
        fprintf(stderr, "%s\n", piderr);
        printf(piderr);
    }
    abort();
}

Someone told me that flock and printf aren't async-signal-safe. And I could not find an alternate async-signal-safe function for flockin this list.

and according to the above link:

when a signal interrupts an unsafe function and the signal-catching function calls an unsafe function, the behavior is undefined

Is there a way to make flock async-signal-safe? Or is there another solution to execute flock when I receive TERM signal?

Solemn answered 6/6, 2013 at 16:29 Comment(1)
Possible duplicate of How to avoid using printf in a signal handler? for printf, #16979559 for flock.Georgetta
D
4

You can use fcntl() as an alternative to flock().

Delwin answered 6/6, 2013 at 17:12 Comment(2)
Be aware that the semantics of fcntl() locks are different from and less useful than those of flock().Undertaking
In fact I can use fcntl to develop a new property flock() function as indicated in this topic. Thank you for the answerSolemn
U
4

flock() is generally async-signal-safe because it is a system call. Its semantics make it hard to implement it differently. It is not in POSIX's list of async-signal-safe functions because it is not in POSIX at all.

You likely do not need the explicit unlock because flock() locks are released automatically when all file descriptors referring to the open file description are closed.

The printf() and fprintf() calls should be replaced with appropriate write() calls. The stdio functions are not in the list of async-signal-safe functions and are often strongly async-signal-unsafe.

The abort() call is probably best replaced by setting the signal to the default action and resending it to self; this way, shells know that your program exited because of the signal and can abort command sequences when appropriate.

Undertaking answered 6/6, 2013 at 21:21 Comment(2)
Can I use flock() without problems in the sigaction handler?Solemn
Yes, but as I said you may not need to.Undertaking
U
0

You can use exit() instead of abort() in your signal handler, and then put your unsafe functions in an exit handler using atexit().

update: In general, you should not put any potentially blocking system calls in your signal handler. One way to avoid this is to just set a flag in your signal handler, and then perform the functions you wanted in the context of your main loop.

volatile int shutdown = 0;

void signal_term_handler(int sig)
{
    shutdown = 1;
}

void cleanup() {
    printf("EXIT :TERM signal Received!\n");
    int rc = flock(pid_file, LOCK_UN | LOCK_NB);
    if(rc) {
        char *piderr = "PID file unlock failed!";
        fprintf(stderr, "%s\n", piderr);
        printf(piderr);
    }
}

void *workerFunction(void *arg) {
    while (!shutdown) {
       ... do stuff ...
    }
    return NULL;
}

int main(int argc, char *argv[]) {
    //...
    pthread_create(...,workerFunction,...);
    pthread_join(...);
    cleanup();
    return 0;
}
Unkindly answered 6/6, 2013 at 17:6 Comment(2)
Exit-handlers may be called synchronously. Doing so from an asynchronously invoked signal handler make them run how?Hemicycle
Right, I didn't read the question carefully enough. I guess I was answering a more basic question about how to avoid unsafe functions in a signal handler. In this case, you would want to replace exit() with something like setting a shutdown flag.Unkindly

© 2022 - 2024 — McMap. All rights reserved.