View | Details | Raw Unified | Return to bug 226920 | Differences between
and this patch

Collapse All | Expand All

(-)Makefile (-1 / +1 lines)
Lines 3-9 Link Here
3
3
4
PORTNAME=	glib
4
PORTNAME=	glib
5
PORTVERSION=	2.50.3
5
PORTVERSION=	2.50.3
6
PORTREVISION=	1
6
PORTREVISION=	2
7
PORTEPOCH=	1
7
PORTEPOCH=	1
8
CATEGORIES=	devel
8
CATEGORIES=	devel
9
MASTER_SITES=	GNOME
9
MASTER_SITES=	GNOME
(-)files/patch-gio_filemonitor (+1056 lines)
Line 0 Link Here
1
# gio: Always purge kqueue subs from missing list
2
# https://github.com/GNOME/glib/commit/e305fe971e4647d971428a772b7290b9c308a96f
3
# kqueue: Fix invalid emission of G_FILE_MONITOR_EVENT_MOVED event
4
# https://github.com/GNOME/glib/commit/76072a2dde4a4acc8be8d3c47efbc6811ebe0c1e
5
# kqueue: Multiple fixes and simplifications
6
# https://github.com/GNOME/glib/commit/aa39a0557c679fc345b0ba72a87c33152eb8ebcd
7
# gpollfilemonitor: Fix use-after-free caused by leaking GSource
8
# https://github.com/GNOME/glib/commit/ba4a9538e14e8ba0ea037cab5f4b23aa47272a4c
9
# Convert gio/kqueue/Makefile.am to gio/kqueue/Makefile.in patch
10
11
--- gio/gpollfilemonitor.c.orig	2016-10-22 05:17:34 UTC
12
+++ gio/gpollfilemonitor.c
13
@@ -50,7 +50,9 @@ g_poll_file_monitor_finalize (GObject* o
14
   
15
   poll_monitor = G_POLL_FILE_MONITOR (object);
16
 
17
+  g_poll_file_monitor_cancel (G_FILE_MONITOR (poll_monitor));
18
   g_object_unref (poll_monitor->file);
19
+  g_clear_object (&poll_monitor->last_info);
20
 
21
   G_OBJECT_CLASS (g_poll_file_monitor_parent_class)->finalize (object);
22
 }
23
--- gio/kqueue/Makefile.in.orig	2017-02-13 15:22:04 UTC
24
+++ gio/kqueue/Makefile.in
25
@@ -183,9 +183,8 @@ LTLIBRARIES = $(installed_test_LTLIBRARI
26
 libkqueue_la_LIBADD =
27
 am__objects_1 =
28
 am_libkqueue_la_OBJECTS = libkqueue_la-gkqueuefilemonitor.lo \
29
-	libkqueue_la-kqueue-helper.lo libkqueue_la-kqueue-thread.lo \
30
-	libkqueue_la-kqueue-sub.lo libkqueue_la-kqueue-missing.lo \
31
-	libkqueue_la-kqueue-utils.lo libkqueue_la-kqueue-exclusions.lo \
32
+	libkqueue_la-kqueue-helper.lo \
33
+	libkqueue_la-kqueue-missing.lo \
34
 	libkqueue_la-dep-list.lo $(am__objects_1)
35
 libkqueue_la_OBJECTS = $(am_libkqueue_la_OBJECTS)
36
 AM_V_lt = $(am__v_lt_@AM_V@)
37
@@ -778,19 +777,9 @@ all_test_ltlibs = $(test_ltlibraries) $(
38
 @ENABLE_INSTALLED_TESTS_TRUE@installed_test_meta_DATA = $(installed_testcases:=.test)
39
 libkqueue_la_SOURCES = \
40
        gkqueuefilemonitor.c \
41
-       gkqueuefilemonitor.h \
42
        kqueue-helper.c \
43
        kqueue-helper.h \
44
-       kqueue-thread.c \
45
-       kqueue-thread.h \
46
-       kqueue-sub.c \
47
-       kqueue-sub.h \
48
        kqueue-missing.c \
49
-       kqueue-missing.h \
50
-       kqueue-utils.c \
51
-       kqueue-utils.h \
52
-       kqueue-exclusions.c \
53
-       kqueue-exclusions.h \
54
        dep-list.c \
55
        dep-list.h \
56
        $(NULL)
57
--- gio/kqueue/gkqueuefilemonitor.c.orig	2016-10-22 05:18:22 UTC
58
+++ gio/kqueue/gkqueuefilemonitor.c
59
@@ -22,33 +22,73 @@
60
 
61
 #include "config.h"
62
 
63
-#include "gkqueuefilemonitor.h"
64
-#include "kqueue-helper.h"
65
-#include "kqueue-exclusions.h"
66
+#include <sys/types.h>
67
+#include <sys/event.h>
68
+#include <sys/time.h>
69
+#include <sys/socket.h>
70
+#include <sys/stat.h>
71
+
72
+#include <errno.h>
73
+#include <fcntl.h>
74
+#include <string.h>
75
+
76
+#include <glib-object.h>
77
+#include <gio/gfilemonitor.h>
78
+#include <gio/glocalfilemonitor.h>
79
+#include <gio/giomodule.h>
80
 #include <gio/gpollfilemonitor.h>
81
 #include <gio/gfile.h>
82
-#include <gio/giomodule.h>
83
+#include <glib-unix.h>
84
+#include "glib-private.h"
85
 
86
+#include "kqueue-helper.h"
87
+#include "dep-list.h"
88
 
89
-struct _GKqueueFileMonitor
90
+G_LOCK_DEFINE_STATIC (kq_lock);
91
+static GSource       *kq_source;
92
+static int	      kq_queue = -1;
93
+
94
+#define G_TYPE_KQUEUE_FILE_MONITOR	(g_kqueue_file_monitor_get_type ())
95
+#define G_KQUEUE_FILE_MONITOR(inst)	(G_TYPE_CHECK_INSTANCE_CAST ((inst), \
96
+					G_TYPE_KQUEUE_FILE_MONITOR, GKqueueFileMonitor))
97
+
98
+typedef GLocalFileMonitorClass GKqueueFileMonitorClass;
99
+
100
+typedef struct
101
 {
102
   GLocalFileMonitor parent_instance;
103
 
104
   kqueue_sub *sub;
105
-
106
+#ifndef O_EVTONLY
107
   GFileMonitor *fallback;
108
   GFile *fbfile;
109
-};
110
+#endif
111
+} GKqueueFileMonitor;
112
+
113
+GType g_kqueue_file_monitor_get_type (void);
114
+G_DEFINE_TYPE_WITH_CODE (GKqueueFileMonitor, g_kqueue_file_monitor, G_TYPE_LOCAL_FILE_MONITOR,
115
+	g_io_extension_point_implement (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
116
+		g_define_type_id,
117
+                "kqueue",
118
+		20))
119
+
120
+#ifndef O_EVTONLY
121
+#define O_KQFLAG O_RDONLY
122
+#else
123
+#define O_KQFLAG O_EVTONLY
124
+#endif
125
+
126
+#define NOTE_ALL (NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_ATTRIB|NOTE_RENAME)
127
 
128
 static gboolean g_kqueue_file_monitor_cancel (GFileMonitor* monitor);
129
+static gboolean g_kqueue_file_monitor_is_supported (void);
130
 
131
-G_DEFINE_TYPE_WITH_CODE (GKqueueFileMonitor, g_kqueue_file_monitor, G_TYPE_LOCAL_FILE_MONITOR,
132
-       g_io_extension_point_implement (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
133
-               g_define_type_id,
134
-               "kqueue",
135
-               20))
136
+static kqueue_sub	*_kqsub_new (const gchar *, GLocalFileMonitor *, GFileMonitorSource *);
137
+static void		 _kqsub_free (kqueue_sub *);
138
+static gboolean		 _kqsub_cancel (kqueue_sub *);
139
 
140
 
141
+#ifndef O_EVTONLY
142
 static void
143
 _fallback_callback (GFileMonitor      *unused,
144
                     GFile             *first,
145
@@ -57,21 +97,41 @@ _fallback_callback (GFileMonitor      *u
146
                     gpointer           udata)
147
 {
148
   GKqueueFileMonitor *kq_mon = G_KQUEUE_FILE_MONITOR (udata);
149
-  GFileMonitor *mon = G_FILE_MONITOR (kq_mon);
150
-  g_assert (kq_mon != NULL);
151
-  g_assert (mon != NULL);
152
-  (void) unused;
153
-
154
-  if (event == G_FILE_MONITOR_EVENT_CHANGED)
155
-    {
156
-      GLocalFileMonitor *local_monitor = G_LOCAL_FILE_MONITOR (kq_mon);
157
 
158
-      _kh_dir_diff (kq_mon->sub, local_monitor->source);
159
-    }
160
-  else
161
-    g_file_monitor_emit_event (mon, first, second, event);
162
+  g_file_monitor_emit_event (G_FILE_MONITOR (kq_mon), first, second, event);
163
 }
164
 
165
+/*
166
+ * _ke_is_excluded:
167
+ * @full_path - a path to file to check.
168
+ *
169
+ * Returns: TRUE if the file should be excluded from the kqueue-powered
170
+ *      monitoring, FALSE otherwise.
171
+ **/
172
+gboolean
173
+_ke_is_excluded (const char *full_path)
174
+{
175
+  GFile *f = NULL;
176
+  GMount *mount = NULL;
177
+
178
+  f = g_file_new_for_path (full_path);
179
+
180
+  if (f != NULL) {
181
+    mount = g_file_find_enclosing_mount (f, NULL, NULL);
182
+    g_object_unref (f);
183
+  }
184
+
185
+  if ((mount != NULL && (g_mount_can_unmount (mount))) || g_str_has_prefix (full_path, "/mnt/"))
186
+  {
187
+    g_warning ("Excluding %s from kernel notification, falling back to poll", full_path);
188
+    if (mount)
189
+      g_object_unref (mount);
190
+    return TRUE;
191
+  }
192
+
193
+  return FALSE;
194
+}
195
+#endif /* !O_EVTONLY */
196
 
197
 static void
198
 g_kqueue_file_monitor_finalize (GObject *object)
199
@@ -80,16 +140,18 @@ g_kqueue_file_monitor_finalize (GObject 
200
 
201
   if (kqueue_monitor->sub)
202
     {
203
-      _kh_cancel_sub (kqueue_monitor->sub);
204
-      _kh_sub_free (kqueue_monitor->sub);
205
+      _kqsub_cancel (kqueue_monitor->sub);
206
+      _kqsub_free (kqueue_monitor->sub);
207
       kqueue_monitor->sub = NULL;
208
     }
209
 
210
+#ifndef O_EVTONLY
211
   if (kqueue_monitor->fallback)
212
     g_object_unref (kqueue_monitor->fallback);
213
 
214
   if (kqueue_monitor->fbfile)
215
     g_object_unref (kqueue_monitor->fbfile);
216
+#endif
217
 
218
   if (G_OBJECT_CLASS (g_kqueue_file_monitor_parent_class)->finalize)
219
     (*G_OBJECT_CLASS (g_kqueue_file_monitor_parent_class)->finalize) (object);
220
@@ -103,21 +165,25 @@ g_kqueue_file_monitor_start (GLocalFileM
221
                              GFileMonitorSource *source)
222
 {
223
   GKqueueFileMonitor *kqueue_monitor = G_KQUEUE_FILE_MONITOR (local_monitor);
224
-  GObject *obj;
225
-  GKqueueFileMonitorClass *klass;
226
-  GObjectClass *parent_class;
227
-  kqueue_sub *sub = NULL;
228
-  gboolean ret_kh_startup = FALSE;
229
-  const gchar *path = NULL; 
230
-
231
-
232
-  ret_kh_startup = _kh_startup ();
233
-  g_assert (ret_kh_startup);
234
+  kqueue_sub *sub;
235
+  const gchar *path;
236
 
237
   path = filename;
238
-  if (!path)
239
+  if (path == NULL)
240
     path = dirname;
241
 
242
+#ifndef O_EVTONLY
243
+  if (_ke_is_excluded (path))
244
+    {
245
+      GFile *file = g_file_new_for_path (path);
246
+      kqueue_monitor->fbfile = file;
247
+      kqueue_monitor->fallback = _g_poll_file_monitor_new (file);
248
+      g_signal_connect (kqueue_monitor->fallback, "changed",
249
+			G_CALLBACK (_fallback_callback), kqueue_monitor);
250
+      return;
251
+    }
252
+#endif
253
+
254
   /* For a directory monitor, create a subscription object anyway.
255
    * It will be used for directory diff calculation routines. 
256
    * Wait, directory diff in a GKqueueFileMonitor?
257
@@ -125,33 +191,13 @@ g_kqueue_file_monitor_start (GLocalFileM
258
    * file, GIO uses a GKqueueFileMonitor object for that. If a directory
259
    * will be created under that path, GKqueueFileMonitor will have to
260
    * handle the directory notifications. */
261
+  sub = _kqsub_new (path, local_monitor, source);
262
+  if (sub == NULL)
263
+    return;
264
 
265
-  sub = _kh_sub_new (path, TRUE, source);
266
-
267
-  /* FIXME: what to do about errors here? we can't return NULL or another
268
-   * kind of error and an assertion is probably too hard (same issue as in
269
-   * the inotify backend) */
270
-  g_assert (sub != NULL);
271
   kqueue_monitor->sub = sub;
272
-
273
-  if (!_ke_is_excluded (path))
274
-    _kh_add_sub (sub);
275
-  else
276
-    {
277
-      GFile *file = g_file_new_for_path (path);
278
-      kqueue_monitor->fbfile = file;
279
-      kqueue_monitor->fallback = _g_poll_file_monitor_new (file);
280
-      g_signal_connect (kqueue_monitor->fallback,
281
-                        "changed",
282
-                        G_CALLBACK (_fallback_callback),
283
-                        kqueue_monitor);
284
-    }
285
-}
286
-
287
-static gboolean
288
-g_kqueue_file_monitor_is_supported (void)
289
-{
290
-  return _kh_startup ();
291
+  if (!_kqsub_start_watching (sub))
292
+    _km_add_missing (sub);
293
 }
294
 
295
 static void
296
@@ -175,24 +221,218 @@ g_kqueue_file_monitor_init (GKqueueFileM
297
 }
298
 
299
 static gboolean
300
+g_kqueue_file_monitor_callback (gint fd, GIOCondition condition, gpointer user_data)
301
+{
302
+  gint64 now = g_source_get_time (kq_source);
303
+  kqueue_sub *sub;
304
+  GFileMonitorSource *source;
305
+  struct kevent ev;
306
+  struct timespec ts;
307
+
308
+  memset (&ts, 0, sizeof(ts));
309
+  while (kevent(fd, NULL, 0, &ev, 1, &ts) > 0)
310
+    {
311
+        GFileMonitorEvent mask = 0;
312
+
313
+        if (ev.filter != EVFILT_VNODE || ev.udata == NULL)
314
+          continue;
315
+
316
+	sub = ev.udata;
317
+        source = sub->source;
318
+
319
+        if (ev.flags & EV_ERROR)
320
+          ev.fflags = NOTE_REVOKE;
321
+
322
+        if (ev.fflags & (NOTE_DELETE | NOTE_REVOKE))
323
+          {
324
+            _kqsub_cancel (sub);
325
+            _km_add_missing (sub);
326
+          }
327
+
328
+        if (sub->is_dir && ev.fflags & (NOTE_WRITE | NOTE_EXTEND))
329
+          {
330
+            _kh_dir_diff (sub);
331
+            ev.fflags &= ~(NOTE_WRITE | NOTE_EXTEND);
332
+          }
333
+
334
+        if (ev.fflags & NOTE_DELETE)
335
+          {
336
+            mask = G_FILE_MONITOR_EVENT_DELETED;
337
+          }
338
+        else if (ev.fflags & NOTE_ATTRIB)
339
+          {
340
+            mask = G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED;
341
+          }
342
+        else if (ev.fflags & (NOTE_WRITE | NOTE_EXTEND))
343
+          {
344
+            mask = G_FILE_MONITOR_EVENT_CHANGED;
345
+          }
346
+        else if (ev.fflags & NOTE_RENAME)
347
+          {
348
+            /* Since there’s apparently no way to get the new name of the
349
+             * file out of kqueue(), all we can do is say that this one has
350
+             * been deleted. */
351
+            mask = G_FILE_MONITOR_EVENT_DELETED;
352
+          }
353
+        else if (ev.fflags & NOTE_REVOKE)
354
+          {
355
+            mask = G_FILE_MONITOR_EVENT_UNMOUNTED;
356
+          }
357
+
358
+        if (mask)
359
+          g_file_monitor_source_handle_event (source, mask, NULL, NULL, NULL, now);
360
+    }
361
+
362
+  return TRUE;
363
+}
364
+
365
+static gboolean
366
+g_kqueue_file_monitor_is_supported (void)
367
+{
368
+  int errsv;
369
+
370
+  G_LOCK (kq_lock);
371
+
372
+  if (kq_queue == -1)
373
+    {
374
+      kq_queue = kqueue ();
375
+      errsv = errno;
376
+
377
+      if (kq_queue == -1)
378
+        {
379
+          g_warning ("Unable to create a kqueue: %s", g_strerror (errsv));
380
+          G_UNLOCK (kq_lock);
381
+          return FALSE;
382
+        }
383
+
384
+      kq_source = g_unix_fd_source_new (kq_queue, G_IO_IN);
385
+      g_source_set_callback (kq_source, (GSourceFunc) g_kqueue_file_monitor_callback, NULL, NULL);
386
+      g_source_attach (kq_source, GLIB_PRIVATE_CALL (g_get_worker_context) ());
387
+    }
388
+
389
+  G_UNLOCK (kq_lock);
390
+
391
+  return TRUE;
392
+}
393
+
394
+static gboolean
395
 g_kqueue_file_monitor_cancel (GFileMonitor *monitor)
396
 {
397
   GKqueueFileMonitor *kqueue_monitor = G_KQUEUE_FILE_MONITOR (monitor);
398
 
399
   if (kqueue_monitor->sub)
400
     {
401
-      _kh_cancel_sub (kqueue_monitor->sub);
402
-      _kh_sub_free (kqueue_monitor->sub);
403
+      _kqsub_cancel (kqueue_monitor->sub);
404
+      _kqsub_free (kqueue_monitor->sub);
405
       kqueue_monitor->sub = NULL;
406
     }
407
+#ifndef O_EVTONLY
408
   else if (kqueue_monitor->fallback)
409
     {
410
       g_signal_handlers_disconnect_by_func (kqueue_monitor->fallback, _fallback_callback, kqueue_monitor);
411
       g_file_monitor_cancel (kqueue_monitor->fallback);
412
     }
413
+#endif
414
 
415
   if (G_FILE_MONITOR_CLASS (g_kqueue_file_monitor_parent_class)->cancel)
416
     (*G_FILE_MONITOR_CLASS (g_kqueue_file_monitor_parent_class)->cancel) (monitor);
417
 
418
   return TRUE;
419
 }
420
+
421
+static kqueue_sub *
422
+_kqsub_new (const gchar *filename, GLocalFileMonitor *mon, GFileMonitorSource *source)
423
+{
424
+  kqueue_sub *sub;
425
+
426
+  sub = g_slice_new (kqueue_sub);
427
+  sub->filename = g_strdup (filename);
428
+  sub->mon = mon;
429
+  g_source_ref ((GSource *) source);
430
+  sub->source = source;
431
+  sub->fd = -1;
432
+  sub->deps = NULL;
433
+  sub->is_dir = 0;
434
+
435
+  return sub;
436
+}
437
+
438
+static void
439
+_kqsub_free (kqueue_sub *sub)
440
+{
441
+  g_assert (sub->deps == NULL);
442
+  g_assert (sub->fd == -1);
443
+
444
+  g_source_unref ((GSource *) sub->source);
445
+  g_free (sub->filename);
446
+  g_slice_free (kqueue_sub, sub);
447
+}
448
+
449
+static gboolean
450
+_kqsub_cancel (kqueue_sub *sub)
451
+{
452
+  struct kevent ev;
453
+
454
+  if (sub->deps)
455
+    {
456
+      dl_free (sub->deps);
457
+      sub->deps = NULL;
458
+    }
459
+
460
+  _km_remove (sub);
461
+
462
+  /* Only in the missing list?  We're done! */
463
+  if (sub->fd == -1)
464
+    return TRUE;
465
+
466
+  EV_SET (&ev, sub->fd, EVFILT_VNODE, EV_DELETE, NOTE_ALL, 0, sub);
467
+  if (kevent (kq_queue, &ev, 1, NULL, 0, NULL) == -1)
468
+    {
469
+      g_warning ("Unable to remove event for %s: %s", sub->filename, g_strerror (errno));
470
+      return FALSE;
471
+    }
472
+
473
+  close (sub->fd);
474
+  sub->fd = -1;
475
+
476
+  return TRUE;
477
+}
478
+
479
+gboolean
480
+_kqsub_start_watching (kqueue_sub *sub)
481
+{
482
+  struct stat st;
483
+  struct kevent ev;
484
+
485
+  sub->fd = open (sub->filename, O_KQFLAG);
486
+  if (sub->fd == -1)
487
+      return FALSE;
488
+
489
+  if (fstat (sub->fd, &st) == -1)
490
+    {
491
+      g_warning ("fstat failed for %s: %s", sub->filename, g_strerror (errno));
492
+      close (sub->fd);
493
+      sub->fd = -1;
494
+      return FALSE;
495
+    }
496
+
497
+  sub->is_dir = (st.st_mode & S_IFDIR) ? 1 : 0;
498
+  if (sub->is_dir)
499
+    {
500
+      if (sub->deps)
501
+        dl_free (sub->deps);
502
+
503
+      sub->deps = dl_listing (sub->filename);
504
+    }
505
+
506
+  EV_SET (&ev, sub->fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_ALL, 0, sub);
507
+  if (kevent (kq_queue, &ev, 1, NULL, 0, NULL) == -1)
508
+    {
509
+      g_warning ("Unable to add event for %s: %s", sub->filename, g_strerror (errno));
510
+      close (sub->fd);
511
+      sub->fd = -1;
512
+      return FALSE;
513
+    }
514
+
515
+  return TRUE;
516
+}
517
--- gio/kqueue/kqueue-helper.c.orig	2016-10-22 05:18:22 UTC
518
+++ gio/kqueue/kqueue-helper.c
519
@@ -34,81 +34,6 @@
520
 #include <errno.h>
521
 #include <pthread.h>
522
 #include "kqueue-helper.h"
523
-#include "kqueue-utils.h"
524
-#include "kqueue-thread.h"
525
-#include "kqueue-missing.h"
526
-#include "kqueue-exclusions.h"
527
-
528
-static gboolean kh_debug_enabled = FALSE;
529
-#define KH_W if (kh_debug_enabled) g_warning
530
-
531
-static GHashTable *subs_hash_table = NULL;
532
-G_LOCK_DEFINE_STATIC (hash_lock);
533
-
534
-static int kqueue_descriptor = -1;
535
-static int kqueue_socket_pair[] = {-1, -1};
536
-static pthread_t kqueue_thread;
537
-
538
-
539
-void _kh_file_appeared_cb (kqueue_sub *sub);
540
-
541
-/**
542
- * accessor function for kqueue_descriptor
543
- **/
544
-int
545
-get_kqueue_descriptor()
546
-{
547
-  return kqueue_descriptor;
548
-}
549
-
550
-/**
551
- * convert_kqueue_events_to_gio:
552
- * @flags: a set of kqueue filter flags
553
- * @done: a pointer to #gboolean indicating that the
554
- *      conversion has been done (out)
555
- *
556
- * Translates kqueue filter flags into GIO event flags.
557
- *
558
- * Returns: a #GFileMonitorEvent
559
- **/
560
-static GFileMonitorEvent
561
-convert_kqueue_events_to_gio (uint32_t flags, gboolean *done)
562
-{
563
-  g_assert (done != NULL);
564
-  *done = FALSE;
565
-
566
-  /* TODO: The following notifications should be emulated, if possible:
567
-   * - G_FILE_MONITOR_EVENT_PRE_UNMOUNT
568
-   */
569
-  if (flags & NOTE_DELETE)
570
-    {    
571
-      *done = TRUE;
572
-      return G_FILE_MONITOR_EVENT_DELETED;
573
-    }
574
-  if (flags & NOTE_ATTRIB)
575
-    {
576
-      *done = TRUE;
577
-      return G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED;
578
-    }
579
-  if (flags & (NOTE_WRITE | NOTE_EXTEND))
580
-    {
581
-      *done = TRUE;
582
-      return G_FILE_MONITOR_EVENT_CHANGED;
583
-    }
584
-  if (flags & NOTE_RENAME)
585
-    {
586
-      *done = TRUE;
587
-      return G_FILE_MONITOR_EVENT_MOVED;
588
-    }
589
-  if (flags & NOTE_REVOKE)
590
-    {
591
-      *done = TRUE;
592
-      return G_FILE_MONITOR_EVENT_UNMOUNTED;
593
-    }
594
-
595
-  /* done is FALSE */
596
-  return 0;
597
-}
598
 
599
 typedef struct {
600
   kqueue_sub *sub;
601
@@ -236,323 +161,21 @@ static const traverse_cbs cbs = {
602
 
603
 
604
 void
605
-_kh_dir_diff (kqueue_sub *sub, GFileMonitorSource *source)
606
+_kh_dir_diff (kqueue_sub *sub)
607
 {
608
   dep_list *was;
609
   handle_ctx ctx;
610
 
611
-  g_assert (sub != NULL);
612
-  g_assert (source != NULL);
613
-
614
   memset (&ctx, 0, sizeof (handle_ctx));
615
   ctx.sub = sub;
616
-  ctx.source = source;
617
+  ctx.source = sub->source;
618
 
619
   was = sub->deps;
620
   sub->deps = dl_listing (sub->filename);
621
- 
622
+
623
   dl_calculate (was, sub->deps, &cbs, &ctx);
624
 
625
   dl_free (was);
626
 }
627
 
628
 
629
-/**
630
- * process_kqueue_notifications:
631
- * @gioc: unused.
632
- * @cond: unused.
633
- * @data: unused.
634
- *
635
- * Processes notifications, coming from the kqueue thread.
636
- *
637
- * Reads notifications from the command file descriptor, emits the
638
- * "changed" event on the appropriate monitor.
639
- *
640
- * A typical GIO Channel callback function.
641
- *
642
- * Returns: %TRUE
643
- **/
644
-static gboolean
645
-process_kqueue_notifications (GIOChannel   *gioc,
646
-                              GIOCondition  cond,
647
-                              gpointer      data)
648
-{
649
-  struct kqueue_notification n;
650
-  kqueue_sub *sub = NULL;
651
-  GFileMonitorSource *source = NULL;
652
-  GFileMonitorEvent mask = 0;
653
-  
654
-  g_assert (kqueue_socket_pair[0] != -1);
655
-  if (!_ku_read (kqueue_socket_pair[0], &n, sizeof (struct kqueue_notification)))
656
-    {
657
-      KH_W ("Failed to read a kqueue notification, error %d", errno);
658
-      return TRUE;
659
-    }
660
-
661
-  G_LOCK (hash_lock);
662
-  sub = (kqueue_sub *) g_hash_table_lookup (subs_hash_table, GINT_TO_POINTER (n.fd));
663
-  G_UNLOCK (hash_lock);
664
-
665
-  if (sub == NULL)
666
-    {
667
-      KH_W ("Got a notification for a deleted or non-existing subscription %d",
668
-             n.fd);
669
-      return TRUE;
670
-    }
671
-
672
-  source = sub->user_data;
673
-  g_assert (source != NULL);
674
-
675
-  if (n.flags & (NOTE_DELETE | NOTE_REVOKE))
676
-    {
677
-      if (sub->deps)
678
-        {
679
-          dl_free (sub->deps);
680
-          sub->deps = NULL;  
681
-        }  
682
-      _km_add_missing (sub);
683
-
684
-      if (!(n.flags & NOTE_REVOKE))
685
-        {
686
-          /* Note that NOTE_REVOKE is issued by the kqueue thread
687
-           * on EV_ERROR kevent. In this case, a file descriptor is
688
-           * already closed from the kqueue thread, no need to close
689
-           * it manually */ 
690
-          _kh_cancel_sub (sub);
691
-        }
692
-    }
693
-
694
-  if (sub->is_dir && n.flags & (NOTE_WRITE | NOTE_EXTEND))
695
-    {
696
-      _kh_dir_diff (sub, source);
697
-      n.flags &= ~(NOTE_WRITE | NOTE_EXTEND);
698
-    }
699
-
700
-  if (n.flags)
701
-    {
702
-      gboolean done = FALSE;
703
-      mask = convert_kqueue_events_to_gio (n.flags, &done);
704
-      if (done == TRUE)
705
-        g_file_monitor_source_handle_event (source, mask, NULL, NULL, NULL, g_get_monotonic_time ());
706
-    }
707
-
708
-  return TRUE;
709
-}
710
-
711
-
712
-/*
713
- * _kh_startup_impl:
714
- * @unused: unused
715
- *
716
- * Kqueue backend startup code. Should be called only once.
717
- *
718
- * Returns: %TRUE on success, %FALSE otherwise.
719
- **/
720
-static gpointer
721
-_kh_startup_impl (gpointer unused)
722
-{
723
-  GIOChannel *channel = NULL;
724
-  gboolean result = FALSE;
725
-
726
-  kqueue_descriptor = kqueue ();
727
-  result = (kqueue_descriptor != -1);
728
-  if (!result)
729
-    {
730
-      KH_W ("Failed to initialize kqueue\n!");
731
-      return GINT_TO_POINTER (FALSE);
732
-    }
733
-
734
-  result = socketpair (AF_UNIX, SOCK_STREAM, 0, kqueue_socket_pair);
735
-  if (result != 0)
736
-    {
737
-      KH_W ("Failed to create socket pair\n!");
738
-      return GINT_TO_POINTER (FALSE) ;
739
-    }
740
-
741
-  result = pthread_create (&kqueue_thread,
742
-                           NULL,
743
-                           _kqueue_thread_func,
744
-                           &kqueue_socket_pair[1]);
745
-  if (result != 0)
746
-    {
747
-      KH_W ("Failed to run kqueue thread\n!");
748
-      return GINT_TO_POINTER (FALSE);
749
-    }
750
-
751
-  _km_init (_kh_file_appeared_cb);
752
-
753
-  channel = g_io_channel_unix_new (kqueue_socket_pair[0]);
754
-  g_io_add_watch (channel, G_IO_IN, process_kqueue_notifications, NULL);
755
-
756
-  subs_hash_table = g_hash_table_new (g_direct_hash, g_direct_equal);
757
-
758
-  KH_W ("started gio kqueue backend\n");
759
-  return GINT_TO_POINTER (TRUE);
760
-}
761
-
762
-
763
-/*
764
- * _kh_startup:
765
- * Kqueue backend initialization.
766
- *
767
- * Returns: %TRUE on success, %FALSE otherwise.
768
- **/
769
-gboolean
770
-_kh_startup (void)
771
-{
772
-  static GOnce init_once = G_ONCE_INIT;
773
-  g_once (&init_once, _kh_startup_impl, NULL);
774
-  return GPOINTER_TO_INT (init_once.retval);
775
-}
776
-
777
-
778
-/**
779
- * _kh_start_watching:
780
- * @sub: a #kqueue_sub
781
- *
782
- * Starts watching on a subscription.
783
- *
784
- * Returns: %TRUE on success, %FALSE otherwise.
785
- **/
786
-gboolean
787
-_kh_start_watching (kqueue_sub *sub)
788
-{
789
-  g_assert (kqueue_socket_pair[0] != -1);
790
-  g_assert (sub != NULL);
791
-  g_assert (sub->filename != NULL);
792
-
793
-  /* kqueue requires a file descriptor to monitor. Sad but true */
794
-#if defined (O_EVTONLY)
795
-  sub->fd = open (sub->filename, O_EVTONLY);
796
-#else
797
-  sub->fd = open (sub->filename, O_RDONLY);
798
-#endif
799
-
800
-  if (sub->fd == -1)
801
-    {
802
-      KH_W ("failed to open file %s (error %d)", sub->filename, errno);
803
-      return FALSE;
804
-    }
805
-
806
-  _ku_file_information (sub->fd, &sub->is_dir, NULL);
807
-  if (sub->is_dir)
808
-    {
809
-      /* I know, it is very bad to make such decisions in this way and here.
810
-       * We already do have an user_data at the #kqueue_sub, and it may point to
811
-       * GKqueueFileMonitor or GKqueueDirectoryMonitor. For a directory case,
812
-       * we need to scan in contents for the further diffs. Ideally this process
813
-       * should be delegated to the GKqueueDirectoryMonitor, but for now I will
814
-       * do it in a dirty way right here. */
815
-      if (sub->deps)
816
-        dl_free (sub->deps);
817
-
818
-      sub->deps = dl_listing (sub->filename);  
819
-    }
820
-
821
-  G_LOCK (hash_lock);
822
-  g_hash_table_insert (subs_hash_table, GINT_TO_POINTER (sub->fd), sub);
823
-  G_UNLOCK (hash_lock);
824
-
825
-  _kqueue_thread_push_fd (sub->fd);
826
-  
827
-  /* Bump the kqueue thread. It will pick up a new sub entry to monitor */
828
-  if (!_ku_write (kqueue_socket_pair[0], "A", 1))
829
-    KH_W ("Failed to bump the kqueue thread (add fd, error %d)", errno);
830
-  return TRUE;
831
-}
832
-
833
-
834
-/**
835
- * _kh_add_sub:
836
- * @sub: a #kqueue_sub
837
- *
838
- * Adds a subscription for monitoring.
839
- *
840
- * This funciton tries to start watching a subscription with
841
- * _kh_start_watching(). On failure, i.e. when a file does not exist yet,
842
- * the subscription will be added to a list of missing files to continue
843
- * watching when the file will appear.
844
- *
845
- * Returns: %TRUE
846
- **/
847
-gboolean
848
-_kh_add_sub (kqueue_sub *sub)
849
-{
850
-  g_assert (sub != NULL);
851
-
852
-  if (!_kh_start_watching (sub))
853
-    _km_add_missing (sub);
854
-
855
-  return TRUE;
856
-}
857
-
858
-
859
-/**
860
- * _kh_cancel_sub:
861
- * @sub a #kqueue_sub
862
- *
863
- * Stops monitoring on a subscription.
864
- *
865
- * Returns: %TRUE
866
- **/
867
-gboolean
868
-_kh_cancel_sub (kqueue_sub *sub)
869
-{
870
-  gboolean missing = FALSE;
871
-  g_assert (kqueue_socket_pair[0] != -1);
872
-  g_assert (sub != NULL);
873
-
874
-  G_LOCK (hash_lock);
875
-  missing = !g_hash_table_remove (subs_hash_table, GINT_TO_POINTER (sub->fd));
876
-  G_UNLOCK (hash_lock);
877
-
878
-  if (missing)
879
-    {
880
-      /* If there were no fd for this subscription, file is still
881
-       * missing. */
882
-      KH_W ("Removing subscription from missing");
883
-      _km_remove (sub);
884
-    }
885
-  else
886
-    {
887
-      /* fd will be closed in the kqueue thread */
888
-      _kqueue_thread_remove_fd (sub->fd);
889
-
890
-      /* Bump the kqueue thread. It will pick up a new sub entry to remove*/
891
-      if (!_ku_write (kqueue_socket_pair[0], "R", 1))
892
-        KH_W ("Failed to bump the kqueue thread (remove fd, error %d)", errno);
893
-    }
894
-
895
-  return TRUE;
896
-}
897
-
898
-
899
-/**
900
- * _kh_file_appeared_cb:
901
- * @sub: a #kqueue_sub
902
- *
903
- * A callback function for kqueue-missing subsystem.
904
- *
905
- * Signals that a missing file has finally appeared in the filesystem.
906
- * Emits %G_FILE_MONITOR_EVENT_CREATED.
907
- **/
908
-void
909
-_kh_file_appeared_cb (kqueue_sub *sub)
910
-{
911
-  GFile* child;
912
-
913
-  g_assert (sub != NULL);
914
-  g_assert (sub->filename);
915
-
916
-  if (!g_file_test (sub->filename, G_FILE_TEST_EXISTS))
917
-    return;
918
-
919
-  child = g_file_new_for_path (sub->filename);
920
-
921
-  g_file_monitor_emit_event (G_FILE_MONITOR (sub->user_data),
922
-                             child,
923
-                             NULL,
924
-                             G_FILE_MONITOR_EVENT_CREATED);
925
-
926
-  g_object_unref (child);
927
-}
928
--- gio/kqueue/kqueue-helper.h.orig	2016-10-22 05:18:22 UTC
929
+++ gio/kqueue/kqueue-helper.h
930
@@ -23,16 +23,31 @@
931
 #ifndef __KQUEUE_HELPER_H
932
 #define __KQUEUE_HELPER_H
933
 
934
-#include "kqueue-sub.h"
935
 #include <gio/glocalfilemonitor.h>
936
 #include <gio/gfilemonitor.h>
937
 
938
-gboolean _kh_startup        (void);
939
-gboolean _kh_add_sub        (kqueue_sub *sub);
940
-gboolean _kh_cancel_sub     (kqueue_sub *sub);
941
+#include "dep-list.h"
942
 
943
-gboolean _kh_start_watching (kqueue_sub *sub);
944
+/**
945
+ * kqueue_sub:
946
+ * @filename: a name of the file to monitor
947
+ * @fd: the associated file descriptor (used by kqueue)
948
+ *
949
+ * Represents a subscription on a file or directory.
950
+ */
951
+typedef struct
952
+{
953
+  GLocalFileMonitor   *mon;
954
+  GFileMonitorSource  *source;
955
+  gchar*    filename;
956
+  int       fd;
957
+  dep_list* deps;
958
+  int       is_dir;
959
+} kqueue_sub;
960
 
961
-void     _kh_dir_diff       (kqueue_sub *sub, GFileMonitorSource *source);
962
+gboolean _kqsub_start_watching (kqueue_sub *sub);
963
+void _kh_dir_diff    (kqueue_sub *sub);
964
+void _km_add_missing (kqueue_sub *sub);
965
+void _km_remove      (kqueue_sub *sub);
966
 
967
 #endif /* __KQUEUE_HELPER_H */
968
--- gio/kqueue/kqueue-missing.c.orig	2016-10-22 05:18:22 UTC
969
+++ gio/kqueue/kqueue-missing.c
970
@@ -23,12 +23,12 @@
971
 #include <glib.h>
972
 
973
 #include "kqueue-helper.h"
974
-#include "kqueue-sub.h"
975
-#include "kqueue-missing.h"
976
 
977
 
978
 #define SCAN_MISSING_TIME 4 /* 1/4 Hz */
979
 
980
+void _kh_file_appeared_cb (kqueue_sub *sub);
981
+
982
 static gboolean km_scan_missing (gpointer user_data);
983
 
984
 static gboolean km_debug_enabled = FALSE;
985
@@ -38,21 +38,6 @@ static GSList *missing_subs_list = NULL;
986
 G_LOCK_DEFINE_STATIC (missing_lock);
987
 
988
 static volatile gboolean scan_missing_running = FALSE;
989
-static on_create_cb file_appeared_callback;
990
-
991
-
992
-/**
993
- * _km_init:
994
- * @cb: a callback function. It will be called when a watched file
995
- *     will appear.
996
- *
997
- * Initialize the kqueue-missing module (optional).
998
- **/
999
-void
1000
-_km_init (on_create_cb cb)
1001
-{
1002
-  file_appeared_callback = cb;
1003
-}
1004
 
1005
 
1006
 /**
1007
@@ -83,6 +68,35 @@ _km_add_missing (kqueue_sub *sub)
1008
     }
1009
 }
1010
 
1011
+/**
1012
+ * _kh_file_appeared_cb:
1013
+ * @sub: a #kqueue_sub
1014
+ *
1015
+ * A callback function for kqueue-missing subsystem.
1016
+ *
1017
+ * Signals that a missing file has finally appeared in the filesystem.
1018
+ * Emits %G_FILE_MONITOR_EVENT_CREATED.
1019
+ **/
1020
+void
1021
+_kh_file_appeared_cb (kqueue_sub *sub)
1022
+{
1023
+  GFile *child;
1024
+
1025
+  g_assert (sub != NULL);
1026
+  g_assert (sub->filename);
1027
+
1028
+  if (!g_file_test (sub->filename, G_FILE_TEST_EXISTS))
1029
+    return;
1030
+
1031
+  child = g_file_new_for_path (sub->filename);
1032
+
1033
+  g_file_monitor_emit_event (G_FILE_MONITOR (sub->mon),
1034
+                             child,
1035
+                             NULL,
1036
+                             G_FILE_MONITOR_EVENT_CREATED);
1037
+
1038
+  g_object_unref (child);
1039
+}
1040
 
1041
 /**
1042
  * km_scan_missing:
1043
@@ -114,11 +128,10 @@ km_scan_missing (gpointer user_data)
1044
       g_assert (sub != NULL);
1045
       g_assert (sub->filename != NULL);
1046
 
1047
-      if (_kh_start_watching (sub))
1048
+      if (_kqsub_start_watching (sub))
1049
         {
1050
           KM_W ("file %s now exists, starting watching", sub->filename);
1051
-          if (file_appeared_callback)
1052
-            file_appeared_callback (sub);
1053
+          _kh_file_appeared_cb (sub);
1054
           not_missing = g_slist_prepend (not_missing, head);
1055
         }
1056
     }
(-)files/patch-gio_kqueue_gkqueuefilemonitor.c (-45 lines)
Lines 1-45 Link Here
1
https://bugzilla.gnome.org/show_bug.cgi?id=739424
2
https://bug739424.bugzilla-attachments.gnome.org/attachment.cgi?id=351191
3
4
--- gio/kqueue/gkqueuefilemonitor.c.orig	2018-01-15 21:00:32.535064000 +0100
5
+++ gio/kqueue/gkqueuefilemonitor.c	2018-01-15 21:07:20.920334000 +0100
6
@@ -29,6 +29,15 @@
7
 #include <gio/gfile.h>
8
 #include <gio/giomodule.h>
9
 
10
+/*
11
+ * Because ``kqueue_sub'' are not refcounted, we need
12
+ * ensure no other thread is getting a reference to
13
+ * the element we want to free.
14
+ *
15
+ * That's why _kh_cancel_sub() must be called with
16
+ * this lock held to prevent a race.
17
+ */
18
+G_LOCK_EXTERN (hash_lock);
19
 
20
 struct _GKqueueFileMonitor
21
 {
22
@@ -80,9 +89,11 @@ g_kqueue_file_monitor_finalize (GObject *object)
23
 
24
   if (kqueue_monitor->sub)
25
     {
26
+      G_LOCK (hash_lock);
27
       _kh_cancel_sub (kqueue_monitor->sub);
28
       _kh_sub_free (kqueue_monitor->sub);
29
       kqueue_monitor->sub = NULL;
30
+      G_UNLOCK (hash_lock);
31
     }
32
 
33
   if (kqueue_monitor->fallback)
34
@@ -181,9 +192,11 @@ g_kqueue_file_monitor_cancel (GFileMonitor *monitor)
35
 
36
   if (kqueue_monitor->sub)
37
     {
38
+      G_LOCK (hash_lock);
39
       _kh_cancel_sub (kqueue_monitor->sub);
40
       _kh_sub_free (kqueue_monitor->sub);
41
       kqueue_monitor->sub = NULL;
42
+      G_UNLOCK (hash_lock);
43
     }
44
   else if (kqueue_monitor->fallback)
45
     {
(-)files/patch-gio_kqueue_kqueue-helper.c (-96 lines)
Lines 1-96 Link Here
1
This bug combines serveral patches:
2
https://bugzilla.gnome.org/show_bug.cgi?id=778515
3
and
4
https://bugzilla.gnome.org/show_bug.cgi?id=739424
5
https://bug739424.bugzilla-attachments.gnome.org/attachment.cgi?id=351191
6
7
https://bugzilla.gnome.org/show_bug.cgi?id=776147
8
https://git.gnome.org/browse/glib/commit/?id=76072a2dde4a4acc8be8d3c47efbc6811ebe0c1e
9
10
--- gio/kqueue/kqueue-helper.c.orig	2018-01-28 21:18:25.213606000 +0100
11
+++ gio/kqueue/kqueue-helper.c	2018-01-28 21:18:34.964780000 +0100
12
@@ -43,7 +43,7 @@ static gboolean kh_debug_enabled = FALSE;
13
 #define KH_W if (kh_debug_enabled) g_warning
14
 
15
 static GHashTable *subs_hash_table = NULL;
16
-G_LOCK_DEFINE_STATIC (hash_lock);
17
+G_LOCK_DEFINE (hash_lock);
18
 
19
 static int kqueue_descriptor = -1;
20
 static int kqueue_socket_pair[] = {-1, -1};
21
@@ -97,8 +97,10 @@ convert_kqueue_events_to_gio (uint32_t flags, gboolean
22
     }
23
   if (flags & NOTE_RENAME)
24
     {
25
+      /* Since there’s apparently no way to get the new name of the file out of
26
+       * kqueue(), all we can do is say that this one has been deleted. */
27
       *done = TRUE;
28
-      return G_FILE_MONITOR_EVENT_MOVED;
29
+      return G_FILE_MONITOR_EVENT_DELETED;
30
     }
31
   if (flags & NOTE_REVOKE)
32
     {
33
@@ -291,10 +293,10 @@ process_kqueue_notifications (GIOChannel   *gioc,
34
 
35
   G_LOCK (hash_lock);
36
   sub = (kqueue_sub *) g_hash_table_lookup (subs_hash_table, GINT_TO_POINTER (n.fd));
37
-  G_UNLOCK (hash_lock);
38
 
39
   if (sub == NULL)
40
     {
41
+      G_UNLOCK (hash_lock);
42
       KH_W ("Got a notification for a deleted or non-existing subscription %d",
43
              n.fd);
44
       return TRUE;
45
@@ -336,6 +338,7 @@ process_kqueue_notifications (GIOChannel   *gioc,
46
         g_file_monitor_source_handle_event (source, mask, NULL, NULL, NULL, g_get_monotonic_time ());
47
     }
48
 
49
+  G_UNLOCK (hash_lock);
50
   return TRUE;
51
 }
52
 
53
@@ -451,13 +454,14 @@ _kh_start_watching (kqueue_sub *sub)
54
 
55
   G_LOCK (hash_lock);
56
   g_hash_table_insert (subs_hash_table, GINT_TO_POINTER (sub->fd), sub);
57
-  G_UNLOCK (hash_lock);
58
 
59
   _kqueue_thread_push_fd (sub->fd);
60
   
61
   /* Bump the kqueue thread. It will pick up a new sub entry to monitor */
62
   if (!_ku_write (kqueue_socket_pair[0], "A", 1))
63
     KH_W ("Failed to bump the kqueue thread (add fd, error %d)", errno);
64
+  G_UNLOCK (hash_lock);
65
+
66
   return TRUE;
67
 }
68
 
69
@@ -498,22 +502,15 @@ _kh_add_sub (kqueue_sub *sub)
70
 gboolean
71
 _kh_cancel_sub (kqueue_sub *sub)
72
 {
73
-  gboolean missing = FALSE;
74
+  gboolean removed = FALSE;
75
   g_assert (kqueue_socket_pair[0] != -1);
76
   g_assert (sub != NULL);
77
 
78
-  G_LOCK (hash_lock);
79
-  missing = !g_hash_table_remove (subs_hash_table, GINT_TO_POINTER (sub->fd));
80
-  G_UNLOCK (hash_lock);
81
+  _km_remove (sub);
82
 
83
-  if (missing)
84
-    {
85
-      /* If there were no fd for this subscription, file is still
86
-       * missing. */
87
-      KH_W ("Removing subscription from missing");
88
-      _km_remove (sub);
89
-    }
90
-  else
91
+  removed = g_hash_table_remove (subs_hash_table, GINT_TO_POINTER (sub->fd));
92
+
93
+  if (removed)
94
     {
95
       /* fd will be closed in the kqueue thread */
96
       _kqueue_thread_remove_fd (sub->fd);

Return to bug 226920