[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,
+ ¬ify_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