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