コード例 #1
0
/**
 * _kh_cancel_sub:
 * @sub a #kqueue_sub
 *
 * Stops monitoring on a subscription.
 *
 * Returns: %TRUE
 **/
gboolean
_kh_cancel_sub (kqueue_sub *sub)
{
  gboolean missing = FALSE;
  g_assert (kqueue_socket_pair[0] != -1);
  g_assert (sub != NULL);

  G_LOCK (hash_lock);
  missing = !g_hash_table_remove (subs_hash_table, GINT_TO_POINTER (sub->fd));
  G_UNLOCK (hash_lock);

  if (missing)
    {
      /* If there were no fd for this subscription, file is still
       * missing. */
      KH_W ("Removing subscription from missing");
      _km_remove (sub);
    }
  else
    {
      /* fd will be closed in the kqueue thread */
      _kqueue_thread_remove_fd (sub->fd);

      /* Bump the kqueue thread. It will pick up a new sub entry to remove*/
      if (!_ku_write (kqueue_socket_pair[0], "R", 1))
        KH_W ("Failed to bump the kqueue thread (remove fd, error %d)", errno);
    }

  return TRUE;
}
コード例 #2
0
ファイル: kqueue-helper.c プロジェクト: johne53/MB3Glib
/**
 * _kh_cancel_sub:
 * @sub a #kqueue_sub
 *
 * Stops monitoring on a subscription.
 *
 * Returns: %TRUE
 **/
gboolean
_kh_cancel_sub (kqueue_sub *sub)
{
  gboolean removed = FALSE;
  g_assert (kqueue_socket_pair[0] != -1);
  g_assert (sub != NULL);

  _km_remove (sub);

  G_LOCK (hash_lock);
  removed = g_hash_table_remove (subs_hash_table, GINT_TO_POINTER (sub->fd));
  G_UNLOCK (hash_lock);

  if (removed)
    {
      /* fd will be closed in the kqueue thread */
      _kqueue_thread_remove_fd (sub->fd);

      /* Bump the kqueue thread. It will pick up a new sub entry to remove*/
      if (!_ku_write (kqueue_socket_pair[0], "R", 1))
        KH_W ("Failed to bump the kqueue thread (remove fd, error %d)", errno);
    }

  return TRUE;
}
コード例 #3
0
/**
 * handle_overwritten:
 * @data: a pointer to user data (#handle_context).
 * @path: file name of the overwritten file.
 * @node: inode number of the overwritten file.
 *
 * A callback function for the directory diff calculation routine,
 * produces G_FILE_MONITOR_EVENT_DELETED/CREATED event pair when
 * an overwrite occurs in the directory (see dep-list for details).
 **/
static void
handle_overwritten (void *udata, const char *path, ino_t inode)
{
  handle_ctx *ctx = NULL;
  GFile *file = NULL;
  gchar *fpath = NULL;

  (void) inode;
  ctx = (handle_ctx *) udata;
  g_assert (udata != NULL);
  g_assert (ctx->sub != NULL);
  g_assert (ctx->monitor != NULL);

  fpath = _ku_path_concat (ctx->sub->filename, path);
  if (fpath == NULL)
    {
      KH_W ("Failed to allocate a string for a new event");
      return;
    }

  file = g_file_new_for_path (fpath);
  g_file_monitor_emit_event (ctx->monitor,
                             file,
                             NULL,
                             G_FILE_MONITOR_EVENT_DELETED);
  g_file_monitor_emit_event (ctx->monitor,
                             file,
                             NULL,
                             G_FILE_MONITOR_EVENT_CREATED);

  g_free (fpath);
  g_object_unref (file);
}
コード例 #4
0
ファイル: kqueue-helper.c プロジェクト: johne53/MB3Glib
/**
 * _kh_start_watching:
 * @sub: a #kqueue_sub
 *
 * Starts watching on a subscription.
 *
 * Returns: %TRUE on success, %FALSE otherwise.
 **/
gboolean
_kh_start_watching (kqueue_sub *sub)
{
  g_assert (kqueue_socket_pair[0] != -1);
  g_assert (sub != NULL);
  g_assert (sub->filename != NULL);

  /* kqueue requires a file descriptor to monitor. Sad but true */
#if defined (O_EVTONLY)
  sub->fd = open (sub->filename, O_EVTONLY);
#else
  sub->fd = open (sub->filename, O_RDONLY);
#endif

  if (sub->fd == -1)
    {
      KH_W ("failed to open file %s (error %d)", sub->filename, errno);
      return FALSE;
    }

  _ku_file_information (sub->fd, &sub->is_dir, NULL);
  if (sub->is_dir)
    {
      /* I know, it is very bad to make such decisions in this way and here.
       * We already do have an user_data at the #kqueue_sub, and it may point to
       * GKqueueFileMonitor or GKqueueDirectoryMonitor. For a directory case,
       * we need to scan in contents for the further diffs. Ideally this process
       * should be delegated to the GKqueueDirectoryMonitor, but for now I will
       * do it in a dirty way right here. */
      if (sub->deps)
        dl_free (sub->deps);

      sub->deps = dl_listing (sub->filename);  
    }

  G_LOCK (hash_lock);
  g_hash_table_insert (subs_hash_table, GINT_TO_POINTER (sub->fd), sub);
  G_UNLOCK (hash_lock);

  _kqueue_thread_push_fd (sub->fd);
  
  /* Bump the kqueue thread. It will pick up a new sub entry to monitor */
  if (!_ku_write (kqueue_socket_pair[0], "A", 1))
    KH_W ("Failed to bump the kqueue thread (add fd, error %d)", errno);
  return TRUE;
}
コード例 #5
0
/**
 * handle_moved:
 * @udata: a pointer to user data (#handle_context).
 * @from_path: file name of the source file.
 * @from_inode: inode number of the source file.
 * @to_path: file name of the replaced file.
 * @to_inode: inode number of the replaced file.
 *
 * A callback function for the directory diff calculation routine,
 * produces G_FILE_MONITOR_EVENT_MOVED event on a move.
 **/
static void
handle_moved (void       *udata,
              const char *from_path,
              ino_t       from_inode,
              const char *to_path,
              ino_t       to_inode)
{
  handle_ctx *ctx = NULL;
  GFile *file = NULL;
  GFile *other = NULL;
  gchar *path = NULL;
  gchar *npath = NULL;

  (void) from_inode;
  (void) to_inode;

  ctx = (handle_ctx *) udata;
  g_assert (udata != NULL);
  g_assert (ctx->sub != NULL);
  g_assert (ctx->monitor != NULL);


  path = _ku_path_concat (ctx->sub->filename, from_path);
  npath = _ku_path_concat (ctx->sub->filename, to_path);
  if (path == NULL || npath == NULL)
    {
      KH_W ("Failed to allocate strings for event");
      return;
    }

  file = g_file_new_for_path (path);
  other = g_file_new_for_path (npath);

  if (ctx->sub->pair_moves)
    {
      g_file_monitor_emit_event (ctx->monitor,
                                 file,
                                 other,
                                 G_FILE_MONITOR_EVENT_MOVED);
    }
  else
    {
      g_file_monitor_emit_event (ctx->monitor,
                                 file,
                                 NULL,
                                 G_FILE_MONITOR_EVENT_DELETED);
      g_file_monitor_emit_event (ctx->monitor,
                                 other,
                                 NULL,
                                 G_FILE_MONITOR_EVENT_CREATED);
    }

  g_free (path);
  g_free (npath);

  g_object_unref (file);
  g_object_unref (other);
}
コード例 #6
0
ファイル: kqueue-helper.c プロジェクト: johne53/MB3Glib
/*
 * _kh_startup_impl:
 * @unused: unused
 *
 * Kqueue backend startup code. Should be called only once.
 *
 * Returns: %TRUE on success, %FALSE otherwise.
 **/
static gpointer
_kh_startup_impl (gpointer unused)
{
  GIOChannel *channel = NULL;
  gboolean result = FALSE;

  kqueue_descriptor = kqueue ();
  result = (kqueue_descriptor != -1);
  if (!result)
    {
      KH_W ("Failed to initialize kqueue\n!");
      return GINT_TO_POINTER (FALSE);
    }

  result = socketpair (AF_UNIX, SOCK_STREAM, 0, kqueue_socket_pair);
  if (result != 0)
    {
      KH_W ("Failed to create socket pair\n!");
      return GINT_TO_POINTER (FALSE) ;
    }

  result = pthread_create (&kqueue_thread,
                           NULL,
                           _kqueue_thread_func,
                           &kqueue_socket_pair[1]);
  if (result != 0)
    {
      KH_W ("Failed to run kqueue thread\n!");
      return GINT_TO_POINTER (FALSE);
    }

  _km_init (_kh_file_appeared_cb);

  channel = g_io_channel_unix_new (kqueue_socket_pair[0]);
  g_io_add_watch (channel, G_IO_IN, process_kqueue_notifications, NULL);

  subs_hash_table = g_hash_table_new (g_direct_hash, g_direct_equal);

  KH_W ("started gio kqueue backend\n");
  return GINT_TO_POINTER (TRUE);
}
コード例 #7
0
ファイル: kqueue-helper.c プロジェクト: johne53/MB3Glib
/**
 * process_kqueue_notifications:
 * @gioc: unused.
 * @cond: unused.
 * @data: unused.
 *
 * Processes notifications, coming from the kqueue thread.
 *
 * Reads notifications from the command file descriptor, emits the
 * "changed" event on the appropriate monitor.
 *
 * A typical GIO Channel callback function.
 *
 * Returns: %TRUE
 **/
static gboolean
process_kqueue_notifications (GIOChannel   *gioc,
                              GIOCondition  cond,
                              gpointer      data)
{
  struct kqueue_notification n;
  kqueue_sub *sub = NULL;
  GFileMonitorSource *source = NULL;
  GFileMonitorEvent mask = 0;
  
  g_assert (kqueue_socket_pair[0] != -1);
  if (!_ku_read (kqueue_socket_pair[0], &n, sizeof (struct kqueue_notification)))
    {
      KH_W ("Failed to read a kqueue notification, error %d", errno);
      return TRUE;
    }

  G_LOCK (hash_lock);
  sub = (kqueue_sub *) g_hash_table_lookup (subs_hash_table, GINT_TO_POINTER (n.fd));
  G_UNLOCK (hash_lock);

  if (sub == NULL)
    {
      KH_W ("Got a notification for a deleted or non-existing subscription %d",
             n.fd);
      return TRUE;
    }

  source = sub->user_data;
  g_assert (source != NULL);

  if (n.flags & (NOTE_DELETE | NOTE_REVOKE))
    {
      if (sub->deps)
        {
          dl_free (sub->deps);
          sub->deps = NULL;  
        }  
      _km_add_missing (sub);

      if (!(n.flags & NOTE_REVOKE))
        {
          /* Note that NOTE_REVOKE is issued by the kqueue thread
           * on EV_ERROR kevent. In this case, a file descriptor is
           * already closed from the kqueue thread, no need to close
           * it manually */ 
          _kh_cancel_sub (sub);
        }
    }

  if (sub->is_dir && n.flags & (NOTE_WRITE | NOTE_EXTEND))
    {
      _kh_dir_diff (sub, source);
      n.flags &= ~(NOTE_WRITE | NOTE_EXTEND);
    }

  if (n.flags)
    {
      gboolean done = FALSE;
      mask = convert_kqueue_events_to_gio (n.flags, &done);
      if (done == TRUE)
        g_file_monitor_source_handle_event (source, mask, NULL, NULL, NULL, g_get_monotonic_time ());
    }

  return TRUE;
}