mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-26 10:03:40 +03:00
add simple event loop
This commit is contained in:
parent
476fe607ec
commit
9152c76506
@ -18,7 +18,8 @@ typedef struct ExecContext ExecContext;
|
||||
struct ExecStatus {
|
||||
pid_t pid;
|
||||
time_t timestamp;
|
||||
int status; /* as in wait() */
|
||||
int code; /* as in siginfo_t::si_code */
|
||||
int status; /* as in sigingo_t::si_status */
|
||||
};
|
||||
|
||||
struct ExecCommand {
|
||||
|
2
main.c
2
main.c
@ -44,6 +44,8 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
manager_run_jobs(m);
|
||||
|
||||
manager_loop(m);
|
||||
|
||||
retval = 0;
|
||||
|
||||
finish:
|
||||
|
128
manager.c
128
manager.c
@ -3,6 +3,12 @@
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <signal.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/poll.h>
|
||||
|
||||
#include "manager.h"
|
||||
#include "hashmap.h"
|
||||
@ -12,10 +18,14 @@
|
||||
|
||||
Manager* manager_new(void) {
|
||||
Manager *m;
|
||||
sigset_t mask;
|
||||
struct epoll_event ev;
|
||||
|
||||
if (!(m = new0(Manager, 1)))
|
||||
return NULL;
|
||||
|
||||
m->signal_fd = m->epoll_fd = -1;
|
||||
|
||||
if (!(m->names = hashmap_new(string_hash_func, string_compare_func)))
|
||||
goto fail;
|
||||
|
||||
@ -25,6 +35,26 @@ Manager* manager_new(void) {
|
||||
if (!(m->transaction_jobs = hashmap_new(trivial_hash_func, trivial_compare_func)))
|
||||
goto fail;
|
||||
|
||||
if (!(m->watch_pids = hashmap_new(trivial_hash_func, trivial_compare_func)))
|
||||
goto fail;
|
||||
|
||||
if ((m->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0)
|
||||
goto fail;
|
||||
|
||||
assert_se(sigemptyset(&mask) == 0);
|
||||
assert_se(sigaddset(&mask, SIGCHLD) == 0);
|
||||
assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
|
||||
|
||||
if ((m->signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0)
|
||||
goto fail;
|
||||
|
||||
zero(ev);
|
||||
ev.events = EPOLLIN;
|
||||
ev.data.fd = m->signal_fd;
|
||||
|
||||
if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->signal_fd, &ev) < 0)
|
||||
goto fail;
|
||||
|
||||
return m;
|
||||
|
||||
fail:
|
||||
@ -47,6 +77,12 @@ void manager_free(Manager *m) {
|
||||
hashmap_free(m->names);
|
||||
hashmap_free(m->jobs);
|
||||
hashmap_free(m->transaction_jobs);
|
||||
hashmap_free(m->watch_pids);
|
||||
|
||||
if (m->epoll_fd >= 0)
|
||||
close_nointr(m->epoll_fd);
|
||||
if (m->signal_fd >= 0)
|
||||
close_nointr(m->signal_fd);
|
||||
|
||||
free(m);
|
||||
}
|
||||
@ -890,5 +926,97 @@ void manager_run_jobs(Manager *m) {
|
||||
|
||||
HASHMAP_FOREACH(j, m->jobs, state) {
|
||||
r = job_run_and_invalidate(j);
|
||||
|
||||
/* FIXME... the list of jobs might have changed */
|
||||
}
|
||||
}
|
||||
|
||||
int manager_dispatch_sigchld(Manager *m) {
|
||||
assert(m);
|
||||
|
||||
for (;;) {
|
||||
siginfo_t si;
|
||||
Name *n;
|
||||
|
||||
zero(si);
|
||||
if (waitid(P_ALL, 0, &si, WNOHANG) < 0)
|
||||
return -errno;
|
||||
|
||||
if (si.si_pid == 0)
|
||||
break;
|
||||
|
||||
if (!(n = hashmap_remove(m->watch_pids, UINT32_TO_PTR(si.si_pid))))
|
||||
continue;
|
||||
|
||||
NAME_VTABLE(n)->sigchld_event(n, si.si_pid, si.si_code, si.si_status);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int manager_process_signal_fd(Manager *m) {
|
||||
ssize_t n;
|
||||
struct signalfd_siginfo sfsi;
|
||||
bool sigchld = false;
|
||||
|
||||
assert(m);
|
||||
|
||||
for (;;) {
|
||||
if ((n = read(m->signal_fd, &sfsi, sizeof(sfsi))) != sizeof(sfsi)) {
|
||||
|
||||
if (n >= 0)
|
||||
return -EIO;
|
||||
|
||||
if (errno == EAGAIN)
|
||||
return 0;
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (sfsi.ssi_signo == SIGCHLD)
|
||||
sigchld = true;
|
||||
}
|
||||
|
||||
if (sigchld)
|
||||
manager_dispatch_sigchld(m);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int manager_loop(Manager *m) {
|
||||
int r;
|
||||
struct epoll_event events[32];
|
||||
|
||||
assert(m);
|
||||
|
||||
for (;;) {
|
||||
int n, i;
|
||||
|
||||
if ((n = epoll_wait(m->epoll_fd, events, ELEMENTSOF(events), -1)) < 0) {
|
||||
|
||||
if (errno == -EINTR)
|
||||
continue;
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
|
||||
if (events[i].data.fd == m->signal_fd) {
|
||||
|
||||
/* An incoming signal? */
|
||||
if (events[i].events != POLLIN)
|
||||
return -EINVAL;
|
||||
|
||||
if ((r = manager_process_signal_fd(m)) < 0)
|
||||
return -r;
|
||||
} else {
|
||||
Name *n;
|
||||
|
||||
/* Some other fd event, to be dispatched to the names */
|
||||
assert_se(n = events[i].data.ptr);
|
||||
NAME_VTABLE(n)->fd_event(n, events[i].data.fd, events[i].events);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,10 @@ struct Manager {
|
||||
|
||||
bool dispatching_load_queue:1;
|
||||
|
||||
Hashmap *pids; /* pid => Name object n:1 */
|
||||
Hashmap *watch_pids; /* pid => Name object n:1 */
|
||||
|
||||
int epoll_fd;
|
||||
int signal_fd;
|
||||
};
|
||||
|
||||
Manager* manager_new(void);
|
||||
@ -55,5 +58,6 @@ void manager_transaction_unlink_job(Manager *m, Job *j);
|
||||
void manager_clear_jobs(Manager *m);
|
||||
|
||||
void manager_run_jobs(Manager *m);
|
||||
int manager_loop(Manager *m);
|
||||
|
||||
#endif
|
||||
|
43
name.c
43
name.c
@ -3,6 +3,7 @@
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
#include "set.h"
|
||||
#include "name.h"
|
||||
@ -11,7 +12,7 @@
|
||||
#include "load-fragment.h"
|
||||
#include "load-dropin.h"
|
||||
|
||||
static const NameVTable * const name_vtable[_NAME_TYPE_MAX] = {
|
||||
const NameVTable * const name_vtable[_NAME_TYPE_MAX] = {
|
||||
[NAME_SERVICE] = &service_vtable,
|
||||
[NAME_TIMER] = &timer_vtable,
|
||||
[NAME_SOCKET] = &socket_vtable,
|
||||
@ -22,8 +23,6 @@ static const NameVTable * const name_vtable[_NAME_TYPE_MAX] = {
|
||||
[NAME_SNAPSHOT] = &snapshot_vtable
|
||||
};
|
||||
|
||||
#define NAME_VTABLE(n) name_vtable[(n)->meta.type]
|
||||
|
||||
NameType name_type_from_string(const char *n) {
|
||||
NameType t;
|
||||
|
||||
@ -700,3 +699,41 @@ void name_notify(Name *n, NameActiveState os, NameActiveState ns) {
|
||||
else if (NAME_IS_ACTIVE_OR_ACTIVATING(os) && NAME_IS_INACTIVE_OR_DEACTIVATING(ns))
|
||||
retroactively_stop_dependencies(n);
|
||||
}
|
||||
|
||||
int name_watch_fd(Name *n, int fd, uint32_t events) {
|
||||
struct epoll_event ev;
|
||||
|
||||
assert(n);
|
||||
assert(fd >= 0);
|
||||
|
||||
zero(ev);
|
||||
ev.data.fd = fd;
|
||||
ev.data.ptr = n;
|
||||
ev.events = events;
|
||||
|
||||
if (epoll_ctl(n->meta.manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void name_unwatch_fd(Name *n, int fd) {
|
||||
assert(n);
|
||||
assert(fd >= 0);
|
||||
|
||||
assert_se(epoll_ctl(n->meta.manager->epoll_fd, EPOLL_CTL_DEL, fd, NULL) >= 0 || errno == ENOENT);
|
||||
}
|
||||
|
||||
int name_watch_pid(Name *n, pid_t pid) {
|
||||
assert(n);
|
||||
assert(pid >= 1);
|
||||
|
||||
return hashmap_put(n->meta.manager->watch_pids, UINT32_TO_PTR(pid), n);
|
||||
}
|
||||
|
||||
void name_unwatch_pid(Name *n, pid_t pid) {
|
||||
assert(n);
|
||||
assert(pid >= 1);
|
||||
|
||||
hashmap_remove(n->meta.manager->watch_pids, UINT32_TO_PTR(pid));
|
||||
}
|
||||
|
13
name.h
13
name.h
@ -140,9 +140,16 @@ struct NameVTable {
|
||||
* a simpler one that the engine can understand */
|
||||
NameActiveState (*active_state)(Name *n);
|
||||
|
||||
void (*fd_event)(Name *n, int fd, uint32_t events);
|
||||
void (*sigchld_event)(Name *n, pid_t pid, int code, int status);
|
||||
|
||||
void (*free_hook)(Name *n);
|
||||
};
|
||||
|
||||
extern const NameVTable * const name_vtable[_NAME_TYPE_MAX];
|
||||
|
||||
#define NAME_VTABLE(n) name_vtable[(n)->meta.type]
|
||||
|
||||
/* For casting a name into the various name types */
|
||||
#define DEFINE_CAST(UPPERCASE, MixedCase) \
|
||||
static inline MixedCase* UPPERCASE(Name *name) { \
|
||||
@ -191,4 +198,10 @@ int name_reload(Name *n);
|
||||
|
||||
void name_notify(Name *n, NameActiveState os, NameActiveState ns);
|
||||
|
||||
int name_watch_fd(Name *n, int fd, uint32_t events);
|
||||
void name_unwatch_fd(Name *n, int fd);
|
||||
|
||||
int name_watch_pid(Name *n, pid_t pid);
|
||||
void name_unwatch_pid(Name *n, pid_t pid);
|
||||
|
||||
#endif
|
||||
|
@ -21,7 +21,7 @@ int socket_address_parse(SocketAddress *a, const char *s) {
|
||||
assert(a);
|
||||
assert(s);
|
||||
|
||||
memset(a, 0, sizeof(*a));
|
||||
zero(*a);
|
||||
a->type = SOCK_STREAM;
|
||||
|
||||
if (*s == '[') {
|
||||
|
27
socket.c
27
socket.c
@ -5,6 +5,7 @@
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/poll.h>
|
||||
|
||||
#include "name.h"
|
||||
#include "socket.h"
|
||||
@ -124,7 +125,9 @@ static void close_fds(Socket *s) {
|
||||
if (p->fd < 0)
|
||||
continue;
|
||||
|
||||
close_nointr(p->fd);
|
||||
name_unwatch_fd(NAME(s), p->fd);
|
||||
assert_se(close_nointr(p->fd) >= 0);
|
||||
|
||||
p->fd = -1;
|
||||
}
|
||||
}
|
||||
@ -185,6 +188,9 @@ static int socket_start(Name *n) {
|
||||
goto rollback;
|
||||
}
|
||||
}
|
||||
|
||||
if ((r = name_watch_fd(n, p->fd, POLLIN)) < 0)
|
||||
goto rollback;
|
||||
}
|
||||
|
||||
socket_set_state(s, SOCKET_LISTENING);
|
||||
@ -231,6 +237,23 @@ static NameActiveState socket_active_state(Name *n) {
|
||||
return state_table[SOCKET(n)->state];
|
||||
}
|
||||
|
||||
static void socket_fd_event(Name *n, int fd, uint32_t events) {
|
||||
Socket *s = SOCKET(n);
|
||||
|
||||
assert(n);
|
||||
|
||||
if (events != POLLIN)
|
||||
goto fail;
|
||||
|
||||
log_info("POLLIN on %s", name_id(n));
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
close_fds(s);
|
||||
socket_set_state(s, SOCKET_MAINTAINANCE);
|
||||
}
|
||||
|
||||
static void socket_free_hook(Name *n) {
|
||||
SocketExecCommand c;
|
||||
Socket *s = SOCKET(n);
|
||||
@ -268,5 +291,7 @@ const NameVTable socket_vtable = {
|
||||
|
||||
.active_state = socket_active_state,
|
||||
|
||||
.fd_event = socket_fd_event,
|
||||
|
||||
.free_hook = socket_free_hook
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user