summaryrefslogtreecommitdiffstats
path: root/client.c
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@openbsd.org>2009-11-04 20:50:11 +0000
committerNicholas Marriott <nicm@openbsd.org>2009-11-04 20:50:11 +0000
commitabf3a5d50ec4003f58f460cc9ab3c00671c920f8 (patch)
tree214252ffd3ea45a0998d965b5e2736e80100a9a9 /client.c
parentf575e39b0a367ae9b8a7cf54ceead865b8885eed (diff)
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.
Diffstat (limited to 'client.c')
-rw-r--r--client.c214
1 files changed, 124 insertions, 90 deletions
diff --git a/client.c b/client.c
index 4d5fd696..60fef91a 100644
--- a/client.c
+++ b/client.c
@@ -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)
@@ -154,76 +157,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. */
@@ -235,12 +216,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)
@@ -249,6 +296,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)
@@ -281,7 +329,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)
@@ -299,23 +353,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);
-}