summaryrefslogtreecommitdiffstats
path: root/client.c
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@openbsd.org>2009-09-02 23:49:25 +0000
committerNicholas Marriott <nicm@openbsd.org>2009-09-02 23:49:25 +0000
commit751a2fa915bc73e45e4914a26ddb3d1cb3e6a653 (patch)
tree9ee1d06da25600ce81f74e6f729f781d6e6092b7 /client.c
parent81a457e6fb169141fe567feb7bf70f98a8ad6c2a (diff)
Fix a race condition when asking a client to take over the terminal (switching
to a different poll loop): If a MSG_READY was followed very quickly by a MSG_EXIT (for example if doing "tmux new 'exit'"), both messages could be read as part of the same imsg_read in the first client poll loop. The MSG_READY would then cause a switch to the second client loop, which would immediately call poll(2) again, causing the client to hang forever waiting for an exit message that it already had. Change to call imsg_get to process any existing messages before polling.
Diffstat (limited to 'client.c')
-rw-r--r--client.c23
1 files changed, 16 insertions, 7 deletions
diff --git a/client.c b/client.c
index 8724c35e..abf2f782 100644
--- a/client.c
+++ b/client.c
@@ -152,12 +152,21 @@ int
client_main(struct client_ctx *cctx)
{
struct pollfd pfd;
- int nfds;
+ int n, nfds;
siginit();
logfile("client");
+ /*
+ * 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.
+ */
+ if (client_msg_dispatch(cctx) != 0)
+ goto out;
+
for (;;) {
if (sigterm)
client_write_server(cctx, MSG_EXITING, NULL, 0);
@@ -190,6 +199,10 @@ client_main(struct client_ctx *cctx)
fatalx("socket error");
if (pfd.revents & POLLIN) {
+ if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0) {
+ cctx->exittype = CCTX_DIED;
+ break;
+ }
if (client_msg_dispatch(cctx) != 0)
break;
}
@@ -201,7 +214,8 @@ client_main(struct client_ctx *cctx)
}
}
}
-
+
+out:
if (sigterm) {
printf("[terminated]\n");
return (1);
@@ -252,11 +266,6 @@ client_msg_dispatch(struct client_ctx *cctx)
struct msg_print_data printdata;
ssize_t n, datalen;
- if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0) {
- cctx->exittype = CCTX_DIED;
- return (-1);
- }
-
for (;;) {
if ((n = imsg_get(&cctx->ibuf, &imsg)) == -1)
fatalx("imsg_get failed");
id='n123' href='#n123'>123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213