From dd36982ad51632bc47ce7b73cad0696e85d593c3 Mon Sep 17 00:00:00 2001 From: Tiago Cunha Date: Sun, 8 Nov 2009 22:40:36 +0000 Subject: [PATCH] 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. --- buffer-poll.c | 12 +- client.c | 216 ++++++++++------- cmd-kill-server.c | 4 +- cmd-pipe-pane.c | 4 +- job.c | 6 +- server-client.c | 38 +-- server-job.c | 12 +- server-window.c | 19 +- server.c | 600 +++++++++++++++++++++------------------------- tmux.c | 305 +++++++++++------------ tmux.h | 29 ++- window.c | 6 +- 12 files changed, 611 insertions(+), 640 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 @@ -19,6 +19,7 @@ #include #include +#include #include #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 @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -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 @@ -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 @@ -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 @@ -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 @@ -18,6 +18,7 @@ #include +#include #include #include #include @@ -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 @@ -18,6 +18,7 @@ #include +#include #include #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 @@ -18,6 +18,7 @@ #include +#include #include #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 @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -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,150 +199,39 @@ 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; + struct timeval tv; - siginit(); - log_debug("server socket is %d", srv_fd); + memset(&tv, 0, sizeof tv); + tv.tv_usec = POLL_TIMEOUT * 1000; - last = time(NULL); + while (!server_should_shutdown()) { + server_update_socket(); - pfds = NULL; - for (;;) { - /* If sigterm, kill all windows and clients. */ - if (sigterm) - server_shutdown(); - - /* 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); + event_loopexit(&tv); + event_loop(EVLOOP_ONCE); - /* Call second-based timers. */ - now = time(NULL); - if (now != last) { - last = now; - server_second_timers(); - } - - /* 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(); - - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - if (ARRAY_ITEM(&sessions, i) != NULL) - session_destroy(ARRAY_ITEM(&sessions, i)); - } - ARRAY_FREE(&sessions); - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - if (ARRAY_ITEM(&clients, i) != NULL) - server_client_lost(ARRAY_ITEM(&clients, i)); - } - 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); -} - -/* Kill all clients. */ -void -server_shutdown(void) -{ - struct session *s; - struct client *c; - u_int i, j; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c != NULL) { - if (c->flags & (CLIENT_BAD|CLIENT_SUSPENDED)) - server_client_lost(c); - else - server_write_client(c, MSG_SHUTDOWN, NULL, 0); - } - } - - 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) - session_destroy(s); - } + } } /* Check if the server should be shutting down (no more clients or windows). */ @@ -457,49 +251,28 @@ server_should_shutdown(void) return (1); } -/* Handle SIGCHLD. */ +/* Shutdown the server by killing all clients and windows. */ void -server_child_signal(void) +server_send_shutdown(void) { - struct window *w; - struct window_pane *wp; - struct job *job; - int status; - pid_t pid; - u_int i; + struct client *c; + struct session *s; + u_int i; - for (;;) { - switch (pid = waitpid(WAIT_ANY, &status, WNOHANG|WUNTRACED)) { - case -1: - if (errno == ECHILD) - return; - fatal("waitpid failed"); - case 0: - return; + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c != NULL) { + if (c->flags & (CLIENT_BAD|CLIENT_SUSPENDED)) + server_client_lost(c); + else + server_write_client(c, MSG_SHUTDOWN, NULL, 0); + c->session = NULL; } - if (!WIFSTOPPED(status)) { - SLIST_FOREACH(job, &all_jobs, lentry) { - if (pid == job->pid) { - job->pid = -1; - job->status = status; - } - } - continue; - } - 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); - } - } - } + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + if ((s = ARRAY_ITEM(&sessions, i)) != NULL) + session_destroy(s); } } @@ -528,12 +301,215 @@ server_clean_dead(void) } } -/* Call any once-per-second timers. */ +/* 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); +} + +/* Callback for server socket. */ void -server_second_timers(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; + } +} + +/* Handle SIGCHLD. */ +void +server_child_signal(void) +{ + int status; + pid_t pid; + + for (;;) { + switch (pid = waitpid(WAIT_ANY, &status, WNOHANG|WUNTRACED)) { + case -1: + if (errno == ECHILD) + return; + fatal("waitpid failed"); + case 0: + return; + } + 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; + } + } + } + + SLIST_FOREACH(job, &all_jobs, lentry) { + if (pid == job->pid) { + job->pid = -1; + job->status = status; + } + } +} + +/* Handle stopped children. */ +void +server_child_stopped(pid_t pid, int status) +{ + struct window *w; + struct window_pane *wp; + u_int i; + + if (WSTOPSIG(status) == SIGTTIN || WSTOPSIG(status) == SIGTTOU) + return; + + 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) { + if (killpg(pid, SIGCONT) != 0) + kill(pid, SIGCONT); + } + } + } +} + +/* Handle once-per-second timer events. */ +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 @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -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; + imsg_compose(main_ibuf, msg, PROTOCOL_VERSION, -1, -1, buf, len); - if ((nfds = poll(&pfd, 1, INFTIM)) == -1) { - if (errno == EAGAIN || errno == EINTR) - continue; - fatal("poll failed"); - } - if (nfds == 0) - continue; + main_set_signals(); - if (pfd.revents & (POLLERR|POLLHUP|POLLNVAL)) - fatalx("socket error"); + 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 & POLLIN) { - if (dispatch_imsg(ibuf, shellcmd, &retcode) != 0) - break; - } + main_exitval = 0; + event_dispatch(); - if (pfd.revents & POLLOUT) { - if (msgbuf_write(&ibuf->w) < 0) - fatalx("msgbuf_write failed"); - } - } + main_clear_signals(); - options_free(&global_s_options); - options_free(&global_w_options); - - return (retcode); + client_main(); /* doesn't return */ } -int -dispatch_imsg(struct imsgbuf *ibuf, const char *shellcmd, int *retcode) + +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); + } +} + +void +main_callback(unused int fd, short events, void *data) +{ + char *shellcmd = data; + + 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); +} + +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 @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -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 @@ -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') {