diff options
author | Calvin Lee <cyrus296@gmail.com> | 2018-02-04 10:37:46 -0700 |
---|---|---|
committer | Calvin Lee <cyrus296@gmail.com> | 2018-02-04 12:31:07 -0700 |
commit | a83bca6db5348033b21ebb4ed7bc189d39e2b0c4 (patch) | |
tree | ab10cd02219ad353a97794139e92e8801ce5871f /swaybar | |
parent | Merge pull request #1579 from tmccombs/patch-1 (diff) | |
download | sway-a83bca6db5348033b21ebb4ed7bc189d39e2b0c4.tar.gz sway-a83bca6db5348033b21ebb4ed7bc189d39e2b0c4.tar.zst sway-a83bca6db5348033b21ebb4ed7bc189d39e2b0c4.zip |
Handle swaybar status line errors
The event loop API was redesigned to avoid race conditions as well.
Fixes #1583
Diffstat (limited to 'swaybar')
-rw-r--r-- | swaybar/bar.c | 10 | ||||
-rw-r--r-- | swaybar/event_loop.c | 53 | ||||
-rw-r--r-- | swaybar/status_line.c | 29 |
3 files changed, 84 insertions, 8 deletions
diff --git a/swaybar/bar.c b/swaybar/bar.c index 6db556a8..deddf971 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c | |||
@@ -274,6 +274,14 @@ static void respond_ipc(int fd, short mask, void *_bar) { | |||
274 | 274 | ||
275 | static void respond_command(int fd, short mask, void *_bar) { | 275 | static void respond_command(int fd, short mask, void *_bar) { |
276 | struct bar *bar = (struct bar *)_bar; | 276 | struct bar *bar = (struct bar *)_bar; |
277 | if (mask & POLLHUP) { | ||
278 | // Something's wrong with the command | ||
279 | handle_status_hup(bar->status); | ||
280 | dirty = true; | ||
281 | // We will stop watching the status line so swaybar won't | ||
282 | // flood the CPU with its HUPs | ||
283 | remove_event(fd); | ||
284 | } | ||
277 | dirty = handle_status_line(bar); | 285 | dirty = handle_status_line(bar); |
278 | } | 286 | } |
279 | 287 | ||
@@ -286,7 +294,7 @@ static void respond_output(int fd, short mask, void *_output) { | |||
286 | 294 | ||
287 | void bar_run(struct bar *bar) { | 295 | void bar_run(struct bar *bar) { |
288 | add_event(bar->ipc_event_socketfd, POLLIN, respond_ipc, bar); | 296 | add_event(bar->ipc_event_socketfd, POLLIN, respond_ipc, bar); |
289 | add_event(bar->status_read_fd, POLLIN, respond_command, bar); | 297 | add_event(bar->status_read_fd, POLLIN | POLLHUP, respond_command, bar); |
290 | 298 | ||
291 | int i; | 299 | int i; |
292 | for (i = 0; i < bar->outputs->length; ++i) { | 300 | for (i = 0; i < bar->outputs->length; ++i) { |
diff --git a/swaybar/event_loop.c b/swaybar/event_loop.c index 0d1be1da..bde8203f 100644 --- a/swaybar/event_loop.c +++ b/swaybar/event_loop.c | |||
@@ -20,6 +20,19 @@ struct timer_item { | |||
20 | void *data; | 20 | void *data; |
21 | }; | 21 | }; |
22 | 22 | ||
23 | enum state_item_flags { | ||
24 | ITEM_IS_FD, | ||
25 | ITEM_IS_TIMER, | ||
26 | }; | ||
27 | |||
28 | struct state_item { | ||
29 | enum state_item_flags flags; | ||
30 | union { | ||
31 | int fd; | ||
32 | timer_t timer; | ||
33 | } inner; | ||
34 | }; | ||
35 | |||
23 | static struct { | 36 | static struct { |
24 | // The order of each must be kept consistent | 37 | // The order of each must be kept consistent |
25 | struct { /* pollfd array */ | 38 | struct { /* pollfd array */ |
@@ -31,6 +44,9 @@ static struct { | |||
31 | 44 | ||
32 | // Timer list | 45 | // Timer list |
33 | list_t *timers; | 46 | list_t *timers; |
47 | |||
48 | // List of state changes at the end of each iteration | ||
49 | list_t *state; | ||
34 | } event_loop; | 50 | } event_loop; |
35 | 51 | ||
36 | void add_timer(timer_t timer, | 52 | void add_timer(timer_t timer, |
@@ -72,7 +88,7 @@ void add_event(int fd, short mask, | |||
72 | return; | 88 | return; |
73 | } | 89 | } |
74 | 90 | ||
75 | bool remove_event(int fd) { | 91 | static void _remove_event(int fd) { |
76 | int index = -1; | 92 | int index = -1; |
77 | for (int i = 0; i < event_loop.fds.length; ++i) { | 93 | for (int i = 0; i < event_loop.fds.length; ++i) { |
78 | if (event_loop.fds.items[i].fd == fd) { | 94 | if (event_loop.fds.items[i].fd == fd) { |
@@ -87,12 +103,16 @@ bool remove_event(int fd) { | |||
87 | sizeof(struct pollfd) * event_loop.fds.length - index); | 103 | sizeof(struct pollfd) * event_loop.fds.length - index); |
88 | 104 | ||
89 | list_del(event_loop.items, index); | 105 | list_del(event_loop.items, index); |
90 | return true; | ||
91 | } else { | ||
92 | return false; | ||
93 | } | 106 | } |
94 | } | 107 | } |
95 | 108 | ||
109 | void remove_event(int fd) { | ||
110 | struct state_item *item = malloc(sizeof(struct state_item)); | ||
111 | item->flags = ITEM_IS_FD; | ||
112 | item->inner.fd = fd; | ||
113 | list_add(event_loop.state, item); | ||
114 | } | ||
115 | |||
96 | static int timer_item_timer_cmp(const void *_timer_item, const void *_timer) { | 116 | static int timer_item_timer_cmp(const void *_timer_item, const void *_timer) { |
97 | const struct timer_item *timer_item = _timer_item; | 117 | const struct timer_item *timer_item = _timer_item; |
98 | const timer_t *timer = _timer; | 118 | const timer_t *timer = _timer; |
@@ -102,14 +122,19 @@ static int timer_item_timer_cmp(const void *_timer_item, const void *_timer) { | |||
102 | return -1; | 122 | return -1; |
103 | } | 123 | } |
104 | } | 124 | } |
105 | bool remove_timer(timer_t timer) { | 125 | static void _remove_timer(timer_t timer) { |
106 | int index = list_seq_find(event_loop.timers, timer_item_timer_cmp, &timer); | 126 | int index = list_seq_find(event_loop.timers, timer_item_timer_cmp, &timer); |
107 | if (index != -1) { | 127 | if (index != -1) { |
108 | free(event_loop.timers->items[index]); | 128 | free(event_loop.timers->items[index]); |
109 | list_del(event_loop.timers, index); | 129 | list_del(event_loop.timers, index); |
110 | return true; | ||
111 | } | 130 | } |
112 | return false; | 131 | } |
132 | |||
133 | void remove_timer(timer_t timer) { | ||
134 | struct state_item *item = malloc(sizeof(struct state_item)); | ||
135 | item->flags = ITEM_IS_TIMER; | ||
136 | item->inner.timer = timer; | ||
137 | list_add(event_loop.state, item); | ||
113 | } | 138 | } |
114 | 139 | ||
115 | void event_loop_poll() { | 140 | void event_loop_poll() { |
@@ -133,6 +158,19 @@ void event_loop_poll() { | |||
133 | item->cb(item->timer, item->data); | 158 | item->cb(item->timer, item->data); |
134 | } | 159 | } |
135 | } | 160 | } |
161 | |||
162 | // Remove all requested items from the event loop. We can't do this | ||
163 | // during normal operation, as it will cause race conditions. | ||
164 | for (int i = 0; i < event_loop.state->length; ++i) { | ||
165 | struct state_item *item = event_loop.state->items[i]; | ||
166 | if (item->flags == ITEM_IS_FD) { | ||
167 | _remove_event(item->inner.fd); | ||
168 | } else { | ||
169 | _remove_timer(item->inner.timer); | ||
170 | } | ||
171 | free(item); | ||
172 | } | ||
173 | event_loop.state->length = 0; // reset state list | ||
136 | } | 174 | } |
137 | 175 | ||
138 | void init_event_loop() { | 176 | void init_event_loop() { |
@@ -141,4 +179,5 @@ void init_event_loop() { | |||
141 | event_loop.fds.items = malloc(event_loop.fds.capacity * sizeof(struct pollfd)); | 179 | event_loop.fds.items = malloc(event_loop.fds.capacity * sizeof(struct pollfd)); |
142 | event_loop.items = create_list(); | 180 | event_loop.items = create_list(); |
143 | event_loop.timers = create_list(); | 181 | event_loop.timers = create_list(); |
182 | event_loop.state = create_list(); | ||
144 | } | 183 | } |
diff --git a/swaybar/status_line.c b/swaybar/status_line.c index e3cc0bf4..bbb798f1 100644 --- a/swaybar/status_line.c +++ b/swaybar/status_line.c | |||
@@ -511,6 +511,35 @@ bool handle_status_line(struct bar *bar) { | |||
511 | return dirty; | 511 | return dirty; |
512 | } | 512 | } |
513 | 513 | ||
514 | void handle_status_hup(struct status_line *line) { | ||
515 | // This is somewhat hacky, but free all previous status line state and | ||
516 | // then create a status block that displays an error string. This is so | ||
517 | // we can have pretty error colors. | ||
518 | sway_log(L_ERROR, "Replacing statusline with error string, as the status command has failed"); | ||
519 | if (line->block_line) { | ||
520 | list_foreach(line->block_line, free_status_block); | ||
521 | list_free(line->block_line); | ||
522 | } | ||
523 | line->block_line = create_list(); | ||
524 | struct status_block *new = calloc(1, sizeof(struct status_block)); | ||
525 | new->full_text = strdup("ERROR: swaybar cannot access the statusline"); | ||
526 | new->color = 0xff0000ff; | ||
527 | new->min_width = 0; | ||
528 | new->align = strdup("left"); | ||
529 | new->markup = false; | ||
530 | new->separator = true; | ||
531 | new->separator_block_width = 9; | ||
532 | new->background = 0x0; | ||
533 | new->border = 0x0; | ||
534 | new->border_top = 1; | ||
535 | new->border_bottom = 1; | ||
536 | new->border_left = 1; | ||
537 | new->border_right = 1; | ||
538 | list_add(line->block_line, new); | ||
539 | |||
540 | line->protocol = I3BAR; | ||
541 | } | ||
542 | |||
514 | struct status_line *init_status_line() { | 543 | struct status_line *init_status_line() { |
515 | struct status_line *line = malloc(sizeof(struct status_line)); | 544 | struct status_line *line = malloc(sizeof(struct status_line)); |
516 | line->block_line = create_list(); | 545 | line->block_line = create_list(); |