swaybar: use select instead of busyloop

Use of busyloop caused high cpu usage for sway because swaybar had to be
redrawn all the time. By using select instead the bar only has to be
redrawn when the status_command changes (i.e. every second) or when the
workspaces are updated.

Fix #345
This commit is contained in:
Mikkel Oscar Lyderik 2015-12-19 16:24:51 +01:00
parent 616ea27e19
commit bc9b93f597

View file

@ -4,13 +4,14 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <unistd.h> #include <unistd.h>
#include <sys/select.h>
#include <errno.h>
#include <json-c/json.h> #include <json-c/json.h>
#include <sys/un.h> #include <sys/un.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <getopt.h> #include <getopt.h>
#include "ipc-client.h" #include "ipc-client.h"
#include "readline.h"
#include "client/registry.h" #include "client/registry.h"
#include "client/window.h" #include "client/window.h"
#include "client/pango.h" #include "client/pango.h"
@ -50,7 +51,8 @@ int socketfd;
pid_t pid; pid_t pid;
int pipefd[2]; int pipefd[2];
FILE *command; FILE *command;
char *line, *output, *status_command; char line[1024];
char *output, *status_command;
struct registry *registry; struct registry *registry;
struct window *window; struct window *window;
bool dirty = true; bool dirty = true;
@ -106,7 +108,6 @@ void sway_terminate(void) {
close(pipefd[0]); close(pipefd[0]);
} }
free(line);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -304,29 +305,6 @@ void bar_ipc_init(int outputi, const char *bar_id) {
ipc_update_workspaces(); ipc_update_workspaces();
} }
void update() {
int pending;
// If no command is set, we don't have to update anything
if (status_command) {
if (ioctl(fileno(command), FIONREAD, &pending) != -1 && pending > 0) {
free(line);
line = read_line(command);
int l = strlen(line) - 1;
if (line[l] == '\n') {
line[l] = '\0';
}
dirty = true;
}
}
if (ioctl(socketfd, FIONREAD, &pending) != -1 && pending > 0) {
uint32_t len;
char *buf = ipc_recv_response(socketfd, &len);
free(buf);
ipc_update_workspaces();
dirty = true;
}
}
void render() { void render() {
// Clear // Clear
cairo_save(window->cairo); cairo_save(window->cairo);
@ -379,6 +357,51 @@ void render() {
} }
} }
void poll_for_update() {
fd_set readfds;
int activity;
while (1) {
if (dirty && window_prerender(window) && window->cairo) {
render();
window_render(window);
}
if (wl_display_dispatch(registry->display) == -1) {
break;
}
dirty = false;
FD_ZERO(&readfds);
FD_SET(socketfd, &readfds);
FD_SET(pipefd[0], &readfds);
activity = select(FD_SETSIZE, &readfds, NULL, NULL, NULL);
if (activity < 0) {
sway_log(L_ERROR, "polling failed: %d", errno);
}
if (FD_ISSET(socketfd, &readfds)) {
sway_log(L_DEBUG, "Got workspace update.");
uint32_t len;
char *buf = ipc_recv_response(socketfd, &len);
free(buf);
ipc_update_workspaces();
dirty = true;
}
if (status_command && FD_ISSET(pipefd[0], &readfds)) {
sway_log(L_DEBUG, "Got update from status command.");
fgets(line, sizeof(line), command);
int l = strlen(line) - 1;
if (line[l] == '\n') {
line[l] = '\0';
}
dirty = true;
}
}
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
init_log(L_INFO); init_log(L_INFO);
@ -465,7 +488,6 @@ int main(int argc, char **argv) {
close(pipefd[1]); close(pipefd[1]);
command = fdopen(pipefd[0], "r"); command = fdopen(pipefd[0], "r");
line = malloc(1024);
line[0] = '\0'; line[0] = '\0';
} }
@ -479,13 +501,7 @@ int main(int argc, char **argv) {
get_text_size(window, &width, &height, "Test string for measuring purposes"); get_text_size(window, &width, &height, "Test string for measuring purposes");
window->height = height + MARGIN * 2; window->height = height + MARGIN * 2;
do { poll_for_update();
update();
if (dirty && window_prerender(window) && window->cairo) {
render();
window_render(window);
}
} while (wl_display_dispatch(registry->display) != -1);
window_teardown(window); window_teardown(window);
registry_teardown(registry); registry_teardown(registry);
@ -493,7 +509,6 @@ int main(int argc, char **argv) {
// terminate status_command process // terminate status_command process
kill(pid, SIGTERM); kill(pid, SIGTERM);
close(pipefd[0]); close(pipefd[0]);
free(line);
return 0; return 0;
} }