0

I have program that uses the logger. The logger is a shared library with yet one process for output (it uses Linux MQ to send messages from main process to logging process).
In my app I try to listen SIGINT and SIGPIPE signals to shut down my server:

/* Releases all captured resources and shuts down server */
void shutdown_server(int status) {
    LOG_I("Shutting down server...");
    close(srv_sock);
    settings_destroy(&settings);
    LOG_I("Success!");
    shutdown_log();
    exit(status);
}

/* Handles signals */
void handle_signal_action(int sig_number)
{
    if (sig_number == SIGINT) {
        LOG_D("SIGINT was catched!\n");
        shutdown_server(EXIT_SUCCESS);
    } else if (sig_number == SIGPIPE) {
        LOG_D("SIGPIPE was catched!\n");
        shutdown_server(EXIT_SUCCESS);
    }
}

/** Subscribes to events when thread was terminated or no reader of the pipe **/
int setup_signals(void (*handler)(int))
{
    struct sigaction sa;
    sa.sa_handler = handler;
    if (sigaction(SIGINT, &sa, 0) != 0) {
        LOG_E("Can't subscribe to SIGINT");
        return -1;
    }
    if (sigaction(SIGPIPE, &sa, 0) != 0) {
        LOG_E("Can't subscribe to SIGPIPE");
        return -1;
    }
    return 0;
}

/* Entry point */
int main(int argc, char **argv) {
    if (setup_signals(handle_signal_action)) {
        LOG_F("Can't setup signals");
        return -1;
    }

    if (init_log()) {
        printf("Can't initialize logger.\n");
        return -1;
    }

    if (settings_init(&settings, argc, argv)) {
        LOG_F("Can't load configuration");
        exit(EXIT_FAILURE);
    }
    settings_log(&settings);

    if (socket_init(&srv_sock, settings.address, settings.port)) {
        LOG_F("Can't initialize socket");
        exit(EXIT_FAILURE);
    }

    while (1) {
        LOG_W("Hello, world!");
    }
}

The problem is when I press Ctrl+C in terminal my app stops to print log messages but two processes still work.

Where could the problem be?

P.S. If you need more details just write in comments which, I'll add.

ADDED
log.c

#include <log.h>

#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>
#include <unistd.h>

#define STOP_SIG "!>kill"

/* Message */
typedef struct mq_msg {
    log_level_t level;
    char msg[MAX_MSG_SIZE + 1];
} mq_msg_t;

/* Process ID */
pid_t pid;
/* Current log level */
log_level_t cur_log_lvl;
/* Message queue descriptor */
mqd_t mq;
/* Message queue attributes */
struct mq_attr attr;
/* Current message */
mq_msg_t cur_msg;

/* Initialize message queue listner for the child process */
void init_listener() {
    while (1) {
        ssize_t len = mq_receive(mq, (char *)&cur_msg, sizeof(cur_msg), NULL);
        if (len > 0) {
            // Check stop signal
            if (strcmp(STOP_SIG, cur_msg.msg) == 0) { exit(EXIT_SUCCESS); }

            time_t timestamp;
            struct tm *timeinfo;

            time(&timestamp);
            timeinfo = localtime(&timestamp);
            FILE *f = cur_msg.level < LL_WARNING ? stderr : stdout;

            fprintf(f, "[%u][%02d:%02d:%02d] ", (uint32_t)timestamp,
                                                timeinfo->tm_hour,
                                                timeinfo->tm_min,
                                                timeinfo->tm_sec);
            fprintf(f, "%s\n", cur_msg.msg);
            fflush(f);
            usleep(0.725 * 1e6); // TODO: Read about these magic numbers
        }
    }
}

/* Initializes logger */
bool init_log() {
    cur_log_lvl = LL_DEBUG;
    // Initialize a message queue
    attr.mq_flags = 0;
    attr.mq_maxmsg = 10;
    attr.mq_msgsize = sizeof(cur_msg);
    attr.mq_curmsgs = 0;
    mq = mq_open(MQ_NAME, O_CREAT | O_RDONLY, 0644, &attr);
    if (mq == (mqd_t)-1) {
        printf("Can't create a message queue\n");
        return -1;
    }
    // Create a logger process
    pid = fork();
    if (pid == -1) {
        printf("Can't create the logger process\n");
        return -1;
    }

    if (pid == 0) {
        init_listener(); // Listen the message queue
    } else {
        mq = mq_open(MQ_NAME, O_WRONLY); // Connect to the message queue
        if (mq == (mqd_t)-1) {
            printf("Can't connect to the message queue\n");
            return -1;
        }
    }

    return 0;
}

void shutdown_log() {
    if (mq == (mqd_t)-1) { mq_close(mq); }
    if (pid > 0) { 
        memset(cur_msg.msg, 0, sizeof(cur_msg.msg));
        strcpy(cur_msg.msg, STOP_SIG);
        mq_send(mq, (const char *)&cur_msg, sizeof(cur_msg), 0);
    }
}

/* Destructor */
void __attribute__((destructor)) finish_log() {
    shutdown_log();
}

/* Sets log level */
void set_log_level(log_level_t lvl) {
    cur_log_lvl = lvl;
}

/* Returns log level */
log_level_t get_log_level() {
    return cur_log_lvl;
}

/* Sends log message to the message queue */
void trace(const char *format, ...) {
    if (pid != 0) {
        cur_msg.level = LL_DEBUG;
        va_list args;
        va_start(args, format);
        vsnprintf(cur_msg.msg, MAX_MSG_SIZE, format, args);
        va_end(args);
        mq_send(mq, (const char *)&cur_msg, sizeof(cur_msg), 0);
    }
}
Denis Sologub
  • 7,277
  • 11
  • 56
  • 123
  • 1
    The code misses to properly initialise the structure passed to `sigaction()`. Define *and* initialise it like this: `struct sigaction sa = {0};` – alk Feb 28 '19 at 13:14
  • @alk I'll try it, hope it will help. Thank you! – Denis Sologub Feb 28 '19 at 13:16
  • It might help if you showed the output of a typical session. – alk Feb 28 '19 at 13:20
  • 1
    What does `settings_destroy()` do? This is important to know as it is called from a signal handler, which limits the set of functions that may be called. – alk Feb 28 '19 at 13:21
  • @alk sorry, I haven't access to computer now. I'll update my question later – Denis Sologub Feb 28 '19 at 13:24
  • 1
    As a general rule of thumb signal handlers should be simple functions, best doing nothing (aside eating the signal) or just only set a `sig_atmic_t` typed global flag or write a trigger to a pipe, indicating they got called. `mq_send()` is not necessarily async-signal-safe. More on this see here: https://stackoverflow.com/q/46354925/694576 – alk Feb 28 '19 at 13:29
  • For a complete example, `log.h` is missing. – Armali Mar 01 '19 at 15:26
  • 1
    @alk thank you very much! Using of `sig_atmic_t` flag instead of my "heavy" handler helped really. – Denis Sologub Mar 01 '19 at 15:29

0 Answers0