From 5f2395357d3a2a0fbbe1d303fc44b687762db238 Mon Sep 17 00:00:00 2001 From: Yan Burman Date: Wed, 3 Jan 2018 11:10:13 +0200 Subject: [PATCH 01/22] Add server Signed-off-by: Yan Burman --- CMakeLists.txt | 2 +- server.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++ server.h | 8 ++++ 3 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 server.c create mode 100644 server.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0eec95a..41d260d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ set(CMAKE_CXX_FLAGS_RELEASE "${warning_flags} \ set(target forker) -add_executable(${target} forker.c) +add_executable(${target} forker.c server.c) target_link_libraries(${target} pthread diff --git a/server.c b/server.c new file mode 100644 index 0000000..8cd6b17 --- /dev/null +++ b/server.c @@ -0,0 +1,114 @@ +/* + ** server.c -- a stream socket server demo + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT "3490" // the port users will be connecting to + +#define BACKLOG 10 // how many pending connections queue will hold + +// get sockaddr, IPv4 or IPv6: +void *get_in_addr(struct sockaddr *sa) +{ + if (sa->sa_family == AF_INET) { + return &(((struct sockaddr_in*)sa)->sin_addr); + } + + return &(((struct sockaddr_in6*)sa)->sin6_addr); +} + +int run_server(void) +{ + int sockfd, new_fd; // listen on sock_fd, new connection on new_fd + struct addrinfo hints, *servinfo, *p; + struct sockaddr_storage their_addr; // connector's address information + socklen_t sin_size; + struct sigaction sa; + int yes = 1; + char s[INET6_ADDRSTRLEN]; + int rv; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; // use my IP + + if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); + return 1; + } + + // loop through all the results and bind to the first we can + for(p = servinfo; p != NULL; p = p->ai_next) { + if ((sockfd = socket(p->ai_family, p->ai_socktype, + p->ai_protocol)) == -1) { + perror("server: socket"); + continue; + } + + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, + sizeof(int)) == -1) { + perror("setsockopt reuse addr"); + exit(1); + } + + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &yes, + sizeof(int)) == -1) { + perror("setsockopt reuse port"); + exit(1); + } + + if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { + close(sockfd); + perror("server: bind"); + continue; + } + + break; + } + + freeaddrinfo(servinfo); // all done with this structure + + if (p == NULL) { + fprintf(stderr, "server: failed to bind\n"); + exit(1); + } + + if (listen(sockfd, BACKLOG) == -1) { + perror("listen"); + exit(1); + } + + printf("server: waiting for connections...\n"); + + while(1) { // main accept() loop + sin_size = sizeof their_addr; + new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size); + if (new_fd == -1) { + perror("accept"); + continue; + } + + inet_ntop(their_addr.ss_family, + get_in_addr((struct sockaddr *)&their_addr), + s, sizeof s); + printf("server: got connection from %s\n", s); + + if (send(new_fd, "Hello, world!", 13, 0) == -1) + perror("send"); + close(new_fd); + } + + return 0; +} diff --git a/server.h b/server.h new file mode 100644 index 0000000..63dc95d --- /dev/null +++ b/server.h @@ -0,0 +1,8 @@ +/* + ** server.c -- a stream socket server demo + */ + +#pragma once + +int run_server(void); + From a71b0fa81e75933144234dbb56b48dfddc741bd4 Mon Sep 17 00:00:00 2001 From: Yan Burman Date: Wed, 3 Jan 2018 11:15:42 +0200 Subject: [PATCH 02/22] Add server to forker Signed-off-by: Yan Burman --- forker.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/forker.c b/forker.c index 741f7bb..b42b1fc 100644 --- a/forker.c +++ b/forker.c @@ -7,6 +7,7 @@ #include #include #include +#include "server.h" #define handle_error(msg) \ do { \ @@ -76,7 +77,7 @@ static void do_forks(int num, int sfd) children[find_empty_child_idx()] = pid; ++n_children; } else { - run_epoll(sfd, 0); + run_server(); } } } From bf5611032f51fd62f64ee0ef75bb215379d1af9f Mon Sep 17 00:00:00 2001 From: Yan Burman Date: Wed, 3 Jan 2018 11:58:11 +0200 Subject: [PATCH 03/22] WIP Signed-off-by: Yan Burman --- CMakeLists.txt | 4 +++- forker.c | 3 +++ mmaper.c | 40 ++++++++++++++++++++++++++++++++++++++++ mmaper.h | 3 +++ server.c | 4 ++-- 5 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 mmaper.c create mode 100644 mmaper.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 41d260d..99e77f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,9 @@ set(CMAKE_CXX_FLAGS_RELEASE "${warning_flags} \ set(target forker) -add_executable(${target} forker.c server.c) +add_executable(${target} forker.c server.c mmaper.c) + +add_executable(client client.c) target_link_libraries(${target} pthread diff --git a/forker.c b/forker.c index b42b1fc..b56a5e9 100644 --- a/forker.c +++ b/forker.c @@ -7,7 +7,9 @@ #include #include #include + #include "server.h" +#include "mmaper.h" #define handle_error(msg) \ do { \ @@ -77,6 +79,7 @@ static void do_forks(int num, int sfd) children[find_empty_child_idx()] = pid; ++n_children; } else { + map_memory(); run_server(); } } diff --git a/mmaper.c b/mmaper.c new file mode 100644 index 0000000..27127e5 --- /dev/null +++ b/mmaper.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include +#include + +static void * mmap_addr; + +#define handle_error(msg) \ + do { \ + perror(msg); \ + exit(EXIT_FAILURE); \ + } while (0) + +#define FILESZ (30L * 1024L * 1024L * 1024L) + +int map_memory(void) +{ + static char template[] = "/tmp/myfileXXXXXX"; + int res; + int fd = mkstemp(template); + if (fd < 0) + handle_error("mkstemp"); + +#if 0 + res = posix_fallocate(fd, 0, FILESZ); + if (res) + handle_error("posix_fallocate"); +#endif + + mmap_addr = mmap(NULL, FILESZ, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mmap_addr == MAP_FAILED) + handle_error("mmap"); + + close(fd); + + return 0; +} + diff --git a/mmaper.h b/mmaper.h new file mode 100644 index 0000000..ae59948 --- /dev/null +++ b/mmaper.h @@ -0,0 +1,3 @@ +#pragma once + +int map_memory(void); diff --git a/server.c b/server.c index 8cd6b17..81ed309 100644 --- a/server.c +++ b/server.c @@ -90,7 +90,7 @@ int run_server(void) exit(1); } - printf("server: waiting for connections...\n"); + printf("server: waiting for connections... (pid: %u)\n", getpid()); while(1) { // main accept() loop sin_size = sizeof their_addr; @@ -103,7 +103,7 @@ int run_server(void) inet_ntop(their_addr.ss_family, get_in_addr((struct sockaddr *)&their_addr), s, sizeof s); - printf("server: got connection from %s\n", s); + printf("server: got connection from %s (pid: %u)\n", s, getpid()); if (send(new_fd, "Hello, world!", 13, 0) == -1) perror("send"); From 4c8ea18bd1d585b863528dc0b252c7893dadba8a Mon Sep 17 00:00:00 2001 From: Yan Burman Date: Wed, 3 Jan 2018 12:04:45 +0200 Subject: [PATCH 04/22] Add client Signed-off-by: Yan Burman --- client.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 client.c diff --git a/client.c b/client.c new file mode 100644 index 0000000..34094e0 --- /dev/null +++ b/client.c @@ -0,0 +1,94 @@ +/* +** client.c -- a stream socket client demo +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define PORT "3490" // the port client will be connecting to + +#define MAXDATASIZE 100 // max number of bytes we can get at once + +// get sockaddr, IPv4 or IPv6: +void *get_in_addr(struct sockaddr *sa) +{ + if (sa->sa_family == AF_INET) { + return &(((struct sockaddr_in*)sa)->sin_addr); + } + + return &(((struct sockaddr_in6*)sa)->sin6_addr); +} + +int main(int argc, char *argv[]) +{ + int sockfd, numbytes; + char buf[MAXDATASIZE]; + struct addrinfo hints, *servinfo, *p; + int rv; + char s[INET6_ADDRSTRLEN]; + + if (argc != 2) { + fprintf(stderr,"usage: client hostname\n"); + exit(1); + } + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + if ((rv = getaddrinfo(argv[1], PORT, &hints, &servinfo)) != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); + return 1; + } + + // loop through all the results and connect to the first we can + for(p = servinfo; p != NULL; p = p->ai_next) { + if ((sockfd = socket(p->ai_family, p->ai_socktype, + p->ai_protocol)) == -1) { + perror("client: socket"); + continue; + } + + if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) { + perror("client: connect"); + close(sockfd); + continue; + } + + break; + } + + if (p == NULL) { + fprintf(stderr, "client: failed to connect\n"); + return 2; + } + + inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), + s, sizeof s); + printf("client: connecting to %s\n", s); + + freeaddrinfo(servinfo); // all done with this structure + + if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) { + perror("recv"); + exit(1); + } + + buf[numbytes] = '\0'; + + printf("client: received '%s'\n",buf); + + close(sockfd); + + return 0; +} + From 23fb97f395d6cc9d908d11276cfccd1f3d482cf9 Mon Sep 17 00:00:00 2001 From: Yan Burman Date: Wed, 3 Jan 2018 12:12:08 +0200 Subject: [PATCH 05/22] Fix file size Signed-off-by: Yan Burman --- mmaper.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mmaper.c b/mmaper.c index 27127e5..753fb4f 100644 --- a/mmaper.c +++ b/mmaper.c @@ -23,6 +23,10 @@ int map_memory(void) if (fd < 0) handle_error("mkstemp"); + res = ftruncate(fd, FILESZ); + if (res) + handle_error("ftruncate"); + #if 0 res = posix_fallocate(fd, 0, FILESZ); if (res) From 6ef80e95f15dd2727f6815c07b705102e3207194 Mon Sep 17 00:00:00 2001 From: Yan Burman Date: Wed, 3 Jan 2018 12:21:11 +0200 Subject: [PATCH 06/22] Add corefilter Signed-off-by: Yan Burman --- mmaper.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/mmaper.c b/mmaper.c index 753fb4f..517bb03 100644 --- a/mmaper.c +++ b/mmaper.c @@ -15,10 +15,29 @@ static void * mmap_addr; #define FILESZ (30L * 1024L * 1024L * 1024L) +#define CORE_FILTER "0x3f" + +int allow_mmap_in_core() +{ + int fd = open("/proc/self/coredump_filter", O_WRONLY); + if (fd < 0) + handle_error("open"); + + ssize_t written = write(fd, CORE_FILTER, sizeof(CORE_FILTER); + if (written != sizeof(CORE_FILTER)) + handle_error("write"); + + close(fd); + return 0; +} + int map_memory(void) { static char template[] = "/tmp/myfileXXXXXX"; int res; + + allow_mmap_in_core(); + int fd = mkstemp(template); if (fd < 0) handle_error("mkstemp"); From 3ef00485dbd819394456c6bdcb7906ee68bafc8a Mon Sep 17 00:00:00 2001 From: Yan Date: Wed, 3 Jan 2018 12:47:16 +0200 Subject: [PATCH 07/22] Add timeing info Signed-off-by: Yan --- forker.c | 6 +++++- mmaper.c | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/forker.c b/forker.c index b56a5e9..7a36808 100644 --- a/forker.c +++ b/forker.c @@ -10,6 +10,7 @@ #include "server.h" #include "mmaper.h" +#include #define handle_error(msg) \ do { \ @@ -146,7 +147,10 @@ void run_epoll(int sfd, int parent) exit(EXIT_SUCCESS); } } else if (fdsi.ssi_signo == SIGCHLD) { - fprintf(stderr, "%d: Got SIGCHLD from %d\n", getpid(), fdsi.ssi_pid); + time_t t = time(NULL); + struct tm *tm = localtime(&t); + + fprintf(stderr, "%d: Got SIGCHLD from %d (%s)\n", getpid(), fdsi.ssi_pid, asctime(tm)); do { pid = waitpid(-1, &status, WNOHANG); if (pid > 0) { diff --git a/mmaper.c b/mmaper.c index 517bb03..6eb4b6b 100644 --- a/mmaper.c +++ b/mmaper.c @@ -23,7 +23,7 @@ int allow_mmap_in_core() if (fd < 0) handle_error("open"); - ssize_t written = write(fd, CORE_FILTER, sizeof(CORE_FILTER); + ssize_t written = write(fd, CORE_FILTER, sizeof(CORE_FILTER)); if (written != sizeof(CORE_FILTER)) handle_error("write"); From 48441c23e7b5b3f05eabe22dbdbecbe366907dae Mon Sep 17 00:00:00 2001 From: Yan Date: Wed, 3 Jan 2018 13:49:27 +0200 Subject: [PATCH 08/22] Add preparations for epoll server Signed-off-by: Yan --- forker.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- mmaper.c | 3 ++- server.c | 2 +- server.h | 2 +- 4 files changed, 76 insertions(+), 4 deletions(-) diff --git a/forker.c b/forker.c index 7a36808..c7f272e 100644 --- a/forker.c +++ b/forker.c @@ -81,7 +81,7 @@ static void do_forks(int num, int sfd) ++n_children; } else { map_memory(); - run_server(); + run_server(sfd); } } } @@ -98,6 +98,77 @@ static void notify_children(int sig) } } +static void signalfd_epoll_child(int fd) +{ + struct signalfd_siginfo fdsi; + ssize_t sz; + pid_t pid; + int status; + + sz = read(fd, &fdsi, sizeof(struct signalfd_siginfo)); + if (sz != sizeof(struct signalfd_siginfo)) + handle_error("read"); + + if (fdsi.ssi_signo == SIGINT) { + fprintf(stderr, "%d: Got SIGINT from %d\n", getpid(), fdsi.ssi_pid); + } else if (fdsi.ssi_signo == SIGQUIT) { + fprintf(stderr, "%d: Got SIGQUIT from %d\n", getpid(), fdsi.ssi_pid); + exit(EXIT_SUCCESS); + } else if (fdsi.ssi_signo == SIGTERM) { + fprintf(stderr, "%d: Got SIGTERM from %d\n", getpid(), fdsi.ssi_pid); + exit(EXIT_SUCCESS); + } else { + fprintf(stderr, "%d: Read unexpected signal from %d\n", getpid(), fdsi.ssi_pid); + } +} + +static void signalfd_epoll_parent(int fd) +{ + struct signalfd_siginfo fdsi; + ssize_t sz; + pid_t pid; + int status; + + sz = read(fd, &fdsi, sizeof(struct signalfd_siginfo)); + if (sz != sizeof(struct signalfd_siginfo)) + handle_error("read"); + + if (fdsi.ssi_signo == SIGINT) { + fprintf(stderr, "%d: Got SIGINT from %d\n", getpid(), fdsi.ssi_pid); + } else if (fdsi.ssi_signo == SIGQUIT) { + fprintf(stderr, "%d: Got SIGQUIT from %d\n", getpid(), fdsi.ssi_pid); + exiting = 1; + notify_children(SIGQUIT); + } else if (fdsi.ssi_signo == SIGTERM) { + fprintf(stderr, "%d: Got SIGTERM from %d\n", getpid(), fdsi.ssi_pid); + exiting = 1; + notify_children(SIGTERM); + } else if (fdsi.ssi_signo == SIGCHLD) { + time_t t = time(NULL); + struct tm *tm = localtime(&t); + + fprintf(stderr, "%d: Got SIGCHLD from %d (%s)\n", getpid(), fdsi.ssi_pid, asctime(tm)); + do { + pid = waitpid(-1, &status, WNOHANG); + if (pid > 0) { + fprintf(stderr, "%d: Process %d exited\n", getpid(), pid); + clear_child(pid); + + if (!exiting) { + do_forks(1, fd); + } else { + if (n_children == 0) { + fprintf(stderr, "%d: All children exited\n", getpid()); + exit(EXIT_SUCCESS); + } + } + } + } while (pid > 0); + } else { + fprintf(stderr, "%d: Read unexpected signal from %d\n", getpid(), fdsi.ssi_pid); + } +} + void run_epoll(int sfd, int parent) { struct epoll_event ev, events[MAX_EVENTS]; diff --git a/mmaper.c b/mmaper.c index 6eb4b6b..f2b6cc1 100644 --- a/mmaper.c +++ b/mmaper.c @@ -13,7 +13,8 @@ static void * mmap_addr; exit(EXIT_FAILURE); \ } while (0) -#define FILESZ (30L * 1024L * 1024L * 1024L) +//#define FILESZ (30L * 1024L * 1024L * 1024L) +#define FILESZ (30L * 1024L) #define CORE_FILTER "0x3f" diff --git a/server.c b/server.c index 81ed309..5c70b03 100644 --- a/server.c +++ b/server.c @@ -28,7 +28,7 @@ void *get_in_addr(struct sockaddr *sa) return &(((struct sockaddr_in6*)sa)->sin6_addr); } -int run_server(void) +int run_server(int sfd) { int sockfd, new_fd; // listen on sock_fd, new connection on new_fd struct addrinfo hints, *servinfo, *p; diff --git a/server.h b/server.h index 63dc95d..9dd1ae9 100644 --- a/server.h +++ b/server.h @@ -4,5 +4,5 @@ #pragma once -int run_server(void); +int run_server(int sfd); From 0e812b08de49c98e9519ef0e7297aef8870d96a8 Mon Sep 17 00:00:00 2001 From: Yan Date: Wed, 3 Jan 2018 13:53:22 +0200 Subject: [PATCH 09/22] Make forker C++ Signed-off-by: Yan --- CMakeLists.txt | 2 +- forker.c => forker.cc | 5 +---- mmaper.h | 2 +- server.h | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) rename forker.c => forker.cc (98%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 99e77f3..c6278ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ set(CMAKE_CXX_FLAGS_RELEASE "${warning_flags} \ set(target forker) -add_executable(${target} forker.c server.c mmaper.c) +add_executable(${target} forker.cc server.c mmaper.c) add_executable(client client.c) diff --git a/forker.c b/forker.cc similarity index 98% rename from forker.c rename to forker.cc index c7f272e..1e5d6fa 100644 --- a/forker.c +++ b/forker.cc @@ -102,8 +102,6 @@ static void signalfd_epoll_child(int fd) { struct signalfd_siginfo fdsi; ssize_t sz; - pid_t pid; - int status; sz = read(fd, &fdsi, sizeof(struct signalfd_siginfo)); if (sz != sizeof(struct signalfd_siginfo)) @@ -248,8 +246,7 @@ void run_epoll(int sfd, int parent) int main(int argc, char *argv[]) { sigset_t mask; - int sfd, epollfd; - struct epoll_event ev; + int sfd; sigemptyset(&mask); sigaddset(&mask, SIGINT); diff --git a/mmaper.h b/mmaper.h index ae59948..79bd370 100644 --- a/mmaper.h +++ b/mmaper.h @@ -1,3 +1,3 @@ #pragma once -int map_memory(void); +extern "C" int map_memory(void); diff --git a/server.h b/server.h index 9dd1ae9..cf2802a 100644 --- a/server.h +++ b/server.h @@ -4,5 +4,5 @@ #pragma once -int run_server(int sfd); +extern "C" int run_server(int sfd); From 9db0cbcb6fcaa0d6045dfec7ced104a0aaaf4d47 Mon Sep 17 00:00:00 2001 From: Yan Date: Wed, 3 Jan 2018 14:36:07 +0200 Subject: [PATCH 10/22] Move epoll to handlers Signed-off-by: Yan --- CMakeLists.txt | 2 +- ChildSignalHandler.cc | 36 +++++++ ChildSignalHandler.hh | 14 +++ Handler.hh | 15 +++ Parent.cc | 90 +++++++++++++++++ Parent.hh | 33 +++++++ ParentSignalHandler.cc | 63 ++++++++++++ ParentSignalHandler.hh | 18 ++++ forker.cc | 219 ++++------------------------------------- 9 files changed, 288 insertions(+), 202 deletions(-) create mode 100644 ChildSignalHandler.cc create mode 100644 ChildSignalHandler.hh create mode 100644 Handler.hh create mode 100644 Parent.cc create mode 100644 Parent.hh create mode 100644 ParentSignalHandler.cc create mode 100644 ParentSignalHandler.hh diff --git a/CMakeLists.txt b/CMakeLists.txt index c6278ba..e9c85e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ set(CMAKE_CXX_FLAGS_RELEASE "${warning_flags} \ set(target forker) -add_executable(${target} forker.cc server.c mmaper.c) +add_executable(${target} forker.cc server.c mmaper.c ChildSignalHandler.cc ParentSignalHandler.cc Parent.cc) add_executable(client client.c) diff --git a/ChildSignalHandler.cc b/ChildSignalHandler.cc new file mode 100644 index 0000000..a07a17e --- /dev/null +++ b/ChildSignalHandler.cc @@ -0,0 +1,36 @@ +#include "ChildSignalHandler.hh" +#include +#include +#include +#include +#include +#include + +#define handle_error(msg) \ + do { \ + perror(msg); \ + exit(EXIT_FAILURE); \ + } while (0) + +void ChildSignalHandler::handle() +{ + struct signalfd_siginfo fdsi; + ssize_t sz; + + sz = read(fd, &fdsi, sizeof(struct signalfd_siginfo)); + if (sz != sizeof(struct signalfd_siginfo)) + handle_error("read"); + + if (fdsi.ssi_signo == SIGINT) { + fprintf(stderr, "%d: Got SIGINT from %d\n", getpid(), fdsi.ssi_pid); + } else if (fdsi.ssi_signo == SIGQUIT) { + fprintf(stderr, "%d: Got SIGQUIT from %d\n", getpid(), fdsi.ssi_pid); + exit(EXIT_SUCCESS); + } else if (fdsi.ssi_signo == SIGTERM) { + fprintf(stderr, "%d: Got SIGTERM from %d\n", getpid(), fdsi.ssi_pid); + exit(EXIT_SUCCESS); + } else { + fprintf(stderr, "%d: Read unexpected signal from %d\n", getpid(), fdsi.ssi_pid); + } +} + diff --git a/ChildSignalHandler.hh b/ChildSignalHandler.hh new file mode 100644 index 0000000..cd5e964 --- /dev/null +++ b/ChildSignalHandler.hh @@ -0,0 +1,14 @@ +#pragma once + +#include "Handler.hh" + +class ChildSignalHandler: public Handler +{ +public: + ChildSignalHandler(int fd) + : Handler(fd) + {} + + virtual void handle(); +}; + diff --git a/Handler.hh b/Handler.hh new file mode 100644 index 0000000..8988996 --- /dev/null +++ b/Handler.hh @@ -0,0 +1,15 @@ +#pragma once + +class Handler +{ +public: + Handler(int fd) + : fd(fd) + {} + + virtual void handle() = 0; + +protected: + int fd; +}; + diff --git a/Parent.cc b/Parent.cc new file mode 100644 index 0000000..306efb5 --- /dev/null +++ b/Parent.cc @@ -0,0 +1,90 @@ +#include "Parent.hh" +#include +#include +#include +#include +#include +#include +#include "server.h" +#include "mmaper.h" + +#define handle_error(msg) \ + do { \ + perror(msg); \ + exit(EXIT_FAILURE); \ + } while (0) + +int Parent::get_child_idx(pid_t pid) +{ + int res = -1; + + for (int i = 0; i < MAX_CHILDREN; ++i) { + if (children[i] == pid) { + res = i; + break; + } + } + + assert(res != -1); + + return res; +} + +int Parent::find_empty_child_idx(void) +{ + int res = -1; + + for (int i = 0; i < MAX_CHILDREN; ++i) { + if (children[i] == 0) { + res = i; + break; + } + } + + assert(res != -1); + + return res; +} + +void Parent::clear_child(pid_t pid) +{ + children[get_child_idx(pid)] = 0; + --n_children; +} + +void Parent::notify_children(int sig) +{ + for (int i = 0; i < MAX_CHILDREN; ++i) { + if (children[i] != 0) { + fprintf(stderr, "%d: Sending signal to %d\n", getpid(), children[i]); + kill(children[i], sig); + } + } +} + +void Parent::add_new_child(pid_t pid) +{ + children[find_empty_child_idx()] = pid; + ++n_children; +} + +void Parent::do_forks(int num) +{ + pid_t pid; + int i; + + for (i = 0; i < num; ++i) { + pid = fork(); + if (pid == -1) + handle_error("fork"); + + if (pid) { + fprintf(stderr, "Forked %d\n", pid); + add_new_child(pid); + } else { + map_memory(); + run_server(sfd); + } + } +} + diff --git a/Parent.hh b/Parent.hh new file mode 100644 index 0000000..93be8ce --- /dev/null +++ b/Parent.hh @@ -0,0 +1,33 @@ +#pragma once +#include +#include + +#define MAX_CHILDREN 10 + +class Parent +{ + friend class ParentSignalHandler; +public: + Parent() + : exiting(0), n_children(0), sfd(-1) + { + memset(children, 0, sizeof(children)); + } + + void set_sfd(int sfd) + { this->sfd = sfd; } + + void notify_children(int sig); + int get_child_idx(pid_t pid); + int find_empty_child_idx(void); + void clear_child(pid_t pid); + void add_new_child(pid_t pid); + void do_forks(int num); + +protected: + int exiting; + + pid_t children[MAX_CHILDREN]; + int n_children; + int sfd; +}; diff --git a/ParentSignalHandler.cc b/ParentSignalHandler.cc new file mode 100644 index 0000000..28c66ce --- /dev/null +++ b/ParentSignalHandler.cc @@ -0,0 +1,63 @@ +#include "ParentSignalHandler.hh" +#include +#include +#include +#include +#include +#include +#include +#include + +#define handle_error(msg) \ + do { \ + perror(msg); \ + exit(EXIT_FAILURE); \ + } while (0) + +void ParentSignalHandler::handle() +{ + struct signalfd_siginfo fdsi; + ssize_t sz; + pid_t pid; + int status; + + sz = read(fd, &fdsi, sizeof(struct signalfd_siginfo)); + if (sz != sizeof(struct signalfd_siginfo)) + handle_error("read"); + + if (fdsi.ssi_signo == SIGINT) { + fprintf(stderr, "%d: Got SIGINT from %d\n", getpid(), fdsi.ssi_pid); + } else if (fdsi.ssi_signo == SIGQUIT) { + fprintf(stderr, "%d: Got SIGQUIT from %d\n", getpid(), fdsi.ssi_pid); + parent->exiting = 1; + parent->notify_children(SIGQUIT); + } else if (fdsi.ssi_signo == SIGTERM) { + fprintf(stderr, "%d: Got SIGTERM from %d\n", getpid(), fdsi.ssi_pid); + parent->exiting = 1; + parent->notify_children(SIGTERM); + } else if (fdsi.ssi_signo == SIGCHLD) { + time_t t = time(NULL); + struct tm *tm = localtime(&t); + + fprintf(stderr, "%d: Got SIGCHLD from %d (%s)\n", getpid(), fdsi.ssi_pid, asctime(tm)); + do { + pid = waitpid(-1, &status, WNOHANG); + if (pid > 0) { + fprintf(stderr, "%d: Process %d exited\n", getpid(), pid); + parent->clear_child(pid); + + if (!parent->exiting) { + parent->do_forks(1); + } else { + if (parent->n_children == 0) { + fprintf(stderr, "%d: All children exited\n", getpid()); + exit(EXIT_SUCCESS); + } + } + } + } while (pid > 0); + } else { + fprintf(stderr, "%d: Read unexpected signal from %d\n", getpid(), fdsi.ssi_pid); + } +} + diff --git a/ParentSignalHandler.hh b/ParentSignalHandler.hh new file mode 100644 index 0000000..c69b571 --- /dev/null +++ b/ParentSignalHandler.hh @@ -0,0 +1,18 @@ +#pragma once + +#include "Handler.hh" +#include "Parent.hh" + +class ParentSignalHandler: public Handler +{ +public: + ParentSignalHandler(int fd, Parent* parent) + : Handler(fd), parent(parent) + {} + + virtual void handle(); + +protected: + Parent* parent; +}; + diff --git a/forker.cc b/forker.cc index 1e5d6fa..6fa2d8c 100644 --- a/forker.cc +++ b/forker.cc @@ -8,9 +8,10 @@ #include #include -#include "server.h" -#include "mmaper.h" -#include +#include "Parent.hh" +#include "Handler.hh" +#include "ParentSignalHandler.hh" +#include "ChildSignalHandler.hh" #define handle_error(msg) \ do { \ @@ -18,162 +19,16 @@ exit(EXIT_FAILURE); \ } while (0) -#define MAX_CHILDREN 10 - -static pid_t children[MAX_CHILDREN]; -static int n_children; - -static int get_child_idx(pid_t pid) -{ - int res = -1; - - for (int i = 0; i < MAX_CHILDREN; ++i) { - if (children[i] == pid) { - res = i; - break; - } - } - - assert(res != -1); - - return res; -} - -static int find_empty_child_idx(void) -{ - int res = -1; - - for (int i = 0; i < MAX_CHILDREN; ++i) { - if (children[i] == 0) { - res = i; - break; - } - } - - assert(res != -1); - - return res; -} - -static void clear_child(pid_t pid) -{ - children[get_child_idx(pid)] = 0; - --n_children; -} - #define MAX_EVENTS MAX_CHILDREN -void run_epoll(int sfd, int parent); - -static void do_forks(int num, int sfd) -{ - pid_t pid; - int i; - - for (i = 0; i < num; ++i) { - pid = fork(); - if (pid == -1) - handle_error("fork"); - - if (pid) { - fprintf(stderr, "Forked %d\n", pid); - children[find_empty_child_idx()] = pid; - ++n_children; - } else { - map_memory(); - run_server(sfd); - } - } -} - -static int exiting; - -static void notify_children(int sig) -{ - for (int i = 0; i < MAX_CHILDREN; ++i) { - if (children[i] != 0) { - fprintf(stderr, "%d: Sending signal to %d\n", getpid(), children[i]); - kill(children[i], sig); - } - } -} - -static void signalfd_epoll_child(int fd) -{ - struct signalfd_siginfo fdsi; - ssize_t sz; - - sz = read(fd, &fdsi, sizeof(struct signalfd_siginfo)); - if (sz != sizeof(struct signalfd_siginfo)) - handle_error("read"); - - if (fdsi.ssi_signo == SIGINT) { - fprintf(stderr, "%d: Got SIGINT from %d\n", getpid(), fdsi.ssi_pid); - } else if (fdsi.ssi_signo == SIGQUIT) { - fprintf(stderr, "%d: Got SIGQUIT from %d\n", getpid(), fdsi.ssi_pid); - exit(EXIT_SUCCESS); - } else if (fdsi.ssi_signo == SIGTERM) { - fprintf(stderr, "%d: Got SIGTERM from %d\n", getpid(), fdsi.ssi_pid); - exit(EXIT_SUCCESS); - } else { - fprintf(stderr, "%d: Read unexpected signal from %d\n", getpid(), fdsi.ssi_pid); - } -} - -static void signalfd_epoll_parent(int fd) -{ - struct signalfd_siginfo fdsi; - ssize_t sz; - pid_t pid; - int status; - - sz = read(fd, &fdsi, sizeof(struct signalfd_siginfo)); - if (sz != sizeof(struct signalfd_siginfo)) - handle_error("read"); +void run_epoll(int sfd, int is_parent); - if (fdsi.ssi_signo == SIGINT) { - fprintf(stderr, "%d: Got SIGINT from %d\n", getpid(), fdsi.ssi_pid); - } else if (fdsi.ssi_signo == SIGQUIT) { - fprintf(stderr, "%d: Got SIGQUIT from %d\n", getpid(), fdsi.ssi_pid); - exiting = 1; - notify_children(SIGQUIT); - } else if (fdsi.ssi_signo == SIGTERM) { - fprintf(stderr, "%d: Got SIGTERM from %d\n", getpid(), fdsi.ssi_pid); - exiting = 1; - notify_children(SIGTERM); - } else if (fdsi.ssi_signo == SIGCHLD) { - time_t t = time(NULL); - struct tm *tm = localtime(&t); +static Parent parent; - fprintf(stderr, "%d: Got SIGCHLD from %d (%s)\n", getpid(), fdsi.ssi_pid, asctime(tm)); - do { - pid = waitpid(-1, &status, WNOHANG); - if (pid > 0) { - fprintf(stderr, "%d: Process %d exited\n", getpid(), pid); - clear_child(pid); - - if (!exiting) { - do_forks(1, fd); - } else { - if (n_children == 0) { - fprintf(stderr, "%d: All children exited\n", getpid()); - exit(EXIT_SUCCESS); - } - } - } - } while (pid > 0); - } else { - fprintf(stderr, "%d: Read unexpected signal from %d\n", getpid(), fdsi.ssi_pid); - } -} - -void run_epoll(int sfd, int parent) +void run_epoll(int sfd, int is_parent) { struct epoll_event ev, events[MAX_EVENTS]; - int nfds, n, status; - pid_t pid; - struct signalfd_siginfo fdsi; - ssize_t sz; + int nfds, n; int epollfd = epoll_create1(EPOLL_CLOEXEC); if (epollfd == -1) { @@ -181,7 +36,11 @@ void run_epoll(int sfd, int parent) } ev.events = EPOLLIN; - ev.data.fd = sfd; + if (is_parent) + ev.data.ptr = new ParentSignalHandler(sfd, &parent); + else + ev.data.ptr = new ChildSignalHandler(sfd); + if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sfd, &ev) == -1) { handle_error("epoll_ctl: signalfd"); } @@ -193,52 +52,8 @@ void run_epoll(int sfd, int parent) } for (n = 0; n < nfds; ++n) { - sz = read(events[n].data.fd, &fdsi, sizeof(struct signalfd_siginfo)); - if (sz != sizeof(struct signalfd_siginfo)) - handle_error("read"); - - if (fdsi.ssi_signo == SIGINT) { - fprintf(stderr, "%d: Got SIGINT from %d\n", getpid(), fdsi.ssi_pid); - } else if (fdsi.ssi_signo == SIGQUIT) { - fprintf(stderr, "%d: Got SIGQUIT from %d\n", getpid(), fdsi.ssi_pid); - if (parent) { - exiting = 1; - notify_children(SIGQUIT); - } else { - exit(EXIT_SUCCESS); - } - } else if (fdsi.ssi_signo == SIGTERM) { - fprintf(stderr, "%d: Got SIGTERM from %d\n", getpid(), fdsi.ssi_pid); - if (parent) { - exiting = 1; - notify_children(SIGTERM); - } else { - exit(EXIT_SUCCESS); - } - } else if (fdsi.ssi_signo == SIGCHLD) { - time_t t = time(NULL); - struct tm *tm = localtime(&t); - - fprintf(stderr, "%d: Got SIGCHLD from %d (%s)\n", getpid(), fdsi.ssi_pid, asctime(tm)); - do { - pid = waitpid(-1, &status, WNOHANG); - if (pid > 0) { - fprintf(stderr, "%d: Process %d exited\n", getpid(), pid); - clear_child(pid); - - if (!exiting) { - do_forks(1, sfd); - } else { - if (n_children == 0) { - fprintf(stderr, "%d: All children exited\n", getpid()); - exit(EXIT_SUCCESS); - } - } - } - } while (pid > 0); - } else { - fprintf(stderr, "%d: Read unexpected signal from %d\n", getpid(), fdsi.ssi_pid); - } + Handler *handler = (Handler*)ev.data.ptr; + handler->handle(); } } } @@ -264,8 +79,10 @@ int main(int argc, char *argv[]) if (sfd == -1) handle_error("signalfd"); + parent.set_sfd(sfd); + // forking after epoll created leades to world of pain - do_forks(MAX_CHILDREN, sfd); + parent.do_forks(MAX_CHILDREN); run_epoll(sfd, 1); From be9434e474c460cf18c229d2e1cf1a919f5d7f92 Mon Sep 17 00:00:00 2001 From: Yan Date: Wed, 3 Jan 2018 14:39:47 +0200 Subject: [PATCH 11/22] Save epollfd in parent Signed-off-by: Yan --- Parent.hh | 6 +++++- forker.cc | 6 ++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Parent.hh b/Parent.hh index 93be8ce..2ba2ef8 100644 --- a/Parent.hh +++ b/Parent.hh @@ -9,7 +9,7 @@ class Parent friend class ParentSignalHandler; public: Parent() - : exiting(0), n_children(0), sfd(-1) + : exiting(0), n_children(0), sfd(-1), epollfd(-1) { memset(children, 0, sizeof(children)); } @@ -17,6 +17,9 @@ public: void set_sfd(int sfd) { this->sfd = sfd; } + void set_epoll_fd(int fd) + { epoll_fd = fd; } + void notify_children(int sig); int get_child_idx(pid_t pid); int find_empty_child_idx(void); @@ -30,4 +33,5 @@ protected: pid_t children[MAX_CHILDREN]; int n_children; int sfd; + int epoll_fd; }; diff --git a/forker.cc b/forker.cc index 6fa2d8c..4023bba 100644 --- a/forker.cc +++ b/forker.cc @@ -36,10 +36,12 @@ void run_epoll(int sfd, int is_parent) } ev.events = EPOLLIN; - if (is_parent) + if (is_parent) { ev.data.ptr = new ParentSignalHandler(sfd, &parent); - else + parent.set_epoll_fd(epollfd); + } else { ev.data.ptr = new ChildSignalHandler(sfd); + } if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sfd, &ev) == -1) { handle_error("epoll_ctl: signalfd"); From e1858229a18f16ede3d79b7a847c409067a95991 Mon Sep 17 00:00:00 2001 From: Yan Date: Wed, 3 Jan 2018 14:40:30 +0200 Subject: [PATCH 12/22] Update gitignore Signed-off-by: Yan --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b7d6c6e..740a001 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ cmake_install.cmake # binaries forker +client # diff *.orig From 77c4ac61d056241cbbfcec18432b1b45587ac92d Mon Sep 17 00:00:00 2001 From: Yan Date: Wed, 3 Jan 2018 15:22:29 +0200 Subject: [PATCH 13/22] Add inotify handler Signed-off-by: Yan --- CMakeLists.txt | 2 +- ChildSignalHandler.cc | 9 ++------- Parent.cc | 7 +------ Parent.hh | 2 +- ParentSignalHandler.cc | 9 ++------- forker.cc | 23 ++++++++++++++++------- mmaper.c | 7 +------ 7 files changed, 24 insertions(+), 35 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e9c85e3..5f751b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ set(CMAKE_CXX_FLAGS_RELEASE "${warning_flags} \ set(target forker) -add_executable(${target} forker.cc server.c mmaper.c ChildSignalHandler.cc ParentSignalHandler.cc Parent.cc) +add_executable(${target} forker.cc server.c mmaper.c ChildSignalHandler.cc ParentSignalHandler.cc Parent.cc InotifyHandler.cc) add_executable(client client.c) diff --git a/ChildSignalHandler.cc b/ChildSignalHandler.cc index a07a17e..ccddeea 100644 --- a/ChildSignalHandler.cc +++ b/ChildSignalHandler.cc @@ -5,12 +5,7 @@ #include #include #include - -#define handle_error(msg) \ - do { \ - perror(msg); \ - exit(EXIT_FAILURE); \ - } while (0) +#include "common.h" void ChildSignalHandler::handle() { @@ -19,7 +14,7 @@ void ChildSignalHandler::handle() sz = read(fd, &fdsi, sizeof(struct signalfd_siginfo)); if (sz != sizeof(struct signalfd_siginfo)) - handle_error("read"); + handle_error("read child signal handler"); if (fdsi.ssi_signo == SIGINT) { fprintf(stderr, "%d: Got SIGINT from %d\n", getpid(), fdsi.ssi_pid); diff --git a/Parent.cc b/Parent.cc index 306efb5..2c66929 100644 --- a/Parent.cc +++ b/Parent.cc @@ -7,12 +7,7 @@ #include #include "server.h" #include "mmaper.h" - -#define handle_error(msg) \ - do { \ - perror(msg); \ - exit(EXIT_FAILURE); \ - } while (0) +#include "common.h" int Parent::get_child_idx(pid_t pid) { diff --git a/Parent.hh b/Parent.hh index 2ba2ef8..ef66e81 100644 --- a/Parent.hh +++ b/Parent.hh @@ -9,7 +9,7 @@ class Parent friend class ParentSignalHandler; public: Parent() - : exiting(0), n_children(0), sfd(-1), epollfd(-1) + : exiting(0), n_children(0), sfd(-1), epoll_fd(-1) { memset(children, 0, sizeof(children)); } diff --git a/ParentSignalHandler.cc b/ParentSignalHandler.cc index 28c66ce..5ed9238 100644 --- a/ParentSignalHandler.cc +++ b/ParentSignalHandler.cc @@ -7,12 +7,7 @@ #include #include #include - -#define handle_error(msg) \ - do { \ - perror(msg); \ - exit(EXIT_FAILURE); \ - } while (0) +#include "common.h" void ParentSignalHandler::handle() { @@ -23,7 +18,7 @@ void ParentSignalHandler::handle() sz = read(fd, &fdsi, sizeof(struct signalfd_siginfo)); if (sz != sizeof(struct signalfd_siginfo)) - handle_error("read"); + handle_error("read parent signal handler"); if (fdsi.ssi_signo == SIGINT) { fprintf(stderr, "%d: Got SIGINT from %d\n", getpid(), fdsi.ssi_pid); diff --git a/forker.cc b/forker.cc index 4023bba..e42c2fc 100644 --- a/forker.cc +++ b/forker.cc @@ -8,16 +8,12 @@ #include #include +#include "common.h" #include "Parent.hh" #include "Handler.hh" #include "ParentSignalHandler.hh" #include "ChildSignalHandler.hh" - -#define handle_error(msg) \ - do { \ - perror(msg); \ - exit(EXIT_FAILURE); \ - } while (0) +#include "InotifyHandler.hh" #define MAX_EVENTS MAX_CHILDREN @@ -37,8 +33,21 @@ void run_epoll(int sfd, int is_parent) ev.events = EPOLLIN; if (is_parent) { + struct epoll_event inotify_ev; + ev.data.ptr = new ParentSignalHandler(sfd, &parent); parent.set_epoll_fd(epollfd); + + InotifyHandler *ino_handler = new InotifyHandler(); + + inotify_ev.events = EPOLLIN; + inotify_ev.data.ptr = ino_handler; + + int inotify_fd = ino_handler->init("/tmp"); + + if (epoll_ctl(epollfd, EPOLL_CTL_ADD, inotify_fd, &inotify_ev) == -1) { + handle_error("epoll_ctl: inotify_fd"); + } } else { ev.data.ptr = new ChildSignalHandler(sfd); } @@ -54,7 +63,7 @@ void run_epoll(int sfd, int is_parent) } for (n = 0; n < nfds; ++n) { - Handler *handler = (Handler*)ev.data.ptr; + Handler *handler = (Handler*)events[n].data.ptr; handler->handle(); } } diff --git a/mmaper.c b/mmaper.c index f2b6cc1..7254dcd 100644 --- a/mmaper.c +++ b/mmaper.c @@ -4,15 +4,10 @@ #include #include #include +#include "common.h" static void * mmap_addr; -#define handle_error(msg) \ - do { \ - perror(msg); \ - exit(EXIT_FAILURE); \ - } while (0) - //#define FILESZ (30L * 1024L * 1024L * 1024L) #define FILESZ (30L * 1024L) From 0d9682ceacd927f5b2d4c8fca52f91a67566a864 Mon Sep 17 00:00:00 2001 From: Yan Date: Wed, 3 Jan 2018 15:48:28 +0200 Subject: [PATCH 14/22] Add respawn function to child Signed-off-by: Yan --- Parent.cc | 26 ++++++++++++++++++++++++-- Parent.hh | 3 +++ ParentSignalHandler.cc | 5 +++-- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/Parent.cc b/Parent.cc index 2c66929..03ca832 100644 --- a/Parent.cc +++ b/Parent.cc @@ -63,6 +63,29 @@ void Parent::add_new_child(pid_t pid) ++n_children; } +void Parent::child_fn() +{ + map_memory(); + run_server(sfd); +} + +void Parent::respawn(int child_idx) +{ + assert(children[child_idx] == 0); + + pid_t pid = fork(); + if (pid == -1) + handle_error("fork respawn"); + + if (pid) { + fprintf(stderr, "Respawned %d\n", pid); + children[child_idx] = pid; + ++n_children; + } else { + child_fn(); + } +} + void Parent::do_forks(int num) { pid_t pid; @@ -77,8 +100,7 @@ void Parent::do_forks(int num) fprintf(stderr, "Forked %d\n", pid); add_new_child(pid); } else { - map_memory(); - run_server(sfd); + child_fn(); } } } diff --git a/Parent.hh b/Parent.hh index ef66e81..420eb8b 100644 --- a/Parent.hh +++ b/Parent.hh @@ -26,6 +26,7 @@ public: void clear_child(pid_t pid); void add_new_child(pid_t pid); void do_forks(int num); + void respawn(int child_idx); protected: int exiting; @@ -34,4 +35,6 @@ protected: int n_children; int sfd; int epoll_fd; + + void child_fn(); }; diff --git a/ParentSignalHandler.cc b/ParentSignalHandler.cc index 5ed9238..b065e37 100644 --- a/ParentSignalHandler.cc +++ b/ParentSignalHandler.cc @@ -38,11 +38,12 @@ void ParentSignalHandler::handle() do { pid = waitpid(-1, &status, WNOHANG); if (pid > 0) { - fprintf(stderr, "%d: Process %d exited\n", getpid(), pid); + int child_idx = parent->get_child_idx(pid); + fprintf(stderr, "%d: Process %d exited (idx:%d)\n", getpid(), pid, child_idx); parent->clear_child(pid); if (!parent->exiting) { - parent->do_forks(1); + parent->respawn(child_idx); } else { if (parent->n_children == 0) { fprintf(stderr, "%d: All children exited\n", getpid()); From 6e903adf512aeec1eab00a676fb8e9477b326dc3 Mon Sep 17 00:00:00 2001 From: Yan Date: Wed, 3 Jan 2018 16:07:29 +0200 Subject: [PATCH 15/22] Add indexes for each child Signed-off-by: Yan --- Parent.cc | 25 ++++++++++++++++--------- Parent.hh | 4 +++- mmaper.c | 14 ++++++++++++-- mmaper.h | 2 +- 4 files changed, 32 insertions(+), 13 deletions(-) diff --git a/Parent.cc b/Parent.cc index 03ca832..7b1648f 100644 --- a/Parent.cc +++ b/Parent.cc @@ -63,26 +63,31 @@ void Parent::add_new_child(pid_t pid) ++n_children; } -void Parent::child_fn() +void Parent::set_new_child(int child_idx, pid_t pid) { - map_memory(); + assert(children[child_idx] == 0); + + children[child_idx] = pid; + ++n_children; +} + +void Parent::child_fn(int idx) +{ + map_memory(idx); run_server(sfd); } void Parent::respawn(int child_idx) { - assert(children[child_idx] == 0); - pid_t pid = fork(); if (pid == -1) handle_error("fork respawn"); if (pid) { fprintf(stderr, "Respawned %d\n", pid); - children[child_idx] = pid; - ++n_children; + set_new_child(child_idx, pid); } else { - child_fn(); + child_fn(child_idx); } } @@ -90,17 +95,19 @@ void Parent::do_forks(int num) { pid_t pid; int i; + int idx; for (i = 0; i < num; ++i) { + idx = find_empty_child_idx(); pid = fork(); if (pid == -1) handle_error("fork"); if (pid) { fprintf(stderr, "Forked %d\n", pid); - add_new_child(pid); + set_new_child(idx, pid); } else { - child_fn(); + child_fn(idx); } } } diff --git a/Parent.hh b/Parent.hh index 420eb8b..4fc905e 100644 --- a/Parent.hh +++ b/Parent.hh @@ -28,6 +28,8 @@ public: void do_forks(int num); void respawn(int child_idx); + void set_new_child(int child_idx, pid_t pid); + protected: int exiting; @@ -36,5 +38,5 @@ protected: int sfd; int epoll_fd; - void child_fn(); + void child_fn(int idx); }; diff --git a/mmaper.c b/mmaper.c index 7254dcd..8d33e82 100644 --- a/mmaper.c +++ b/mmaper.c @@ -4,6 +4,8 @@ #include #include #include +#include + #include "common.h" static void * mmap_addr; @@ -27,17 +29,25 @@ int allow_mmap_in_core() return 0; } -int map_memory(void) +int map_memory(int idx) { static char template[] = "/tmp/myfileXXXXXX"; int res; allow_mmap_in_core(); +#if 0 int fd = mkstemp(template); if (fd < 0) handle_error("mkstemp"); - +#endif + + char fname[PATH_MAX]; + snprintf(fname, sizeof(fname), "/tmp/mmaped_file_%d", idx); + int fd = open(fname, O_CREAT | O_RDWR, S_IWUSR | S_IRUSR); + if (fd < 0) + handle_error("open"); + res = ftruncate(fd, FILESZ); if (res) handle_error("ftruncate"); diff --git a/mmaper.h b/mmaper.h index 79bd370..05c4f92 100644 --- a/mmaper.h +++ b/mmaper.h @@ -1,3 +1,3 @@ #pragma once -extern "C" int map_memory(void); +extern "C" int map_memory(int idx); From b5fe06089770fde1babeb4e8316f5640c5f8ad35 Mon Sep 17 00:00:00 2001 From: Yan Date: Wed, 3 Jan 2018 16:32:04 +0200 Subject: [PATCH 16/22] Working fully async server Signed-off-by: Yan --- CMakeLists.txt | 2 +- ChildSignalHandler.cc | 1 + server.c => EchoServerHandler.cc | 88 +++++++++++++++--------------- EchoServerHandler.hh | 17 ++++++ InotifyHandler.cc | 93 ++++++++++++++++++++++++++++++++ InotifyHandler.hh | 19 +++++++ Parent.cc | 73 ++++++++++++++++++++++++- Parent.hh | 1 + ParentSignalHandler.cc | 2 + common.h | 13 +++++ forker.cc | 58 +------------------- server.h | 8 --- 12 files changed, 263 insertions(+), 112 deletions(-) rename server.c => EchoServerHandler.cc (56%) create mode 100644 EchoServerHandler.hh create mode 100644 InotifyHandler.cc create mode 100644 InotifyHandler.hh create mode 100644 common.h delete mode 100644 server.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f751b8..814f8d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ set(CMAKE_CXX_FLAGS_RELEASE "${warning_flags} \ set(target forker) -add_executable(${target} forker.cc server.c mmaper.c ChildSignalHandler.cc ParentSignalHandler.cc Parent.cc InotifyHandler.cc) +add_executable(${target} forker.cc mmaper.c ChildSignalHandler.cc ParentSignalHandler.cc Parent.cc InotifyHandler.cc EchoServerHandler.cc) add_executable(client client.c) diff --git a/ChildSignalHandler.cc b/ChildSignalHandler.cc index ccddeea..b938515 100644 --- a/ChildSignalHandler.cc +++ b/ChildSignalHandler.cc @@ -18,6 +18,7 @@ void ChildSignalHandler::handle() if (fdsi.ssi_signo == SIGINT) { fprintf(stderr, "%d: Got SIGINT from %d\n", getpid(), fdsi.ssi_pid); + exit(EXIT_SUCCESS); } else if (fdsi.ssi_signo == SIGQUIT) { fprintf(stderr, "%d: Got SIGQUIT from %d\n", getpid(), fdsi.ssi_pid); exit(EXIT_SUCCESS); diff --git a/server.c b/EchoServerHandler.cc similarity index 56% rename from server.c rename to EchoServerHandler.cc index 5c70b03..0467f43 100644 --- a/server.c +++ b/EchoServerHandler.cc @@ -1,25 +1,20 @@ -/* - ** server.c -- a stream socket server demo - */ - +#include "EchoServerHandler.hh" #include -#include -#include -#include -#include #include +#include #include #include #include +#include #include -#include +#include "common.h" #define PORT "3490" // the port users will be connecting to #define BACKLOG 10 // how many pending connections queue will hold // get sockaddr, IPv4 or IPv6: -void *get_in_addr(struct sockaddr *sa) +static void *get_in_addr(struct sockaddr *sa) { if (sa->sa_family == AF_INET) { return &(((struct sockaddr_in*)sa)->sin_addr); @@ -28,15 +23,16 @@ void *get_in_addr(struct sockaddr *sa) return &(((struct sockaddr_in6*)sa)->sin6_addr); } -int run_server(int sfd) +EchoServerHandler::EchoServerHandler() +: Handler(-1), accept_fd(-1) { - int sockfd, new_fd; // listen on sock_fd, new connection on new_fd +} + +int EchoServerHandler::init() +{ + int sockfd; // listen on sock_fd struct addrinfo hints, *servinfo, *p; - struct sockaddr_storage their_addr; // connector's address information - socklen_t sin_size; - struct sigaction sa; int yes = 1; - char s[INET6_ADDRSTRLEN]; int rv; memset(&hints, 0, sizeof hints); @@ -46,32 +42,30 @@ int run_server(int sfd) if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); - return 1; + exit(1); } // loop through all the results and bind to the first we can for(p = servinfo; p != NULL; p = p->ai_next) { if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { - perror("server: socket"); + handle_error("socket"); continue; } if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { - perror("setsockopt reuse addr"); - exit(1); + handle_error("setsockopt reuse addr"); } if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(int)) == -1) { - perror("setsockopt reuse port"); - exit(1); + handle_error("setsockopt reuse port"); } if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { close(sockfd); - perror("server: bind"); + handle_error("server: bind"); continue; } @@ -81,34 +75,40 @@ int run_server(int sfd) freeaddrinfo(servinfo); // all done with this structure if (p == NULL) { - fprintf(stderr, "server: failed to bind\n"); - exit(1); + handle_error("server: failed to bind"); } if (listen(sockfd, BACKLOG) == -1) { - perror("listen"); - exit(1); + handle_error("listen"); } printf("server: waiting for connections... (pid: %u)\n", getpid()); - while(1) { // main accept() loop - sin_size = sizeof their_addr; - new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size); - if (new_fd == -1) { - perror("accept"); - continue; - } - - inet_ntop(their_addr.ss_family, - get_in_addr((struct sockaddr *)&their_addr), - s, sizeof s); - printf("server: got connection from %s (pid: %u)\n", s, getpid()); + accept_fd = sockfd; - if (send(new_fd, "Hello, world!", 13, 0) == -1) - perror("send"); - close(new_fd); - } + return accept_fd; +} - return 0; +void EchoServerHandler::handle() +{ + int new_fd; // new connection on new_fd + struct sockaddr_storage their_addr; // connector's address information + socklen_t sin_size; + char s[INET6_ADDRSTRLEN]; + + sin_size = sizeof their_addr; + new_fd = accept(accept_fd, (struct sockaddr *)&their_addr, &sin_size); + if (new_fd == -1) { + handle_error("accept"); + } + + inet_ntop(their_addr.ss_family, + get_in_addr((struct sockaddr *)&their_addr), + s, sizeof s); + printf("server: got connection from %s (pid: %u)\n", s, getpid()); + + if (send(new_fd, "Hello, world!", 13, 0) == -1) + perror("send"); + close(new_fd); } + diff --git a/EchoServerHandler.hh b/EchoServerHandler.hh new file mode 100644 index 0000000..9ee569d --- /dev/null +++ b/EchoServerHandler.hh @@ -0,0 +1,17 @@ +#pragma once + +#include "Handler.hh" + +class EchoServerHandler: public Handler +{ +public: + EchoServerHandler(); + + int init(); + + virtual void handle(); + +protected: + int accept_fd; +}; + diff --git a/InotifyHandler.cc b/InotifyHandler.cc new file mode 100644 index 0000000..db7811d --- /dev/null +++ b/InotifyHandler.cc @@ -0,0 +1,93 @@ +#include "InotifyHandler.hh" +#include +#include +#include +#include +#include "common.h" + +InotifyHandler::InotifyHandler() +: Handler(-1), inotify_fd(-1), path(NULL) +{ +} + +int InotifyHandler::init(const char* path) +{ + inotify_fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); + if (inotify_fd == -1) + handle_error("inotify_init1"); + + watch_descriptor = inotify_add_watch(inotify_fd, path, IN_CREATE | IN_ISDIR); + if (watch_descriptor == -1) + handle_error("inotify_add_watch"); + + this->path = path; + + return inotify_fd; +} + +void InotifyHandler::handle() +{ + /* Some systems cannot read integer variables if they are not + properly aligned. On other systems, incorrect alignment may + decrease performance. Hence, the buffer used for reading from + the inotify file descriptor should have the same alignment as + struct inotify_event. */ + + char buf[4096] + __attribute__ ((aligned(__alignof__(struct inotify_event)))); + const struct inotify_event *event; + ssize_t len; + char *ptr; + + /* Loop while events can be read from inotify file descriptor. */ + + for (;;) { + + /* Read some events. */ + + len = read(inotify_fd, buf, sizeof buf); + if (len == -1 && errno != EAGAIN) { + handle_error("inotify read"); + } + + /* If the nonblocking read() found no events to read, then + it returns -1 with errno set to EAGAIN. In that case, + we exit the loop. */ + + if (len <= 0) + break; + + /* Loop over all events in the buffer */ + + for (ptr = buf; ptr < buf + len; + ptr += sizeof(struct inotify_event) + event->len) { + + event = (const struct inotify_event *) ptr; + + /* Print event type */ + + if (event->mask & IN_OPEN) + printf("IN_OPEN: "); + if (event->mask & IN_CLOSE_NOWRITE) + printf("IN_CLOSE_NOWRITE: "); + if (event->mask & IN_CLOSE_WRITE) + printf("IN_CLOSE_WRITE: "); + + /* Print the name of the watched directory */ + printf("%s/", path); + + /* Print the name of the file */ + + if (event->len) + printf("%s", event->name); + + /* Print type of filesystem object */ + + if (event->mask & IN_ISDIR) + printf(" [directory]\n"); + else + printf(" [file]\n"); + } + } +} + diff --git a/InotifyHandler.hh b/InotifyHandler.hh new file mode 100644 index 0000000..fe0f94c --- /dev/null +++ b/InotifyHandler.hh @@ -0,0 +1,19 @@ +#pragma once + +#include "Handler.hh" + +class InotifyHandler: public Handler +{ +public: + InotifyHandler(); + + int init(const char* path); + + virtual void handle(); + +protected: + int inotify_fd; + int watch_descriptor; + const char* path; +}; + diff --git a/Parent.cc b/Parent.cc index 7b1648f..6019125 100644 --- a/Parent.cc +++ b/Parent.cc @@ -5,10 +5,19 @@ #include #include #include -#include "server.h" +#include + #include "mmaper.h" #include "common.h" +#include "Handler.hh" +#include "ParentSignalHandler.hh" +#include "ChildSignalHandler.hh" +#include "InotifyHandler.hh" +#include "EchoServerHandler.hh" + +#define MAX_EVENTS MAX_CHILDREN + int Parent::get_child_idx(pid_t pid) { int res = -1; @@ -74,7 +83,7 @@ void Parent::set_new_child(int child_idx, pid_t pid) void Parent::child_fn(int idx) { map_memory(idx); - run_server(sfd); + run_epoll(0); } void Parent::respawn(int child_idx) @@ -112,3 +121,63 @@ void Parent::do_forks(int num) } } +void Parent::run_epoll(int is_parent) +{ + struct epoll_event ev, events[MAX_EVENTS]; + int nfds, n; + + int epollfd = epoll_create1(EPOLL_CLOEXEC); + if (epollfd == -1) { + handle_error("epoll_create1"); + } + + ev.events = EPOLLIN; + if (is_parent) { + struct epoll_event inotify_ev; + + ev.data.ptr = new ParentSignalHandler(sfd, this); + set_epoll_fd(epollfd); + + InotifyHandler *ino_handler = new InotifyHandler(); + + inotify_ev.events = EPOLLIN; + inotify_ev.data.ptr = ino_handler; + + int inotify_fd = ino_handler->init("/tmp"); + + if (epoll_ctl(epollfd, EPOLL_CTL_ADD, inotify_fd, &inotify_ev) == -1) { + handle_error("epoll_ctl: inotify_fd"); + } + } else { + ev.data.ptr = new ChildSignalHandler(sfd); + + struct epoll_event accept_ev; + + EchoServerHandler *echo_handler = new EchoServerHandler(); + + accept_ev.events = EPOLLIN; + accept_ev.data.ptr = echo_handler; + + int accept_fd = echo_handler->init(); + + if (epoll_ctl(epollfd, EPOLL_CTL_ADD, accept_fd, &accept_ev) == -1) { + handle_error("epoll_ctl: accept_fd"); + } + } + + if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sfd, &ev) == -1) { + handle_error("epoll_ctl: signalfd"); + } + + for (;;) { + nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1); + if (nfds == -1) { + handle_error("epoll_wait"); + } + + for (n = 0; n < nfds; ++n) { + Handler *handler = (Handler*)events[n].data.ptr; + handler->handle(); + } + } +} diff --git a/Parent.hh b/Parent.hh index 4fc905e..32900ee 100644 --- a/Parent.hh +++ b/Parent.hh @@ -28,6 +28,7 @@ public: void do_forks(int num); void respawn(int child_idx); + void run_epoll(int is_parent); void set_new_child(int child_idx, pid_t pid); protected: diff --git a/ParentSignalHandler.cc b/ParentSignalHandler.cc index b065e37..dab080e 100644 --- a/ParentSignalHandler.cc +++ b/ParentSignalHandler.cc @@ -22,6 +22,8 @@ void ParentSignalHandler::handle() if (fdsi.ssi_signo == SIGINT) { fprintf(stderr, "%d: Got SIGINT from %d\n", getpid(), fdsi.ssi_pid); + parent->exiting = 1; + parent->notify_children(SIGQUIT); } else if (fdsi.ssi_signo == SIGQUIT) { fprintf(stderr, "%d: Got SIGQUIT from %d\n", getpid(), fdsi.ssi_pid); parent->exiting = 1; diff --git a/common.h b/common.h new file mode 100644 index 0000000..f87aa70 --- /dev/null +++ b/common.h @@ -0,0 +1,13 @@ +#pragma once +#include +#include +#include +#include + +#define handle_error(msg) \ + do { \ + perror(msg); \ + exit(EXIT_FAILURE); \ + } while (0) + + diff --git a/forker.cc b/forker.cc index e42c2fc..47c8dba 100644 --- a/forker.cc +++ b/forker.cc @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -10,65 +9,10 @@ #include "common.h" #include "Parent.hh" -#include "Handler.hh" -#include "ParentSignalHandler.hh" -#include "ChildSignalHandler.hh" -#include "InotifyHandler.hh" -#define MAX_EVENTS MAX_CHILDREN - -void run_epoll(int sfd, int is_parent); static Parent parent; -void run_epoll(int sfd, int is_parent) -{ - struct epoll_event ev, events[MAX_EVENTS]; - int nfds, n; - - int epollfd = epoll_create1(EPOLL_CLOEXEC); - if (epollfd == -1) { - handle_error("epoll_create1"); - } - - ev.events = EPOLLIN; - if (is_parent) { - struct epoll_event inotify_ev; - - ev.data.ptr = new ParentSignalHandler(sfd, &parent); - parent.set_epoll_fd(epollfd); - - InotifyHandler *ino_handler = new InotifyHandler(); - - inotify_ev.events = EPOLLIN; - inotify_ev.data.ptr = ino_handler; - - int inotify_fd = ino_handler->init("/tmp"); - - if (epoll_ctl(epollfd, EPOLL_CTL_ADD, inotify_fd, &inotify_ev) == -1) { - handle_error("epoll_ctl: inotify_fd"); - } - } else { - ev.data.ptr = new ChildSignalHandler(sfd); - } - - if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sfd, &ev) == -1) { - handle_error("epoll_ctl: signalfd"); - } - - for (;;) { - nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1); - if (nfds == -1) { - handle_error("epoll_wait"); - } - - for (n = 0; n < nfds; ++n) { - Handler *handler = (Handler*)events[n].data.ptr; - handler->handle(); - } - } -} - int main(int argc, char *argv[]) { sigset_t mask; @@ -95,7 +39,7 @@ int main(int argc, char *argv[]) // forking after epoll created leades to world of pain parent.do_forks(MAX_CHILDREN); - run_epoll(sfd, 1); + parent.run_epoll(sfd); return EXIT_SUCCESS; } diff --git a/server.h b/server.h deleted file mode 100644 index cf2802a..0000000 --- a/server.h +++ /dev/null @@ -1,8 +0,0 @@ -/* - ** server.c -- a stream socket server demo - */ - -#pragma once - -extern "C" int run_server(int sfd); - From a8740209bbc4040d80c557aafe8ce7ff2ba29cea Mon Sep 17 00:00:00 2001 From: Yan Date: Wed, 3 Jan 2018 16:37:12 +0200 Subject: [PATCH 17/22] Slight child refactoring Signed-off-by: Yan --- ChildSignalHandler.cc | 11 ++++++++--- ChildSignalHandler.hh | 3 +++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/ChildSignalHandler.cc b/ChildSignalHandler.cc index b938515..a2fe906 100644 --- a/ChildSignalHandler.cc +++ b/ChildSignalHandler.cc @@ -7,6 +7,11 @@ #include #include "common.h" +void ChildSignalHandler::handle_exit() +{ + exit(EXIT_SUCCESS); +} + void ChildSignalHandler::handle() { struct signalfd_siginfo fdsi; @@ -18,13 +23,13 @@ void ChildSignalHandler::handle() if (fdsi.ssi_signo == SIGINT) { fprintf(stderr, "%d: Got SIGINT from %d\n", getpid(), fdsi.ssi_pid); - exit(EXIT_SUCCESS); + handle_exit(); } else if (fdsi.ssi_signo == SIGQUIT) { fprintf(stderr, "%d: Got SIGQUIT from %d\n", getpid(), fdsi.ssi_pid); - exit(EXIT_SUCCESS); + handle_exit(); } else if (fdsi.ssi_signo == SIGTERM) { fprintf(stderr, "%d: Got SIGTERM from %d\n", getpid(), fdsi.ssi_pid); - exit(EXIT_SUCCESS); + handle_exit(); } else { fprintf(stderr, "%d: Read unexpected signal from %d\n", getpid(), fdsi.ssi_pid); } diff --git a/ChildSignalHandler.hh b/ChildSignalHandler.hh index cd5e964..7e75b4e 100644 --- a/ChildSignalHandler.hh +++ b/ChildSignalHandler.hh @@ -10,5 +10,8 @@ public: {} virtual void handle(); + +protected: + void handle_exit(); }; From 71688f6107aae617118eb3e6c08e08d2fed857fa Mon Sep 17 00:00:00 2001 From: Yan Date: Wed, 3 Jan 2018 16:55:25 +0200 Subject: [PATCH 18/22] Add child SIGSEGV handler Signed-off-by: Yan --- CMakeLists.txt | 2 +- Parent.cc | 2 ++ child.c | 31 +++++++++++++++++++++++++++++++ child.h | 4 ++++ 4 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 child.c create mode 100644 child.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 814f8d4..7bf153b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ set(CMAKE_CXX_FLAGS_RELEASE "${warning_flags} \ set(target forker) -add_executable(${target} forker.cc mmaper.c ChildSignalHandler.cc ParentSignalHandler.cc Parent.cc InotifyHandler.cc EchoServerHandler.cc) +add_executable(${target} forker.cc mmaper.c child.c ChildSignalHandler.cc ParentSignalHandler.cc Parent.cc InotifyHandler.cc EchoServerHandler.cc) add_executable(client client.c) diff --git a/Parent.cc b/Parent.cc index 6019125..6847baf 100644 --- a/Parent.cc +++ b/Parent.cc @@ -9,6 +9,7 @@ #include "mmaper.h" #include "common.h" +#include "child.h" #include "Handler.hh" #include "ParentSignalHandler.hh" @@ -83,6 +84,7 @@ void Parent::set_new_child(int child_idx, pid_t pid) void Parent::child_fn(int idx) { map_memory(idx); + set_child_idx(idx); run_epoll(0); } diff --git a/child.c b/child.c new file mode 100644 index 0000000..6884437 --- /dev/null +++ b/child.c @@ -0,0 +1,31 @@ +#include +#include +#include + +#include "common.h" + +static int child_idx; + +static void signal_handler(int sig, siginfo_t *si, void *arg) +{ + fprintf(stderr, "Child %d got signal: %d\n", child_idx, sig); + kill(getpid(), sig); +} + +typedef void (*sighandler_t)(int); + +void set_child_idx(int idx) +{ + struct sigaction act; + + memset(&act, 0, sizeof(sigaction)); + sigemptyset(&act.sa_mask); + act.sa_flags = (int)(SA_NODEFER | SA_RESETHAND | SA_SIGINFO); + act.sa_sigaction = signal_handler; + + sigaction(SIGSEGV, &act, NULL); + + child_idx = idx; + +} + diff --git a/child.h b/child.h new file mode 100644 index 0000000..a810fa8 --- /dev/null +++ b/child.h @@ -0,0 +1,4 @@ +#pragma once + +extern "C" void set_child_idx(int idx); + From ddbc44bfb8ab97bf3eeeaefea03307b889954ab1 Mon Sep 17 00:00:00 2001 From: Yan Date: Wed, 3 Jan 2018 17:00:50 +0200 Subject: [PATCH 19/22] Add writing out of child info to /tmp Signed-off-by: Yan --- child.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/child.c b/child.c index 6884437..428bce4 100644 --- a/child.c +++ b/child.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include "common.h" @@ -8,8 +10,17 @@ static int child_idx; static void signal_handler(int sig, siginfo_t *si, void *arg) { - fprintf(stderr, "Child %d got signal: %d\n", child_idx, sig); - kill(getpid(), sig); + char path[PATH_MAX]; + pid_t pid = getpid(); + + snprintf(path, sizeof(path), "/tmp/child_%d_%d", pid, child_idx); + int fd = creat(path, S_IWUSR | S_IRUSR); + if (fd < 0) + handle_error("creat in signal handler"); + close(fd); + + fprintf(stderr, "Child idx %d pid: %d got signal: %d\n", child_idx, pid, sig); + kill(pid, sig); } typedef void (*sighandler_t)(int); From 16e6ba3a81e6ef3f671c6ce2fa2e2abdc75e4bb3 Mon Sep 17 00:00:00 2001 From: Yan Date: Wed, 3 Jan 2018 17:07:14 +0200 Subject: [PATCH 20/22] WIP try to parse the child info Signed-off-by: Yan --- InotifyHandler.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/InotifyHandler.cc b/InotifyHandler.cc index db7811d..645b2cf 100644 --- a/InotifyHandler.cc +++ b/InotifyHandler.cc @@ -81,6 +81,14 @@ void InotifyHandler::handle() if (event->len) printf("%s", event->name); + { + pid_t pid = 0; + int idx = 0; + int n_vals = sscanf(event->name, "child_%d_%d", &pid, &idx); + if (n_vals == 2 && pid != 0 && idx != 0) + printf("Child idx %d pid %d is dying\n", idx, pid); + } + /* Print type of filesystem object */ if (event->mask & IN_ISDIR) From f4594efd4d246811a53b5c47ba78028e9e8f8645 Mon Sep 17 00:00:00 2001 From: Yan Date: Thu, 4 Jan 2018 07:57:09 +0200 Subject: [PATCH 21/22] Respawn child when it begins to die Signed-off-by: Yan --- ChildSignalHandler.cc | 4 +++- InotifyHandler.cc | 42 ++++++++++++++++++++++++++++++++---------- InotifyHandler.hh | 8 +++++++- Parent.cc | 6 +++--- Parent.hh | 5 ++++- ParentSignalHandler.cc | 11 ++++------- child.c | 12 +++++++++--- child.h | 1 + 8 files changed, 63 insertions(+), 26 deletions(-) diff --git a/ChildSignalHandler.cc b/ChildSignalHandler.cc index a2fe906..b9cf891 100644 --- a/ChildSignalHandler.cc +++ b/ChildSignalHandler.cc @@ -6,10 +6,12 @@ #include #include #include "common.h" +#include "child.h" void ChildSignalHandler::handle_exit() { - exit(EXIT_SUCCESS); + write_child_exit_info(); + exit(EXIT_SUCCESS); } void ChildSignalHandler::handle() diff --git a/InotifyHandler.cc b/InotifyHandler.cc index 645b2cf..3592f45 100644 --- a/InotifyHandler.cc +++ b/InotifyHandler.cc @@ -3,10 +3,13 @@ #include #include #include +#include +#include + #include "common.h" -InotifyHandler::InotifyHandler() -: Handler(-1), inotify_fd(-1), path(NULL) +InotifyHandler::InotifyHandler(Parent* parent) +: Handler(-1), inotify_fd(-1), path(NULL), parent(parent), watched_dir_fd(-1), watched_dir(NULL) { } @@ -20,6 +23,14 @@ int InotifyHandler::init(const char* path) if (watch_descriptor == -1) handle_error("inotify_add_watch"); + watched_dir = opendir(path); + if (watched_dir == NULL) + handle_error("opendir"); + + watched_dir_fd = dirfd(watched_dir); + if (watched_dir_fd < 0) + handle_error("open watched dir"); + this->path = path; return inotify_fd; @@ -33,7 +44,7 @@ void InotifyHandler::handle() the inotify file descriptor should have the same alignment as struct inotify_event. */ - char buf[4096] + char buf[8192] __attribute__ ((aligned(__alignof__(struct inotify_event)))); const struct inotify_event *event; ssize_t len; @@ -81,13 +92,6 @@ void InotifyHandler::handle() if (event->len) printf("%s", event->name); - { - pid_t pid = 0; - int idx = 0; - int n_vals = sscanf(event->name, "child_%d_%d", &pid, &idx); - if (n_vals == 2 && pid != 0 && idx != 0) - printf("Child idx %d pid %d is dying\n", idx, pid); - } /* Print type of filesystem object */ @@ -95,6 +99,24 @@ void InotifyHandler::handle() printf(" [directory]\n"); else printf(" [file]\n"); + + { + pid_t pid = 0; + int idx = 0; + int n_vals = sscanf(event->name, "child_%d_%d", &pid, &idx); + if (n_vals == 2 && pid != 0 && idx != 0) { + time_t t = time(NULL); + struct tm *tm = localtime(&t); + printf("Child idx %d pid %d is dying: %s", idx, pid, asctime(tm)); + + unlinkat(watched_dir_fd, event->name, 0); + + parent->clear_child(pid); + if (!parent->is_exiting()) { + parent->respawn(idx); + } + } + } } } } diff --git a/InotifyHandler.hh b/InotifyHandler.hh index fe0f94c..5b2fde1 100644 --- a/InotifyHandler.hh +++ b/InotifyHandler.hh @@ -1,11 +1,14 @@ #pragma once #include "Handler.hh" +#include "Parent.hh" + +#include class InotifyHandler: public Handler { public: - InotifyHandler(); + InotifyHandler(Parent* parent); int init(const char* path); @@ -15,5 +18,8 @@ protected: int inotify_fd; int watch_descriptor; const char* path; + Parent* parent; + int watched_dir_fd; + DIR* watched_dir; }; diff --git a/Parent.cc b/Parent.cc index 6847baf..eb8c27a 100644 --- a/Parent.cc +++ b/Parent.cc @@ -70,7 +70,6 @@ void Parent::notify_children(int sig) void Parent::add_new_child(pid_t pid) { children[find_empty_child_idx()] = pid; - ++n_children; } void Parent::set_new_child(int child_idx, pid_t pid) @@ -78,7 +77,6 @@ void Parent::set_new_child(int child_idx, pid_t pid) assert(children[child_idx] == 0); children[child_idx] = pid; - ++n_children; } void Parent::child_fn(int idx) @@ -97,6 +95,7 @@ void Parent::respawn(int child_idx) if (pid) { fprintf(stderr, "Respawned %d\n", pid); set_new_child(child_idx, pid); + ++n_children; } else { child_fn(child_idx); } @@ -117,6 +116,7 @@ void Parent::do_forks(int num) if (pid) { fprintf(stderr, "Forked %d\n", pid); set_new_child(idx, pid); + ++n_children; } else { child_fn(idx); } @@ -140,7 +140,7 @@ void Parent::run_epoll(int is_parent) ev.data.ptr = new ParentSignalHandler(sfd, this); set_epoll_fd(epollfd); - InotifyHandler *ino_handler = new InotifyHandler(); + InotifyHandler *ino_handler = new InotifyHandler(this); inotify_ev.events = EPOLLIN; inotify_ev.data.ptr = ino_handler; diff --git a/Parent.hh b/Parent.hh index 32900ee..92152b8 100644 --- a/Parent.hh +++ b/Parent.hh @@ -2,7 +2,7 @@ #include #include -#define MAX_CHILDREN 10 +#define MAX_CHILDREN 2 class Parent { @@ -31,6 +31,9 @@ public: void run_epoll(int is_parent); void set_new_child(int child_idx, pid_t pid); + bool is_exiting() + { return exiting == 1; } + protected: int exiting; diff --git a/ParentSignalHandler.cc b/ParentSignalHandler.cc index dab080e..18dabfd 100644 --- a/ParentSignalHandler.cc +++ b/ParentSignalHandler.cc @@ -36,17 +36,14 @@ void ParentSignalHandler::handle() time_t t = time(NULL); struct tm *tm = localtime(&t); - fprintf(stderr, "%d: Got SIGCHLD from %d (%s)\n", getpid(), fdsi.ssi_pid, asctime(tm)); + fprintf(stderr, "%d: Got SIGCHLD from %d %s", getpid(), fdsi.ssi_pid, asctime(tm)); do { pid = waitpid(-1, &status, WNOHANG); if (pid > 0) { - int child_idx = parent->get_child_idx(pid); - fprintf(stderr, "%d: Process %d exited (idx:%d)\n", getpid(), pid, child_idx); - parent->clear_child(pid); + --parent->n_children; + fprintf(stderr, "%d: Process %d exited\n", getpid(), pid); - if (!parent->exiting) { - parent->respawn(child_idx); - } else { + if (parent->exiting) { if (parent->n_children == 0) { fprintf(stderr, "%d: All children exited\n", getpid()); exit(EXIT_SUCCESS); diff --git a/child.c b/child.c index 428bce4..813ac90 100644 --- a/child.c +++ b/child.c @@ -8,19 +8,25 @@ static int child_idx; -static void signal_handler(int sig, siginfo_t *si, void *arg) +void write_child_exit_info() { char path[PATH_MAX]; pid_t pid = getpid(); + fprintf(stderr, "Child idx %d pid: %d got signal\n", child_idx, pid); + snprintf(path, sizeof(path), "/tmp/child_%d_%d", pid, child_idx); int fd = creat(path, S_IWUSR | S_IRUSR); if (fd < 0) handle_error("creat in signal handler"); close(fd); +} + +static void signal_handler(int sig, siginfo_t *si, void *arg) +{ + write_child_exit_info(); - fprintf(stderr, "Child idx %d pid: %d got signal: %d\n", child_idx, pid, sig); - kill(pid, sig); + kill(getpid(), sig); } typedef void (*sighandler_t)(int); diff --git a/child.h b/child.h index a810fa8..3417218 100644 --- a/child.h +++ b/child.h @@ -1,4 +1,5 @@ #pragma once extern "C" void set_child_idx(int idx); +extern "C" void write_child_exit_info(); From ed0a1b98cddb03ddf0d4dd6a6a50fe05bb3d724c Mon Sep 17 00:00:00 2001 From: Yan Date: Thu, 4 Jan 2018 14:51:38 +0200 Subject: [PATCH 22/22] Add memory poison and attempts to solve memory COW problem Signed-off-by: Yan --- InotifyHandler.cc | 1 + Parent.cc | 8 ++++---- Parent.hh | 2 +- child.c | 3 +++ mmaper.c | 50 +++++++++++++++++++++++++++++++++++++++++++---- mmaper.h | 10 +++++++++- 6 files changed, 64 insertions(+), 10 deletions(-) diff --git a/InotifyHandler.cc b/InotifyHandler.cc index 3592f45..c603ba1 100644 --- a/InotifyHandler.cc +++ b/InotifyHandler.cc @@ -104,6 +104,7 @@ void InotifyHandler::handle() pid_t pid = 0; int idx = 0; int n_vals = sscanf(event->name, "child_%d_%d", &pid, &idx); + fprintf(stderr, "file: %s, n_vals:%d, pid: %d, idx:%d\n", event->name, n_vals, pid, idx); if (n_vals == 2 && pid != 0 && idx != 0) { time_t t = time(NULL); struct tm *tm = localtime(&t); diff --git a/Parent.cc b/Parent.cc index eb8c27a..f3e6dad 100644 --- a/Parent.cc +++ b/Parent.cc @@ -79,9 +79,9 @@ void Parent::set_new_child(int child_idx, pid_t pid) children[child_idx] = pid; } -void Parent::child_fn(int idx) +void Parent::child_fn(int idx, bool respawned) { - map_memory(idx); + map_memory(idx, respawned); set_child_idx(idx); run_epoll(0); } @@ -97,7 +97,7 @@ void Parent::respawn(int child_idx) set_new_child(child_idx, pid); ++n_children; } else { - child_fn(child_idx); + child_fn(child_idx, true); } } @@ -118,7 +118,7 @@ void Parent::do_forks(int num) set_new_child(idx, pid); ++n_children; } else { - child_fn(idx); + child_fn(idx, false); } } } diff --git a/Parent.hh b/Parent.hh index 92152b8..9c45904 100644 --- a/Parent.hh +++ b/Parent.hh @@ -42,5 +42,5 @@ protected: int sfd; int epoll_fd; - void child_fn(int idx); + void child_fn(int idx, bool respawned); }; diff --git a/child.c b/child.c index 813ac90..80965f7 100644 --- a/child.c +++ b/child.c @@ -5,6 +5,7 @@ #include #include "common.h" +#include "mmaper.h" static int child_idx; @@ -24,6 +25,8 @@ void write_child_exit_info() static void signal_handler(int sig, siginfo_t *si, void *arg) { + map_remap_private(child_idx); + write_child_exit_info(); kill(getpid(), sig); diff --git a/mmaper.c b/mmaper.c index 8d33e82..a97c4cb 100644 --- a/mmaper.c +++ b/mmaper.c @@ -5,13 +5,18 @@ #include #include #include +#include +#include #include "common.h" +#include "mmaper.h" static void * mmap_addr; +static int g_idx; +#define FILESZ (5L * 1024L * 1024L * 1024L) //#define FILESZ (30L * 1024L * 1024L * 1024L) -#define FILESZ (30L * 1024L) +//#define FILESZ (30L * 1024L) #define CORE_FILTER "0x3f" @@ -29,11 +34,43 @@ int allow_mmap_in_core() return 0; } -int map_memory(int idx) +static void fill_filename(char* fname, size_t sz, int idx) +{ + snprintf(fname, sz, "/tmp/mmaped_file_%d", idx); +} + +void map_remap_private(int idx) +{ + char fname[PATH_MAX]; + fill_filename(fname, sizeof(fname), idx); + int fd = open(fname, O_CREAT | O_RDWR, S_IWUSR | S_IRUSR); + if (fd < 0) + handle_error("open"); + + fprintf(stderr, "Starting remap: 0x%p\n", mmap_addr); + + int res = munmap(mmap_addr, FILESZ); + if (res) + handle_error("munmap"); + + void* new_map = mmap(mmap_addr, FILESZ, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, 0); + if (new_map == MAP_FAILED) + handle_error("mmap private"); + + fprintf(stderr, "Ending remap: 0x%p\n", new_map); + + assert(new_map == mmap_addr); + + close(fd); +} + +int map_memory(int idx, int respawned) { static char template[] = "/tmp/myfileXXXXXX"; int res; + g_idx = idx; + allow_mmap_in_core(); #if 0 @@ -43,7 +80,7 @@ int map_memory(int idx) #endif char fname[PATH_MAX]; - snprintf(fname, sizeof(fname), "/tmp/mmaped_file_%d", idx); + fill_filename(fname, sizeof(fname), idx); int fd = open(fname, O_CREAT | O_RDWR, S_IWUSR | S_IRUSR); if (fd < 0) handle_error("open"); @@ -52,7 +89,7 @@ int map_memory(int idx) if (res) handle_error("ftruncate"); -#if 0 +#if 1 res = posix_fallocate(fd, 0, FILESZ); if (res) handle_error("posix_fallocate"); @@ -64,6 +101,11 @@ int map_memory(int idx) close(fd); + if (!respawned) + memset(mmap_addr, 'S', FILESZ); + else + memset(mmap_addr, 'E', FILESZ); + return 0; } diff --git a/mmaper.h b/mmaper.h index 05c4f92..032520b 100644 --- a/mmaper.h +++ b/mmaper.h @@ -1,3 +1,11 @@ #pragma once -extern "C" int map_memory(int idx); +#ifdef __cplusplus +#define EXTERN extern "C" +#else +#define EXTERN +#endif + +EXTERN int map_memory(int idx, int respawned); +EXTERN void map_remap_private(int idx); +