bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[very WIP PATCH 1/1] Very WIP: Add GHurdFileMonitor


From: Sergey Bugaev
Subject: [very WIP PATCH 1/1] Very WIP: Add GHurdFileMonitor
Date: Tue, 6 Dec 2022 17:48:28 +0300

---
 gio/giomodule.c             |   4 +
 gio/hurd/fs_notify.defs     |   9 ++
 gio/hurd/fs_notify.h        |  10 ++
 gio/hurd/ghurdfilemonitor.c | 269 ++++++++++++++++++++++++++++++++++++
 gio/hurd/ghurdfilemonitor.h |  43 ++++++
 gio/hurd/meson.build        |  20 +++
 gio/meson.build             |   5 +
 7 files changed, 360 insertions(+)
 create mode 100644 gio/hurd/fs_notify.defs
 create mode 100644 gio/hurd/fs_notify.h
 create mode 100644 gio/hurd/ghurdfilemonitor.c
 create mode 100644 gio/hurd/ghurdfilemonitor.h
 create mode 100644 gio/hurd/meson.build

diff --git a/gio/giomodule.c b/gio/giomodule.c
index 11ce7d8b9..3c57f22cc 100644
--- a/gio/giomodule.c
+++ b/gio/giomodule.c
@@ -1076,6 +1076,7 @@ _g_io_module_get_default (const gchar         
*extension_point,
 extern GType g_inotify_file_monitor_get_type (void);
 extern GType g_kqueue_file_monitor_get_type (void);
 extern GType g_win32_file_monitor_get_type (void);
+extern GType g_hurd_file_monitor_get_type (void);
 
 extern GType _g_unix_volume_monitor_get_type (void);
 extern GType _g_local_vfs_get_type (void);
@@ -1352,6 +1353,9 @@ _g_io_modules_ensure_loaded (void)
 #if defined(HAVE_KQUEUE)
       g_type_ensure (g_kqueue_file_monitor_get_type ());
 #endif
+#ifdef __GNU__
+      g_type_ensure (g_hurd_file_monitor_get_type ());
+#endif
 #ifdef G_OS_WIN32
       g_type_ensure (_g_win32_volume_monitor_get_type ());
       g_type_ensure (g_win32_file_monitor_get_type ());
diff --git a/gio/hurd/fs_notify.defs b/gio/hurd/fs_notify.defs
new file mode 100644
index 000000000..e9b70d486
--- /dev/null
+++ b/gio/hurd/fs_notify.defs
@@ -0,0 +1,9 @@
+#define SERVERPREFIX S_
+
+#define FS_NOTIFY_INTRAN ghurdfilemonitor_t g_hurd_file_monitor_lookup_by_port 
(fs_notify_t)
+#define FS_NOTIFY_INTRAN_PAYLOAD ghurdfilemonitor_t 
g_hurd_file_monitor_lookup_by_payload
+#define FS_NOTIFY_DESTRUCTOR g_object_unref (ghurdfilemonitor_t)
+
+#define FS_NOTIFY_IMPORTS import "fs_notify.h";
+
+#include <hurd/fs_notify.defs>
diff --git a/gio/hurd/fs_notify.h b/gio/hurd/fs_notify.h
new file mode 100644
index 000000000..ac78341b9
--- /dev/null
+++ b/gio/hurd/fs_notify.h
@@ -0,0 +1,10 @@
+#include "ghurdfilemonitor.h"
+
+/* This declaration exists solely to appease MIG;
+   regular C code should not use it.  */
+typedef GHurdFileMonitor *ghurdfilemonitor_t;
+
+GHurdFileMonitor *g_hurd_file_monitor_lookup_by_port (mach_port_t);
+GHurdFileMonitor *g_hurd_file_monitor_lookup_by_payload (unsigned long);
+
+boolean_t fs_notify_server (mach_msg_header_t *, mach_msg_header_t *);
diff --git a/gio/hurd/ghurdfilemonitor.c b/gio/hurd/ghurdfilemonitor.c
new file mode 100644
index 000000000..0c9bf5687
--- /dev/null
+++ b/gio/hurd/ghurdfilemonitor.c
@@ -0,0 +1,269 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2022 Sergey Bugaev
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see 
<http://www.gnu.org/licenses/>.
+ */
+
+#include "ghurdfilemonitor.h"
+#include "fs_notify_S.h"
+#include <gio/giomodule.h>
+
+#include <hurd.h>
+
+struct _GHurdFileMonitor
+{
+  GLocalFileMonitor parent_instance;
+
+  const gchar *basename;
+
+  /* The port we receive change notifications on.  */
+  mach_port_t notify_port;
+  gboolean in_hash_table : 1;
+};
+
+G_DEFINE_TYPE_WITH_CODE (GHurdFileMonitor, g_hurd_file_monitor, 
G_TYPE_LOCAL_FILE_MONITOR,
+                         g_io_extension_point_implement 
(G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
+                                                         g_define_type_id, 
"hurd", 20))
+
+
+static GOnce init_waiter_once = G_ONCE_INIT;
+static mach_port_t notify_port_set;
+/* Hash table mapping notify port names back to their GHurdFileMonitor
+   pointers.  In most cases, this should not be used, since new enough
+   GNU Mach supports protected payloads.  */
+static GHashTable *monitor_hash_table;
+static GMutex monitor_hash_table_lock;
+
+GHurdFileMonitor *
+g_hurd_file_monitor_lookup_by_port (mach_port_t port)
+{
+  gpointer ptr;
+  GHurdFileMonitor *monitor;
+
+  g_mutex_lock (&monitor_hash_table_lock);
+  ptr = g_hash_table_lookup (monitor_hash_table,
+                             GUINT_TO_POINTER (port));
+  g_mutex_unlock (&monitor_hash_table_lock);
+
+  if (ptr == NULL)
+    /* The port is not in the table?  That could happen if the monitor
+       is being torn down, but we're still procesing messages directed
+       to it.  */
+    return NULL;
+  monitor = G_HURD_FILE_MONITOR (ptr);
+  return g_object_ref (monitor);
+}
+
+GHurdFileMonitor *
+g_hurd_file_monitor_lookup_by_payload (unsigned long payload)
+{
+  GHurdFileMonitor *monitor = G_HURD_FILE_MONITOR (payload);
+  return g_object_ref (monitor);
+}
+
+kern_return_t
+S_dir_changed (GHurdFileMonitor *monitor, natural_t tickno,
+               enum dir_changed_type change, const char *name)
+{
+  GFileMonitorEvent event_type;
+  GLocalFileMonitor *local_monitor = G_LOCAL_FILE_MONITOR (monitor);
+
+  if (monitor == NULL)
+    return EOPNOTSUPP;
+
+  switch (change)
+    {
+    case DIR_CHANGED_NEW:
+      event_type = G_FILE_MONITOR_EVENT_CREATED;
+      break;
+    case DIR_CHANGED_UNLINK:
+      event_type = G_FILE_MONITOR_EVENT_DELETED;
+      break;
+    default:
+      return ENOTSUP;
+    }
+
+  g_file_monitor_source_handle_event (local_monitor->source, event_type,
+                                      name, NULL, NULL,
+                                      g_get_monotonic_time ());
+  return 0;
+}
+
+kern_return_t
+S_file_changed (GHurdFileMonitor *monitor, natural_t tickno,
+                enum file_changed_type change,
+                loff_t start, loff_t end)
+{
+  GFileMonitorEvent event_type;
+  GLocalFileMonitor *local_monitor = G_LOCAL_FILE_MONITOR (monitor);
+
+  if (monitor == NULL)
+    return EOPNOTSUPP;
+
+  switch (change)
+    {
+    case FILE_CHANGED_EXTEND:
+    case FILE_CHANGED_TRUNCATE:
+    case FILE_CHANGED_WRITE:
+      event_type = G_FILE_MONITOR_EVENT_CHANGED;
+      break;
+    case FILE_CHANGED_META:
+      event_type = G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED;
+      break;
+    default:
+      return ENOTSUP;
+    }
+
+  g_file_monitor_source_handle_event (local_monitor->source, event_type,
+                                      monitor->basename,
+                                      NULL, NULL, g_get_monotonic_time ());
+
+  return 0;
+}
+
+static gpointer
+worker_thread (gpointer _arg)
+{
+  mach_msg_server (fs_notify_server, 0, notify_port_set);
+  return NULL;
+}
+
+static gpointer
+do_init_waiter (gpointer _arg)
+{
+  error_t err;
+
+  err = __mach_port_allocate (__mach_task_self (), MACH_PORT_RIGHT_PORT_SET,
+                              &notify_port_set);
+  if (err)
+    abort ();
+
+  monitor_hash_table = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+  g_thread_new ("ghurdfilemonitor", worker_thread, NULL);
+  return NULL;
+}
+
+static gboolean
+g_hurd_file_monitor_is_supported (void)
+{
+  return TRUE;
+}
+
+static void
+g_hurd_file_monitor_start (GLocalFileMonitor  *local_monitor,
+                           const gchar        *dirname,
+                           const gchar        *basename,
+                           const gchar        *filename,
+                           GFileMonitorSource *source)
+{
+  GHurdFileMonitor *hurd_monitor = G_HURD_FILE_MONITOR (local_monitor);
+  gchar *path;
+  file_t file;
+  error_t err;
+
+  hurd_monitor->basename = basename;
+
+  // TODO: handle multiple cases of basename/filename and whatever
+  path = g_build_filename (dirname, basename, NULL);
+  file = file_name_lookup (path, 0, 0);
+  if (!file)
+    abort (); // TODO: what do we do?
+  err = __file_notice_changes (file, hurd_monitor->notify_port, 
MACH_MSG_TYPE_MAKE_SEND);
+  if (err)
+    abort ();
+  __mach_port_deallocate (__mach_task_self (), file);
+
+  g_once (&init_waiter_once, do_init_waiter, NULL);
+
+  err = __mach_port_move_member (__mach_task_self (), 
hurd_monitor->notify_port,
+                                 notify_port_set);
+  if (err)
+    abort ();
+
+  g_clear_pointer (&path, g_free);
+}
+
+static gboolean
+g_hurd_file_monitor_cancel (GFileMonitor *monitor)
+{
+  GHurdFileMonitor *hurd_monitor = G_HURD_FILE_MONITOR (monitor);
+  error_t err;
+
+  if (hurd_monitor->in_hash_table)
+    {
+      g_mutex_lock (&monitor_hash_table_lock);
+      g_hash_table_remove (monitor_hash_table,
+                           GUINT_TO_POINTER (hurd_monitor->notify_port));
+      g_mutex_unlock (&monitor_hash_table_lock);
+    }
+
+  err = __mach_port_mod_refs (__mach_task_self (), hurd_monitor->notify_port,
+                              MACH_PORT_RIGHT_RECEIVE, -1);
+  if (err)
+    abort ();
+
+  hurd_monitor->notify_port = MACH_PORT_NULL;
+
+  return TRUE;
+}
+
+static void
+g_hurd_file_monitor_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (g_hurd_file_monitor_parent_class)->finalize (object);
+}
+
+static void
+g_hurd_file_monitor_init (GHurdFileMonitor *monitor)
+{
+  error_t err;
+
+  err = __mach_port_allocate (__mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+                              &monitor->notify_port);
+  if (err)
+    abort ();
+
+#ifdef MACH_MSG_TYPE_PROTECTED_PAYLOAD
+  err = __mach_port_set_protected_payload (__mach_task_self (), 
monitor->notify_port,
+                                           (uintptr_t) monitor);
+#else
+  err = ENOTSUPP;
+#endif
+
+  if (err)
+    {
+      g_mutex_lock (&monitor_hash_table_lock);
+      g_hash_table_insert (monitor_hash_table,
+                           GUINT_TO_POINTER (monitor->notify_port),
+                           monitor);
+      g_mutex_unlock (&monitor_hash_table_lock);
+      monitor->in_hash_table = TRUE;
+    }
+}
+
+static void
+g_hurd_file_monitor_class_init (GHurdFileMonitorClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GFileMonitorClass *file_monitor_class = G_FILE_MONITOR_CLASS (klass);
+  GLocalFileMonitorClass *local_file_monitor_class = 
G_LOCAL_FILE_MONITOR_CLASS (klass);
+
+  local_file_monitor_class->start = g_hurd_file_monitor_start;
+  local_file_monitor_class->is_supported = g_hurd_file_monitor_is_supported;
+  file_monitor_class->cancel = g_hurd_file_monitor_cancel;
+
+  gobject_class->finalize = g_hurd_file_monitor_finalize;
+}
diff --git a/gio/hurd/ghurdfilemonitor.h b/gio/hurd/ghurdfilemonitor.h
new file mode 100644
index 000000000..313d9cd2c
--- /dev/null
+++ b/gio/hurd/ghurdfilemonitor.h
@@ -0,0 +1,43 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2022 Sergey Bugaev
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see 
<http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __G_HURD_FILE_MONITOR_H__
+#define __G_HURD_FILE_MONITOR_H__
+
+#include <gio/glocalfilemonitor.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_HURD_FILE_MONITOR               (g_hurd_file_monitor_get_type 
())
+#define G_HURD_FILE_MONITOR(o)                 (G_TYPE_CHECK_INSTANCE_CAST 
((o), G_TYPE_HURD_FILE_MONITOR, GHurdFileMonitor))
+#define G_HURD_FILE_MONITOR_CLASS(k)           (G_TYPE_CHECK_CLASS_CAST ((k), 
G_TYPE_HURD_FILE_MONITOR, GHurdFileMonitorClass))
+#define G_IS_HURD_FILE_MONITOR(o)              (G_TYPE_CHECK_INSTANCE_TYPE 
((o), G_TYPE_HURD_FILE_MONITOR))
+#define G_IS_HURD_FILE_MONITOR_CLASS(k)                
(G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_HURD_FILE_MONITOR))
+
+typedef struct _GHurdFileMonitor      GHurdFileMonitor;
+typedef struct _GHurdFileMonitorClass GHurdFileMonitorClass;
+
+struct _GHurdFileMonitorClass {
+  GLocalFileMonitorClass parent_class;
+};
+
+GType g_hurd_file_monitor_get_type (void);
+
+G_END_DECLS
+
+#endif /* __G_HURD_FILE_MONITOR_H__ */
diff --git a/gio/hurd/meson.build b/gio/hurd/meson.build
new file mode 100644
index 000000000..2e70b77ae
--- /dev/null
+++ b/gio/hurd/meson.build
@@ -0,0 +1,20 @@
+fs_notify = custom_target('fs_notify',
+  input: 'fs_notify.defs',
+  output: ['fs_notifyServer.c', 'fs_notify_S.h'],
+  command: ['mig', '-n',
+            '-server', '@OUTPUT0@',
+            '-sheader', '@OUTPUT1@',
+            '@INPUT@'])
+
+hurd_sources = [
+  'ghurdfilemonitor.c',
+  fs_notify,
+]
+
+hurd_lib = static_library('hurd',
+  sources : hurd_sources,
+  include_directories : [configinc, glibinc, gmoduleinc],
+  dependencies : [gioenumtypes_dep, libglib_dep, libgobject_dep],
+  gnu_symbol_visibility : 'hidden',
+  pic : true,
+  c_args : [gio_c_args, gio_c_args_internal])
diff --git a/gio/meson.build b/gio/meson.build
index 1f7c1092d..b1fb04bdf 100644
--- a/gio/meson.build
+++ b/gio/meson.build
@@ -800,6 +800,11 @@ if have_func_kqueue and have_func_kevent
   internal_deps += [ kqueue_lib ]
 endif
 
+if host_system == 'gnu'
+  subdir('hurd')
+  internal_deps += [hurd_lib]
+endif
+
 if host_system == 'windows'
   subdir('win32')
   internal_deps += [ giowin32_lib ]
-- 
2.38.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]