aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTiago Cunha <tcunha@gmx.com>2009-11-08 22:40:36 +0000
committerTiago Cunha <tcunha@gmx.com>2009-11-08 22:40:36 +0000
commitdd36982ad51632bc47ce7b73cad0696e85d593c3 (patch)
treeedb86b1ff2689f20522150f2e1fbeb0600f7a58c
parent5ce49941fb8ab4ce65df4ef872028ab89fd855ae (diff)
downloadrtmux-dd36982ad51632bc47ce7b73cad0696e85d593c3.tar.gz
rtmux-dd36982ad51632bc47ce7b73cad0696e85d593c3.tar.bz2
rtmux-dd36982ad51632bc47ce7b73cad0696e85d593c3.zip
Sync OpenBSD patchset 491:
Initial changes to move tmux to libevent. This moves the client-side loops are pretty much fully over to event-based only (tmux.c and client.c) but server-side (server.c and friends) treats libevent as a sort of clever poll, waking up after every event to run various things. Moving the server stuff over to bufferevents and timers and so on will come later.
-rw-r--r--buffer-poll.c12
-rw-r--r--client.c216
-rw-r--r--cmd-kill-server.c4
-rw-r--r--cmd-pipe-pane.c4
-rw-r--r--job.c6
-rw-r--r--server-client.c38
-rw-r--r--server-job.c12
-rw-r--r--server-window.c19
-rw-r--r--server.c574
-rw-r--r--tmux.c303
-rw-r--r--tmux.h29
-rw-r--r--window.c6
12 files changed, 597 insertions, 626 deletions
diff --git a/buffer-poll.c b/buffer-poll.c
index 63b45f47..20ce7b78 100644
--- a/buffer-poll.c
+++ b/buffer-poll.c
@@ -1,4 +1,4 @@
-/* $Id: buffer-poll.c,v 1.18 2009-10-23 17:49:47 tcunha Exp $ */
+/* $Id: buffer-poll.c,v 1.19 2009-11-08 22:40:36 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -19,6 +19,7 @@
#include <sys/types.h>
#include <errno.h>
+#include <event.h>
#include <unistd.h>
#include "tmux.h"
@@ -29,9 +30,7 @@ buffer_poll(int fd, int events, struct buffer *in, struct buffer *out)
{
ssize_t n;
- if (events & (POLLERR|POLLNVAL))
- return (-1);
- if (in != NULL && events & POLLIN) {
+ if (in != NULL && events & EV_READ) {
buffer_ensure(in, BUFSIZ);
n = read(fd, BUFFER_IN(in), BUFFER_FREE(in));
if (n == 0)
@@ -41,9 +40,8 @@ buffer_poll(int fd, int events, struct buffer *in, struct buffer *out)
return (-1);
} else
buffer_add(in, n);
- } else if (events & POLLHUP)
- return (-1);
- if (out != NULL && BUFFER_USED(out) > 0 && events & POLLOUT) {
+ }
+ if (out != NULL && BUFFER_USED(out) > 0 && events & EV_WRITE) {
n = write(fd, BUFFER_OUT(out), BUFFER_USED(out));
if (n == -1) {
if (errno != EINTR && errno != EAGAIN)
diff --git a/client.c b/client.c
index e7eb1981..df40afb3 100644
--- a/client.c
+++ b/client.c
@@ -1,4 +1,4 @@
-/* $Id: client.c,v 1.84 2009-11-02 21:41:16 tcunha Exp $ */
+/* $Id: client.c,v 1.85 2009-11-08 22:40:36 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,6 +24,7 @@
#include <sys/wait.h>
#include <errno.h>
+#include <event.h>
#include <fcntl.h>
#include <pwd.h>
#include <stdlib.h>
@@ -34,13 +35,15 @@
#include "tmux.h"
struct imsgbuf client_ibuf;
+struct event client_event;
const char *client_exitmsg;
-void client_send_identify(int);
-void client_send_environ(void);
-void client_write_server(enum msgtype, void *, size_t);
-int client_dispatch(void);
-void client_suspend(void);
+void client_send_identify(int);
+void client_send_environ(void);
+void client_write_server(enum msgtype, void *, size_t);
+void client_signal(int, short, void *);
+void client_callback(int, short, void *);
+int client_dispatch(void);
struct imsgbuf *
client_init(char *path, int cmdflags, int flags)
@@ -158,76 +161,54 @@ client_write_server(enum msgtype type, void *buf, size_t len)
__dead void
client_main(void)
{
- struct pollfd pfd;
- int n, nfds;
-
- siginit();
+ struct event ev_sigcont, ev_sigterm, ev_sigwinch;
+ struct sigaction sigact;
+ short events;
logfile("client");
+ /* Note: event_init() has already been called. */
+
+ /* Set up signals. */
+ memset(&sigact, 0, sizeof sigact);
+ sigemptyset(&sigact.sa_mask);
+ sigact.sa_flags = SA_RESTART;
+ sigact.sa_handler = SIG_IGN;
+ if (sigaction(SIGINT, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGPIPE, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGUSR1, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGUSR2, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGTSTP, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+
+ signal_set(&ev_sigcont, SIGCONT, client_signal, NULL);
+ signal_add(&ev_sigcont, NULL);
+ signal_set(&ev_sigterm, SIGTERM, client_signal, NULL);
+ signal_add(&ev_sigterm, NULL);
+ signal_set(&ev_sigwinch, SIGWINCH, client_signal, NULL);
+ signal_add(&ev_sigwinch, NULL);
+
/*
* imsg_read in the first client poll loop (before the terminal has
- * been initialiased) may have read messages into the buffer after the
- * MSG_READY switched to here. Process anything outstanding now so poll
- * doesn't hang waiting for messages that have already arrived.
+ * been initialised) may have read messages into the buffer after the
+ * MSG_READY switched to here. Process anything outstanding now to
+ * avoid hanging waiting for messages that have already arrived.
*/
if (client_dispatch() != 0)
goto out;
- for (;;) {
- if (sigterm) {
- client_exitmsg = "terminated";
- client_write_server(MSG_EXITING, NULL, 0);
- }
- if (sigchld) {
- sigchld = 0;
- waitpid(WAIT_ANY, NULL, WNOHANG);
- continue;
- }
- if (sigwinch) {
- sigwinch = 0;
- client_write_server(MSG_RESIZE, NULL, 0);
- continue;
- }
- if (sigcont) {
- sigcont = 0;
- siginit();
- client_write_server(MSG_WAKEUP, NULL, 0);
- continue;
- }
-
- pfd.fd = client_ibuf.fd;
- pfd.events = POLLIN;
- if (client_ibuf.w.queued > 0)
- pfd.events |= POLLOUT;
-
- if ((nfds = poll(&pfd, 1, INFTIM)) == -1) {
- if (errno == EAGAIN || errno == EINTR)
- continue;
- fatal("poll failed");
- }
- if (nfds == 0)
- continue;
-
- if (pfd.revents & (POLLERR|POLLHUP|POLLNVAL))
- fatalx("socket error");
-
- if (pfd.revents & POLLIN) {
- if ((n = imsg_read(&client_ibuf)) == -1 || n == 0) {
- client_exitmsg = "lost server";
- break;
- }
- if (client_dispatch() != 0)
- break;
- }
-
- if (pfd.revents & POLLOUT) {
- if (msgbuf_write(&client_ibuf.w) < 0) {
- client_exitmsg = "lost server";
- break;
- }
- }
- }
+ /* Set up the client-server socket event. */
+ events = EV_READ;
+ if (client_ibuf.w.queued > 0)
+ events |= EV_WRITE;
+ event_set(&client_event, client_ibuf.fd, events, client_callback, NULL);
+ event_add(&client_event, NULL);
+
+ event_dispatch();
out:
/* Print the exit message, if any, and exit. */
@@ -239,12 +220,78 @@ out:
exit(0);
}
+void
+client_signal(int sig, short events, unused void *data)
+{
+ struct sigaction sigact;
+
+ switch (sig) {
+ case SIGTERM:
+ client_exitmsg = "terminated";
+ client_write_server(MSG_EXITING, NULL, 0);
+ break;
+ case SIGWINCH:
+ client_write_server(MSG_RESIZE, NULL, 0);
+ break;
+ case SIGCONT:
+ memset(&sigact, 0, sizeof sigact);
+ sigemptyset(&sigact.sa_mask);
+ sigact.sa_flags = SA_RESTART;
+ sigact.sa_handler = SIG_IGN;
+ if (sigaction(SIGTSTP, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+ client_write_server(MSG_WAKEUP, NULL, 0);
+ break;
+ }
+
+ event_del(&client_event);
+ events = EV_READ;
+ if (client_ibuf.w.queued > 0)
+ events |= EV_WRITE;
+ event_set(&client_event, client_ibuf.fd, events, client_callback, NULL);
+ event_add(&client_event, NULL);
+}
+
+void
+client_callback(unused int fd, short events, unused void *data)
+{
+ int n;
+
+ if (events & EV_READ) {
+ if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
+ goto lost_server;
+ if (client_dispatch() != 0) {
+ event_loopexit(NULL);
+ return;
+ }
+ }
+
+ if (events & EV_WRITE) {
+ if (msgbuf_write(&client_ibuf.w) < 0)
+ goto lost_server;
+ }
+
+ event_del(&client_event);
+ events = EV_READ;
+ if (client_ibuf.w.queued > 0)
+ events |= EV_WRITE;
+ event_set(&client_event, client_ibuf.fd, events, client_callback, NULL);
+ event_add(&client_event, NULL);
+
+ return;
+
+lost_server:
+ client_exitmsg = "lost server";
+ event_loopexit(NULL);
+}
+
int
client_dispatch(void)
{
- struct imsg imsg;
- struct msg_lock_data lockdata;
- ssize_t n, datalen;
+ struct imsg imsg;
+ struct msg_lock_data lockdata;
+ struct sigaction sigact;
+ ssize_t n, datalen;
for (;;) {
if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
@@ -253,6 +300,7 @@ client_dispatch(void)
return (0);
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
+ log_debug("client got %d", imsg.hdr.type);
switch (imsg.hdr.type) {
case MSG_DETACH:
if (datalen != 0)
@@ -285,7 +333,13 @@ client_dispatch(void)
if (datalen != 0)
fatalx("bad MSG_SUSPEND size");
- client_suspend();
+ memset(&sigact, 0, sizeof sigact);
+ sigemptyset(&sigact.sa_mask);
+ sigact.sa_flags = SA_RESTART;
+ sigact.sa_handler = SIG_DFL;
+ if (sigaction(SIGTSTP, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+ kill(getpid(), SIGTSTP);
break;
case MSG_LOCK:
if (datalen != sizeof lockdata)
@@ -303,23 +357,3 @@ client_dispatch(void)
imsg_free(&imsg);
}
}
-
-void
-client_suspend(void)
-{
- struct sigaction act;
-
- memset(&act, 0, sizeof act);
- sigemptyset(&act.sa_mask);
- act.sa_flags = SA_RESTART;
-
- act.sa_handler = SIG_DFL;
- if (sigaction(SIGTSTP, &act, NULL) != 0)
- fatal("sigaction failed");
-
- act.sa_handler = sighandler;
- if (sigaction(SIGCONT, &act, NULL) != 0)
- fatal("sigaction failed");
-
- kill(getpid(), SIGTSTP);
-}
diff --git a/cmd-kill-server.c b/cmd-kill-server.c
index a53718b3..16f559ad 100644
--- a/cmd-kill-server.c
+++ b/cmd-kill-server.c
@@ -1,4 +1,4 @@
-/* $Id: cmd-kill-server.c,v 1.8 2009-07-28 22:12:16 tcunha Exp $ */
+/* $Id: cmd-kill-server.c,v 1.9 2009-11-08 22:40:36 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -43,7 +43,7 @@ const struct cmd_entry cmd_kill_server_entry = {
int
cmd_kill_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx)
{
- sigterm = 1;
+ kill(getpid(), SIGTERM);
return (0);
}
diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c
index 921a304f..3492d083 100644
--- a/cmd-pipe-pane.c
+++ b/cmd-pipe-pane.c
@@ -1,4 +1,4 @@
-/* $Id: cmd-pipe-pane.c,v 1.3 2009-10-23 17:26:40 tcunha Exp $ */
+/* $Id: cmd-pipe-pane.c,v 1.4 2009-11-08 22:40:36 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -87,7 +87,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
case 0:
/* Child process. */
close(pipe_fd[0]);
- sigreset();
+ server_signal_clear();
if (dup2(pipe_fd[1], STDIN_FILENO) == -1)
_exit(1);
diff --git a/job.c b/job.c
index cd263325..3520752b 100644
--- a/job.c
+++ b/job.c
@@ -1,4 +1,4 @@
-/* $Id: job.c,v 1.9 2009-11-02 21:38:26 tcunha Exp $ */
+/* $Id: job.c,v 1.10 2009-11-08 22:40:36 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -86,6 +86,7 @@ job_add(struct jobs *jobs, int flags, struct client *c, const char *cmd,
job->fd = -1;
job->out = buffer_create(BUFSIZ);
+ memset(&job->event, 0, sizeof job->event);
job->callbackfn = callbackfn;
job->freefn = freefn;
@@ -125,6 +126,7 @@ job_free(struct job *job)
close(job->fd);
if (job->out != NULL)
buffer_destroy(job->out);
+ event_del(&job->event);
xfree(job);
}
@@ -146,7 +148,7 @@ job_run(struct job *job)
case -1:
return (-1);
case 0: /* child */
- sigreset();
+ server_signal_clear();
/* XXX environ? */
if (dup2(out[1], STDOUT_FILENO) == -1)
diff --git a/server-client.c b/server-client.c
index 4cfc08a2..dfa4fa3a 100644
--- a/server-client.c
+++ b/server-client.c
@@ -1,4 +1,4 @@
-/* $Id: server-client.c,v 1.12 2009-11-04 22:46:25 tcunha Exp $ */
+/* $Id: server-client.c,v 1.13 2009-11-08 22:40:36 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,6 +18,7 @@
#include <sys/types.h>
+#include <event.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
@@ -133,7 +134,9 @@ server_client_lost(struct client *c)
close(c->ibuf.fd);
imsg_clear(&c->ibuf);
-
+ event_del(&c->event);
+ event_del(&c->tty.event);
+
for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) {
if (ARRAY_ITEM(&dead_clients, i) == NULL) {
ARRAY_SET(&dead_clients, i, c);
@@ -161,25 +164,31 @@ server_client_prepare(void)
events = 0;
if (!(c->flags & CLIENT_BAD))
- events |= POLLIN;
+ events |= EV_READ;
if (c->ibuf.w.queued > 0)
- events |= POLLOUT;
- server_poll_add(c->ibuf.fd, events, server_client_callback, c);
+ events |= EV_WRITE;
+ event_del(&c->event);
+ event_set(&c->event,
+ c->ibuf.fd, events, server_client_callback, c);
+ event_add(&c->event, NULL);
if (c->tty.fd == -1)
continue;
if (c->flags & CLIENT_SUSPENDED || c->session == NULL)
continue;
- events = POLLIN;
+ events = EV_READ;
if (BUFFER_USED(c->tty.out) > 0)
- events |= POLLOUT;
- server_poll_add(c->tty.fd, events, server_client_callback, c);
+ events |= EV_WRITE;
+ event_del(&c->tty.event);
+ event_set(&c->tty.event,
+ c->tty.fd, events, server_client_callback, c);
+ event_add(&c->tty.event, NULL);
}
}
/* Process a single client event. */
void
-server_client_callback(int fd, int events, void *data)
+server_client_callback(int fd, short events, void *data)
{
struct client *c = data;
@@ -187,10 +196,7 @@ server_client_callback(int fd, int events, void *data)
return;
if (fd == c->ibuf.fd) {
- if (events & (POLLERR|POLLNVAL|POLLHUP))
- goto client_lost;
-
- if (events & POLLOUT && msgbuf_write(&c->ibuf.w) < 0)
+ if (events & EV_WRITE && msgbuf_write(&c->ibuf.w) < 0)
goto client_lost;
if (c->flags & CLIENT_BAD) {
@@ -199,7 +205,7 @@ server_client_callback(int fd, int events, void *data)
return;
}
- if (events & POLLIN && server_client_msg_dispatch(c) != 0)
+ if (events & EV_READ && server_client_msg_dispatch(c) != 0)
goto client_lost;
}
@@ -210,7 +216,7 @@ server_client_callback(int fd, int events, void *data)
if (buffer_poll(fd, events, c->tty.in, c->tty.out) != 0)
goto client_lost;
}
-
+
return;
client_lost:
@@ -423,7 +429,7 @@ server_client_check_redraw(struct client *c)
if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) {
if (options_get_number(&s->options, "set-titles"))
server_client_set_title(c);
-
+
if (c->message_string != NULL)
redraw = status_message_redraw(c);
else if (c->prompt_string != NULL)
diff --git a/server-job.c b/server-job.c
index 7417de96..79ee9d50 100644
--- a/server-job.c
+++ b/server-job.c
@@ -1,4 +1,4 @@
-/* $Id: server-job.c,v 1.3 2009-11-02 21:38:26 tcunha Exp $ */
+/* $Id: server-job.c,v 1.4 2009-11-08 22:40:36 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,6 +18,7 @@
#include <sys/types.h>
+#include <event.h>
#include <unistd.h>
#include "tmux.h"
@@ -31,13 +32,16 @@ server_job_prepare(void)
SLIST_FOREACH(job, &all_jobs, lentry) {
if (job->fd == -1)
continue;
- server_poll_add(job->fd, POLLIN, server_job_callback, job);
+ event_del(&job->event);
+ event_set(
+ &job->event, job->fd, EV_READ, server_job_callback, job);
+ event_add(&job->event, NULL);
}
}
/* Process a single job event. */
void
-server_job_callback(int fd, int events, void *data)
+server_job_callback(int fd, short events, void *data)
{
struct job *job = data;
@@ -55,7 +59,7 @@ void
server_job_loop(void)
{
struct job *job;
-
+
restart:
SLIST_FOREACH(job, &all_jobs, lentry) {
if (job->flags & JOB_DONE || job->fd != -1 || job->pid != -1)
diff --git a/server-window.c b/server-window.c
index 9a411cd3..80a20330 100644
--- a/server-window.c
+++ b/server-window.c
@@ -1,4 +1,4 @@
-/* $Id: server-window.c,v 1.4 2009-11-04 22:47:29 tcunha Exp $ */
+/* $Id: server-window.c,v 1.5 2009-11-08 22:40:36 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,6 +18,7 @@
#include <sys/types.h>
+#include <event.h>
#include <unistd.h>
#include "tmux.h"
@@ -47,19 +48,23 @@ server_window_prepare(void)
continue;
events = 0;
if (!server_window_backoff(wp))
- events |= POLLIN;
+ events = EV_READ;
if (BUFFER_USED(wp->out) > 0)
- events |= POLLOUT;
- server_poll_add(
+ events |= EV_WRITE;
+ event_del(&wp->event);
+ event_set(&wp->event,
wp->fd, events, server_window_callback, wp);
+ event_add(&wp->event, NULL);
if (wp->pipe_fd == -1)
continue;
events = 0;
if (BUFFER_USED(wp->pipe_buf) > 0)
- events |= POLLOUT;
- server_poll_add(
+ events |= EV_WRITE;
+ event_del(&wp->pipe_event);
+ event_set(&wp->pipe_event,
wp->pipe_fd, events, server_window_callback, wp);
+ event_add(&wp->pipe_event, NULL);
}
}
}
@@ -90,7 +95,7 @@ server_window_backoff(struct window_pane *wp)
/* Process a single window pane event. */
void
-server_window_callback(int fd, int events, void *data)
+server_window_callback(int fd, short events, void *data)
{
struct window_pane *wp = data;
diff --git a/server.c b/server.c
index 8df12e56..a31603c4 100644
--- a/server.c
+++ b/server.c
@@ -1,4 +1,4 @@
-/* $Id: server.c,v 1.216 2009-11-04 22:42:31 tcunha Exp $ */
+/* $Id: server.c,v 1.217 2009-11-08 22:40:36 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,6 +24,7 @@
#include <sys/wait.h>
#include <errno.h>
+#include <event.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
@@ -44,112 +45,28 @@
struct clients clients;
struct clients dead_clients;
-/* Mapping of a pollfd to an fd independent of its position in the array. */
-struct poll_item {
- int fd;
- int events;
-
- void (*fn)(int, int, void *);
- void *data;
-
- RB_ENTRY(poll_item) entry;
-};
-RB_HEAD(poll_items, poll_item) poll_items;
-
-int server_poll_cmp(struct poll_item *, struct poll_item *);
-struct poll_item*server_poll_lookup(int);
-struct pollfd *server_poll_flatten(int *);
-void server_poll_dispatch(struct pollfd *, int);
-void server_poll_reset(void);
-RB_PROTOTYPE(poll_items, poll_item, entry, server_poll_cmp);
-RB_GENERATE(poll_items, poll_item, entry, server_poll_cmp);
+int server_fd;
+int server_shutdown;
+struct event server_ev_accept;
+struct event server_ev_sigterm;
+struct event server_ev_sigusr1;
+struct event server_ev_sigchld;
+struct event server_ev_second;
int server_create_socket(void);
-void server_callback(int, int, void *);
-int server_main(int);
-void server_shutdown(void);
+void server_loop(void);
int server_should_shutdown(void);
-void server_child_signal(void);
+void server_send_shutdown(void);
void server_clean_dead(void);
-void server_second_timers(void);
+int server_update_socket(void);
+void server_accept_callback(int, short, void *);
+void server_signal_callback(int, short, void *);
+void server_child_signal(void);
+void server_child_exited(pid_t, int);
+void server_child_stopped(pid_t, int);
+void server_second_callback(int, short, void *);
void server_lock_server(void);
void server_lock_sessions(void);
-int server_update_socket(void);
-
-int
-server_poll_cmp(struct poll_item *pitem1, struct poll_item *pitem2)
-{
- return (pitem1->fd - pitem2->fd);
-}
-
-void
-server_poll_add(int fd, int events, void (*fn)(int, int, void *), void *data)
-{
- struct poll_item *pitem;
-
- pitem = xmalloc(sizeof *pitem);
- pitem->fd = fd;
- pitem->events = events;
-
- pitem->fn = fn;
- pitem->data = data;
-
- RB_INSERT(poll_items, &poll_items, pitem);
-}
-
-struct poll_item *
-server_poll_lookup(int fd)
-{
- struct poll_item pitem;
-
- pitem.fd = fd;
- return (RB_FIND(poll_items, &poll_items, &pitem));
-}
-
-struct pollfd *
-server_poll_flatten(int *nfds)
-{
- struct poll_item *pitem;
- struct pollfd *pfds;
-
- pfds = NULL;
- *nfds = 0;
- RB_FOREACH(pitem, poll_items, &poll_items) {
- pfds = xrealloc(pfds, (*nfds) + 1, sizeof *pfds);
- pfds[*nfds].fd = pitem->fd;
- pfds[*nfds].events = pitem->events;
- (*nfds)++;
- }
- return (pfds);
-}
-
-void
-server_poll_dispatch(struct pollfd *pfds, int nfds)
-{
- struct poll_item *pitem;
- struct pollfd *pfd;
-
- while (nfds > 0) {
- pfd = &pfds[--nfds];
- if (pfd->revents != 0) {
- pitem = server_poll_lookup(pfd->fd);
- pitem->fn(pitem->fd, pfd->revents, pitem->data);
- }
- }
- xfree(pfds);
-}
-
-void
-server_poll_reset(void)
-{
- struct poll_item *pitem;
-
- while (!RB_EMPTY(&poll_items)) {
- pitem = RB_ROOT(&poll_items);
- RB_REMOVE(poll_items, &poll_items, pitem);
- xfree(pitem);
- }
-}
/* Create server socket. */
int
@@ -190,39 +107,14 @@ server_create_socket(void)
return (fd);
}
-/* Callback for server socket. */
-void
-server_callback(int fd, int events, unused void *data)
-{
- struct sockaddr_storage sa;
- socklen_t slen = sizeof sa;
- int newfd;
-
- if (events & (POLLERR|POLLNVAL|POLLHUP))
- fatalx("lost server socket");
- if (!(events & POLLIN))
- return;
-
- newfd = accept(fd, (struct sockaddr *) &sa, &slen);
- if (newfd == -1) {
- if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED)
- return;
- fatal("accept failed");
- }
- if (sigterm) {
- close(newfd);
- return;
- }
- server_client_create(newfd);
-}
-
/* Fork new server. */
int
server_start(char *path)
{
struct client *c;
- int pair[2], srv_fd;
+ int pair[2];
char *cause;
+ struct timeval tv;
#ifdef HAVE_SETPROCTITLE
char rpathbuf[MAXPATHLEN];
#endif
@@ -272,7 +164,7 @@ server_start(char *path)
setproctitle("server (%s)", rpathbuf);
#endif
- srv_fd = server_create_socket();
+ server_fd = server_create_socket();
server_client_create(pair[1]);
if (access(SYSTEM_CFG, R_OK) == 0) {
@@ -285,7 +177,20 @@ server_start(char *path)
if (cfg_file != NULL && load_cfg(cfg_file, NULL, &cause) != 0)
goto error;
- exit(server_main(srv_fd));
+ event_init();
+
+ event_set(&server_ev_accept,
+ server_fd, EV_READ|EV_PERSIST, server_accept_callback, NULL);
+ event_add(&server_ev_accept, NULL);
+
+ memset(&tv, 0, sizeof tv);
+ tv.tv_sec = 1;
+ evtimer_set(&server_ev_second, server_second_callback, NULL);
+ evtimer_add(&server_ev_second, &tv);
+
+ server_signal_set();
+ server_loop();
+ exit(0);
error:
/* Write the error and shutdown the server. */
@@ -294,127 +199,65 @@ error:
server_write_error(c, cause);
xfree(cause);
- sigterm = 1;
- server_shutdown();
+ server_shutdown = 1;
- exit(server_main(srv_fd));
+ server_signal_set();
+ server_loop();
+ exit(1);
}
/* Main server loop. */
-int
-server_main(int srv_fd)
+void
+server_loop(void)
{
- struct pollfd *pfds;
- int nfds, xtimeout;
- u_int i;
- time_t now, last;
-
- siginit();
- log_debug("server socket is %d", srv_fd);
+ struct timeval tv;
- last = time(NULL);
+ memset(&tv, 0, sizeof tv);
+ tv.tv_usec = POLL_TIMEOUT * 1000;
- pfds = NULL;
- for (;;) {
- /* If sigterm, kill all windows and clients. */
- if (sigterm)
- server_shutdown();
+ while (!server_should_shutdown()) {
+ server_update_socket();
- /* Stop if no sessions or clients left. */
- if (server_should_shutdown())
- break;
-
- /* Handle child exit. */
- if (sigchld) {
- sigchld = 0;
- server_child_signal();
- continue;
- }
-
- /* Recreate socket on SIGUSR1. */
- if (sigusr1) {
- sigusr1 = 0;
- close(srv_fd);
- srv_fd = server_create_socket();
- continue;
- }
-
- /* Initialise pollfd array and add server socket. */
- server_poll_reset();
- server_poll_add(srv_fd, POLLIN, server_callback, NULL);
-
- /* Fill window and client sockets. */
server_job_prepare();
server_window_prepare();
server_client_prepare();
-
- /* Update socket permissions. */
- xtimeout = INFTIM;
- if (server_update_socket() != 0)
- xtimeout = POLL_TIMEOUT;
-
- /* Do the poll. */
- pfds = server_poll_flatten(&nfds);
- if (poll(pfds, nfds, xtimeout) == -1) {
- if (errno == EAGAIN || errno == EINTR)
- continue;
- fatal("poll failed");
- }
- server_poll_dispatch(pfds, nfds);
- /* Call second-based timers. */
- now = time(NULL);
- if (now != last) {
- last = now;
- server_second_timers();
- }
+ event_loopexit(&tv);
+ event_loop(EVLOOP_ONCE);
- /* Run once-per-loop events. */
server_job_loop();
server_window_loop();
server_client_loop();
- /* Collect any unset key bindings. */
key_bindings_clean();
-
- /* Collect dead clients and sessions. */
server_clean_dead();
- }
- server_poll_reset();
+ }
+}
+
+/* Check if the server should be shutting down (no more clients or windows). */
+int
+server_should_shutdown(void)
+{
+ u_int i;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
if (ARRAY_ITEM(&sessions, i) != NULL)
- session_destroy(ARRAY_ITEM(&sessions, i));
+ return (0);
}
- ARRAY_FREE(&sessions);
-
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
if (ARRAY_ITEM(&clients, i) != NULL)
- server_client_lost(ARRAY_ITEM(&clients, i));
+ return (0);
}
- ARRAY_FREE(&clients);
-
- mode_key_free_trees();
- key_bindings_free();
-
- close(srv_fd);
-
- unlink(socket_path);
- xfree(socket_path);
-
- options_free(&global_s_options);
- options_free(&global_w_options);
-
- return (0);
+ return (1);
}
-/* Kill all clients. */
+/* Shutdown the server by killing all clients and windows. */
void
-server_shutdown(void)
+server_send_shutdown(void)
{
- struct session *s;
struct client *c;
- u_int i, j;
+ struct session *s;
+ u_int i;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
@@ -423,50 +266,175 @@ server_shutdown(void)
server_client_lost(c);
else
server_write_client(c, MSG_SHUTDOWN, NULL, 0);
+ c->session = NULL;
}
}
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
- s = ARRAY_ITEM(&sessions, i);
- for (j = 0; j < ARRAY_LENGTH(&clients); j++) {
- c = ARRAY_ITEM(&clients, j);
- if (c != NULL && c->session == s) {
- s = NULL;
- break;
- }
- }
- if (s != NULL)
+ if ((s = ARRAY_ITEM(&sessions, i)) != NULL)
session_destroy(s);
}
}
-/* Check if the server should be shutting down (no more clients or windows). */
+/* Free dead, unreferenced clients and sessions. */
+void
+server_clean_dead(void)
+{
+ struct session *s;
+ struct client *c;
+ u_int i;
+
+ for (i = 0; i < ARRAY_LENGTH(&dead_sessions); i++) {
+ s = ARRAY_ITEM(&dead_sessions, i);
+ if (s == NULL || s->references != 0)
+ continue;
+ ARRAY_SET(&dead_sessions, i, NULL);
+ xfree(s);
+ }
+
+ for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) {
+ c = ARRAY_ITEM(&dead_clients, i);
+ if (c == NULL || c->references != 0)
+ continue;
+ ARRAY_SET(&dead_clients, i, NULL);
+ xfree(c);
+ }
+}
+
+/* Update socket execute permissions based on whether sessions are attached. */
int
-server_should_shutdown(void)
+server_update_socket(void)
{
- u_int i;
+ struct session *s;
+ u_int i;
+ static int last = -1;
+ int n;
+ n = 0;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
- if (ARRAY_ITEM(&sessions, i) != NULL)
- return (0);
+ s = ARRAY_ITEM(&sessions, i);
+ if (s != NULL && !(s->flags & SESSION_UNATTACHED)) {
+ n++;
+ break;
+ }
}
- for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
- if (ARRAY_ITEM(&clients, i) != NULL)
- return (0);
+
+ if (n != last) {
+ last = n;
+ if (n != 0)
+ chmod(socket_path, S_IRWXU);
+ else
+ chmod(socket_path, S_IRUSR|S_IWUSR);
+ }
+
+ return (n);
+}
+
+/* Callback for server socket. */
+void
+server_accept_callback(int fd, short events, unused void *data)
+{
+ struct sockaddr_storage sa;
+ socklen_t slen = sizeof sa;
+ int newfd;
+
+ if (!(events & EV_READ))
+ return;
+
+ newfd = accept(fd, (struct sockaddr *) &sa, &slen);
+ if (newfd == -1) {
+ if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED)
+ return;
+ fatal("accept failed");
+ }
+ if (server_shutdown) {
+ close(newfd);
+ return;
+ }
+ server_client_create(newfd);
+
+}
+
+/* Set up server signal handling. */
+void
+server_signal_set(void)
+{
+ struct sigaction sigact;
+
+ memset(&sigact, 0, sizeof sigact);
+ sigemptyset(&sigact.sa_mask);
+ sigact.sa_flags = SA_RESTART;
+ sigact.sa_handler = SIG_IGN;
+ if (sigaction(SIGINT, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGPIPE, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGUSR2, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGTSTP, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+
+ signal_set(&server_ev_sigchld, SIGCHLD, server_signal_callback, NULL);
+ signal_add(&server_ev_sigchld, NULL);
+ signal_set(&server_ev_sigterm, SIGTERM, server_signal_callback, NULL);
+ signal_add(&server_ev_sigterm, NULL);
+ signal_set(&server_ev_sigusr1, SIGUSR1, server_signal_callback, NULL);
+ signal_add(&server_ev_sigusr1, NULL);
+}
+
+/* Destroy server signal events. */
+void
+server_signal_clear(void)
+{
+ struct sigaction sigact;
+
+ memset(&sigact, 0, sizeof sigact);
+ sigemptyset(&sigact.sa_mask);
+ sigact.sa_flags = SA_RESTART;
+ sigact.sa_handler = SIG_DFL;
+ if (sigaction(SIGINT, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGPIPE, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGUSR2, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGTSTP, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+
+ signal_del(&server_ev_sigchld);
+ signal_del(&server_ev_sigterm);
+ signal_del(&server_ev_sigusr1);
+}
+
+/* Signal handler. */
+void
+server_signal_callback(int sig, unused short events, unused void *data)
+{
+ switch (sig) {
+ case SIGTERM:
+ server_shutdown = 1;
+ server_send_shutdown();
+ break;
+ case SIGCHLD:
+ server_child_signal();
+ break;
+ case SIGUSR1:
+ event_del(&server_ev_accept);
+ close(server_fd);
+ server_fd = server_create_socket();
+ event_set(&server_ev_accept, server_fd,
+ EV_READ|EV_PERSIST, server_accept_callback, NULL);
+ event_add(&server_ev_accept, NULL);
+ break;
}
- return (1);
}
/* Handle SIGCHLD. */
void
server_child_signal(void)
{
- struct window *w;
- struct window_pane *wp;
- struct job *job;
- int status;
- pid_t pid;
- u_int i;
+ int status;
+ pid_t pid;
for (;;) {
switch (pid = waitpid(WAIT_ANY, &status, WNOHANG|WUNTRACED)) {
@@ -477,63 +445,71 @@ server_child_signal(void)
case 0:
return;
}
- if (!WIFSTOPPED(status)) {
- SLIST_FOREACH(job, &all_jobs, lentry) {
- if (pid == job->pid) {
- job->pid = -1;
- job->status = status;
- }
- }
+ if (WIFSTOPPED(status))
+ server_child_stopped(pid, status);
+ else if (WIFEXITED(status))
+ server_child_exited(pid, status);
+ }
+}
+
+/* Handle exited children. */
+void
+server_child_exited(pid_t pid, int status)
+{
+ struct window *w;
+ struct window_pane *wp;
+ struct job *job;
+ u_int i;
+
+ for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
+ if ((w = ARRAY_ITEM(&windows, i)) == NULL)
continue;
+ TAILQ_FOREACH(wp, &w->panes, entry) {
+ if (wp->pid == pid) {
+ close(wp->fd);
+ wp->fd = -1;
+ }
}
- if (WSTOPSIG(status) == SIGTTIN || WSTOPSIG(status) == SIGTTOU)
- continue;
+ }
- for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
- w = ARRAY_ITEM(&windows, i);
- if (w == NULL)
- continue;
- TAILQ_FOREACH(wp, &w->panes, entry) {
- if (wp->pid == pid) {
- if (killpg(pid, SIGCONT) != 0)
- kill(pid, SIGCONT);
- }
- }
+ SLIST_FOREACH(job, &all_jobs, lentry) {
+ if (pid == job->pid) {
+ job->pid = -1;
+ job->status = status;
}
}
}
-/* Free dead, unreferenced clients and sessions. */
+/* Handle stopped children. */
void
-server_clean_dead(void)
+server_child_stopped(pid_t pid, int status)
{
- struct session *s;
- struct client *c;
- u_int i;
+ struct window *w;
+ struct window_pane *wp;
+ u_int i;
- for (i = 0; i < ARRAY_LENGTH(&dead_sessions); i++) {
- s = ARRAY_ITEM(&dead_sessions, i);
- if (s == NULL || s->references != 0)
- continue;
- ARRAY_SET(&dead_sessions, i, NULL);
- xfree(s);
- }
+ if (WSTOPSIG(status) == SIGTTIN || WSTOPSIG(status) == SIGTTOU)
+ return;
- for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) {
- c = ARRAY_ITEM(&dead_clients, i);
- if (c == NULL || c->references != 0)
+ for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
+ if ((w = ARRAY_ITEM(&windows, i)) == NULL)
continue;
- ARRAY_SET(&dead_clients, i, NULL);
- xfree(c);
+ TAILQ_FOREACH(wp, &w->panes, entry) {
+ if (wp->pid == pid) {
+ if (killpg(pid, SIGCONT) != 0)
+ kill(pid, SIGCONT);
+ }
+ }
}
}
-/* Call any once-per-second timers. */
+/* Handle once-per-second timer events. */
void
-server_second_timers(void)
+server_second_callback(unused int fd, unused short events, unused void *arg)
{
struct window *w;
struct window_pane *wp;
+ struct timeval tv;
u_int i;
if (options_get_number(&global_s_options, "lock-server"))
@@ -551,6 +527,11 @@ server_second_timers(void)
wp->mode->timer(wp);
}
}
+
+ evtimer_del(&server_ev_second);
+ memset(&tv, 0, sizeof tv);
+ tv.tv_sec = 1;
+ evtimer_add(&server_ev_second, &tv);
}
/* Lock the server if ALL sessions have hit the time limit. */
@@ -609,32 +590,3 @@ server_lock_sessions(void)
}
}
}
-
-/* Update socket execute permissions based on whether sessions are attached. */
-int
-server_update_socket(void)
-{
- struct session *s;
- u_int i;
- static int last = -1;
- int n;
-
- n = 0;
- for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
- s = ARRAY_ITEM(&sessions, i);
- if (s != NULL && !(s->flags & SESSION_UNATTACHED)) {
- n++;
- break;
- }
- }
-
- if (n != last) {
- last = n;
- if (n != 0)
- chmod(socket_path, S_IRWXU);
- else
- chmod(socket_path, S_IRUSR|S_IWUSR);
- }
-
- return (n);
-}
diff --git a/tmux.c b/tmux.c
index 075ee788..6ef45dea 100644
--- a/tmux.c
+++ b/tmux.c
@@ -1,4 +1,4 @@
-/* $Id: tmux.c,v 1.184 2009-11-04 23:09:09 tcunha Exp $ */
+/* $Id: tmux.c,v 1.185 2009-11-08 22:40:36 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -20,6 +20,7 @@
#include <sys/stat.h>
#include <errno.h>
+#include <event.h>
#include <pwd.h>
#include <signal.h>
#include <stdlib.h>
@@ -33,13 +34,6 @@
extern char *malloc_options;
#endif
-volatile sig_atomic_t sigwinch;
-volatile sig_atomic_t sigterm;
-volatile sig_atomic_t sigcont;
-volatile sig_atomic_t sigchld;
-volatile sig_atomic_t sigusr1;
-volatile sig_atomic_t sigusr2;
-
char *cfg_file;
struct options global_s_options; /* session options */
struct options global_w_options; /* window options */
@@ -54,9 +48,18 @@ int login_shell;
__dead void usage(void);
void fill_session(struct msg_command_data *);
char *makesockpath(const char *);
-int dispatch_imsg(struct imsgbuf *, const char *, int *);
__dead void shell_exec(const char *, const char *);
+struct imsgbuf *main_ibuf;
+struct event main_ev_sigterm;
+int main_exitval;
+
+void main_set_signals(void);
+void main_clear_signals(void);
+void main_signal(int, short, unused void *);
+void main_callback(int, short, void *);
+void main_dispatch(const char *);
+
#ifndef HAVE_PROGNAME
char *__progname = (char *) "tmux";
#endif
@@ -84,96 +87,6 @@ logfile(const char *name)
}
}
-void
-sighandler(int sig)
-{
- int saved_errno;
-
- saved_errno = errno;
- switch (sig) {
- case SIGWINCH:
- sigwinch = 1;
- break;
- case SIGTERM:
- sigterm = 1;
- break;
- case SIGCHLD:
- sigchld = 1;
- break;
- case SIGCONT:
- sigcont = 1;
- break;
- case SIGUSR1:
- sigusr1 = 1;
- break;
- case SIGUSR2:
- sigusr2 = 1;
- break;
- }
- errno = saved_errno;
-}
-
-void
-siginit(void)
-{
- struct sigaction act;
-
- memset(&act, 0, sizeof act);
- sigemptyset(&act.sa_mask);
- act.sa_flags = SA_RESTART;
-
- act.sa_handler = SIG_IGN;
- if (sigaction(SIGPIPE, &act, NULL) != 0)
- fatal("sigaction failed");
- if (sigaction(SIGINT, &act, NULL) != 0)
- fatal("sigaction failed");
- if (sigaction(SIGTSTP, &act, NULL) != 0)
- fatal("sigaction failed");
- if (sigaction(SIGQUIT, &act, NULL) != 0)
- fatal("sigaction failed");
-
- act.sa_handler = sighandler;
- if (sigaction(SIGWINCH, &act, NULL) != 0)
- fatal("sigaction failed");
- if (sigaction(SIGTERM, &act, NULL) != 0)
- fatal("sigaction failed");
- if (sigaction(SIGCHLD, &act, NULL) != 0)
- fatal("sigaction failed");
- if (sigaction(SIGUSR1, &act, NULL) != 0)
- fatal("sigaction failed");
- if (sigaction(SIGUSR2, &act, NULL) != 0)
- fatal("sigaction failed");
-}
-
-void
-sigreset(void)
-{
- struct sigaction act;
-
- memset(&act, 0, sizeof act);
- sigemptyset(&act.sa_mask);
-
- act.sa_handler = SIG_DFL;
- if (sigaction(SIGPIPE, &act, NULL) != 0)
- fatal("sigaction failed");
- if (sigaction(SIGUSR1, &act, NULL) != 0)
- fatal("sigaction failed");
- if (sigaction(SIGUSR2, &act, NULL) != 0)
- fatal("sigaction failed");
- if (sigaction(SIGINT, &act, NULL) != 0)
- fatal("sigaction failed");
- if (sigaction(SIGTSTP, &act, NULL) != 0)
- fatal("sigaction failed");
- if (sigaction(SIGQUIT, &act, NULL) != 0)
- fatal("sigaction failed");
- if (sigaction(SIGWINCH, &act, NULL) != 0)
- fatal("sigaction failed");
- if (sigaction(SIGTERM, &act, NULL) != 0)
- fatal("sigaction failed");
- if (sigaction(SIGCHLD, &act, NULL) != 0)
- fatal("sigaction failed");
-}
-
const char *
getshell(void)
{
@@ -284,23 +197,43 @@ makesockpath(const char *label)
return (path);
}
+__dead void
+shell_exec(const char *shell, const char *shellcmd)
+{
+ const char *shellname, *ptr;
+ char *argv0;
+
+ ptr = strrchr(shell, '/');
+ if (ptr != NULL && *(ptr + 1) != '\0')
+ shellname = ptr + 1;
+ else
+ shellname = shell;
+ if (login_shell)
+ xasprintf(&argv0, "-%s", shellname);
+ else
+ xasprintf(&argv0, "%s", shellname);
+ setenv("SHELL", shell, 1);
+
+ execl(shell, argv0, "-c", shellcmd, (char *) NULL);
+ fatal("execl failed");
+}
+
int
main(int argc, char **argv)
{
struct cmd_list *cmdlist;
struct cmd *cmd;
- struct pollfd pfd;
enum msgtype msg;
struct passwd *pw;
struct options *so, *wo;
struct keylist *keylist;
- struct imsgbuf *ibuf;
struct msg_command_data cmddata;
char *s, *shellcmd, *path, *label, *home, *cause;
char cwd[MAXPATHLEN], **var;
void *buf;
size_t len;
- int nfds, retcode, opt, flags, cmdflags = 0;
+ int opt, flags, cmdflags = 0;
+ short events;
#if defined(DEBUG) && defined(__OpenBSD__)
malloc_options = (char *) "AFGJPX";
@@ -362,7 +295,6 @@ main(int argc, char **argv)
usage();
log_open_tty(debug_level);
- siginit();
if (!(flags & IDENTIFY_UTF8)) {
/*
@@ -552,63 +484,121 @@ main(int argc, char **argv)
cmd_list_free(cmdlist);
}
- if ((ibuf = client_init(path, cmdflags, flags)) == NULL)
+ if ((main_ibuf = client_init(path, cmdflags, flags)) == NULL)
exit(1);
xfree(path);
- imsg_compose(ibuf, msg, PROTOCOL_VERSION, -1, -1, buf, len);
+ event_init();
- retcode = 0;
- for (;;) {
- pfd.fd = ibuf->fd;
- pfd.events = POLLIN;
- if (ibuf->w.queued != 0)
- pfd.events |= POLLOUT;
-
- if ((nfds = poll(&pfd, 1, INFTIM)) == -1) {
- if (errno == EAGAIN || errno == EINTR)
- continue;
- fatal("poll failed");
- }
- if (nfds == 0)
- continue;
+ imsg_compose(main_ibuf, msg, PROTOCOL_VERSION, -1, -1, buf, len);
- if (pfd.revents & (POLLERR|POLLHUP|POLLNVAL))
- fatalx("socket error");
+ main_set_signals();
- if (pfd.revents & POLLIN) {
- if (dispatch_imsg(ibuf, shellcmd, &retcode) != 0)
- break;
- }
+ events = EV_READ;
+ if (main_ibuf->w.queued > 0)
+ events |= EV_WRITE;
+ event_once(main_ibuf->fd, events, main_callback, shellcmd, NULL);
- if (pfd.revents & POLLOUT) {
- if (msgbuf_write(&ibuf->w) < 0)
- fatalx("msgbuf_write failed");
- }
+ main_exitval = 0;
+ event_dispatch();
+
+ main_clear_signals();
+
+ client_main(); /* doesn't return */
+}
+
+
+void
+main_set_signals(void)
+{
+ struct sigaction sigact;
+
+ memset(&sigact, 0, sizeof sigact);
+ sigemptyset(&sigact.sa_mask);
+ sigact.sa_flags = SA_RESTART;
+ sigact.sa_handler = SIG_IGN;
+ if (sigaction(SIGINT, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGPIPE, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGUSR1, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGUSR2, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGTSTP, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+
+ signal_set(&main_ev_sigterm, SIGTERM, main_signal, NULL);
+ signal_add(&main_ev_sigterm, NULL);
+}
+
+void
+main_clear_signals(void)
+{
+ struct sigaction sigact;
+
+ memset(&sigact, 0, sizeof sigact);
+ sigemptyset(&sigact.sa_mask);
+ sigact.sa_flags = SA_RESTART;
+ sigact.sa_handler = SIG_DFL;
+ if (sigaction(SIGINT, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGPIPE, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGUSR1, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGUSR2, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGTSTP, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+
+ event_del(&main_ev_sigterm);
+}
+
+void
+main_signal(int sig, unused short events, unused void *data)
+{
+ switch (sig) {
+ case SIGTERM:
+ exit(1);
}
+}
- options_free(&global_s_options);
- options_free(&global_w_options);
+void
+main_callback(unused int fd, short events, void *data)
+{
+ char *shellcmd = data;
- return (retcode);
+ if (events & EV_READ)
+ main_dispatch(shellcmd);
+
+ if (events & EV_WRITE) {
+ if (msgbuf_write(&main_ibuf->w) < 0)
+ fatalx("msgbuf_write failed");
+ }
+
+ events = EV_READ;
+ if (main_ibuf->w.queued > 0)
+ events |= EV_WRITE;
+ event_once(main_ibuf->fd, events, main_callback, shellcmd, NULL);
}
-int
-dispatch_imsg(struct imsgbuf *ibuf, const char *shellcmd, int *retcode)
+void
+main_dispatch(const char *shellcmd)
{
struct imsg imsg;
ssize_t n, datalen;
struct msg_print_data printdata;
struct msg_shell_data shelldata;
- if ((n = imsg_read(ibuf)) == -1 || n == 0)
+ if ((n = imsg_read(main_ibuf)) == -1 || n == 0)
fatalx("imsg_read failed");
for (;;) {
- if ((n = imsg_get(ibuf, &imsg)) == -1)
+ if ((n = imsg_get(main_ibuf, &imsg)) == -1)
fatalx("imsg_get failed");
if (n == 0)
- return (0);
+ return;
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
switch (imsg.hdr.type) {
@@ -617,10 +607,8 @@ dispatch_imsg(struct imsgbuf *ibuf, const char *shellcmd, int *retcode)
if (datalen != 0)
fatalx("bad MSG_EXIT size");
- return (-1);
+ exit(main_exitval);
case MSG_ERROR:
- *retcode = 1;
- /* FALLTHROUGH */
case MSG_PRINT:
if (datalen != sizeof printdata)
fatalx("bad MSG_PRINT size");
@@ -628,26 +616,30 @@ dispatch_imsg(struct imsgbuf *ibuf, const char *shellcmd, int *retcode)
printdata.msg[(sizeof printdata.msg) - 1] = '\0';
log_info("%s", printdata.msg);
+ if (imsg.hdr.type == MSG_ERROR)
+ main_exitval = 1;
break;
case MSG_READY:
if (datalen != 0)
fatalx("bad MSG_READY size");
- client_main(); /* doesn't return */
+ event_loopexit(NULL); /* move to client_main() */
+ break;
case MSG_VERSION:
if (datalen != 0)
fatalx("bad MSG_VERSION size");
log_warnx("protocol version mismatch (client %u, "
"server %u)", PROTOCOL_VERSION, imsg.hdr.peerid);
- *retcode = 1;
- return (-1);
+ exit(1);
case MSG_SHELL:
if (datalen != sizeof shelldata)
fatalx("bad MSG_SHELL size");
memcpy(&shelldata, imsg.data, sizeof shelldata);
shelldata.shell[(sizeof shelldata.shell) - 1] = '\0';
-
+
+ main_clear_signals();
+
shell_exec(shelldata.shell, shellcmd);
default:
fatalx("unexpected message");
@@ -656,26 +648,3 @@ dispatch_imsg(struct imsgbuf *ibuf, const char *shellcmd, int *retcode)
imsg_free(&imsg);
}
}
-
-__dead void
-shell_exec(const char *shell, const char *shellcmd)
-{
- const char *shellname, *ptr;
- char *argv0;
-
- sigreset();
-
- ptr = strrchr(shell, '/');
- if (ptr != NULL && *(ptr + 1) != '\0')
- shellname = ptr + 1;
- else
- shellname = shell;
- if (login_shell)
- xasprintf(&argv0, "-%s", shellname);
- else
- xasprintf(&argv0, "%s", shellname);
- setenv("SHELL", shell, 1);
-
- execl(shell, argv0, "-c", shellcmd, (char *) NULL);
- fatal("execl failed");
-}
diff --git a/tmux.h b/tmux.h
index ad3ee870..cc6a5d44 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1,4 +1,4 @@
-/* $Id: tmux.h,v 1.496 2009-11-04 22:46:25 tcunha Exp $ */
+/* $Id: tmux.h,v 1.497 2009-11-08 22:40:36 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -27,6 +27,7 @@
#include <sys/time.h>
#include <sys/uio.h>
+#include <event.h>
#include <limits.h>
#include <signal.h>
#include <stdarg.h>
@@ -659,6 +660,7 @@ struct job {
struct client *client;
int fd;
+ struct event event;
struct buffer *out;
void (*callbackfn)(struct job *);
@@ -794,14 +796,17 @@ struct window_pane {
char *cwd;
pid_t pid;
- int fd;
char tty[TTY_NAME_MAX];
+
+ int fd;
+ struct event event;
struct buffer *in;
struct buffer *out;
struct input_ctx ictx;
int pipe_fd;
+ struct event pipe_event;
struct buffer *pipe_buf;
size_t pipe_off;
@@ -996,6 +1001,7 @@ struct tty {
struct tty_term *term;
int fd;
+ struct event event;
struct buffer *in;
struct buffer *out;
@@ -1060,6 +1066,7 @@ struct mouse_event {
/* Client connection. */
struct client {
struct imsgbuf ibuf;
+ struct event event;
struct timeval creation_time;
struct timeval activity_time;
@@ -1233,12 +1240,6 @@ extern const struct set_option_entry set_option_table[];
extern const struct set_option_entry set_window_option_table[];
/* tmux.c */
-extern volatile sig_atomic_t sigwinch;
-extern volatile sig_atomic_t sigterm;
-extern volatile sig_atomic_t sigcont;
-extern volatile sig_atomic_t sigchld;
-extern volatile sig_atomic_t sigusr1;
-extern volatile sig_atomic_t sigusr2;
extern struct options global_s_options;
extern struct options global_w_options;
extern struct environ global_environ;
@@ -1249,9 +1250,6 @@ extern time_t start_time;
extern char *socket_path;
extern int login_shell;
void logfile(const char *);
-void siginit(void);
-void sigreset(void);
-void sighandler(int);
const char *getshell(void);
int checkshell(const char *);
int areshell(const char *);
@@ -1580,23 +1578,24 @@ const char *key_string_lookup_key(int);
extern struct clients clients;
extern struct clients dead_clients;
int server_start(char *);
-void server_poll_add(int, int, void (*)(int, int, void *), void *);
+void server_signal_set(void);
+void server_signal_clear(void);
/* server-client.c */
void server_client_create(int);
void server_client_lost(struct client *);
void server_client_prepare(void);
-void server_client_callback(int, int, void *);
+void server_client_callback(int, short, void *);
void server_client_loop(void);
/* server-job.c */
void server_job_prepare(void);
-void server_job_callback(int, int, void *);
+void server_job_callback(int, short, void *);
void server_job_loop(void);
/* server-window.c */
void server_window_prepare(void);
-void server_window_callback(int, int, void *);
+void server_window_callback(int, short, void *);
void server_window_loop(void);
/* server-fn.c */
diff --git a/window.c b/window.c
index 1830617e..a9995399 100644
--- a/window.c
+++ b/window.c
@@ -1,4 +1,4 @@
-/* $Id: window.c,v 1.117 2009-10-23 17:41:20 tcunha Exp $ */
+/* $Id: window.c,v 1.118 2009-11-08 22:40:36 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -453,10 +453,12 @@ window_pane_destroy(struct window_pane *wp)
if (wp->pipe_fd != -1) {
buffer_destroy(wp->pipe_buf);
close(wp->pipe_fd);
+ event_del(&wp->pipe_event);
}
buffer_destroy(wp->in);
buffer_destroy(wp->out);
+ event_del(&wp->event);
if (wp->cwd != NULL)
xfree(wp->cwd);
@@ -541,7 +543,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
setenv(envent->name, envent->value, 1);
}
- sigreset();
+ server_signal_clear();
log_close();
if (*wp->cmd != '\0') {