Home | History | Annotate | Download | only in inotify
      1 /*
      2    Copyright (C) 2005 John McCutchan
      3 
      4    The Gnome Library is free software; you can redistribute it and/or
      5    modify it under the terms of the GNU Library General Public License as
      6    published by the Free Software Foundation; either version 2 of the
      7    License, or (at your option) any later version.
      8 
      9    The Gnome Library is distributed in the hope that it will be useful,
     10    but WITHOUT ANY WARRANTY; without even the implied warranty of
     11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12    Library General Public License for more details.
     13 
     14    You should have received a copy of the GNU Library General Public
     15    License along with the Gnome Library; see the file COPYING.LIB.  If not,
     16    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
     17    Boston, MA 02111-1307, USA.
     18 
     19    Authors:.
     20 		John McCutchan <john (at) johnmccutchan.com>
     21 */
     22 
     23 #include "config.h"
     24 
     25 #include <stdio.h>
     26 #include <sys/ioctl.h>
     27 #include <unistd.h>
     28 #include <errno.h>
     29 #include <string.h>
     30 #include <glib.h>
     31 #include "inotify-kernel.h"
     32 #include <sys/inotify.h>
     33 
     34 /* Timings for pairing MOVED_TO / MOVED_FROM events */
     35 #define PROCESS_EVENTS_TIME 1000 /* milliseconds (1 hz) */
     36 #define DEFAULT_HOLD_UNTIL_TIME 0 /* 0 millisecond */
     37 #define MOVE_HOLD_UNTIL_TIME 0 /* 0 milliseconds */
     38 
     39 static int inotify_instance_fd = -1;
     40 static GQueue *events_to_process = NULL;
     41 static GQueue *event_queue = NULL;
     42 static GHashTable * cookie_hash = NULL;
     43 static GIOChannel *inotify_read_ioc;
     44 static GPollFD ik_poll_fd;
     45 static gboolean ik_poll_fd_enabled = TRUE;
     46 static void (*user_cb)(ik_event_t *event);
     47 
     48 static gboolean ik_read_callback (gpointer user_data);
     49 static gboolean ik_process_eq_callback (gpointer user_data);
     50 
     51 static guint32 ik_move_matches = 0;
     52 static guint32 ik_move_misses = 0;
     53 
     54 static gboolean process_eq_running = FALSE;
     55 
     56 /* We use the lock from inotify-helper.c
     57  *
     58  * There are two places that we take this lock
     59  *
     60  * 1) In ik_read_callback
     61  *
     62  * 2) ik_process_eq_callback.
     63  *
     64  *
     65  * The rest of locking is taken care of in inotify-helper.c
     66  */
     67 G_LOCK_EXTERN (inotify_lock);
     68 
     69 typedef struct ik_event_internal {
     70   ik_event_t *event;
     71   gboolean seen;
     72   gboolean sent;
     73   GTimeVal hold_until;
     74   struct ik_event_internal *pair;
     75 } ik_event_internal_t;
     76 
     77 /* In order to perform non-sleeping inotify event chunking we need
     78  * a custom GSource
     79  */
     80 static gboolean
     81 ik_source_prepare (GSource *source,
     82 		   gint    *timeout)
     83 {
     84   return FALSE;
     85 }
     86 
     87 static gboolean
     88 ik_source_timeout (gpointer data)
     89 {
     90   GSource *source = (GSource *)data;
     91 
     92   /* Re-active the PollFD */
     93   g_source_add_poll (source, &ik_poll_fd);
     94   g_source_unref (source);
     95   ik_poll_fd_enabled = TRUE;
     96 
     97   return FALSE;
     98 }
     99 
    100 #define MAX_PENDING_COUNT 2
    101 #define PENDING_THRESHOLD(qsize) ((qsize) >> 1)
    102 #define PENDING_MARGINAL_COST(p) ((unsigned int)(1 << (p)))
    103 #define MAX_QUEUED_EVENTS 2048
    104 #define AVERAGE_EVENT_SIZE sizeof (struct inotify_event) + 16
    105 #define TIMEOUT_MILLISECONDS 10
    106 
    107 static gboolean
    108 ik_source_check (GSource *source)
    109 {
    110   static int prev_pending = 0, pending_count = 0;
    111 
    112   /* We already disabled the PollFD or
    113    * nothing to be read from inotify */
    114   if (!ik_poll_fd_enabled || !(ik_poll_fd.revents & G_IO_IN))
    115     return FALSE;
    116 
    117   if (pending_count < MAX_PENDING_COUNT)
    118     {
    119       unsigned int pending;
    120 
    121       if (ioctl (inotify_instance_fd, FIONREAD, &pending) == -1)
    122 	goto do_read;
    123 
    124       pending /= AVERAGE_EVENT_SIZE;
    125 
    126       /* Don't wait if the number of pending events is too close
    127        * to the maximum queue size.
    128        */
    129       if (pending > PENDING_THRESHOLD (MAX_QUEUED_EVENTS))
    130 	goto do_read;
    131 
    132       /* With each successive iteration, the minimum rate for
    133        * further sleep doubles.
    134        */
    135       if (pending-prev_pending < PENDING_MARGINAL_COST (pending_count))
    136 	goto do_read;
    137 
    138       prev_pending = pending;
    139       pending_count++;
    140 
    141       /* We are going to wait to read the events: */
    142 
    143       /* Remove the PollFD from the source */
    144       g_source_remove_poll (source, &ik_poll_fd);
    145       /* To avoid threading issues we need to flag that we've done that */
    146       ik_poll_fd_enabled = FALSE;
    147       /* Set a timeout to re-add the PollFD to the source */
    148       g_source_ref (source);
    149       g_timeout_add (TIMEOUT_MILLISECONDS, ik_source_timeout, source);
    150 
    151       return FALSE;
    152     }
    153 
    154 do_read:
    155   /* We are ready to read events from inotify */
    156 
    157   prev_pending = 0;
    158   pending_count = 0;
    159 
    160   return TRUE;
    161 }
    162 
    163 static gboolean
    164 ik_source_dispatch (GSource     *source,
    165 		    GSourceFunc  callback,
    166 		    gpointer     user_data)
    167 {
    168   if (callback)
    169     return callback (user_data);
    170   return TRUE;
    171 }
    172 
    173 static GSourceFuncs ik_source_funcs =
    174 {
    175   ik_source_prepare,
    176   ik_source_check,
    177   ik_source_dispatch,
    178   NULL
    179 };
    180 
    181 gboolean _ik_startup (void (*cb)(ik_event_t *event))
    182 {
    183   static gboolean initialized = FALSE;
    184   GSource *source;
    185 
    186   user_cb = cb;
    187   /* Ignore multi-calls */
    188   if (initialized)
    189     return inotify_instance_fd >= 0;
    190 
    191   initialized = TRUE;
    192   inotify_instance_fd = inotify_init ();
    193 
    194   if (inotify_instance_fd < 0)
    195     return FALSE;
    196 
    197   inotify_read_ioc = g_io_channel_unix_new (inotify_instance_fd);
    198   ik_poll_fd.fd = inotify_instance_fd;
    199   ik_poll_fd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
    200   g_io_channel_set_encoding (inotify_read_ioc, NULL, NULL);
    201   g_io_channel_set_flags (inotify_read_ioc, G_IO_FLAG_NONBLOCK, NULL);
    202 
    203   source = g_source_new (&ik_source_funcs, sizeof (GSource));
    204   g_source_add_poll (source, &ik_poll_fd);
    205   g_source_set_callback (source, ik_read_callback, NULL, NULL);
    206   g_source_attach (source, NULL);
    207   g_source_unref (source);
    208 
    209   cookie_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
    210   event_queue = g_queue_new ();
    211   events_to_process = g_queue_new ();
    212 
    213   return TRUE;
    214 }
    215 
    216 static ik_event_internal_t *
    217 ik_event_internal_new (ik_event_t *event)
    218 {
    219   ik_event_internal_t *internal_event = g_new0 (ik_event_internal_t, 1);
    220   GTimeVal tv;
    221 
    222   g_assert (event);
    223 
    224   g_get_current_time (&tv);
    225   g_time_val_add (&tv, DEFAULT_HOLD_UNTIL_TIME);
    226   internal_event->event = event;
    227   internal_event->hold_until = tv;
    228 
    229   return internal_event;
    230 }
    231 
    232 static ik_event_t *
    233 ik_event_new (char *buffer)
    234 {
    235   struct inotify_event *kevent = (struct inotify_event *)buffer;
    236   ik_event_t *event = g_new0 (ik_event_t, 1);
    237 
    238   g_assert (buffer);
    239 
    240   event->wd = kevent->wd;
    241   event->mask = kevent->mask;
    242   event->cookie = kevent->cookie;
    243   event->len = kevent->len;
    244   if (event->len)
    245     event->name = g_strdup (kevent->name);
    246   else
    247     event->name = g_strdup ("");
    248 
    249   return event;
    250 }
    251 
    252 ik_event_t *
    253 _ik_event_new_dummy (const char *name,
    254                      gint32      wd,
    255                      guint32     mask)
    256 {
    257   ik_event_t *event = g_new0 (ik_event_t, 1);
    258   event->wd = wd;
    259   event->mask = mask;
    260   event->cookie = 0;
    261   if (name)
    262     event->name = g_strdup (name);
    263   else
    264     event->name = g_strdup("");
    265 
    266   event->len = strlen (event->name);
    267 
    268   return event;
    269 }
    270 
    271 void
    272 _ik_event_free (ik_event_t *event)
    273 {
    274   if (event->pair)
    275     _ik_event_free (event->pair);
    276   g_free (event->name);
    277   g_free (event);
    278 }
    279 
    280 gint32
    281 _ik_watch (const char *path,
    282            guint32     mask,
    283            int        *err)
    284 {
    285   gint32 wd = -1;
    286 
    287   g_assert (path != NULL);
    288   g_assert (inotify_instance_fd >= 0);
    289 
    290   wd = inotify_add_watch (inotify_instance_fd, path, mask);
    291 
    292   if (wd < 0)
    293     {
    294       int e = errno;
    295       /* FIXME: debug msg failed to add watch */
    296       if (err)
    297 	*err = e;
    298       return wd;
    299     }
    300 
    301   g_assert (wd >= 0);
    302   return wd;
    303 }
    304 
    305 int
    306 _ik_ignore (const char *path,
    307             gint32      wd)
    308 {
    309   g_assert (wd >= 0);
    310   g_assert (inotify_instance_fd >= 0);
    311 
    312   if (inotify_rm_watch (inotify_instance_fd, wd) < 0)
    313     {
    314       /* int e = errno; */
    315       /* failed to rm watch */
    316       return -1;
    317     }
    318 
    319   return 0;
    320 }
    321 
    322 void
    323 _ik_move_stats (guint32 *matches,
    324                 guint32 *misses)
    325 {
    326   if (matches)
    327     *matches = ik_move_matches;
    328 
    329   if (misses)
    330     *misses = ik_move_misses;
    331 }
    332 
    333 const char *
    334 _ik_mask_to_string (guint32 mask)
    335 {
    336   gboolean is_dir = mask & IN_ISDIR;
    337   mask &= ~IN_ISDIR;
    338 
    339   if (is_dir)
    340     {
    341       switch (mask)
    342 	{
    343 	case IN_ACCESS:
    344 	  return "ACCESS (dir)";
    345 	case IN_MODIFY:
    346 	  return "MODIFY (dir)";
    347 	case IN_ATTRIB:
    348 	  return "ATTRIB (dir)";
    349 	case IN_CLOSE_WRITE:
    350 	  return "CLOSE_WRITE (dir)";
    351 	case IN_CLOSE_NOWRITE:
    352 	  return "CLOSE_NOWRITE (dir)";
    353 	case IN_OPEN:
    354 	  return "OPEN (dir)";
    355 	case IN_MOVED_FROM:
    356 	  return "MOVED_FROM (dir)";
    357 	case IN_MOVED_TO:
    358 	  return "MOVED_TO (dir)";
    359 	case IN_DELETE:
    360 	  return "DELETE (dir)";
    361 	case IN_CREATE:
    362 	  return "CREATE (dir)";
    363 	case IN_DELETE_SELF:
    364 	  return "DELETE_SELF (dir)";
    365 	case IN_UNMOUNT:
    366 	  return "UNMOUNT (dir)";
    367 	case IN_Q_OVERFLOW:
    368 	  return "Q_OVERFLOW (dir)";
    369 	case IN_IGNORED:
    370 	  return "IGNORED (dir)";
    371 	default:
    372 	  return "UNKNOWN_EVENT (dir)";
    373 	}
    374     }
    375   else
    376     {
    377       switch (mask)
    378 	{
    379 	case IN_ACCESS:
    380 	  return "ACCESS";
    381 	case IN_MODIFY:
    382 	  return "MODIFY";
    383 	case IN_ATTRIB:
    384 	  return "ATTRIB";
    385 	case IN_CLOSE_WRITE:
    386 	  return "CLOSE_WRITE";
    387 	case IN_CLOSE_NOWRITE:
    388 	  return "CLOSE_NOWRITE";
    389 	case IN_OPEN:
    390 	  return "OPEN";
    391 	case IN_MOVED_FROM:
    392 	  return "MOVED_FROM";
    393 	case IN_MOVED_TO:
    394 	  return "MOVED_TO";
    395 	case IN_DELETE:
    396 	  return "DELETE";
    397 	case IN_CREATE:
    398 	  return "CREATE";
    399 	case IN_DELETE_SELF:
    400 	  return "DELETE_SELF";
    401 	case IN_UNMOUNT:
    402 	  return "UNMOUNT";
    403 	case IN_Q_OVERFLOW:
    404 	  return "Q_OVERFLOW";
    405 	case IN_IGNORED:
    406 	  return "IGNORED";
    407 	default:
    408 	  return "UNKNOWN_EVENT";
    409 	}
    410     }
    411 }
    412 
    413 
    414 static void
    415 ik_read_events (gsize  *buffer_size_out,
    416                 gchar **buffer_out)
    417 {
    418   static gchar *buffer = NULL;
    419   static gsize buffer_size;
    420 
    421   /* Initialize the buffer on our first call */
    422   if (buffer == NULL)
    423     {
    424       buffer_size = AVERAGE_EVENT_SIZE;
    425       buffer_size *= MAX_QUEUED_EVENTS;
    426       buffer = g_malloc (buffer_size);
    427     }
    428 
    429   *buffer_size_out = 0;
    430   *buffer_out = NULL;
    431 
    432   memset (buffer, 0, buffer_size);
    433 
    434   if (g_io_channel_read_chars (inotify_read_ioc, (char *)buffer, buffer_size, buffer_size_out, NULL) != G_IO_STATUS_NORMAL) {
    435     /* error reading */
    436   }
    437   *buffer_out = buffer;
    438 }
    439 
    440 static gboolean
    441 ik_read_callback (gpointer user_data)
    442 {
    443   gchar *buffer;
    444   gsize buffer_size, buffer_i, events;
    445 
    446   G_LOCK (inotify_lock);
    447   ik_read_events (&buffer_size, &buffer);
    448 
    449   buffer_i = 0;
    450   events = 0;
    451   while (buffer_i < buffer_size)
    452     {
    453       struct inotify_event *event;
    454       gsize event_size;
    455       event = (struct inotify_event *)&buffer[buffer_i];
    456       event_size = sizeof(struct inotify_event) + event->len;
    457       g_queue_push_tail (events_to_process, ik_event_internal_new (ik_event_new (&buffer[buffer_i])));
    458       buffer_i += event_size;
    459       events++;
    460     }
    461 
    462   /* If the event process callback is off, turn it back on */
    463   if (!process_eq_running && events)
    464     {
    465       process_eq_running = TRUE;
    466       g_timeout_add (PROCESS_EVENTS_TIME, ik_process_eq_callback, NULL);
    467     }
    468 
    469   G_UNLOCK (inotify_lock);
    470 
    471   return TRUE;
    472 }
    473 
    474 static gboolean
    475 g_timeval_lt (GTimeVal *val1,
    476               GTimeVal *val2)
    477 {
    478   if (val1->tv_sec < val2->tv_sec)
    479     return TRUE;
    480 
    481   if (val1->tv_sec > val2->tv_sec)
    482     return FALSE;
    483 
    484   /* val1->tv_sec == val2->tv_sec */
    485   if (val1->tv_usec < val2->tv_usec)
    486     return TRUE;
    487 
    488   return FALSE;
    489 }
    490 
    491 static gboolean
    492 g_timeval_eq (GTimeVal *val1,
    493               GTimeVal *val2)
    494 {
    495   return (val1->tv_sec == val2->tv_sec) && (val1->tv_usec == val2->tv_usec);
    496 }
    497 
    498 static void
    499 ik_pair_events (ik_event_internal_t *event1,
    500                 ik_event_internal_t *event2)
    501 {
    502   g_assert (event1 && event2);
    503   /* We should only be pairing events that have the same cookie */
    504   g_assert (event1->event->cookie == event2->event->cookie);
    505   /* We shouldn't pair an event that already is paired */
    506   g_assert (event1->pair == NULL && event2->pair == NULL);
    507 
    508   /* Pair the internal structures and the ik_event_t structures */
    509   event1->pair = event2;
    510   event1->event->pair = event2->event;
    511 
    512   if (g_timeval_lt (&event1->hold_until, &event2->hold_until))
    513     event1->hold_until = event2->hold_until;
    514 
    515   event2->hold_until = event1->hold_until;
    516 }
    517 
    518 static void
    519 ik_event_add_microseconds (ik_event_internal_t *event,
    520                            glong                ms)
    521 {
    522   g_assert (event);
    523   g_time_val_add (&event->hold_until, ms);
    524 }
    525 
    526 static gboolean
    527 ik_event_ready (ik_event_internal_t *event)
    528 {
    529   GTimeVal tv;
    530   g_assert (event);
    531 
    532   g_get_current_time (&tv);
    533 
    534   /* An event is ready if,
    535    *
    536    * it has no cookie -- there is nothing to be gained by holding it
    537    * or, it is already paired -- we don't need to hold it anymore
    538    * or, we have held it long enough
    539    */
    540   return
    541     event->event->cookie == 0 ||
    542     event->pair != NULL ||
    543     g_timeval_lt (&event->hold_until, &tv) ||
    544     g_timeval_eq (&event->hold_until, &tv);
    545 }
    546 
    547 static void
    548 ik_pair_moves (gpointer data,
    549                gpointer user_data)
    550 {
    551   ik_event_internal_t *event = (ik_event_internal_t *)data;
    552 
    553   if (event->seen == TRUE || event->sent == TRUE)
    554     return;
    555 
    556   if (event->event->cookie != 0)
    557     {
    558       /* When we get a MOVED_FROM event we delay sending the event by
    559        * MOVE_HOLD_UNTIL_TIME microseconds. We need to do this because a
    560        * MOVED_TO pair _might_ be coming in the near future */
    561       if (event->event->mask & IN_MOVED_FROM)
    562 	{
    563 	  g_hash_table_insert (cookie_hash, GINT_TO_POINTER (event->event->cookie), event);
    564 	  /* because we don't deliver move events there is no point in waiting for the match right now. */
    565 	  ik_event_add_microseconds (event, MOVE_HOLD_UNTIL_TIME);
    566 	}
    567       else if (event->event->mask & IN_MOVED_TO)
    568 	{
    569 	  /* We need to check if we are waiting for this MOVED_TO events cookie to pair it with
    570 	   * a MOVED_FROM */
    571 	  ik_event_internal_t *match = NULL;
    572 	  match = g_hash_table_lookup (cookie_hash, GINT_TO_POINTER (event->event->cookie));
    573 	  if (match)
    574 	    {
    575 	      g_hash_table_remove (cookie_hash, GINT_TO_POINTER (event->event->cookie));
    576 	      ik_pair_events (match, event);
    577 	    }
    578 	}
    579     }
    580   event->seen = TRUE;
    581 }
    582 
    583 static void
    584 ik_process_events (void)
    585 {
    586   g_queue_foreach (events_to_process, ik_pair_moves, NULL);
    587 
    588   while (!g_queue_is_empty (events_to_process))
    589     {
    590       ik_event_internal_t *event = g_queue_peek_head (events_to_process);
    591 
    592       /* This must have been sent as part of a MOVED_TO/MOVED_FROM */
    593       if (event->sent)
    594 	{
    595 	  /* Pop event */
    596 	  g_queue_pop_head (events_to_process);
    597 	  /* Free the internal event structure */
    598 	  g_free (event);
    599 	  continue;
    600 	}
    601 
    602       /* The event isn't ready yet */
    603       if (!ik_event_ready (event))
    604 	break;
    605 
    606       /* Pop it */
    607       event = g_queue_pop_head (events_to_process);
    608 
    609       /* Check if this is a MOVED_FROM that is also sitting in the cookie_hash */
    610       if (event->event->cookie && event->pair == NULL &&
    611 	  g_hash_table_lookup (cookie_hash, GINT_TO_POINTER (event->event->cookie)))
    612 	g_hash_table_remove (cookie_hash, GINT_TO_POINTER (event->event->cookie));
    613 
    614       if (event->pair)
    615 	{
    616 	  /* We send out paired MOVED_FROM/MOVED_TO events in the same event buffer */
    617 	  /* g_assert (event->event->mask == IN_MOVED_FROM && event->pair->event->mask == IN_MOVED_TO); */
    618 	  /* Copy the paired data */
    619 	  event->pair->sent = TRUE;
    620 	  event->sent = TRUE;
    621 	  ik_move_matches++;
    622 	}
    623       else if (event->event->cookie)
    624 	{
    625 	  /* If we couldn't pair a MOVED_FROM and MOVED_TO together, we change
    626 	   * the event masks */
    627 	  /* Changeing MOVED_FROM to DELETE and MOVED_TO to create lets us make
    628 	   * the gaurantee that you will never see a non-matched MOVE event */
    629 
    630 	  if (event->event->mask & IN_MOVED_FROM)
    631 	    {
    632 	      event->event->mask = IN_DELETE|(event->event->mask & IN_ISDIR);
    633 	      ik_move_misses++; /* not super accurate, if we aren't watching the destination it still counts as a miss */
    634 	    }
    635 	  if (event->event->mask & IN_MOVED_TO)
    636 	    event->event->mask = IN_CREATE|(event->event->mask & IN_ISDIR);
    637 	}
    638 
    639       /* Push the ik_event_t onto the event queue */
    640       g_queue_push_tail (event_queue, event->event);
    641       /* Free the internal event structure */
    642       g_free (event);
    643     }
    644 }
    645 
    646 static gboolean
    647 ik_process_eq_callback (gpointer user_data)
    648 {
    649   gboolean res;
    650 
    651   /* Try and move as many events to the event queue */
    652   G_LOCK (inotify_lock);
    653   ik_process_events ();
    654 
    655   while (!g_queue_is_empty (event_queue))
    656     {
    657       ik_event_t *event = g_queue_pop_head (event_queue);
    658 
    659       user_cb (event);
    660     }
    661 
    662   res = TRUE;
    663 
    664   if (g_queue_get_length (events_to_process) == 0)
    665     {
    666       process_eq_running = FALSE;
    667       res = FALSE;
    668     }
    669 
    670   G_UNLOCK (inotify_lock);
    671 
    672   return res;
    673 }
    674