If i3bar is running in hide mode, when i3wm exit, i3bar will exit
without killing its child process, leaving a couple of processes in
'T' mode (i.e. Stopped).

With this patch, when i3bar needs to quit, it will call ev_break()
rather than exit(), thus gives the code after ev_loop() a chance to
clean things up.

I'm not very sure I've done things right. I might change some exit()s
called before ev_loop() into ev_break(), or leave some exit()s
unconverted. Someone please review this patch.
From 9cdd4ad0d84c20efe1824a609995b368322f5eb2 Mon Sep 17 00:00:00 2001
From: darkraven <[email protected]>
Date: Sat, 3 Mar 2012 20:22:06 +0800
Subject: [PATCH] Convert exit() to ev_break(), so i3bar could exit cleanly,
 esp. when i3bar is in hide mode

---
 i3bar/src/child.c      |   10 ++++++++--
 i3bar/src/ipc.c        |   33 ++++++++++++++++++++++++---------
 i3bar/src/main.c       |    7 +++++--
 i3bar/src/outputs.c    |    3 ++-
 i3bar/src/workspaces.c |    3 ++-
 i3bar/src/xcb.c        |    6 ++++--
 6 files changed, 45 insertions(+), 17 deletions(-)

diff --git a/i3bar/src/child.c b/i3bar/src/child.c
index c98befb..596e89d 100644
--- a/i3bar/src/child.c
+++ b/i3bar/src/child.c
@@ -37,6 +37,8 @@ bool plaintext = false;
 yajl_callbacks callbacks;
 yajl_handle parser;
 
+char *statusline;
+
 typedef struct parser_ctx {
     /* A copy of the last JSON map key. */
     char *last_map_key;
@@ -162,12 +164,16 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) {
                 /* finish up */
                 break;
             }
-            ELOG("read() failed!: %s\n", strerror(errno));
-            exit(EXIT_FAILURE);
+            ELOG("read() failed!: %s\n", strerror(errno))
+            return_status = EXIT_FAILURE;
+            ev_break(main_loop, EVBREAK_ALL);
+            FREE(buffer);
+            return;
         }
         if (n == 0) {
             /* end of file, kill the watcher */
             ELOG("stdin: received EOF\n");
+            FREE(buffer);
             cleanup();
             draw_bars();
             return;
diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c
index 8f8174e..1675eb6 100644
--- a/i3bar/src/ipc.c
+++ b/i3bar/src/ipc.c
@@ -144,6 +144,7 @@ handler_t event_handlers[] = {
 void got_data(struct ev_loop *loop, ev_io *watcher, int events) {
     DLOG("Got data!\n");
     int fd = watcher->fd;
+    char *buffer = NULL;
 
     /* First we only read the header, because we know its length */
     uint32_t header_len = strlen(I3_IPC_MAGIC) + sizeof(uint32_t)*2;
@@ -156,14 +157,15 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) {
         int n = read(fd, header + rec, header_len - rec);
         if (n == -1) {
             ELOG("read() failed: %s\n", strerror(errno));
-            exit(EXIT_FAILURE);
+            return_status = EXIT_FAILURE;
+            goto got_data_end;
         }
         if (n == 0) {
             /* EOF received. Since i3 will restart i3bar instances as appropriate,
              * we exit here. */
-            DLOG("EOF received, exiting...\n");
-            clean_xcb();
-            exit(EXIT_SUCCESS);
+            ELOG("EOF received, exiting...\n");
+            return_status = EXIT_SUCCESS;
+            goto got_data_end;
         }
         rec += n;
     }
@@ -173,7 +175,8 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) {
              (int) strlen(I3_IPC_MAGIC),
              header,
              I3_IPC_MAGIC);
-        exit(EXIT_FAILURE);
+        return_status = EXIT_FAILURE;
+        goto got_data_end;
     }
 
     char *walk = header + strlen(I3_IPC_MAGIC);
@@ -185,18 +188,20 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) {
 
     /* Now that we know, what to expect, we can start read()ing the rest
      * of the message */
-    char *buffer = smalloc(size + 1);
+    buffer = smalloc(size + 1);
     rec = 0;
 
     while (rec < size) {
         int n = read(fd, buffer + rec, size - rec);
         if (n == -1) {
             ELOG("read() failed: %s\n", strerror(errno));
-            exit(EXIT_FAILURE);
+            return_status = EXIT_FAILURE;
+            goto got_data_end;
         }
         if (n == 0) {
             ELOG("Nothing to read!\n");
-            exit(EXIT_FAILURE);
+            return_status = EXIT_FAILURE;
+            goto got_data_end;
         }
         rec += n;
     }
@@ -213,6 +218,13 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) {
 
     FREE(header);
     FREE(buffer);
+    return;
+
+got_data_end:
+    FREE(header);
+    FREE(buffer);
+    ev_break(main_loop, EVBREAK_ALL);
+    return;
 }
 
 /*
@@ -250,7 +262,10 @@ int i3_send_msg(uint32_t type, const char *payload) {
         int n = write(i3_connection->fd, buffer + written, to_write);
         if (n == -1) {
             ELOG("write() failed: %s\n", strerror(errno));
-            exit(EXIT_FAILURE);
+            FREE(buffer);
+            return_status = EXIT_FAILURE;
+            ev_break(main_loop, EVBREAK_ALL);
+            return 1;
         }
 
         to_write -= n;
diff --git a/i3bar/src/main.c b/i3bar/src/main.c
index e648e00..2c32955 100644
--- a/i3bar/src/main.c
+++ b/i3bar/src/main.c
@@ -17,6 +17,8 @@
 
 #include "common.h"
 
+struct ev_loop *main_loop;
+int return_status;
 /*
  * Glob path, i.e. expand ~
  *
@@ -148,7 +150,8 @@ int main(int argc, char **argv) {
 
     /* From here on everything should run smooth for itself, just start listening for
      * events. We stop simply stop the event-loop, when we are finished */
-    ev_loop(main_loop, 0);
+    return_status = EXIT_SUCCESS;
+    ev_run(main_loop, 0);
 
     kill_child();
 
@@ -159,5 +162,5 @@ int main(int argc, char **argv) {
 
     free_workspaces();
 
-    return 0;
+    return return_status;
 }
diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c
index 9dc5cab..6ad72f8 100644
--- a/i3bar/src/outputs.c
+++ b/i3bar/src/outputs.c
@@ -300,7 +300,8 @@ void parse_outputs_json(char *json) {
 #endif
         case yajl_status_error:
             ELOG("Could not parse outputs-reply!\n");
-            exit(EXIT_FAILURE);
+            return_status = EXIT_FAILURE;
+            ev_break(main_loop, EVBREAK_ALL);
             break;
     }
 
diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c
index 5df1899..a6a326c 100644
--- a/i3bar/src/workspaces.c
+++ b/i3bar/src/workspaces.c
@@ -256,7 +256,8 @@ void parse_workspaces_json(char *json) {
 #endif
         case yajl_status_error:
             ELOG("Could not parse workspaces-reply!\n");
-            exit(EXIT_FAILURE);
+            return_status = EXIT_FAILURE;
+            ev_break(main_loop, EVBREAK_ALL);
             break;
     }
 
diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c
index 2b173ee..1541533 100644
--- a/i3bar/src/xcb.c
+++ b/i3bar/src/xcb.c
@@ -214,7 +214,8 @@ void unhide_bars() {
                                               values);
 
         if (xcb_request_failed(cookie, "Could not reconfigure window")) {
-            exit(EXIT_FAILURE);
+            return_status = EXIT_FAILURE;
+            ev_break(main_loop, EVBREAK_ALL);
         }
         xcb_map_window(xcb_connection, walk->bar);
     }
@@ -681,7 +682,8 @@ void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) {
 
     if (xcb_connection_has_error(xcb_connection)) {
         ELOG("X11 connection was closed unexpectedly - maybe your X server terminated / crashed?\n");
-        exit(1);
+        return_status = EXIT_FAILURE;
+        ev_break(main_loop, EVBREAK_ALL);
     }
 
     while ((event = xcb_poll_for_event(xcb_connection)) != NULL) {
-- 
1.7.9.2

Reply via email to