История изменений
Исправление 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() можешь сам заменить по вкусу.