FreeBSD Bugzilla – Attachment 192768 Details for
Bug 226920
devel/glib20: pull the latest file monitor fix from upstream
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Proposed patch (since 466648 revision)
glib20.diff (text/plain), 33.49 KB, created by
lightside
on 2018-04-24 03:23:47 UTC
(
hide
)
Description:
Proposed patch (since 466648 revision)
Filename:
MIME Type:
Creator:
lightside
Created:
2018-04-24 03:23:47 UTC
Size:
33.49 KB
patch
obsolete
>Index: Makefile >=================================================================== >--- Makefile (revision 466648) >+++ Makefile (working copy) >@@ -3,7 +3,7 @@ > > PORTNAME= glib > PORTVERSION= 2.50.3 >-PORTREVISION= 2 >+PORTREVISION= 3 > PORTEPOCH= 1 > CATEGORIES= devel > MASTER_SITES= GNOME >Index: files/patch-gio_filemonitor >=================================================================== >--- files/patch-gio_filemonitor (nonexistent) >+++ files/patch-gio_filemonitor (working copy) >@@ -0,0 +1,1037 @@ >+# gio: Always purge kqueue subs from missing list >+# https://gitlab.gnome.org/GNOME/glib/commit/e305fe971e4647d971428a772b7290b9c308a96f >+# kqueue: Fix invalid emission of G_FILE_MONITOR_EVENT_MOVED event >+# https://gitlab.gnome.org/GNOME/glib/commit/76072a2dde4a4acc8be8d3c47efbc6811ebe0c1e >+# kqueue: Multiple fixes and simplifications >+# https://gitlab.gnome.org/GNOME/glib/commit/aa39a0557c679fc345b0ba72a87c33152eb8ebcd >+# gpollfilemonitor: Fix use-after-free caused by leaking GSource >+# https://gitlab.gnome.org/GNOME/glib/commit/ba4a9538e14e8ba0ea037cab5f4b23aa47272a4c >+# Reorder operations in _kqsub_cancel() to prevent races. >+# https://gitlab.gnome.org/GNOME/glib/commit/ab179184b883ad378a420223f378071821f0c8b9 >+ >+--- gio/gpollfilemonitor.c.orig 2016-10-22 05:17:34 UTC >++++ gio/gpollfilemonitor.c >+@@ -50,7 +50,9 @@ g_poll_file_monitor_finalize (GObject* o >+ >+ poll_monitor = G_POLL_FILE_MONITOR (object); >+ >++ g_poll_file_monitor_cancel (G_FILE_MONITOR (poll_monitor)); >+ g_object_unref (poll_monitor->file); >++ g_clear_object (&poll_monitor->last_info); >+ >+ G_OBJECT_CLASS (g_poll_file_monitor_parent_class)->finalize (object); >+ } >+--- gio/kqueue/Makefile.in.orig 2017-02-13 15:22:04 UTC >++++ gio/kqueue/Makefile.in >+@@ -183,9 +183,8 @@ LTLIBRARIES = $(installed_test_LTLIBRARI >+ libkqueue_la_LIBADD = >+ am__objects_1 = >+ am_libkqueue_la_OBJECTS = libkqueue_la-gkqueuefilemonitor.lo \ >+- libkqueue_la-kqueue-helper.lo libkqueue_la-kqueue-thread.lo \ >+- libkqueue_la-kqueue-sub.lo libkqueue_la-kqueue-missing.lo \ >+- libkqueue_la-kqueue-utils.lo libkqueue_la-kqueue-exclusions.lo \ >++ libkqueue_la-kqueue-helper.lo \ >++ libkqueue_la-kqueue-missing.lo \ >+ libkqueue_la-dep-list.lo $(am__objects_1) >+ libkqueue_la_OBJECTS = $(am_libkqueue_la_OBJECTS) >+ AM_V_lt = $(am__v_lt_@AM_V@) >+--- gio/kqueue/gkqueuefilemonitor.c.orig 2016-10-22 05:18:22 UTC >++++ gio/kqueue/gkqueuefilemonitor.c >+@@ -22,33 +22,73 @@ >+ >+ #include "config.h" >+ >+-#include "gkqueuefilemonitor.h" >+-#include "kqueue-helper.h" >+-#include "kqueue-exclusions.h" >++#include <sys/types.h> >++#include <sys/event.h> >++#include <sys/time.h> >++#include <sys/socket.h> >++#include <sys/stat.h> >++ >++#include <errno.h> >++#include <fcntl.h> >++#include <string.h> >++ >++#include <glib-object.h> >++#include <gio/gfilemonitor.h> >++#include <gio/glocalfilemonitor.h> >++#include <gio/giomodule.h> >+ #include <gio/gpollfilemonitor.h> >+ #include <gio/gfile.h> >+-#include <gio/giomodule.h> >++#include <glib-unix.h> >++#include "glib-private.h" >+ >++#include "kqueue-helper.h" >++#include "dep-list.h" >+ >+-struct _GKqueueFileMonitor >++G_LOCK_DEFINE_STATIC (kq_lock); >++static GSource *kq_source; >++static int kq_queue = -1; >++ >++#define G_TYPE_KQUEUE_FILE_MONITOR (g_kqueue_file_monitor_get_type ()) >++#define G_KQUEUE_FILE_MONITOR(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \ >++ G_TYPE_KQUEUE_FILE_MONITOR, GKqueueFileMonitor)) >++ >++typedef GLocalFileMonitorClass GKqueueFileMonitorClass; >++ >++typedef struct >+ { >+ GLocalFileMonitor parent_instance; >+ >+ kqueue_sub *sub; >+- >++#ifndef O_EVTONLY >+ GFileMonitor *fallback; >+ GFile *fbfile; >+-}; >++#endif >++} GKqueueFileMonitor; >++ >++GType g_kqueue_file_monitor_get_type (void); >++G_DEFINE_TYPE_WITH_CODE (GKqueueFileMonitor, g_kqueue_file_monitor, G_TYPE_LOCAL_FILE_MONITOR, >++ g_io_extension_point_implement (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME, >++ g_define_type_id, >++ "kqueue", >++ 20)) >++ >++#ifndef O_EVTONLY >++#define O_KQFLAG O_RDONLY >++#else >++#define O_KQFLAG O_EVTONLY >++#endif >++ >++#define NOTE_ALL (NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_ATTRIB|NOTE_RENAME) >+ >+ static gboolean g_kqueue_file_monitor_cancel (GFileMonitor* monitor); >++static gboolean g_kqueue_file_monitor_is_supported (void); >+ >+-G_DEFINE_TYPE_WITH_CODE (GKqueueFileMonitor, g_kqueue_file_monitor, G_TYPE_LOCAL_FILE_MONITOR, >+- g_io_extension_point_implement (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME, >+- g_define_type_id, >+- "kqueue", >+- 20)) >++static kqueue_sub *_kqsub_new (const gchar *, GLocalFileMonitor *, GFileMonitorSource *); >++static void _kqsub_free (kqueue_sub *); >++static gboolean _kqsub_cancel (kqueue_sub *); >+ >+ >++#ifndef O_EVTONLY >+ static void >+ _fallback_callback (GFileMonitor *unused, >+ GFile *first, >+@@ -57,21 +97,41 @@ _fallback_callback (GFileMonitor *u >+ gpointer udata) >+ { >+ GKqueueFileMonitor *kq_mon = G_KQUEUE_FILE_MONITOR (udata); >+- GFileMonitor *mon = G_FILE_MONITOR (kq_mon); >+- g_assert (kq_mon != NULL); >+- g_assert (mon != NULL); >+- (void) unused; >+- >+- if (event == G_FILE_MONITOR_EVENT_CHANGED) >+- { >+- GLocalFileMonitor *local_monitor = G_LOCAL_FILE_MONITOR (kq_mon); >+ >+- _kh_dir_diff (kq_mon->sub, local_monitor->source); >+- } >+- else >+- g_file_monitor_emit_event (mon, first, second, event); >++ g_file_monitor_emit_event (G_FILE_MONITOR (kq_mon), first, second, event); >+ } >+ >++/* >++ * _ke_is_excluded: >++ * @full_path - a path to file to check. >++ * >++ * Returns: TRUE if the file should be excluded from the kqueue-powered >++ * monitoring, FALSE otherwise. >++ **/ >++gboolean >++_ke_is_excluded (const char *full_path) >++{ >++ GFile *f = NULL; >++ GMount *mount = NULL; >++ >++ f = g_file_new_for_path (full_path); >++ >++ if (f != NULL) { >++ mount = g_file_find_enclosing_mount (f, NULL, NULL); >++ g_object_unref (f); >++ } >++ >++ if ((mount != NULL && (g_mount_can_unmount (mount))) || g_str_has_prefix (full_path, "/mnt/")) >++ { >++ g_warning ("Excluding %s from kernel notification, falling back to poll", full_path); >++ if (mount) >++ g_object_unref (mount); >++ return TRUE; >++ } >++ >++ return FALSE; >++} >++#endif /* !O_EVTONLY */ >+ >+ static void >+ g_kqueue_file_monitor_finalize (GObject *object) >+@@ -80,16 +140,18 @@ g_kqueue_file_monitor_finalize (GObject >+ >+ if (kqueue_monitor->sub) >+ { >+- _kh_cancel_sub (kqueue_monitor->sub); >+- _kh_sub_free (kqueue_monitor->sub); >++ _kqsub_cancel (kqueue_monitor->sub); >++ _kqsub_free (kqueue_monitor->sub); >+ kqueue_monitor->sub = NULL; >+ } >+ >++#ifndef O_EVTONLY >+ if (kqueue_monitor->fallback) >+ g_object_unref (kqueue_monitor->fallback); >+ >+ if (kqueue_monitor->fbfile) >+ g_object_unref (kqueue_monitor->fbfile); >++#endif >+ >+ if (G_OBJECT_CLASS (g_kqueue_file_monitor_parent_class)->finalize) >+ (*G_OBJECT_CLASS (g_kqueue_file_monitor_parent_class)->finalize) (object); >+@@ -103,21 +165,25 @@ g_kqueue_file_monitor_start (GLocalFileM >+ GFileMonitorSource *source) >+ { >+ GKqueueFileMonitor *kqueue_monitor = G_KQUEUE_FILE_MONITOR (local_monitor); >+- GObject *obj; >+- GKqueueFileMonitorClass *klass; >+- GObjectClass *parent_class; >+- kqueue_sub *sub = NULL; >+- gboolean ret_kh_startup = FALSE; >+- const gchar *path = NULL; >+- >+- >+- ret_kh_startup = _kh_startup (); >+- g_assert (ret_kh_startup); >++ kqueue_sub *sub; >++ const gchar *path; >+ >+ path = filename; >+- if (!path) >++ if (path == NULL) >+ path = dirname; >+ >++#ifndef O_EVTONLY >++ if (_ke_is_excluded (path)) >++ { >++ GFile *file = g_file_new_for_path (path); >++ kqueue_monitor->fbfile = file; >++ kqueue_monitor->fallback = _g_poll_file_monitor_new (file); >++ g_signal_connect (kqueue_monitor->fallback, "changed", >++ G_CALLBACK (_fallback_callback), kqueue_monitor); >++ return; >++ } >++#endif >++ >+ /* For a directory monitor, create a subscription object anyway. >+ * It will be used for directory diff calculation routines. >+ * Wait, directory diff in a GKqueueFileMonitor? >+@@ -125,33 +191,13 @@ g_kqueue_file_monitor_start (GLocalFileM >+ * file, GIO uses a GKqueueFileMonitor object for that. If a directory >+ * will be created under that path, GKqueueFileMonitor will have to >+ * handle the directory notifications. */ >++ sub = _kqsub_new (path, local_monitor, source); >++ if (sub == NULL) >++ return; >+ >+- sub = _kh_sub_new (path, TRUE, source); >+- >+- /* FIXME: what to do about errors here? we can't return NULL or another >+- * kind of error and an assertion is probably too hard (same issue as in >+- * the inotify backend) */ >+- g_assert (sub != NULL); >+ kqueue_monitor->sub = sub; >+- >+- if (!_ke_is_excluded (path)) >+- _kh_add_sub (sub); >+- else >+- { >+- GFile *file = g_file_new_for_path (path); >+- kqueue_monitor->fbfile = file; >+- kqueue_monitor->fallback = _g_poll_file_monitor_new (file); >+- g_signal_connect (kqueue_monitor->fallback, >+- "changed", >+- G_CALLBACK (_fallback_callback), >+- kqueue_monitor); >+- } >+-} >+- >+-static gboolean >+-g_kqueue_file_monitor_is_supported (void) >+-{ >+- return _kh_startup (); >++ if (!_kqsub_start_watching (sub)) >++ _km_add_missing (sub); >+ } >+ >+ static void >+@@ -175,24 +221,218 @@ g_kqueue_file_monitor_init (GKqueueFileM >+ } >+ >+ static gboolean >++g_kqueue_file_monitor_callback (gint fd, GIOCondition condition, gpointer user_data) >++{ >++ gint64 now = g_source_get_time (kq_source); >++ kqueue_sub *sub; >++ GFileMonitorSource *source; >++ struct kevent ev; >++ struct timespec ts; >++ >++ memset (&ts, 0, sizeof(ts)); >++ while (kevent(fd, NULL, 0, &ev, 1, &ts) > 0) >++ { >++ GFileMonitorEvent mask = 0; >++ >++ if (ev.filter != EVFILT_VNODE || ev.udata == NULL) >++ continue; >++ >++ sub = ev.udata; >++ source = sub->source; >++ >++ if (ev.flags & EV_ERROR) >++ ev.fflags = NOTE_REVOKE; >++ >++ if (ev.fflags & (NOTE_DELETE | NOTE_REVOKE)) >++ { >++ _kqsub_cancel (sub); >++ _km_add_missing (sub); >++ } >++ >++ if (sub->is_dir && ev.fflags & (NOTE_WRITE | NOTE_EXTEND)) >++ { >++ _kh_dir_diff (sub); >++ ev.fflags &= ~(NOTE_WRITE | NOTE_EXTEND); >++ } >++ >++ if (ev.fflags & NOTE_DELETE) >++ { >++ mask = G_FILE_MONITOR_EVENT_DELETED; >++ } >++ else if (ev.fflags & NOTE_ATTRIB) >++ { >++ mask = G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED; >++ } >++ else if (ev.fflags & (NOTE_WRITE | NOTE_EXTEND)) >++ { >++ mask = G_FILE_MONITOR_EVENT_CHANGED; >++ } >++ else if (ev.fflags & NOTE_RENAME) >++ { >++ /* Since thereâs apparently no way to get the new name of the >++ * file out of kqueue(), all we can do is say that this one has >++ * been deleted. */ >++ mask = G_FILE_MONITOR_EVENT_DELETED; >++ } >++ else if (ev.fflags & NOTE_REVOKE) >++ { >++ mask = G_FILE_MONITOR_EVENT_UNMOUNTED; >++ } >++ >++ if (mask) >++ g_file_monitor_source_handle_event (source, mask, NULL, NULL, NULL, now); >++ } >++ >++ return TRUE; >++} >++ >++static gboolean >++g_kqueue_file_monitor_is_supported (void) >++{ >++ int errsv; >++ >++ G_LOCK (kq_lock); >++ >++ if (kq_queue == -1) >++ { >++ kq_queue = kqueue (); >++ errsv = errno; >++ >++ if (kq_queue == -1) >++ { >++ g_warning ("Unable to create a kqueue: %s", g_strerror (errsv)); >++ G_UNLOCK (kq_lock); >++ return FALSE; >++ } >++ >++ kq_source = g_unix_fd_source_new (kq_queue, G_IO_IN); >++ g_source_set_callback (kq_source, (GSourceFunc) g_kqueue_file_monitor_callback, NULL, NULL); >++ g_source_attach (kq_source, GLIB_PRIVATE_CALL (g_get_worker_context) ()); >++ } >++ >++ G_UNLOCK (kq_lock); >++ >++ return TRUE; >++} >++ >++static gboolean >+ g_kqueue_file_monitor_cancel (GFileMonitor *monitor) >+ { >+ GKqueueFileMonitor *kqueue_monitor = G_KQUEUE_FILE_MONITOR (monitor); >+ >+ if (kqueue_monitor->sub) >+ { >+- _kh_cancel_sub (kqueue_monitor->sub); >+- _kh_sub_free (kqueue_monitor->sub); >++ _kqsub_cancel (kqueue_monitor->sub); >++ _kqsub_free (kqueue_monitor->sub); >+ kqueue_monitor->sub = NULL; >+ } >++#ifndef O_EVTONLY >+ else if (kqueue_monitor->fallback) >+ { >+ g_signal_handlers_disconnect_by_func (kqueue_monitor->fallback, _fallback_callback, kqueue_monitor); >+ g_file_monitor_cancel (kqueue_monitor->fallback); >+ } >++#endif >+ >+ if (G_FILE_MONITOR_CLASS (g_kqueue_file_monitor_parent_class)->cancel) >+ (*G_FILE_MONITOR_CLASS (g_kqueue_file_monitor_parent_class)->cancel) (monitor); >+ >+ return TRUE; >+ } >++ >++static kqueue_sub * >++_kqsub_new (const gchar *filename, GLocalFileMonitor *mon, GFileMonitorSource *source) >++{ >++ kqueue_sub *sub; >++ >++ sub = g_slice_new (kqueue_sub); >++ sub->filename = g_strdup (filename); >++ sub->mon = mon; >++ g_source_ref ((GSource *) source); >++ sub->source = source; >++ sub->fd = -1; >++ sub->deps = NULL; >++ sub->is_dir = 0; >++ >++ return sub; >++} >++ >++static void >++_kqsub_free (kqueue_sub *sub) >++{ >++ g_assert (sub->deps == NULL); >++ g_assert (sub->fd == -1); >++ >++ g_source_unref ((GSource *) sub->source); >++ g_free (sub->filename); >++ g_slice_free (kqueue_sub, sub); >++} >++ >++static gboolean >++_kqsub_cancel (kqueue_sub *sub) >++{ >++ struct kevent ev; >++ >++ /* Remove the event and close the file descriptor to automatically >++ * delete pending events. */ >++ if (sub->fd != -1) >++ { >++ EV_SET (&ev, sub->fd, EVFILT_VNODE, EV_DELETE, NOTE_ALL, 0, sub); >++ if (kevent (kq_queue, &ev, 1, NULL, 0, NULL) == -1) >++ { >++ g_warning ("Unable to remove event for %s: %s", sub->filename, g_strerror (errno)); >++ return FALSE; >++ } >++ close (sub->fd); >++ sub->fd = -1; >++ } >++ >++ _km_remove (sub); >++ >++ if (sub->deps) >++ { >++ dl_free (sub->deps); >++ sub->deps = NULL; >++ } >++ >++ return TRUE; >++} >++ >++gboolean >++_kqsub_start_watching (kqueue_sub *sub) >++{ >++ struct stat st; >++ struct kevent ev; >++ >++ sub->fd = open (sub->filename, O_KQFLAG); >++ if (sub->fd == -1) >++ return FALSE; >++ >++ if (fstat (sub->fd, &st) == -1) >++ { >++ g_warning ("fstat failed for %s: %s", sub->filename, g_strerror (errno)); >++ close (sub->fd); >++ sub->fd = -1; >++ return FALSE; >++ } >++ >++ sub->is_dir = (st.st_mode & S_IFDIR) ? 1 : 0; >++ if (sub->is_dir) >++ { >++ if (sub->deps) >++ dl_free (sub->deps); >++ >++ sub->deps = dl_listing (sub->filename); >++ } >++ >++ EV_SET (&ev, sub->fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_ALL, 0, sub); >++ if (kevent (kq_queue, &ev, 1, NULL, 0, NULL) == -1) >++ { >++ g_warning ("Unable to add event for %s: %s", sub->filename, g_strerror (errno)); >++ close (sub->fd); >++ sub->fd = -1; >++ return FALSE; >++ } >++ >++ return TRUE; >++} >+--- gio/kqueue/kqueue-helper.c.orig 2016-10-22 05:18:22 UTC >++++ gio/kqueue/kqueue-helper.c >+@@ -34,81 +34,6 @@ >+ #include <errno.h> >+ #include <pthread.h> >+ #include "kqueue-helper.h" >+-#include "kqueue-utils.h" >+-#include "kqueue-thread.h" >+-#include "kqueue-missing.h" >+-#include "kqueue-exclusions.h" >+- >+-static gboolean kh_debug_enabled = FALSE; >+-#define KH_W if (kh_debug_enabled) g_warning >+- >+-static GHashTable *subs_hash_table = NULL; >+-G_LOCK_DEFINE_STATIC (hash_lock); >+- >+-static int kqueue_descriptor = -1; >+-static int kqueue_socket_pair[] = {-1, -1}; >+-static pthread_t kqueue_thread; >+- >+- >+-void _kh_file_appeared_cb (kqueue_sub *sub); >+- >+-/** >+- * accessor function for kqueue_descriptor >+- **/ >+-int >+-get_kqueue_descriptor() >+-{ >+- return kqueue_descriptor; >+-} >+- >+-/** >+- * convert_kqueue_events_to_gio: >+- * @flags: a set of kqueue filter flags >+- * @done: a pointer to #gboolean indicating that the >+- * conversion has been done (out) >+- * >+- * Translates kqueue filter flags into GIO event flags. >+- * >+- * Returns: a #GFileMonitorEvent >+- **/ >+-static GFileMonitorEvent >+-convert_kqueue_events_to_gio (uint32_t flags, gboolean *done) >+-{ >+- g_assert (done != NULL); >+- *done = FALSE; >+- >+- /* TODO: The following notifications should be emulated, if possible: >+- * - G_FILE_MONITOR_EVENT_PRE_UNMOUNT >+- */ >+- if (flags & NOTE_DELETE) >+- { >+- *done = TRUE; >+- return G_FILE_MONITOR_EVENT_DELETED; >+- } >+- if (flags & NOTE_ATTRIB) >+- { >+- *done = TRUE; >+- return G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED; >+- } >+- if (flags & (NOTE_WRITE | NOTE_EXTEND)) >+- { >+- *done = TRUE; >+- return G_FILE_MONITOR_EVENT_CHANGED; >+- } >+- if (flags & NOTE_RENAME) >+- { >+- *done = TRUE; >+- return G_FILE_MONITOR_EVENT_MOVED; >+- } >+- if (flags & NOTE_REVOKE) >+- { >+- *done = TRUE; >+- return G_FILE_MONITOR_EVENT_UNMOUNTED; >+- } >+- >+- /* done is FALSE */ >+- return 0; >+-} >+ >+ typedef struct { >+ kqueue_sub *sub; >+@@ -236,323 +161,21 @@ static const traverse_cbs cbs = { >+ >+ >+ void >+-_kh_dir_diff (kqueue_sub *sub, GFileMonitorSource *source) >++_kh_dir_diff (kqueue_sub *sub) >+ { >+ dep_list *was; >+ handle_ctx ctx; >+ >+- g_assert (sub != NULL); >+- g_assert (source != NULL); >+- >+ memset (&ctx, 0, sizeof (handle_ctx)); >+ ctx.sub = sub; >+- ctx.source = source; >++ ctx.source = sub->source; >+ >+ was = sub->deps; >+ sub->deps = dl_listing (sub->filename); >+- >++ >+ dl_calculate (was, sub->deps, &cbs, &ctx); >+ >+ dl_free (was); >+ } >+ >+ >+-/** >+- * 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; >+-} >+- >+- >+-/* >+- * _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); >+-} >+- >+- >+-/* >+- * _kh_startup: >+- * Kqueue backend initialization. >+- * >+- * Returns: %TRUE on success, %FALSE otherwise. >+- **/ >+-gboolean >+-_kh_startup (void) >+-{ >+- static GOnce init_once = G_ONCE_INIT; >+- g_once (&init_once, _kh_startup_impl, NULL); >+- return GPOINTER_TO_INT (init_once.retval); >+-} >+- >+- >+-/** >+- * _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; >+-} >+- >+- >+-/** >+- * _kh_add_sub: >+- * @sub: a #kqueue_sub >+- * >+- * Adds a subscription for monitoring. >+- * >+- * This funciton tries to start watching a subscription with >+- * _kh_start_watching(). On failure, i.e. when a file does not exist yet, >+- * the subscription will be added to a list of missing files to continue >+- * watching when the file will appear. >+- * >+- * Returns: %TRUE >+- **/ >+-gboolean >+-_kh_add_sub (kqueue_sub *sub) >+-{ >+- g_assert (sub != NULL); >+- >+- if (!_kh_start_watching (sub)) >+- _km_add_missing (sub); >+- >+- return TRUE; >+-} >+- >+- >+-/** >+- * _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; >+-} >+- >+- >+-/** >+- * _kh_file_appeared_cb: >+- * @sub: a #kqueue_sub >+- * >+- * A callback function for kqueue-missing subsystem. >+- * >+- * Signals that a missing file has finally appeared in the filesystem. >+- * Emits %G_FILE_MONITOR_EVENT_CREATED. >+- **/ >+-void >+-_kh_file_appeared_cb (kqueue_sub *sub) >+-{ >+- GFile* child; >+- >+- g_assert (sub != NULL); >+- g_assert (sub->filename); >+- >+- if (!g_file_test (sub->filename, G_FILE_TEST_EXISTS)) >+- return; >+- >+- child = g_file_new_for_path (sub->filename); >+- >+- g_file_monitor_emit_event (G_FILE_MONITOR (sub->user_data), >+- child, >+- NULL, >+- G_FILE_MONITOR_EVENT_CREATED); >+- >+- g_object_unref (child); >+-} >+--- gio/kqueue/kqueue-helper.h.orig 2016-10-22 05:18:22 UTC >++++ gio/kqueue/kqueue-helper.h >+@@ -23,16 +23,31 @@ >+ #ifndef __KQUEUE_HELPER_H >+ #define __KQUEUE_HELPER_H >+ >+-#include "kqueue-sub.h" >+ #include <gio/glocalfilemonitor.h> >+ #include <gio/gfilemonitor.h> >+ >+-gboolean _kh_startup (void); >+-gboolean _kh_add_sub (kqueue_sub *sub); >+-gboolean _kh_cancel_sub (kqueue_sub *sub); >++#include "dep-list.h" >+ >+-gboolean _kh_start_watching (kqueue_sub *sub); >++/** >++ * kqueue_sub: >++ * @filename: a name of the file to monitor >++ * @fd: the associated file descriptor (used by kqueue) >++ * >++ * Represents a subscription on a file or directory. >++ */ >++typedef struct >++{ >++ GLocalFileMonitor *mon; >++ GFileMonitorSource *source; >++ gchar* filename; >++ int fd; >++ dep_list* deps; >++ int is_dir; >++} kqueue_sub; >+ >+-void _kh_dir_diff (kqueue_sub *sub, GFileMonitorSource *source); >++gboolean _kqsub_start_watching (kqueue_sub *sub); >++void _kh_dir_diff (kqueue_sub *sub); >++void _km_add_missing (kqueue_sub *sub); >++void _km_remove (kqueue_sub *sub); >+ >+ #endif /* __KQUEUE_HELPER_H */ >+--- gio/kqueue/kqueue-missing.c.orig 2016-10-22 05:18:22 UTC >++++ gio/kqueue/kqueue-missing.c >+@@ -23,12 +23,12 @@ >+ #include <glib.h> >+ >+ #include "kqueue-helper.h" >+-#include "kqueue-sub.h" >+-#include "kqueue-missing.h" >+ >+ >+ #define SCAN_MISSING_TIME 4 /* 1/4 Hz */ >+ >++void _kh_file_appeared_cb (kqueue_sub *sub); >++ >+ static gboolean km_scan_missing (gpointer user_data); >+ >+ static gboolean km_debug_enabled = FALSE; >+@@ -38,21 +38,6 @@ static GSList *missing_subs_list = NULL; >+ G_LOCK_DEFINE_STATIC (missing_lock); >+ >+ static volatile gboolean scan_missing_running = FALSE; >+-static on_create_cb file_appeared_callback; >+- >+- >+-/** >+- * _km_init: >+- * @cb: a callback function. It will be called when a watched file >+- * will appear. >+- * >+- * Initialize the kqueue-missing module (optional). >+- **/ >+-void >+-_km_init (on_create_cb cb) >+-{ >+- file_appeared_callback = cb; >+-} >+ >+ >+ /** >+@@ -83,6 +68,35 @@ _km_add_missing (kqueue_sub *sub) >+ } >+ } >+ >++/** >++ * _kh_file_appeared_cb: >++ * @sub: a #kqueue_sub >++ * >++ * A callback function for kqueue-missing subsystem. >++ * >++ * Signals that a missing file has finally appeared in the filesystem. >++ * Emits %G_FILE_MONITOR_EVENT_CREATED. >++ **/ >++void >++_kh_file_appeared_cb (kqueue_sub *sub) >++{ >++ GFile *child; >++ >++ g_assert (sub != NULL); >++ g_assert (sub->filename); >++ >++ if (!g_file_test (sub->filename, G_FILE_TEST_EXISTS)) >++ return; >++ >++ child = g_file_new_for_path (sub->filename); >++ >++ g_file_monitor_emit_event (G_FILE_MONITOR (sub->mon), >++ child, >++ NULL, >++ G_FILE_MONITOR_EVENT_CREATED); >++ >++ g_object_unref (child); >++} >+ >+ /** >+ * km_scan_missing: >+@@ -114,11 +128,10 @@ km_scan_missing (gpointer user_data) >+ g_assert (sub != NULL); >+ g_assert (sub->filename != NULL); >+ >+- if (_kh_start_watching (sub)) >++ if (_kqsub_start_watching (sub)) >+ { >+ KM_W ("file %s now exists, starting watching", sub->filename); >+- if (file_appeared_callback) >+- file_appeared_callback (sub); >++ _kh_file_appeared_cb (sub); >+ not_missing = g_slist_prepend (not_missing, head); >+ } >+ } >Index: files/patch-gio_kqueue_gkqueuefilemonitor.c >=================================================================== >--- files/patch-gio_kqueue_gkqueuefilemonitor.c (revision 466648) >+++ files/patch-gio_kqueue_gkqueuefilemonitor.c (nonexistent) >@@ -1,45 +0,0 @@ >-https://bugzilla.gnome.org/show_bug.cgi?id=739424 >-https://bug739424.bugzilla-attachments.gnome.org/attachment.cgi?id=351191 >- >---- gio/kqueue/gkqueuefilemonitor.c.orig 2018-01-15 21:00:32.535064000 +0100 >-+++ gio/kqueue/gkqueuefilemonitor.c 2018-01-15 21:07:20.920334000 +0100 >-@@ -29,6 +29,15 @@ >- #include <gio/gfile.h> >- #include <gio/giomodule.h> >- >-+/* >-+ * Because ``kqueue_sub'' are not refcounted, we need >-+ * ensure no other thread is getting a reference to >-+ * the element we want to free. >-+ * >-+ * That's why _kh_cancel_sub() must be called with >-+ * this lock held to prevent a race. >-+ */ >-+G_LOCK_EXTERN (hash_lock); >- >- struct _GKqueueFileMonitor >- { >-@@ -80,9 +89,11 @@ g_kqueue_file_monitor_finalize (GObject *object) >- >- if (kqueue_monitor->sub) >- { >-+ G_LOCK (hash_lock); >- _kh_cancel_sub (kqueue_monitor->sub); >- _kh_sub_free (kqueue_monitor->sub); >- kqueue_monitor->sub = NULL; >-+ G_UNLOCK (hash_lock); >- } >- >- if (kqueue_monitor->fallback) >-@@ -181,9 +192,11 @@ g_kqueue_file_monitor_cancel (GFileMonitor *monitor) >- >- if (kqueue_monitor->sub) >- { >-+ G_LOCK (hash_lock); >- _kh_cancel_sub (kqueue_monitor->sub); >- _kh_sub_free (kqueue_monitor->sub); >- kqueue_monitor->sub = NULL; >-+ G_UNLOCK (hash_lock); >- } >- else if (kqueue_monitor->fallback) >- { >Index: files/patch-gio_kqueue_kqueue-helper.c >=================================================================== >--- files/patch-gio_kqueue_kqueue-helper.c (revision 466648) >+++ files/patch-gio_kqueue_kqueue-helper.c (nonexistent) >@@ -1,96 +0,0 @@ >-This bug combines serveral patches: >-https://bugzilla.gnome.org/show_bug.cgi?id=778515 >-and >-https://bugzilla.gnome.org/show_bug.cgi?id=739424 >-https://bug739424.bugzilla-attachments.gnome.org/attachment.cgi?id=351191 >- >-https://bugzilla.gnome.org/show_bug.cgi?id=776147 >-https://git.gnome.org/browse/glib/commit/?id=76072a2dde4a4acc8be8d3c47efbc6811ebe0c1e >- >---- gio/kqueue/kqueue-helper.c.orig 2018-01-28 21:18:25.213606000 +0100 >-+++ gio/kqueue/kqueue-helper.c 2018-01-28 21:18:34.964780000 +0100 >-@@ -43,7 +43,7 @@ static gboolean kh_debug_enabled = FALSE; >- #define KH_W if (kh_debug_enabled) g_warning >- >- static GHashTable *subs_hash_table = NULL; >--G_LOCK_DEFINE_STATIC (hash_lock); >-+G_LOCK_DEFINE (hash_lock); >- >- static int kqueue_descriptor = -1; >- static int kqueue_socket_pair[] = {-1, -1}; >-@@ -97,8 +97,10 @@ convert_kqueue_events_to_gio (uint32_t flags, gboolean >- } >- if (flags & NOTE_RENAME) >- { >-+ /* Since thereâs apparently no way to get the new name of the file out of >-+ * kqueue(), all we can do is say that this one has been deleted. */ >- *done = TRUE; >-- return G_FILE_MONITOR_EVENT_MOVED; >-+ return G_FILE_MONITOR_EVENT_DELETED; >- } >- if (flags & NOTE_REVOKE) >- { >-@@ -291,10 +293,10 @@ process_kqueue_notifications (GIOChannel *gioc, >- >- 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) >- { >-+ G_UNLOCK (hash_lock); >- KH_W ("Got a notification for a deleted or non-existing subscription %d", >- n.fd); >- return TRUE; >-@@ -336,6 +338,7 @@ process_kqueue_notifications (GIOChannel *gioc, >- g_file_monitor_source_handle_event (source, mask, NULL, NULL, NULL, g_get_monotonic_time ()); >- } >- >-+ G_UNLOCK (hash_lock); >- return TRUE; >- } >- >-@@ -451,13 +454,14 @@ _kh_start_watching (kqueue_sub *sub) >- >- 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); >-+ G_UNLOCK (hash_lock); >-+ >- return TRUE; >- } >- >-@@ -498,22 +502,15 @@ _kh_add_sub (kqueue_sub *sub) >- gboolean >- _kh_cancel_sub (kqueue_sub *sub) >- { >-- gboolean missing = FALSE; >-+ gboolean removed = 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); >-+ _km_remove (sub); >- >-- if (missing) >-- { >-- /* If there were no fd for this subscription, file is still >-- * missing. */ >-- KH_W ("Removing subscription from missing"); >-- _km_remove (sub); >-- } >-- else >-+ removed = g_hash_table_remove (subs_hash_table, GINT_TO_POINTER (sub->fd)); >-+ >-+ if (removed) >- { >- /* fd will be closed in the kqueue thread */ >- _kqueue_thread_remove_fd (sub->fd);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 226920
:
191808
|
191837
|
191855
|
191861
|
191868
|
191869
|
191870
|
192573
|
192575
|
192641
|
192694
|
192768
|
192769