Created
January 1, 2013 12:48
-
-
Save richardgv/4427175 to your computer and use it in GitHub Desktop.
chjj/compton: Patch to use (p)select() instead of (p)poll()
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/compton.c b/src/compton.c | |
index eff195f..2e43bc8 100644 | |
--- a/src/compton.c | |
+++ b/src/compton.c | |
@@ -4672,14 +4672,9 @@ lceil_ntimes(long dividend, long divisor) { | |
*/ | |
static int | |
evpoll(session_t *ps, int timeout) { | |
- struct pollfd ufd = { | |
- .fd = ConnectionNumber(ps->dpy), | |
- .events = POLLIN | |
- }; | |
- | |
// Always wait infinitely if asked so, to minimize CPU usage | |
if (timeout < 0) { | |
- int ret = poll(&ufd, 1, timeout); | |
+ int ret = fds_poll(ps, timeout); | |
// Reset ps->fade_time so the fading steps during idling are not counted | |
ps->fade_time = get_time_ms(); | |
return ret; | |
@@ -4687,7 +4682,7 @@ evpoll(session_t *ps, int timeout) { | |
// Just do a poll() if we are not using optimization | |
if (!ps->o.sw_opti) | |
- return poll(&ufd, 1, timeout); | |
+ return fds_poll(ps, timeout); | |
// Convert the old timeout to struct timespec | |
struct timespec next_paint_tmout = { | |
@@ -4699,14 +4694,14 @@ evpoll(session_t *ps, int timeout) { | |
// I don't think a 32-bit long could overflow here. | |
long target_relative_offset = (next_paint_tmout.tv_nsec + get_time_timespec().tv_nsec - ps->paint_tm_offset) % NS_PER_SEC; | |
if (target_relative_offset < 0) | |
- target_relative_offset += NS_PER_SEC; | |
+ return fds_poll(ps, timeout); | |
assert(target_relative_offset >= 0); | |
// If the target time is sufficiently close to a refresh time, don't add | |
// an offset, to avoid certain blocking conditions. | |
if ((target_relative_offset % NS_PER_SEC) < SW_OPTI_TOLERANCE) | |
- return poll(&ufd, 1, timeout); | |
+ return fds_poll(ps, timeout); | |
// Add an offset so we wait until the next refresh after timeout | |
next_paint_tmout.tv_nsec += lceil_ntimes(target_relative_offset, ps->refresh_intv) - target_relative_offset; | |
@@ -4715,7 +4710,7 @@ evpoll(session_t *ps, int timeout) { | |
++next_paint_tmout.tv_sec; | |
} | |
- return ppoll(&ufd, 1, &next_paint_tmout, NULL); | |
+ return fds_ppoll(ps, &next_paint_tmout); | |
} | |
/** | |
@@ -5078,6 +5073,11 @@ session_init(session_t *ps_old, int argc, char **argv) { | |
.ignore_tail = NULL, | |
.reset = false, | |
+ .pfds_read = NULL, | |
+ .pfds_write = NULL, | |
+ .pfds_except = NULL, | |
+ .nfds_max = 0, | |
+ | |
.expose_rects = NULL, | |
.size_expose = 0, | |
.n_expose = 0, | |
@@ -5274,6 +5274,8 @@ session_init(session_t *ps_old, int argc, char **argv) { | |
init_atoms(ps); | |
init_alpha_picts(ps); | |
+ fds_insert(ps, ConnectionNumber(ps->dpy), POLLIN); | |
+ | |
ps->gaussian_map = make_gaussian_map(ps->o.shadow_radius); | |
presum_gaussian(ps, ps->gaussian_map); | |
diff --git a/src/compton.h b/src/compton.h | |
index 66ed396..000544f 100644 | |
--- a/src/compton.h | |
+++ b/src/compton.h | |
@@ -44,6 +44,7 @@ | |
#include <inttypes.h> | |
#include <math.h> | |
#include <sys/poll.h> | |
+#include <sys/select.h> | |
#include <sys/time.h> | |
#include <time.h> | |
#include <unistd.h> | |
@@ -233,6 +234,12 @@ typedef enum { | |
VSYNC_OPENGL, | |
} vsync_t; | |
+/// Poll backends. | |
+enum poll_backends { | |
+ POLLBKND_POLL, | |
+ POLLBKND_SELECT, | |
+}; | |
+ | |
#ifdef CONFIG_VSYNC_OPENGL | |
typedef int (*f_WaitVideoSync) (int, int, unsigned *); | |
typedef int (*f_GetVideoSync) (unsigned *); | |
@@ -427,6 +434,18 @@ typedef struct { | |
/// Reset program after next paint. | |
bool reset; | |
+ // === Main loop === | |
+ // Poll backend. | |
+ enum poll_backend loop_bknd; | |
+ // File descriptors to check for reading. | |
+ fd_set *pfds_read; | |
+ // File descriptors to check for writing. | |
+ fd_set *pfds_write; | |
+ // File descriptors to check for exceptions. | |
+ fd_set *pfds_except; | |
+ // Largest file descriptor in fd_set-s above. | |
+ int nfds_max; | |
+ | |
// === Expose event related === | |
/// Pointer to an array of <code>XRectangle</code>-s of exposed region. | |
XRectangle *expose_rects; | |
@@ -1158,7 +1177,7 @@ free_win_res(session_t *ps, win *w) { | |
* The return type must be unsigned long because so many milliseconds have | |
* passed since the epoch. | |
*/ | |
-static unsigned long | |
+static inline unsigned long | |
get_time_ms(void) { | |
struct timeval tv; | |
@@ -1168,6 +1187,109 @@ get_time_ms(void) { | |
+ (unsigned long) tv.tv_usec / 1000; | |
} | |
+/** | |
+ * Add a file descriptor to a select() fd_set. | |
+ */ | |
+static inline bool | |
+fds_insert_select(fd_set **ppfds, int fd) { | |
+ assert(fd <= FD_SETSIZE); | |
+ | |
+ if (!*ppfds) { | |
+ if ((*ppfds = malloc(sizeof(fd_set)))) { | |
+ FD_ZERO(*ppfds); | |
+ } | |
+ else { | |
+ fprintf(stderr, "Failed to allocate memory for select() fdset.\n"); | |
+ exit(1); | |
+ } | |
+ } | |
+ | |
+ FD_SET(fd, *ppfds); | |
+ | |
+ return true; | |
+} | |
+ | |
+/** | |
+ * Add a new file descriptor to wait for. | |
+ */ | |
+static inline bool | |
+fds_insert(session_t *ps, int fd, short events) { | |
+ bool result = true; | |
+ | |
+ ps->nfds_max = max_i(fd + 1, ps->nfds_max); | |
+ | |
+ if (POLLIN & events) | |
+ result = fds_insert_select(&ps->pfds_read, fd) && result; | |
+ if (POLLOUT & events) | |
+ result = fds_insert_select(&ps->pfds_write, fd) && result; | |
+ if (POLLPRI & events) | |
+ result = fds_insert_select(&ps->pfds_except, fd) && result; | |
+ | |
+ return result; | |
+} | |
+ | |
+/** | |
+ * Delete a file descriptor to wait for. | |
+ */ | |
+static inline void | |
+fds_drop(session_t *ps, int fd, short events) { | |
+ // Drop fd from all fd_set-s | |
+ FD_CLR(fd, ps->pfds_read); | |
+ FD_CLR(fd, ps->pfds_write); | |
+ FD_CLR(fd, ps->pfds_except); | |
+} | |
+ | |
+#define CPY_FDS(key) \ | |
+ fd_set * key = NULL; \ | |
+ if (ps->key) { \ | |
+ key = malloc(sizeof(fd_set)); \ | |
+ memcpy(key, ps->key, sizeof(fd_set)); \ | |
+ if (!key) { \ | |
+ fprintf(stderr, "Failed to allocate memory for copying select() fdset.\n"); \ | |
+ exit(1); \ | |
+ } \ | |
+ } \ | |
+ | |
+/** | |
+ * Poll for changes. | |
+ * | |
+ * poll() is much better than select(), but ppoll() does not exist on | |
+ * *BSD. | |
+ */ | |
+static inline int | |
+fds_poll(session_t *ps, int timeout) { | |
+ // Copy fds | |
+ CPY_FDS(pfds_read); | |
+ CPY_FDS(pfds_write); | |
+ CPY_FDS(pfds_except); | |
+ | |
+ struct timeval tv = { | |
+ .tv_sec = timeout / 1000, | |
+ .tv_usec = (timeout % 1000) * 1000, | |
+ }; | |
+ | |
+ return select(ps->nfds_max, pfds_read, pfds_write, pfds_except, | |
+ (timeout < 0 ? NULL : &tv)); | |
+} | |
+ | |
+/** | |
+ * Poll for changes. | |
+ * | |
+ * poll() is much better than select(), but ppoll() does not exist on | |
+ * *BSD. | |
+ */ | |
+static inline int | |
+fds_ppoll(session_t *ps, const struct timespec *timeout) { | |
+ // Copy fds | |
+ CPY_FDS(pfds_read); | |
+ CPY_FDS(pfds_write); | |
+ CPY_FDS(pfds_except); | |
+ | |
+ return pselect(ps->nfds_max, pfds_read, pfds_write, pfds_except, | |
+ timeout, NULL); | |
+} | |
+#undef CPY_FDS | |
+ | |
static int | |
fade_timeout(session_t *ps); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment