mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-06 17:36:14 +01:00
Merge branch 'inotify-kqueue' into 'main'
Introduce a new GFileMonitor backend: libinotify-kqueue See merge request GNOME/glib!3657
This commit is contained in:
commit
1adc303f47
@ -1340,10 +1340,10 @@ _g_io_modules_ensure_loaded (void)
|
|||||||
g_type_ensure (g_memory_settings_backend_get_type ());
|
g_type_ensure (g_memory_settings_backend_get_type ());
|
||||||
g_type_ensure (g_keyfile_settings_backend_get_type ());
|
g_type_ensure (g_keyfile_settings_backend_get_type ());
|
||||||
g_type_ensure (g_power_profile_monitor_dbus_get_type ());
|
g_type_ensure (g_power_profile_monitor_dbus_get_type ());
|
||||||
#if defined(HAVE_INOTIFY_INIT1)
|
#if defined(FILE_MONITOR_BACKEND_INOTIFY) || defined(FILE_MONITOR_BACKEND_LIBINOTIFY_KQUEUE)
|
||||||
g_type_ensure (g_inotify_file_monitor_get_type ());
|
g_type_ensure (g_inotify_file_monitor_get_type ());
|
||||||
#endif
|
#endif
|
||||||
#if defined(HAVE_KQUEUE)
|
#if defined(FILE_MONITOR_BACKEND_KQUEUE)
|
||||||
g_type_ensure (g_kqueue_file_monitor_get_type ());
|
g_type_ensure (g_kqueue_file_monitor_get_type ());
|
||||||
#endif
|
#endif
|
||||||
#ifdef G_OS_WIN32
|
#ifdef G_OS_WIN32
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (C) 2005 John McCutchan
|
Copyright (C) 2005 John McCutchan
|
||||||
Copyright © 2015 Canonical Limited
|
Copyright © 2015 Canonical Limited
|
||||||
|
Copyright © 2024 Future Crew LLC
|
||||||
|
|
||||||
SPDX-License-Identifier: LGPL-2.1-or-later
|
SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
|
||||||
@ -20,6 +21,7 @@
|
|||||||
Authors:
|
Authors:
|
||||||
Ryan Lortie <desrt@desrt.ca>
|
Ryan Lortie <desrt@desrt.ca>
|
||||||
John McCutchan <john@johnmccutchan.com>
|
John McCutchan <john@johnmccutchan.com>
|
||||||
|
Gleb Popov <arrowd@FreeBSD.org>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@ -32,6 +34,9 @@
|
|||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include "inotify-kernel.h"
|
#include "inotify-kernel.h"
|
||||||
#include <sys/inotify.h>
|
#include <sys/inotify.h>
|
||||||
|
#ifdef HAVE_SYS_UIO_H
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#endif
|
||||||
#ifdef HAVE_SYS_FILIO_H
|
#ifdef HAVE_SYS_FILIO_H
|
||||||
#include <sys/filio.h>
|
#include <sys/filio.h>
|
||||||
#endif
|
#endif
|
||||||
@ -95,11 +100,11 @@ typedef struct
|
|||||||
{
|
{
|
||||||
GSource source;
|
GSource source;
|
||||||
|
|
||||||
GQueue queue;
|
GQueue queue; /* (element-type ik_event_t) */
|
||||||
gpointer fd_tag;
|
gpointer fd_tag;
|
||||||
gint fd;
|
gint fd;
|
||||||
|
|
||||||
GHashTable *unmatched_moves;
|
GHashTable *unmatched_moves; /* (element-type guint ik_event_t) */
|
||||||
gboolean is_bored;
|
gboolean is_bored;
|
||||||
} InotifyKernelSource;
|
} InotifyKernelSource;
|
||||||
|
|
||||||
@ -230,6 +235,7 @@ ik_source_dispatch (GSource *source,
|
|||||||
|
|
||||||
if (iks->is_bored || g_source_query_unix_fd (source, iks->fd_tag))
|
if (iks->is_bored || g_source_query_unix_fd (source, iks->fd_tag))
|
||||||
{
|
{
|
||||||
|
#if defined(FILE_MONITOR_BACKEND_INOTIFY)
|
||||||
gchar stack_buffer[4096];
|
gchar stack_buffer[4096];
|
||||||
gsize buffer_len;
|
gsize buffer_len;
|
||||||
gchar *buffer;
|
gchar *buffer;
|
||||||
@ -269,12 +275,10 @@ ik_source_dispatch (GSource *source,
|
|||||||
{
|
{
|
||||||
ik_event_t *pair;
|
ik_event_t *pair;
|
||||||
|
|
||||||
pair = g_hash_table_lookup (iks->unmatched_moves, GUINT_TO_POINTER (event->cookie));
|
if (g_hash_table_steal_extended (iks->unmatched_moves, GUINT_TO_POINTER (event->cookie), NULL, (gpointer*)&pair))
|
||||||
if (pair != NULL)
|
|
||||||
{
|
{
|
||||||
g_assert (!pair->pair);
|
g_assert (!pair->pair);
|
||||||
|
|
||||||
g_hash_table_remove (iks->unmatched_moves, GUINT_TO_POINTER (event->cookie));
|
|
||||||
event->is_second_in_pair = TRUE;
|
event->is_second_in_pair = TRUE;
|
||||||
event->pair = pair;
|
event->pair = pair;
|
||||||
pair->pair = event;
|
pair->pair = event;
|
||||||
@ -312,6 +316,76 @@ ik_source_dispatch (GSource *source,
|
|||||||
|
|
||||||
if (buffer != stack_buffer)
|
if (buffer != stack_buffer)
|
||||||
g_free (buffer);
|
g_free (buffer);
|
||||||
|
#elif defined(FILE_MONITOR_BACKEND_LIBINOTIFY_KQUEUE)
|
||||||
|
struct iovec *received[5];
|
||||||
|
int num_events = libinotify_direct_readv (iks->fd, received, G_N_ELEMENTS(received), /* no_block=*/ 1);
|
||||||
|
|
||||||
|
if (num_events < 0)
|
||||||
|
{
|
||||||
|
int errsv = errno;
|
||||||
|
g_warning ("Failed to read inotify events: %s", g_strerror (errsv));
|
||||||
|
/* fall through and skip the next few blocks */
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < num_events; i++)
|
||||||
|
{
|
||||||
|
struct iovec *cur_event = received[i];
|
||||||
|
while (cur_event->iov_base)
|
||||||
|
{
|
||||||
|
struct inotify_event *kevent = (struct inotify_event *) cur_event->iov_base;
|
||||||
|
|
||||||
|
ik_event_t *event;
|
||||||
|
|
||||||
|
event = ik_event_new (kevent, now);
|
||||||
|
|
||||||
|
if (event->mask & IN_MOVED_TO)
|
||||||
|
{
|
||||||
|
ik_event_t *pair;
|
||||||
|
|
||||||
|
if (g_hash_table_steal_extended (iks->unmatched_moves, GUINT_TO_POINTER (event->cookie), NULL, (gpointer*)&pair))
|
||||||
|
{
|
||||||
|
g_assert (!pair->pair);
|
||||||
|
|
||||||
|
event->is_second_in_pair = TRUE;
|
||||||
|
event->pair = pair;
|
||||||
|
pair->pair = event;
|
||||||
|
|
||||||
|
cur_event++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
interesting = TRUE;
|
||||||
|
}
|
||||||
|
else if (event->mask & IN_MOVED_FROM)
|
||||||
|
{
|
||||||
|
gboolean new;
|
||||||
|
|
||||||
|
new = g_hash_table_insert (iks->unmatched_moves, GUINT_TO_POINTER (event->cookie), event);
|
||||||
|
if G_UNLIKELY (!new)
|
||||||
|
g_warning ("inotify: got IN_MOVED_FROM event with already-pending cookie %#x", event->cookie);
|
||||||
|
|
||||||
|
interesting = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_queue_push_tail (&iks->queue, event);
|
||||||
|
|
||||||
|
cur_event++;
|
||||||
|
}
|
||||||
|
libinotify_free_iovec (received[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_events == 0)
|
||||||
|
{
|
||||||
|
/* We can end up reading nothing if we arrived here due to a
|
||||||
|
* boredom timer but the stream of events stopped meanwhile.
|
||||||
|
*
|
||||||
|
* In that case, we need to switch back to polling the file
|
||||||
|
* descriptor in the usual way.
|
||||||
|
*/
|
||||||
|
g_assert (iks->is_bored);
|
||||||
|
interesting = TRUE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
while (ik_source_can_dispatch_now (iks, now))
|
while (ik_source_can_dispatch_now (iks, now))
|
||||||
@ -369,13 +443,30 @@ ik_source_dispatch (GSource *source,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ik_source_finalize (GSource *source)
|
||||||
|
{
|
||||||
|
InotifyKernelSource *iks;
|
||||||
|
|
||||||
|
iks = (InotifyKernelSource *) source;
|
||||||
|
|
||||||
|
#if defined(FILE_MONITOR_BACKEND_INOTIFY)
|
||||||
|
close (iks->fd);
|
||||||
|
#elif defined(FILE_MONITOR_BACKEND_LIBINOTIFY_KQUEUE)
|
||||||
|
libinotify_direct_close (iks->fd);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
iks->fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
static InotifyKernelSource *
|
static InotifyKernelSource *
|
||||||
ik_source_new (gboolean (* callback) (ik_event_t *event))
|
ik_source_new (gboolean (* callback) (ik_event_t *event))
|
||||||
{
|
{
|
||||||
static GSourceFuncs source_funcs = {
|
static GSourceFuncs source_funcs = {
|
||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
ik_source_dispatch,
|
ik_source_dispatch,
|
||||||
NULL, NULL, NULL
|
ik_source_finalize,
|
||||||
|
NULL, NULL
|
||||||
};
|
};
|
||||||
InotifyKernelSource *iks;
|
InotifyKernelSource *iks;
|
||||||
GSource *source;
|
GSource *source;
|
||||||
@ -387,23 +478,31 @@ ik_source_new (gboolean (* callback) (ik_event_t *event))
|
|||||||
g_source_set_static_name (source, "inotify kernel source");
|
g_source_set_static_name (source, "inotify kernel source");
|
||||||
|
|
||||||
iks->unmatched_moves = g_hash_table_new (NULL, NULL);
|
iks->unmatched_moves = g_hash_table_new (NULL, NULL);
|
||||||
|
#if defined(FILE_MONITOR_BACKEND_INOTIFY)
|
||||||
iks->fd = inotify_init1 (IN_CLOEXEC | IN_NONBLOCK);
|
iks->fd = inotify_init1 (IN_CLOEXEC | IN_NONBLOCK);
|
||||||
|
#elif defined(FILE_MONITOR_BACKEND_LIBINOTIFY_KQUEUE)
|
||||||
|
iks->fd = inotify_init1 (IN_CLOEXEC | IN_NONBLOCK | IN_DIRECT);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef FILE_MONITOR_BACKEND_INOTIFY
|
||||||
if (iks->fd < 0)
|
if (iks->fd < 0)
|
||||||
{
|
{
|
||||||
should_set_nonblock = TRUE;
|
should_set_nonblock = TRUE;
|
||||||
iks->fd = inotify_init ();
|
iks->fd = inotify_init ();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (iks->fd >= 0)
|
if (iks->fd >= 0)
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
|
#ifdef FILE_MONITOR_BACKEND_INOTIFY
|
||||||
if (should_set_nonblock)
|
if (should_set_nonblock)
|
||||||
{
|
{
|
||||||
g_unix_set_fd_nonblocking (iks->fd, TRUE, &error);
|
g_unix_set_fd_nonblocking (iks->fd, TRUE, &error);
|
||||||
g_assert_no_error (error);
|
g_assert_no_error (error);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
iks->fd_tag = g_source_add_unix_fd (source, iks->fd, G_IO_IN);
|
iks->fd_tag = g_source_add_unix_fd (source, iks->fd, G_IO_IN);
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,9 @@ inotify_sources = [
|
|||||||
'ginotifyfilemonitor.c',
|
'ginotifyfilemonitor.c',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# necessary for the libinotify-kqueue backend
|
||||||
|
libinotify_kqueue_dep = dependency('libinotify', required: file_monitor_backend == 'libinotify-kqueue')
|
||||||
|
|
||||||
inotify_lib = static_library('inotify',
|
inotify_lib = static_library('inotify',
|
||||||
sources : [inotify_sources],
|
sources : [inotify_sources],
|
||||||
include_directories : [configinc, glibinc],
|
include_directories : [configinc, glibinc],
|
||||||
@ -36,6 +39,7 @@ inotify_lib = static_library('inotify',
|
|||||||
libglib_dep,
|
libglib_dep,
|
||||||
libgobject_dep,
|
libgobject_dep,
|
||||||
gmodule_inc_dep,
|
gmodule_inc_dep,
|
||||||
|
libinotify_kqueue_dep,
|
||||||
],
|
],
|
||||||
gnu_symbol_visibility : 'hidden',
|
gnu_symbol_visibility : 'hidden',
|
||||||
pic : true,
|
pic : true,
|
||||||
|
@ -789,19 +789,41 @@ gioenumtypes_c = custom_target('gioenumtypes_c',
|
|||||||
|
|
||||||
gioenumtypes_dep = declare_dependency(sources : [gioenumtypes_h, glib_enumtypes_h, gio_visibility_h])
|
gioenumtypes_dep = declare_dependency(sources : [gioenumtypes_h, glib_enumtypes_h, gio_visibility_h])
|
||||||
|
|
||||||
|
file_monitor_backend = get_option('file_monitor_backend')
|
||||||
|
if file_monitor_backend == 'auto'
|
||||||
|
if glib_conf.has('HAVE_SYS_INOTIFY_H') and have_func_inotify_init1
|
||||||
|
file_monitor_backend = 'inotify'
|
||||||
|
elif have_func_kqueue and have_func_kevent
|
||||||
|
file_monitor_backend = 'kqueue'
|
||||||
|
elif host_system == 'windows'
|
||||||
|
file_monitor_backend = 'win32'
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
# inotify
|
# inotify
|
||||||
if glib_conf.has('HAVE_SYS_INOTIFY_H') and have_func_inotify_init1
|
if file_monitor_backend == 'inotify'
|
||||||
|
glib_conf.set('FILE_MONITOR_BACKEND_INOTIFY', 1)
|
||||||
|
subdir('inotify')
|
||||||
|
internal_deps += [ inotify_lib ]
|
||||||
|
endif
|
||||||
|
|
||||||
|
# libinotify-kqueue
|
||||||
|
# uses the same code as inotify, but changes some functions behavior via #ifdef's
|
||||||
|
if file_monitor_backend == 'libinotify-kqueue'
|
||||||
|
glib_conf.set('FILE_MONITOR_BACKEND_LIBINOTIFY_KQUEUE', 1)
|
||||||
subdir('inotify')
|
subdir('inotify')
|
||||||
internal_deps += [ inotify_lib ]
|
internal_deps += [ inotify_lib ]
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# kevent
|
# kevent
|
||||||
if have_func_kqueue and have_func_kevent
|
if file_monitor_backend == 'kqueue'
|
||||||
|
glib_conf.set('FILE_MONITOR_BACKEND_KQUEUE', 1)
|
||||||
subdir('kqueue')
|
subdir('kqueue')
|
||||||
internal_deps += [ kqueue_lib ]
|
internal_deps += [ kqueue_lib ]
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if host_system == 'windows'
|
if file_monitor_backend == 'win32'
|
||||||
|
glib_conf.set('FILE_MONITOR_BACKEND_WIN32', 1)
|
||||||
subdir('win32')
|
subdir('win32')
|
||||||
internal_deps += [ giowin32_lib ]
|
internal_deps += [ giowin32_lib ]
|
||||||
endif
|
endif
|
||||||
|
@ -116,11 +116,15 @@ static const gchar DONT_CARE[] = "";
|
|||||||
static Environment
|
static Environment
|
||||||
get_environment (GFileMonitor *monitor)
|
get_environment (GFileMonitor *monitor)
|
||||||
{
|
{
|
||||||
if (g_str_equal (G_OBJECT_TYPE_NAME (monitor), "GInotifyFileMonitor"))
|
#if defined(FILE_MONITOR_BACKEND_INOTIFY)
|
||||||
return INOTIFY;
|
return INOTIFY;
|
||||||
if (g_str_equal (G_OBJECT_TYPE_NAME (monitor), "GKqueueFileMonitor"))
|
#elif defined(FILE_MONITOR_BACKEND_KQUEUE)
|
||||||
return KQUEUE;
|
return KQUEUE;
|
||||||
|
#elif defined(FILE_MONITOR_BACKEND_LIBINOTIFY_KQUEUE)
|
||||||
|
return INOTIFY | KQUEUE;
|
||||||
|
#else
|
||||||
return NONE;
|
return NONE;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -409,6 +409,7 @@ headers = [
|
|||||||
'strings.h',
|
'strings.h',
|
||||||
'sys/auxv.h',
|
'sys/auxv.h',
|
||||||
'sys/event.h',
|
'sys/event.h',
|
||||||
|
'sys/uio.h',
|
||||||
'sys/filio.h',
|
'sys/filio.h',
|
||||||
'sys/inotify.h',
|
'sys/inotify.h',
|
||||||
'sys/mkdev.h',
|
'sys/mkdev.h',
|
||||||
@ -2738,4 +2739,5 @@ summary({
|
|||||||
'libelf' : get_option('libelf'),
|
'libelf' : get_option('libelf'),
|
||||||
'multiarch' : get_option('multiarch'),
|
'multiarch' : get_option('multiarch'),
|
||||||
'introspection' : enable_gir,
|
'introspection' : enable_gir,
|
||||||
|
'file_monitor_backend' : get_option('file_monitor_backend'),
|
||||||
}, section: 'Options')
|
}, section: 'Options')
|
||||||
|
@ -149,3 +149,9 @@ option('introspection',
|
|||||||
type: 'feature',
|
type: 'feature',
|
||||||
value: 'auto',
|
value: 'auto',
|
||||||
description: 'Enable generating introspection data (requires gobject-introspection)')
|
description: 'Enable generating introspection data (requires gobject-introspection)')
|
||||||
|
|
||||||
|
option('file_monitor_backend',
|
||||||
|
type : 'combo',
|
||||||
|
choices : ['auto', 'inotify', 'kqueue', 'libinotify-kqueue', 'win32'],
|
||||||
|
value : 'auto',
|
||||||
|
description : 'The name of the system API to use as a GFileMonitor backend')
|
||||||
|
Loading…
Reference in New Issue
Block a user