LINUX.ORG.RU

История изменений

Исправление hateyoufeel, (текущая версия) :

Локи однозначно проще чем эти нагромождения.

Да не, не проще.

Блин, ты меня заставил код написать. С локами получилось бы сложнее, на самом деле, потому что дедлок тут поймать будет весьма легко.

#define _GNU_SOURCE

#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/signalfd.h>
#include <unistd.h>
#include <pthread.h>
#include <stdbool.h>

#define UNUSED(x) do{(void)(x);}while(false)

// I don't want to care about message lengths today.
const size_t max_len = 256;

static void die(const char*);
static void logmsg(const char*);
static void* write_logs(void *);

static int log_in = -1,
           log_out = -1;
static sigset_t sigmask;

static void die(const char* fname)
{
    const char* err = strerror(errno);
    fprintf(stderr, "Call to %s failed: %s\n", fname, err);
    exit(EXIT_FAILURE);
}

static void logmsg(const char* msg)
{
    size_t msglen = strlen(msg);
    size_t sz = msglen < max_len ? msglen : max_len;
    write(log_in, msg, sz);
}

int main()
{
    int r;
    pthread_t writer_thread;
    int pipe_fds[2];

    r = pipe2(pipe_fds, O_DIRECT); // O_DIRECT is needed for packet mode and isn't strictly necessary here
    if(r == -1) {
        die("pipe");
    }
    log_in = pipe_fds[1];
    log_out = pipe_fds[0];

    // Set up sigmask
    sigemptyset(&sigmask);
    sigaddset(&sigmask, SIGUSR1);
    // Block SIGUSR1
    // It will be handled separately by signalfd()
    r = sigprocmask(SIG_BLOCK, &sigmask, NULL);
    if(r == -1) {
        die("sigprocmask");
    }

    r = pthread_create(&writer_thread, NULL, write_logs, NULL);
    if(r == -1) {
        die("pthread_create");
    }

    for(unsigned i = 0; ; i++) {
        char str[max_len];
        snprintf(str, max_len, "Message number %u\n", i);
        logmsg(str);
        usleep(1000000);
    }
}

static void* write_logs(void *arg)
{
    const char* filemask = "logfile_%d.log";
    char filename[256] = {};
    int fd = -1;
    int sigfd = -1;
    int log_counter = 0;
    struct pollfd pfds[2];

    UNUSED(arg);

    sigfd = signalfd(-1, &sigmask, 0);
    if (sigfd == -1) {
        die("signalfd");
    }
    snprintf(filename, sizeof(filename), filemask, log_counter);
    const int open_flags = O_WRONLY | O_TRUNC | O_CREAT;
    const int open_mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
    fd = open(filename, open_flags, open_mask);
    if(fd == -1) {
        die("open");
    }

    pfds[0].fd = sigfd;
    pfds[0].events = POLLIN;
    pfds[1].fd = log_out;
    pfds[1].events = POLLIN;

    do {
        int r = poll(pfds, 2, -1);
        switch(r) {
            case -1: 
              if(errno == EAGAIN || errno == EINTR)
                continue;
              else
                die("poll");
            case 0:  continue;
        }
        if(pfds[0].revents & POLLIN) {
            // We have a signal!
            struct signalfd_siginfo sig = {};
            r = read(sigfd, &sig, sizeof(sig));
            if(r == -1) {
                die("read");
            }
            // We only have one signal, so there's no need to check it.
            close(fd);
            snprintf(filename, sizeof(filename), filemask, ++log_counter);
            fd = open(filename, open_flags, open_mask);
            if(fd == -1) {
                die("open");
            }
        }
        if(pfds[1].revents & POLLIN) {
            // We have a message to log!
            char buf[max_len];
            r = read(log_out, buf, max_len-1);
            if(r == -1) {
                die("read");
            }
            r = write(fd, buf, r);
            if(r == -1) {
                die("write");
            }
        }
    } while(true);

    return NULL;
}

Компилить через clang -O2 -Wall -Werror -lpthread logpipe.c -o logpipe.

Пишет в текущую директорию логи в файлы по маске «logfile_%u.log». При получении SIGUSR1 переключается на новый файл.

ТС, вот тебе готовый код. poll() на kqueue() можешь сам заменить по вкусу.

Исправление hateyoufeel, :

Локи однозначно проще чем эти нагромождения.

Да не, не проще.

Блин, ты меня заставил код написать. С локами получилось бы сложнее, на самом деле, потому что дедлок тут поймать будет весьма легко.

#define _GNU_SOURCE

#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/signalfd.h>
#include <unistd.h>
#include <pthread.h>
#include <stdbool.h>

#define UNUSED(x) do{(void)(x);}while(false)

// I don't want to care about message lengths today.
const size_t max_len = 256;

static void die(const char*);
static void logmsg(const char*);
static void* write_logs(void *);

static int log_in = -1,
           log_out = -1;
static sigset_t sigmask;

static void die(const char* fname)
{
    const char* err = strerror(errno);
    fprintf(stderr, "Call to %s failed: %s\n", fname, err);
    exit(EXIT_FAILURE);
}

static void logmsg(const char* msg)
{
    size_t msglen = strlen(msg);
    size_t sz = msglen < max_len ? msglen : max_len;
    write(log_in, msg, sz);
}

int main()
{
    int r;
    pthread_t writer_thread;
    int pipe_fds[2];

    r = pipe2(pipe_fds, O_DIRECT); // O_DIRECT is needed for packet mode and isn't strictly necessary here
    if(r == -1) {
        die("pipe");
    }
    log_in = pipe_fds[1];
    log_out = pipe_fds[0];

    // Set up sigmask
    sigemptyset(&sigmask);
    sigaddset(&sigmask, SIGUSR1);
    // Block SIGUSR1
    // It will be handled separately by signalfd()
    r = sigprocmask(SIG_BLOCK, &sigmask, NULL);
    if(r == -1) {
        die("sigprocmask");
    }

    r = pthread_create(&writer_thread, NULL, write_logs, NULL);
    if(r == -1) {
        die("pthread_create");
    }

    for(unsigned i = 0; ; i++) {
        char str[max_len];
        snprintf(str, max_len, "Message number %u\n", i);
        logmsg(str);
        usleep(1000000);
    }
}

static void* write_logs(void *arg)
{
    const char* filemask = "logfile_%d.log";
    char filename[256] = {};
    int fd = -1;
    int sigfd = -1;
    int log_counter = 0;
    struct pollfd pfds[2];

    UNUSED(arg);

    sigfd = signalfd(-1, &sigmask, 0);
    if (sigfd == -1) {
        die("signalfd");
    }
    snprintf(filename, sizeof(filename), filemask, log_counter);
    const int open_flags = O_WRONLY | O_TRUNC | O_CREAT;
    const int open_mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
    fd = open(filename, open_flags, open_mask);
    if(fd == -1) {
        die("open");
    }

    pfds[0].fd = sigfd;
    pfds[0].events = POLLIN;
    pfds[1].fd = log_out;
    pfds[1].events = POLLIN;

    do {
        int r = poll(pfds, 2, -1);
        switch(r) {
            case -1: die("poll");
                     break;
            case 0:  continue;
        }
        if(pfds[0].revents & POLLIN) {
            // We have a signal!
            struct signalfd_siginfo sig = {};
            r = read(sigfd, &sig, sizeof(sig));
            if(r == -1) {
                die("read");
            }
            // We only have one signal, so there's no need to check it.
            close(fd);
            snprintf(filename, sizeof(filename), filemask, ++log_counter);
            fd = open(filename, open_flags, open_mask);
            if(fd == -1) {
                die("open");
            }
        }
        if(pfds[1].revents & POLLIN) {
            // We have a message to log!
            char buf[max_len];
            r = read(log_out, buf, max_len-1);
            if(r == -1) {
                die("read");
            }
            r = write(fd, buf, r);
            if(r == -1) {
                die("write");
            }
        }
    } while(true);

    return NULL;
}

Компилить через clang -O2 -Wall -Werror -lpthread logpipe.c -o logpipe.

Пишет в текущую директорию логи в файлы по маске «logfile_%u.log». При получении SIGUSR1 переключается на новый файл.

ТС, вот тебе готовый код. poll() на kqueue() можешь сам заменить по вкусу.

Исправление hateyoufeel, :

Локи однозначно проще чем эти нагромождения.

Да не, не проще.

Блин, ты меня заставил код написать. С локами получилось бы сложнее, на самом деле, потому что дедлок тут поймать будет весьма легко.

#define _GNU_SOURCE

#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/signalfd.h>
#include <unistd.h>
#include <pthread.h>
#include <stdbool.h>

#define UNUSED(x) do{(void)(x);}while(false)

// I don't want to care about message lengths today.
const size_t max_len = 256;

static void die(const char*);
static void logmsg(const char*);
static void* write_logs(void *);

static int log_in = -1,
           log_out = -1;
static sigset_t sigmask;

static void die(const char* fname)
{
    const char* err = strerror(errno);
    fprintf(stderr, "Call to %s failed: %s\n", fname, err);
    exit(EXIT_FAILURE);
}

static void logmsg(const char* msg)
{
    size_t msglen = strlen(msg);
    size_t sz = msglen < max_len ? msglen : max_len;
    write(log_in, msg, sz);
}

int main()
{
    int r;
    pthread_t writer_thread;
    int pipe_fds[2];

    r = pipe2(pipe_fds, O_DIRECT); // O_DIRECT is needed for packet mode and isn't strictly necessary here
    if(r == -1) {
        die("pipe");
    }
    log_in = pipe_fds[1];
    log_out = pipe_fds[0];

    // Set up sigmask
    sigemptyset(&sigmask);
    sigaddset(&sigmask, SIGUSR1);
    // Block SIGUSR1
    // It will be handled separately by signalfd()
    r = sigprocmask(SIG_BLOCK, &sigmask, NULL);
    if(r == -1) {
        die("sigprocmask");
    }

    r = pthread_create(&writer_thread, NULL, write_logs, NULL);
    if(r == -1) {
        die("pthread_create");
    }

    for(unsigned i = 0; ; i++) {
        char str[max_len];
        snprintf(str, max_len, "Message number %u\n", i);
        logmsg(str);
        usleep(1000000);
    }
}

static void* write_logs(void *arg)
{
    const char* filemask = "logfile_%d.log";
    char filename[256] = {};
    int fd = -1;
    int sigfd = -1;
    int log_counter = 0;
    struct pollfd pfds[2];

    UNUSED(arg);

    sigfd = signalfd(-1, &sigmask, 0);
    if (sigfd == -1) {
        die("signalfd");
    }
    snprintf(filename, sizeof(filename), filemask, log_counter);
    const int open_flags = O_WRONLY | O_TRUNC | O_CREAT;
    const int open_mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
    fd = open(filename, open_flags, open_mask);
    if(fd == -1) {
        die("open");
    }

    pfds[0].fd = sigfd;
    pfds[0].events = POLLIN;
    pfds[1].fd = log_out;
    pfds[1].events = POLLIN;

    do {
        int r = poll(pfds, 2, -1);
        switch(r) {
            case -1: die("poll");
                     break;
            case 0:  continue;
        }
        if(pfds[0].revents & POLLIN) {
            // We have a signal!
            struct signalfd_siginfo sig = {};
            r = read(sigfd, &sig, sizeof(sig));
            if(r == -1) {
                die("read");
            }
            // We only have one signal, so there's no need to check it.
            close(fd);
            snprintf(filename, sizeof(filename), filemask, ++log_counter);
            fd = open(filename, open_flags, open_mask);
            if(fd == -1) {
                die("open");
            }
        } else if(pfds[1].revents & POLLIN) {
            // We have a message to log!
            char buf[max_len];
            r = read(log_out, buf, max_len-1);
            if(r == -1) {
                die("read");
            }
            r = write(fd, buf, r);
            if(r == -1) {
                die("write");
            }
        }
    } while(true);

    return NULL;
}

Компилить через clang -O2 -Wall -Werror -lpthread logpipe.c -o logpipe.

Пишет в текущую директорию логи в файлы по маске «logfile_%u.log». При получении SIGUSR1 переключается на новый файл.

ТС, вот тебе готовый код. poll() на kqueue() можешь сам заменить по вкусу.

Исправление hateyoufeel, :

Локи однозначно проще чем эти нагромождения.

Да не, не проще.

Блин, ты меня заставил код написать. С локами получилось бы сложнее, на самом деле, потому что дедлок тут поймать будет весьма легко.

#define _GNU_SOURCE

#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/signalfd.h>
#include <unistd.h>
#include <pthread.h>
#include <stdbool.h>

#define UNUSED(x) do{(void)(x);}while(false)

// I don't want to care about message lengths today.
const size_t max_len = 256;

static void die(const char*);
static void logmsg(const char*);
static void* write_logs(void *);

static int log_in = -1,
           log_out = -1;
static sigset_t sigmask;

static void die(const char* fname)
{
    const char* err = strerror(errno);
    fprintf(stderr, "Call to %s failed: %s\n", fname, err);
    exit(EXIT_FAILURE);
}

static void logmsg(const char* msg)
{
    size_t msglen = strlen(msg);
    size_t sz = msglen < max_len ? msglen : max_len;
    write(log_in, msg, sz);
}

int main()
{
    int r;
    pthread_t writer_thread;
    int pipe_fds[2];

    r = pipe2(pipe_fds, O_DIRECT); // O_DIRECT is needed for packet mode and isn't strictly necessary here
    if(r == -1) {
        die("pipe");
    }
    log_in = pipe_fds[1];
    log_out = pipe_fds[0];

    // Set up sigmask
    sigemptyset(&sigmask);
    sigaddset(&sigmask, SIGUSR1);
    // Block SIGUSR1
    // It will be handled separately by signalfd()
    r = sigprocmask(SIG_BLOCK, &sigmask, NULL);
    if(r == -1) {
        die("sigprocmask");
    }

    r = pthread_create(&writer_thread, NULL, write_logs, NULL);
    if(r == -1) {
        die("pthread_create");
    }

    for(unsigned i = 0; ; i++) {
        char str[max_len];
        snprintf(str, max_len, "Message number %u\n", i);
        logmsg(str);
        usleep(1000000);
    }
}

static void* write_logs(void *arg)
{
    const char* filemask = "logfile_%d.log";
    char filename[256] = {};
    int fd = -1;
    int sigfd = -1;
    int log_counter = 0;
    struct pollfd pfds[2];

    UNUSED(arg);

    sigfd = signalfd(-1, &sigmask, 0);
    if (sigfd == -1) {
        die("signalfd");
    }
    snprintf(filename, sizeof(filename), filemask, log_counter);
    const int open_flags = O_WRONLY | O_TRUNC | O_CREAT;
    const int open_mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
    fd = open(filename, open_flags, open_mask);
    if(fd == -1) {
        die("open");
    }

    pfds[0].fd = sigfd;
    pfds[0].events = POLLIN;
    pfds[1].fd = log_out;
    pfds[1].events = POLLIN;

    do {
        int r = poll(pfds, 2, -1);
        switch(r) {
            case -1: die("poll");
                     break;
            case 0:  continue;
        }
        if(pfds[0].revents & POLLIN) {
            // We have a signal!
            struct signalfd_siginfo sig = {};
            r = read(sigfd, &sig, sizeof(sig));
            if(r == -1) {
                die("read");
            }
            // We only have one signal, so there's no need to check it.
            close(fd);
            snprintf(filename, sizeof(filename), filemask, ++log_counter);
            fd = open(filename, open_flags, open_mask);
            if(fd == -1) {
                die("open");
            }
        } else if(pfds[1].revents & POLLIN) {
            // We have a message to log!
            char buf[max_len];
            r = read(log_out, buf, max_len-1);
            if(r == -1) {
                die("read");
            }
            buf[max_len-1] = '\0';
            r = write(fd, buf, r);
            if(r == -1) {
                die("write");
            }
        }
    } while(true);

    return NULL;
}

Компилить через clang -O2 -Wall -Werror -lpthread logpipe.c -o logpipe.

Пишет в текущую директорию логи в файлы по маске «logfile_%u.log». При получении SIGUSR1 переключается на новый файл.

ТС, вот тебе готовый код. poll() на kqueue() можешь сам заменить по вкусу.

Исходная версия hateyoufeel, :

Локи однозначно проще чем эти нагромождения.

Да не, не проще.

Блин, ты меня заставил код написать. С локами получилось бы сложнее, на самом деле, потому что дедлок тут поймать будет весьма легко.

#define _GNU_SOURCE

#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/signalfd.h>
#include <unistd.h>
#include <pthread.h>
#include <stdbool.h>

#define UNUSED(x) do{(void)(x);}while(false)
#define LENGTH(x) (sizeof(x) / sizeof((x)[0]))

// I don't want to care about message lengths today.
const size_t max_len = 256;

static void die(const char*);
static void logmsg(const char*);
static void* write_logs(void *);

static int log_in = -1,
           log_out = -1;
static sigset_t sigmask;

static void die(const char* fname)
{
    const char* err = strerror(errno);
    fprintf(stderr, "Call to %s failed: %s\n", fname, err);
    exit(EXIT_FAILURE);
}

static void logmsg(const char* msg)
{
    size_t msglen = strlen(msg);
    size_t sz = msglen < max_len ? msglen : max_len;
    write(log_in, msg, sz);
}

int main()
{
    int r;
    pthread_t writer_thread;
    int pipe_fds[2];

    r = pipe2(pipe_fds, O_DIRECT); // O_DIRECT is needed for packet mode and isn't strictly necessary here
    if(r == -1) {
        die("pipe");
    }
    log_in = pipe_fds[1];
    log_out = pipe_fds[0];

    // Set up sigmask
    sigemptyset(&sigmask);
    sigaddset(&sigmask, SIGUSR1);
    // Block SIGUSR1
    // It will be handled separately by signalfd()
    r = sigprocmask(SIG_BLOCK, &sigmask, NULL);
    if(r == -1) {
        die("sigprocmask");
    }

    r = pthread_create(&writer_thread, NULL, write_logs, NULL);
    if(r == -1) {
        die("pthread_create");
    }

    for(unsigned i = 0; ; i++) {
        char str[max_len];
        snprintf(str, max_len, "Message number %u\n", i);
        logmsg(str);
        usleep(1000000);
    }
}

void* write_logs(void *arg)
{
    const char* filemask = "logfile_%d.log";
    char filename[256] = {};
    int fd = -1;
    int sigfd = -1;
    int log_counter = 0;
    struct pollfd pfds[2];

    UNUSED(arg);

    sigfd = signalfd(-1, &sigmask, 0);
    if (sigfd == -1) {
        die("signalfd");
    }
    snprintf(filename, sizeof(filename), filemask, log_counter);
    const int open_flags = O_WRONLY | O_TRUNC | O_CREAT;
    const int open_mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
    fd = open(filename, open_flags, open_mask);
    if(fd == -1) {
        die("open");
    }

    pfds[0].fd = sigfd;
    pfds[0].events = POLLIN;
    pfds[1].fd = log_out;
    pfds[1].events = POLLIN;

    do {
        int r = poll(pfds, 2, -1);
        switch(r) {
            case -1: die("poll");
                     break;
            case 0:  continue;
        }
        if(pfds[0].revents & POLLIN) {
            // We have a signal!
            struct signalfd_siginfo sig = {};
            r = read(sigfd, &sig, sizeof(sig));
            if(r == -1) {
                die("read");
            }
            // We only have one signal, so there's no need to check it.
            close(fd);
            snprintf(filename, sizeof(filename), filemask, ++log_counter);
            fd = open(filename, open_flags, open_mask);
            if(fd == -1) {
                die("open");
            }
        } else if(pfds[1].revents & POLLIN) {
            // We have a message to log!
            char buf[max_len];
            r = read(log_out, buf, max_len-1);
            if(r == -1) {
                die("read");
            }
            buf[max_len-1] = '\0';
            r = write(fd, buf, r);
            if(r == -1) {
                die("write");
            }
        }
    } while(true);

    return NULL;
}

Пишет в текущую директорию логи в файлы по маске «logfile_%u.log». При получении SIGUSR1 переключается на новый файл.

ТС, вот тебе готовый код. poll() на kqueue() можешь сам заменить по вкусу.