Skip to content

Instantly share code, notes, and snippets.

@richardgv
Created January 1, 2013 12:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save richardgv/4427175 to your computer and use it in GitHub Desktop.
Save richardgv/4427175 to your computer and use it in GitHub Desktop.
chjj/compton: Patch to use (p)select() instead of (p)poll()
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