Fix blocking in inotify reader.
authorDana Jansens <danakj@orodu.net>
Tue, 26 Jul 2011 13:40:52 +0000 (09:40 -0400)
committerDana Jansens <danakj@orodu.net>
Sun, 16 Oct 2011 22:54:05 +0000 (18:54 -0400)
If the inotify reader reads an event and it ends at the same place the read()
  ended, then we don't know that there is anything more available, so don't
  try read() again until after it has been poll()'d.

obt/watch_inotify.c

index 336e0e074fd06eeefbe271851e2d24fa72d7c038..2093a7694fd71476a48e36fb80c49e619b6d21cc 100644 (file)
@@ -107,10 +107,10 @@ static gboolean source_read(GSource *source, GSourceFunc cb, gpointer data)
     gchar buffer[BUF_LEN];
     gchar *name;
     guint name_len; /* number of bytes read for the name */
-    guint event_len; /* number of bytes read for the event */
     gint len; /* number of bytes in the buffer */
     gint pos; /* position in the buffer */
     enum {
+        READING_DONE,
         READING_EVENT,
         READING_NAME_BUFFER,
         READING_NAME_HEAP
@@ -118,20 +118,19 @@ static gboolean source_read(GSource *source, GSourceFunc cb, gpointer data)
     struct inotify_event event;
 
     pos = BUF_LEN;
-    state = READING_EVENT;
-    len = event_len = name_len = 0;
+    state = READING_DONE;
+    len = name_len = 0;
 
     /* sometimes we can end up here even tho no events have been reported by
        the kernel.  blame glib?  but we'll block if we read in that case. */
-    while (ino_source->pfd.revents) {
-        if (pos == len || !len || event_len) {
-            /* refill the buffer */
+    if (ino_source->pfd.revents)
+        state = READING_EVENT;
 
-            if (event_len)
-                pos = event_len;
-            else
-                pos = 0;
+    while (state != READING_DONE) {
+        if (pos == len || !len) {
+            /* refill the buffer */
 
+            pos = 0;
             len = read(ino_source->pfd.fd, &buffer[pos], BUF_LEN-pos);
 
             if (len < 0) {
@@ -269,7 +268,11 @@ static gboolean source_read(GSource *source, GSourceFunc cb, gpointer data)
 
             if (state == READING_NAME_HEAP)
                 g_free(name);
-            state = READING_EVENT;
+            /* is there another event in the buffer after this one */
+            if (pos == len)
+                state = READING_DONE;
+            else
+                state = READING_EVENT;
         }
     }
     return TRUE;