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