2016-02-22 16:49:43 -08:00
|
|
|
#include <assert.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <signal.h>
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
|
#include <stdlib.h>
|
2016-03-07 14:52:10 -08:00
|
|
|
#include <sys/socket.h>
|
2016-03-07 15:19:00 -08:00
|
|
|
#include <sys/stat.h>
|
2016-03-07 14:52:10 -08:00
|
|
|
#include <sys/types.h>
|
2016-02-22 16:49:43 -08:00
|
|
|
#include <unistd.h>
|
|
|
|
|
|
2016-03-05 22:54:26 -08:00
|
|
|
#include "log.h"
|
2016-02-22 21:53:25 -08:00
|
|
|
#include "server.h"
|
2016-02-22 16:49:43 -08:00
|
|
|
#include "wakeup.h"
|
|
|
|
|
|
|
|
|
|
#include "peer.h"
|
|
|
|
|
|
2016-03-07 17:02:24 -08:00
|
|
|
static char log_module = 'X';
|
|
|
|
|
|
2016-03-02 22:10:55 -08:00
|
|
|
uint32_t peer_count_in = 0, peer_count_out = 0, peer_count_out_in = 0;
|
2016-02-25 16:17:25 -08:00
|
|
|
|
2016-02-22 16:49:43 -08:00
|
|
|
static int peer_epoll_fd;
|
2016-02-24 20:15:09 -08:00
|
|
|
static int peer_shutdown_fd;
|
|
|
|
|
static bool peer_shutdown_flag = false;
|
2016-02-26 11:12:45 -08:00
|
|
|
static struct list_head peer_always_trigger_head = LIST_HEAD_INIT(peer_always_trigger_head);
|
2016-02-22 16:49:43 -08:00
|
|
|
|
2016-02-24 20:15:09 -08:00
|
|
|
static void peer_shutdown_handler(struct peer *peer) {
|
2016-03-07 17:02:24 -08:00
|
|
|
LOG(server_id, "Shutting down");
|
2016-02-22 16:49:43 -08:00
|
|
|
assert(!close(peer->fd));
|
|
|
|
|
free(peer);
|
2016-02-24 20:15:09 -08:00
|
|
|
peer_shutdown_flag = true;
|
2016-02-22 16:49:43 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void peer_init() {
|
2016-02-23 22:24:03 -08:00
|
|
|
peer_epoll_fd = epoll_create1(EPOLL_CLOEXEC);
|
2016-02-22 16:49:43 -08:00
|
|
|
assert(peer_epoll_fd >= 0);
|
|
|
|
|
|
2016-02-24 20:15:09 -08:00
|
|
|
int shutdown_fds[2];
|
2016-03-07 14:52:10 -08:00
|
|
|
assert(!socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, shutdown_fds));
|
2016-02-22 16:49:43 -08:00
|
|
|
|
2016-02-24 20:15:09 -08:00
|
|
|
struct peer *shutdown_peer = malloc(sizeof(*shutdown_peer));
|
|
|
|
|
assert(shutdown_peer);
|
|
|
|
|
shutdown_peer->fd = shutdown_fds[0];
|
|
|
|
|
shutdown_peer->event_handler = peer_shutdown_handler;
|
|
|
|
|
peer_epoll_add(shutdown_peer, EPOLLRDHUP);
|
2016-02-22 16:49:43 -08:00
|
|
|
|
2016-02-24 20:15:09 -08:00
|
|
|
peer_shutdown_fd = shutdown_fds[1];
|
|
|
|
|
signal(SIGINT, peer_shutdown);
|
2016-03-04 13:02:43 -08:00
|
|
|
signal(SIGTERM, peer_shutdown);
|
2016-02-22 16:49:43 -08:00
|
|
|
}
|
|
|
|
|
|
2016-02-23 13:49:23 -08:00
|
|
|
void peer_cleanup() {
|
|
|
|
|
assert(!close(peer_epoll_fd));
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-25 23:37:37 -08:00
|
|
|
void peer_shutdown(int __attribute__((unused)) signal) {
|
2016-02-26 14:31:35 -08:00
|
|
|
if (peer_shutdown_fd != -1) {
|
|
|
|
|
assert(!close(peer_shutdown_fd));
|
|
|
|
|
peer_shutdown_fd = -1;
|
|
|
|
|
}
|
2016-02-24 20:15:09 -08:00
|
|
|
}
|
|
|
|
|
|
2016-02-22 16:49:43 -08:00
|
|
|
void peer_epoll_add(struct peer *peer, uint32_t events) {
|
|
|
|
|
struct epoll_event ev = {
|
|
|
|
|
.events = events,
|
|
|
|
|
.data = {
|
|
|
|
|
.ptr = peer,
|
|
|
|
|
},
|
|
|
|
|
};
|
2016-02-26 11:12:45 -08:00
|
|
|
peer->always_trigger = false;
|
|
|
|
|
int res = epoll_ctl(peer_epoll_fd, EPOLL_CTL_ADD, peer->fd, &ev);
|
|
|
|
|
if (res == -1 && errno == EPERM) {
|
|
|
|
|
// Not a socket
|
|
|
|
|
if (events) {
|
|
|
|
|
list_add(&peer->peer_always_trigger_list, &peer_always_trigger_head);
|
|
|
|
|
peer->always_trigger = true;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
assert(!res);
|
|
|
|
|
}
|
2016-02-22 16:49:43 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void peer_epoll_del(struct peer *peer) {
|
2016-02-26 11:12:45 -08:00
|
|
|
int res = epoll_ctl(peer_epoll_fd, EPOLL_CTL_DEL, peer->fd, NULL);
|
|
|
|
|
if (res == -1 && errno == EPERM) {
|
|
|
|
|
if (peer->always_trigger) {
|
|
|
|
|
list_del(&peer->peer_always_trigger_list);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
assert(!res);
|
|
|
|
|
}
|
2016-02-22 16:49:43 -08:00
|
|
|
}
|
|
|
|
|
|
2016-02-24 20:15:09 -08:00
|
|
|
void peer_call(struct peer *peer) {
|
|
|
|
|
if (peer_shutdown_flag || !peer) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
peer->event_handler(peer);
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-22 16:49:43 -08:00
|
|
|
void peer_loop() {
|
2016-03-07 17:02:24 -08:00
|
|
|
LOG(server_id, "Starting event loop");
|
2016-02-24 20:15:09 -08:00
|
|
|
while (!peer_shutdown_flag) {
|
2016-03-02 22:10:55 -08:00
|
|
|
if (!(peer_count_in + peer_count_out_in)) {
|
2016-03-07 17:02:24 -08:00
|
|
|
LOG(server_id, "No remaining inputs");
|
2016-02-25 16:33:58 -08:00
|
|
|
peer_shutdown(0);
|
2016-03-02 22:10:55 -08:00
|
|
|
} else if (!(peer_count_out + peer_count_out_in)) {
|
2016-03-07 17:02:24 -08:00
|
|
|
LOG(server_id, "No remaining outputs");
|
2016-02-25 16:33:58 -08:00
|
|
|
peer_shutdown(0);
|
|
|
|
|
}
|
2016-02-22 16:49:43 -08:00
|
|
|
#define MAX_EVENTS 10
|
|
|
|
|
struct epoll_event events[MAX_EVENTS];
|
2016-02-26 11:12:45 -08:00
|
|
|
int delay = list_is_empty(&peer_always_trigger_head) ? wakeup_get_delay() : 0;
|
|
|
|
|
int nfds = epoll_wait(peer_epoll_fd, events, MAX_EVENTS, delay);
|
2016-02-22 16:49:43 -08:00
|
|
|
if (nfds == -1 && errno == EINTR) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
assert(nfds >= 0);
|
|
|
|
|
|
|
|
|
|
for (int n = 0; n < nfds; n++) {
|
|
|
|
|
struct peer *peer = events[n].data.ptr;
|
2016-02-26 11:12:45 -08:00
|
|
|
peer_call(peer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
struct peer *iter, *next;
|
|
|
|
|
list_for_each_entry_safe(iter, next, &peer_always_trigger_head, peer_always_trigger_list) {
|
|
|
|
|
peer_call(iter);
|
|
|
|
|
}
|
2016-02-22 16:49:43 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wakeup_dispatch();
|
|
|
|
|
}
|
|
|
|
|
}
|