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_keyfile_settings_backend_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 ());
|
||||
#endif
|
||||
#if defined(HAVE_KQUEUE)
|
||||
#if defined(FILE_MONITOR_BACKEND_KQUEUE)
|
||||
g_type_ensure (g_kqueue_file_monitor_get_type ());
|
||||
#endif
|
||||
#ifdef G_OS_WIN32
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
Copyright (C) 2005 John McCutchan
|
||||
Copyright © 2015 Canonical Limited
|
||||
Copyright © 2024 Future Crew LLC
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
@ -20,6 +21,7 @@
|
||||
Authors:
|
||||
Ryan Lortie <desrt@desrt.ca>
|
||||
John McCutchan <john@johnmccutchan.com>
|
||||
Gleb Popov <arrowd@FreeBSD.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
@ -32,6 +34,9 @@
|
||||
#include <glib.h>
|
||||
#include "inotify-kernel.h"
|
||||
#include <sys/inotify.h>
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_FILIO_H
|
||||
#include <sys/filio.h>
|
||||
#endif
|
||||
@ -95,11 +100,11 @@ typedef struct
|
||||
{
|
||||
GSource source;
|
||||
|
||||
GQueue queue;
|
||||
GQueue queue; /* (element-type ik_event_t) */
|
||||
gpointer fd_tag;
|
||||
gint fd;
|
||||
|
||||
GHashTable *unmatched_moves;
|
||||
GHashTable *unmatched_moves; /* (element-type guint ik_event_t) */
|
||||
gboolean is_bored;
|
||||
} InotifyKernelSource;
|
||||
|
||||
@ -230,6 +235,7 @@ ik_source_dispatch (GSource *source,
|
||||
|
||||
if (iks->is_bored || g_source_query_unix_fd (source, iks->fd_tag))
|
||||
{
|
||||
#if defined(FILE_MONITOR_BACKEND_INOTIFY)
|
||||
gchar stack_buffer[4096];
|
||||
gsize buffer_len;
|
||||
gchar *buffer;
|
||||
@ -269,12 +275,10 @@ ik_source_dispatch (GSource *source,
|
||||
{
|
||||
ik_event_t *pair;
|
||||
|
||||
pair = g_hash_table_lookup (iks->unmatched_moves, GUINT_TO_POINTER (event->cookie));
|
||||
if (pair != NULL)
|
||||
if (g_hash_table_steal_extended (iks->unmatched_moves, GUINT_TO_POINTER (event->cookie), NULL, (gpointer*)&pair))
|
||||
{
|
||||
g_assert (!pair->pair);
|
||||
|
||||
g_hash_table_remove (iks->unmatched_moves, GUINT_TO_POINTER (event->cookie));
|
||||
event->is_second_in_pair = TRUE;
|
||||
event->pair = pair;
|
||||
pair->pair = event;
|
||||
@ -312,6 +316,76 @@ ik_source_dispatch (GSource *source,
|
||||
|
||||
if (buffer != stack_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))
|
||||
@ -369,13 +443,30 @@ ik_source_dispatch (GSource *source,
|
||||
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 *
|
||||
ik_source_new (gboolean (* callback) (ik_event_t *event))
|
||||
{
|
||||
static GSourceFuncs source_funcs = {
|
||||
NULL, NULL,
|
||||
ik_source_dispatch,
|
||||
NULL, NULL, NULL
|
||||
ik_source_finalize,
|
||||
NULL, NULL
|
||||
};
|
||||
InotifyKernelSource *iks;
|
||||
GSource *source;
|
||||
@ -387,23 +478,31 @@ ik_source_new (gboolean (* callback) (ik_event_t *event))
|
||||
g_source_set_static_name (source, "inotify kernel source");
|
||||
|
||||
iks->unmatched_moves = g_hash_table_new (NULL, NULL);
|
||||
#if defined(FILE_MONITOR_BACKEND_INOTIFY)
|
||||
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)
|
||||
{
|
||||
should_set_nonblock = TRUE;
|
||||
iks->fd = inotify_init ();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (iks->fd >= 0)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
#ifdef FILE_MONITOR_BACKEND_INOTIFY
|
||||
if (should_set_nonblock)
|
||||
{
|
||||
g_unix_set_fd_nonblocking (iks->fd, TRUE, &error);
|
||||
g_assert_no_error (error);
|
||||
}
|
||||
#endif
|
||||
|
||||
iks->fd_tag = g_source_add_unix_fd (source, iks->fd, G_IO_IN);
|
||||
}
|
||||
|
@ -28,6 +28,9 @@ inotify_sources = [
|
||||
'ginotifyfilemonitor.c',
|
||||
]
|
||||
|
||||
# necessary for the libinotify-kqueue backend
|
||||
libinotify_kqueue_dep = dependency('libinotify', required: file_monitor_backend == 'libinotify-kqueue')
|
||||
|
||||
inotify_lib = static_library('inotify',
|
||||
sources : [inotify_sources],
|
||||
include_directories : [configinc, glibinc],
|
||||
@ -36,6 +39,7 @@ inotify_lib = static_library('inotify',
|
||||
libglib_dep,
|
||||
libgobject_dep,
|
||||
gmodule_inc_dep,
|
||||
libinotify_kqueue_dep,
|
||||
],
|
||||
gnu_symbol_visibility : 'hidden',
|
||||
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])
|
||||
|
||||
# inotify
|
||||
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
|
||||
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')
|
||||
internal_deps += [ inotify_lib ]
|
||||
endif
|
||||
|
||||
# kevent
|
||||
if have_func_kqueue and have_func_kevent
|
||||
if file_monitor_backend == 'kqueue'
|
||||
glib_conf.set('FILE_MONITOR_BACKEND_KQUEUE', 1)
|
||||
subdir('kqueue')
|
||||
internal_deps += [ kqueue_lib ]
|
||||
endif
|
||||
|
||||
if host_system == 'windows'
|
||||
if file_monitor_backend == 'win32'
|
||||
glib_conf.set('FILE_MONITOR_BACKEND_WIN32', 1)
|
||||
subdir('win32')
|
||||
internal_deps += [ giowin32_lib ]
|
||||
endif
|
||||
|
@ -116,11 +116,15 @@ static const gchar DONT_CARE[] = "";
|
||||
static Environment
|
||||
get_environment (GFileMonitor *monitor)
|
||||
{
|
||||
if (g_str_equal (G_OBJECT_TYPE_NAME (monitor), "GInotifyFileMonitor"))
|
||||
#if defined(FILE_MONITOR_BACKEND_INOTIFY)
|
||||
return INOTIFY;
|
||||
if (g_str_equal (G_OBJECT_TYPE_NAME (monitor), "GKqueueFileMonitor"))
|
||||
#elif defined(FILE_MONITOR_BACKEND_KQUEUE)
|
||||
return KQUEUE;
|
||||
#elif defined(FILE_MONITOR_BACKEND_LIBINOTIFY_KQUEUE)
|
||||
return INOTIFY | KQUEUE;
|
||||
#else
|
||||
return NONE;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -409,6 +409,7 @@ headers = [
|
||||
'strings.h',
|
||||
'sys/auxv.h',
|
||||
'sys/event.h',
|
||||
'sys/uio.h',
|
||||
'sys/filio.h',
|
||||
'sys/inotify.h',
|
||||
'sys/mkdev.h',
|
||||
@ -2738,4 +2739,5 @@ summary({
|
||||
'libelf' : get_option('libelf'),
|
||||
'multiarch' : get_option('multiarch'),
|
||||
'introspection' : enable_gir,
|
||||
'file_monitor_backend' : get_option('file_monitor_backend'),
|
||||
}, section: 'Options')
|
||||
|
@ -149,3 +149,9 @@ option('introspection',
|
||||
type: 'feature',
|
||||
value: 'auto',
|
||||
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