1 Solaris FEN support in Gamin
3 https://bugzilla.gnome.org/show_bug.cgi?id=730679
4 http://osdyson.org/issues/172
5 http://hg.osdyson.org/solaris-desktop-spec-files/raw-file/8f7c0cd200a9/patches/gamin-01-all.diff
7 Fixed issues after the initial integration:
8 1) Using freed node_t pointer in node_add function.
9 Mitigation: When a node is removed, we also remove all the events in the
10 event queue that contain a reference to this node to avoid future memory errors.
11 2) A missing call to node_lstat before calling port_add function.
12 When the system is under load, the timing of callbacks might cause that port_add is
13 called on a node which access, change, and modification time was not read/updated.
14 Mitigation: Call node_lstat before port_add in node_add_event function.
16 diff --git a/configure.in b/configure.in
17 index e4b684e..5836bb7 100644
20 @@ -42,6 +42,12 @@ if test -z "$ENV_CFLAGS"; then
24 +dnl If the user set no CFLAGS, then don't assume the autotools defaults of
25 +dnl "-g -O2". We set default CFLAGS later based on the --disable-debug flag.
26 +if test -z "$ENV_CFLAGS"; then
31 RELDATE=`date +'%a %b %e %Y'`
33 @@ -279,6 +285,43 @@ if test x$kqueue = xtrue; then
34 backends="${backends}, kqueue"
39 + AM_CONDITIONAL(ON_SOLARIS, true)
42 + #ifndef PORT_SOURCE_FILE
43 + #error "Please upgrade to Nevada 72 or above to suppoert FEN"
45 + int main() { return 0; }
47 + if test x$have_fen = x1 ; then
49 + AC_HELP_STRING([--disable-fen], [Disable the FEN backend]),
50 + [fen="${enableval}"], [fen=true])
52 + if test x$fen = xyes; then
54 + elif test x$fen = xno; then
56 + elif test x$fen != xtrue; then
57 + AC_MSG_ERROR(bad value ${enableval} for --disable-fen)
68 +AM_CONDITIONAL(ENABLE_FEN, test x$fen = xtrue)
69 +if test x$fen = xtrue; then
70 + AC_DEFINE(ENABLE_FEN,1,[Use Solaris FEN as backend])
71 + backends="${backends}, FEN"
74 dnl pthread support for reentrance of the client library.
76 [ --with-threads add multithread support(on)])
77 @@ -385,6 +428,14 @@ if test x$dbus_have_struct_cmsgcred = xyes; then
78 AC_DEFINE(HAVE_CMSGCRED,1,[Have cmsgcred structure])
81 +dnl Check for getpeerucred support - Solaris
83 +AC_CHECK_HEADER(ucred.h,
84 + AC_CHECK_LIB(c, getpeerucred,[
85 + AC_DEFINE([HAVE_GETPEERUCRED],[],[Define if has getpeerucred])
86 + AC_DEFINE([HAVE_UCRED_H],[],[Define if <ucred.h> exists])]))
91 AC_MSG_CHECKING(abstract socket namespace)
92 @@ -529,6 +580,16 @@ AC_SUBST(PYTHON_VERSION)
93 AC_SUBST(PYTHON_INCLUDES)
94 AC_SUBST(PYTHON_SITE_PACKAGES)
96 +dnl Check for -lsocket -lnsl
98 +AC_CHECK_FUNC(gethostent, , AC_CHECK_LIB(nsl, gethostent))
99 +AC_CHECK_FUNC(setsockopt, , AC_CHECK_LIB(socket, setsockopt))
101 +dnl Check for <sys/mnttab.h>
103 +AC_CHECK_HEADER(sys/mnttab.h,
104 + AC_DEFINE([HAVE_SYS_MNTTAB_H], [], [Define if <sys/mnttab.h> is there]))
106 dnl After all config-related tweaking of CFLAGS, set it to its "build" value
108 AC_MSG_CHECKING(for more compiler warnings)
109 diff --git a/libgamin/Makefile.am b/libgamin/Makefile.am
110 index 35aa740..4f725a2 100644
111 --- a/libgamin/Makefile.am
112 +++ b/libgamin/Makefile.am
113 @@ -39,13 +39,24 @@ CLEANFILES=gam_error.c gam_event.c
115 libgamin_1_la_LIBADD =
118 +libgamin_1_la_LDFLAGS = -Wl,-M$(srcdir)/gamin_sym.version \
119 + -version-info @GAMIN_VERSION_INFO@ @THREAD_LIBS@
121 libgamin_1_la_LDFLAGS = -Wl,--version-script=$(srcdir)/gamin_sym.version \
122 -version-info @GAMIN_VERSION_INFO@ @THREAD_LIBS@
125 libfam_la_SOURCES = $(libgamin_1_la_SOURCES)
126 libfam_la_LIBADD = $(libgamin_1_la_LIBADD)
127 -libfam_la_LDFLAGS = -Wl,--version-script=$(srcdir)/gamin_sym.version \
130 +libfam_la_LDFLAGS = -Wl,-M$(srcdir)/gamin_sym.version \
131 -version-info @FAM_VERSION_INFO@ @THREAD_LIBS@
133 +libfam_la_LDFLAGS = -Wl,--version-script=$(srcdir)/gamin_sym.version \
134 + -version-info @FAM_VERSION_INFO@ @THREAD_LIBS@
138 # Compile a program locally to check
139 diff --git a/libgamin/gam_api.c b/libgamin/gam_api.c
140 index 4e87e63..3630213 100644
141 --- a/libgamin/gam_api.c
142 +++ b/libgamin/gam_api.c
144 #include <sys/socket.h>
150 +#if defined(HAVE_UCRED_H)
152 +#endif defined(HAVE_UCRED_H)
154 #include "gam_protocol.h"
155 #include "gam_data.h"
156 @@ -660,6 +666,10 @@ gamin_check_cred(GAMDataPtr conn, int fd)
160 +#if defined(HAVE_GETPEERUCRED)
166 #if defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED)
167 @@ -726,11 +736,25 @@ retry:
168 fd, cr_len, (int) sizeof(cr));
171 +#elif defined(HAVE_GETPEERUCRED)
172 + if ((creds = (ucred_t *)malloc(ucred_size()))==(ucred_t *)NULL){
173 + GAM_DEBUG(DEBUG_INFO,"Malloc failed for ucreds");
177 + if (getpeerucred(fd, &creds)!=0){
178 + GAM_DEBUG(DEBUG_INFO,"getpeerucred call failed");
181 + c_uid = ucred_getruid(creds);
182 + c_gid = ucred_getrgid(creds);
183 + c_pid = ucred_getpid(creds);
185 #elif defined(HAVE_CMSGCRED)
186 c_pid = cmsg.cred.cmcred_pid;
187 c_uid = cmsg.cred.cmcred_euid;
188 c_gid = cmsg.cred.cmcred_groups[0];
189 -#else /* !SO_PEERCRED && !HAVE_CMSGCRED */
190 +#else /* !SO_PEERCRED && !HAVE_CMSGCRED && !HAVE_GETPEERUCRED */
191 GAM_DEBUG(DEBUG_INFO,
192 "Socket credentials not supported on this OS\n");
194 diff --git a/libgamin/gamin_sym.version b/libgamin/gamin_sym.version
195 index dba5f20..5c6d661 100644
196 --- a/libgamin/gamin_sym.version
197 +++ b/libgamin/gamin_sym.version
206 FAMMonitorCollection;
207 diff --git a/server/Makefile.am b/server/Makefile.am
208 index 37aed8b..7964d17 100644
209 --- a/server/Makefile.am
210 +++ b/server/Makefile.am
211 @@ -10,7 +10,7 @@ INCLUDES = \
212 -DG_DISABLE_DEPRECATED
215 -INCLUDES += -DGAM_DEBUG_ENABLED
216 +INCLUDES += -DGAM_DEBUG_ENABLED -g
220 @@ -68,6 +68,18 @@ if ENABLE_KQUEUE
221 gam_server_SOURCES += gam_kqueue.c gam_kqueue.h
225 +gam_server_SOURCES += gam_fen.c gam_fen.h \
236 if ENABLE_HURD_MACH_NOTIFY
237 gam_server_SOURCES += gam_hurd_mach_notify.c gam_hurd_mach_notify.h
239 diff --git a/server/fen-dump.c b/server/fen-dump.c
241 index 0000000..98d20eb
243 +++ b/server/fen-dump.c
245 +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
246 +/* vim:set expandtab ts=4 shiftwidth=4: */
248 + * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
251 + * This library is free software; you can redistribute it and/or
252 + * modify it under the terms of the GNU Lesser General Public
253 + * License as published by the Free Software Foundation; either
254 + * version 2 of the License, or (at your option) any later version.
256 + * This library is distributed in the hope that it will be useful,
257 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
258 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
259 + * Lesser General Public License for more details.
261 + * You should have received a copy of the GNU Lesser General
262 + * Public License along with this library; if not, write to the
263 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
264 + * Boston, MA 02111-1307, USA.
266 + * Authors: Lin Ma <lin.ma@sun.com>
271 +#include <glib/gprintf.h>
272 +#include "fen-node.h"
273 +#include "fen-dump.h"
275 +G_LOCK_EXTERN (fen_lock);
277 +/*-------------------- node ------------------*/
279 +dump_node (node_t* node, gpointer data)
281 + g_printf ("n:0x%p ds:0x%p s:0x%p %s\n", node, node->dir_subs, node->subs, NODE_NAME(node));
285 +dump_tree (node_t* node)
287 + if (G_TRYLOCK (fen_lock)) {
288 + node_traverse(NULL, dump_node, NULL);
289 + G_UNLOCK (fen_lock);
293 +/* ------------------ fdata port hash --------------------*/
295 +dump_hash_cb (gpointer key,
297 + gpointer user_data)
299 + g_printf ("k:0x%p v:0x%p >\n", key, value);
303 +dump_hash (GHashTable* hash, gpointer user_data)
305 + if (G_TRYLOCK (fen_lock)) {
306 + if (g_hash_table_size (hash) > 0) {
307 + g_hash_table_foreach (hash, dump_hash_cb, user_data);
309 + G_UNLOCK (fen_lock);
314 +/* ------------------ event --------------------*/
316 +dump_event (node_event_t* ev, gpointer user_data)
318 + node_t* node = ev->user_data;
319 + g_printf ("ne:0x%p e:%p n:0x%p ds:0x%p s:0x%p s\n", ev, ev->e, node, node->dir_subs, node->subs, NODE_NAME(node));
322 diff --git a/server/fen-dump.h b/server/fen-dump.h
324 index 0000000..ffac822
326 +++ b/server/fen-dump.h
328 +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
329 +/* vim:set expandtab ts=4 shiftwidth=4: */
331 + * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
334 + * This library is free software; you can redistribute it and/or
335 + * modify it under the terms of the GNU Lesser General Public
336 + * License as published by the Free Software Foundation; either
337 + * version 2 of the License, or (at your option) any later version.
339 + * This library is distributed in the hope that it will be useful,
340 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
341 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
342 + * Lesser General Public License for more details.
344 + * You should have received a copy of the GNU Lesser General
345 + * Public License along with this library; if not, write to the
346 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
347 + * Boston, MA 02111-1307, USA.
349 + * Authors: Lin Ma <lin.ma@sun.com>
352 +#ifndef _FEN_DUMP_H_
353 +#define _FEN_DUMP_H_
356 +#endif /* _FEN_DUMP_H_ */
357 diff --git a/server/fen-helper.c b/server/fen-helper.c
359 index 0000000..e68e7c3
361 +++ b/server/fen-helper.c
363 +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
364 +/* vim:set expandtab ts=4 shiftwidth=4: */
366 + * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
369 + * This library is free software; you can redistribute it and/or
370 + * modify it under the terms of the GNU Lesser General Public
371 + * License as published by the Free Software Foundation; either
372 + * version 2 of the License, or (at your option) any later version.
374 + * This library is distributed in the hope that it will be useful,
375 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
376 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
377 + * Lesser General Public License for more details.
379 + * You should have received a copy of the GNU Lesser General
380 + * Public License along with this library; if not, write to the
381 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
382 + * Boston, MA 02111-1307, USA.
384 + * Authors: Lin Ma <lin.ma@sun.com>
389 +#include "fen-helper.h"
390 +#include "fen-kernel.h"
391 +#ifdef GIO_COMPILATION
392 +#include "gfilemonitor.h"
394 +#include "gam_event.h"
395 +#include "gam_server.h"
396 +#include "gam_protocol.h"
399 +#ifdef GIO_COMPILATION
400 +#define FH_W if (fh_debug_enabled) g_debug
401 +static gboolean fh_debug_enabled = FALSE;
403 +#include "gam_error.h"
404 +#define FH_W(...) GAM_DEBUG(DEBUG_INFO, __VA_ARGS__)
407 +G_LOCK_EXTERN (fen_lock);
411 +scan_children_init(node_t *f, gpointer sub)
416 + FH_W ("%s %s [0x%p]\n", __func__, NODE_NAME(f), f);
418 +#ifdef GIO_COMPILATION
420 + event = G_FILE_MONITOR_EVENT_CREATED;
423 + event = GAMIN_EVENT_EXISTS;
426 + if (!NODE_HAS_FLAG(f, NODE_FLAG_SNAPSHOT_UPDATED)) {
427 + /* TODO snapshot should also compare to the sub created timestamp. */
428 + /* GIO initially doesn't emit created/existed events. */
429 + node_create_children_snapshot(f, event, emit);
431 + GHashTableIter iter;
434 + g_hash_table_iter_init (&iter, f->children);
435 + while (g_hash_table_iter_next (&iter, NULL, &value)) {
436 + node_t *child = (node_t *)value;
438 +#ifdef GIO_COMPILATION
439 + /* GIO initially doesn't emit created/existed events. */
440 + /* g_file_monitor_emit_event(G_FILE_MONITOR(sub), child->gfile, NULL, event); */
442 + gam_server_emit_one_event(NODE_NAME(child), gam_subscription_is_dir(sub), event, sub, 1);
451 + * Won't hold a ref, we have a timout callback to clean unused node_t.
452 + * If there is no value for a key, add it and return it; else return the old
456 +fen_add (const gchar *filename, gpointer sub, gboolean is_mondir)
460 + g_assert (filename);
464 + f = node_find(NULL, filename, TRUE);
465 + FH_W ("%s 0x%p sub[0x%p] %s\n", __func__, f, sub, filename);
468 + /* Update timestamp, the events in global queue will compare itself to this
469 + * timestamp to decide if be emitted. TODO, timestamp should be per sub.
471 + if (!NODE_IS_ACTIVE(f)) {
472 + g_get_current_time(&f->atv);
476 + f->dir_subs = g_list_prepend(f->dir_subs, sub);
478 + f->subs = g_list_prepend(f->subs, sub);
481 + if (NODE_HAS_STATE(f, NODE_STATE_ASSOCIATED) ||
482 + (node_lstat(f) == 0 && port_add(f) == 0)) {
483 +#ifndef GIO_COMPILATION
484 + gam_server_emit_one_event (NODE_NAME(f),
485 + gam_subscription_is_dir (sub), GAMIN_EVENT_EXISTS, sub, 1);
488 + scan_children_init (f, sub);
491 +#ifndef GIO_COMPILATION
492 + gam_server_emit_one_event (NODE_NAME(f),
493 + gam_subscription_is_dir (sub), GAMIN_EVENT_DELETED, sub, 1);
495 + node_adjust_deleted (f);
497 +#ifndef GIO_COMPILATION
498 + gam_server_emit_one_event (NODE_NAME(f),
499 + gam_subscription_is_dir (sub), GAMIN_EVENT_ENDEXISTS, sub, 1);
501 + G_UNLOCK (fen_lock);
505 +fen_remove (const gchar *filename, gpointer sub, gboolean is_mondir)
509 + g_assert (filename);
513 + f = node_find(NULL, filename, FALSE);
514 + FH_W ("%s 0x%p sub[0x%p] %s\n", __func__, f, sub, filename);
518 + f->dir_subs = g_list_remove(f->dir_subs, sub);
520 + f->subs = g_list_remove(f->subs, sub);
523 + if (!NODE_IS_ACTIVE(f)) {
524 + node_try_delete (f);
527 + G_UNLOCK (fen_lock);
533 + * FEN subsystem initializing.
538 + static gboolean initialized = FALSE;
539 + static gboolean result = FALSE;
543 + G_UNLOCK (fen_lock);
547 + result = node_class_init();
550 + G_UNLOCK (fen_lock);
554 + initialized = TRUE;
556 + G_UNLOCK (fen_lock);
560 diff --git a/server/fen-helper.h b/server/fen-helper.h
562 index 0000000..25df38f
564 +++ b/server/fen-helper.h
566 +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
567 +/* vim:set expandtab ts=4 shiftwidth=4: */
569 + * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
572 + * This library is free software; you can redistribute it and/or
573 + * modify it under the terms of the GNU Lesser General Public
574 + * License as published by the Free Software Foundation; either
575 + * version 2 of the License, or (at your option) any later version.
577 + * This library is distributed in the hope that it will be useful,
578 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
579 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
580 + * Lesser General Public License for more details.
582 + * You should have received a copy of the GNU Lesser General
583 + * Public License along with this library; if not, write to the
584 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
585 + * Boston, MA 02111-1307, USA.
587 + * Authors: Lin Ma <lin.ma@sun.com>
590 +#ifndef _FEN_HELPER_H_
591 +#define _FEN_HELPER_H_
593 +void fen_add (const gchar *filename, gpointer sub, gboolean is_mondir);
594 +void fen_remove (const gchar *filename, gpointer sub, gboolean is_mondir);
596 +gboolean fen_init ();
598 +#endif /* _FEN_HELPER_H_ */
599 diff --git a/server/fen-kernel.c b/server/fen-kernel.c
601 index 0000000..8b9c58b
602 --- /dev/null 2019-12-10 11:10:35.000000000 +0000
603 +++ gamin-0.1.10/server/fen-kernel.c 2019-12-10 11:10:23.000742017 +0000
605 +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
606 +/* vim:set expandtab ts=4 shiftwidth=4: */
608 + * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
611 + * This library is free software; you can redistribute it and/or
612 + * modify it under the terms of the GNU Lesser General Public
613 + * License as published by the Free Software Foundation; either
614 + * version 2 of the License, or (at your option) any later version.
616 + * This library is distributed in the hope that it will be useful,
617 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
618 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
619 + * Lesser General Public License for more details.
621 + * You should have received a copy of the GNU Lesser General
622 + * Public License along with this library; if not, write to the
623 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
624 + * Boston, MA 02111-1307, USA.
626 + * Authors: Lin Ma <lin.ma@sun.com>
631 +#include <strings.h>
636 +#include "fen-kernel.h"
637 +#include "fen-dump.h"
639 +#ifdef GIO_COMPILATION
640 +#define FK_W if (fk_debug_enabled) g_debug
641 +static gboolean fk_debug_enabled = FALSE;
643 +#include "gam_error.h"
644 +#define FK_W(...) GAM_DEBUG(DEBUG_INFO, __VA_ARGS__)
647 +G_GNUC_INTERNAL G_LOCK_DEFINE (fen_lock);
649 +static ulong max_port_events = 512;
650 +static GList *pn_visible_list; /* the queue of ports which don't have the max objs */
651 +static GQueue *g_eventq = NULL;
652 +static timespec_t zero_wait;
653 +static void (*user_process_events_cb) (gpointer, node_event_t*);
654 +static port_event_t *pevents = NULL;
655 +static gint PE_ALLOC = 2048;
656 +static GHashTable *renamed_hash = NULL; /* <parent node, ev> */
658 +typedef struct _PSource {
659 + GSource source; /* Inherit from GSource, must be the first. */
662 + uint_t event_growing_factor;
663 + uint_t pending_events;
666 +#define PGPFD(s) (&((PSource *)(s))->gfd)
667 +#define SLEEP_BASE_TIME 10 /* in milliseconds */
668 +#define EXPECT_INC_EVENTS(pn) (1 << (pn->event_growing_factor))
670 +#define RENAME_EVENTS_INTERVAL 500 /* in milliseconds */
671 +#define PROCESS_PORT_EVENTS_TIME 1000 /* in milliseconds */
672 +guint process_port_event_id = 0;
674 +static gchar* _event_strings(int event);
675 +static const gchar* _event_string (int event);
676 +static GSource *psource_new();
678 +static gboolean port_prepare(GSource *source, gint *timeout_);
679 +static gboolean port_check(GSource *source);
680 +static gboolean port_dispatch(GSource *source, GSourceFunc callback, gpointer user_data);
681 +static GSourceFuncs fen_source_func = {
689 +port_prepare(GSource *source, gint *timeout_)
695 +port_check(GSource *source)
697 + PSource *pn = (PSource *)source;
701 + pn->pending = FALSE;
702 + g_source_add_poll(source, PGPFD(source));
703 + g_source_unref(source);
707 + if (!(PGPFD(pn)->revents & G_IO_IN))
710 + if (port_getn(PGPFD(source)->fd, NULL, 0, &nget, 0) == 0) {
711 + if (nget - pn->pending_events > EXPECT_INC_EVENTS(pn)) {
712 + /* Sleep for a while. */
713 + pn->pending_events = nget;
714 + pn->event_growing_factor ++;
716 + pn->pending = TRUE;
717 + g_source_ref(source);
718 + g_source_remove_poll(source, PGPFD(source));
719 + g_timeout_add(SLEEP_BASE_TIME,
720 + (GSourceFunc)port_check,
726 + pn->pending_events = 0;
727 + pn->event_growing_factor = 0;
733 +port_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
739 + FK_W ("%s 0x%p fd %d\n", __func__, source, PGPFD(source)->fd);
744 + if (port_getn(PGPFD(source)->fd, pevents, PE_ALLOC, &nget, &zero_wait) == 0) {
746 + for (i = 0; i < nget; i++) {
747 + f = (node_t *)pevents[i].portev_user;
749 + if (pevents[i].portev_source == PORT_SOURCE_FILE) {
751 + NODE_CLE_STATE(f, NODE_STATE_ASSOCIATED);
752 + NODE_SET_STATE(f, NODE_STATE_HAS_EVENTS);
754 + if (HAS_NO_EXCEPTION_EVENTS(pevents[i].portev_events)) {
755 + /* If the events do not show it's deleted, update
756 + * file timestamp to avoid missing events next time.
758 + if (node_lstat(f) != 0 /* || port_add(f) != 0 */) {
759 + /* Included deleted event. */
760 + pevents[i].portev_events |= FILE_DELETE;
764 + /* Queue it and waiting for processing. */
765 + g_queue_push_tail(g_eventq,
766 + node_event_new(pevents[i].portev_events, (gpointer)f));
769 + FK_W ("[kernel] unknown portev_source %d\n", pevents[i].portev_source);
776 + FK_W ("[kernel] port_getn %s\n", g_strerror (errno));
779 + } while (nget == PE_ALLOC);
781 + G_UNLOCK (fen_lock);
783 + if (total > 0 && callback) {
784 + FK_W ("[kernel] get total %ld events\n", total);
785 + return callback (user_data);
791 +process_renamed_hash_cb(gpointer key, gpointer value, gpointer user_data)
793 + node_event_t *ev = value;
796 + node_add_event(ev->user_data, ev);
798 + user_process_events_cb(ev->user_data, ev);
800 + /* Always delete self from hash. */
805 +port_events_process_cb(gpointer user_data)
811 + /* Processing g_eventq */
812 + while ((ev = (node_event_t*)g_queue_pop_head (g_eventq)) != NULL) {
814 + /* FK_W ("[%s] 0x%p %s\n", __func__, ev, _event_string (ev->e)); */
817 + gchar *log = _event_strings(ev->e);
818 + FK_W ("%s %s %s\n", __func__, NODE_NAME(ev->user_data), log);
822 +#ifdef GIO_COMPILATION
823 + /* Use the parent node as a hash, because only the dir_subs in the
824 + * parent node should receive MOVE event.
826 + if (NODE_PARENT(ev->user_data)) {
827 + if (ev->e == FILE_RENAME_TO) {
828 + g_hash_table_insert(renamed_hash, NODE_PARENT(ev->user_data), ev);
829 + g_time_val_add(&ev->rename_tv, RENAME_EVENTS_INTERVAL);
832 + if (ev->e == FILE_RENAME_FROM) {
833 + node_event_t *pair_ev;
835 + pair_ev = g_hash_table_lookup(renamed_hash, NODE_PARENT(ev->user_data));
836 + if (pair_ev && node_timeval_lt(&ev->ctv, &pair_ev->rename_tv)) {
837 + g_hash_table_remove(renamed_hash, NODE_PARENT(ev->user_data));
838 + pair_ev->pair_data = ev->user_data;
839 + /* Free ev, exchange pair_ev and ev. */
840 + node_event_delete(ev);
848 + node_add_event(ev->user_data, ev);
850 + user_process_events_cb(ev->user_data, ev);
854 + /* Processing the events in renamed_hash. TODO we should delay it and wait
855 + * for more possible pair.
857 + g_hash_table_foreach_remove(renamed_hash, process_renamed_hash_cb, NULL);
859 + G_UNLOCK (fen_lock);
861 + process_port_event_id = 0;
866 +port_events_read_cb(gpointer user_data)
869 + if (process_port_event_id == 0) {
870 + process_port_event_id = g_timeout_add(PROCESS_PORT_EVENTS_TIME,
871 + port_events_process_cb,
879 + * malloc PSource and port_create, start thread at pnode_ref.
880 + * if psource_new succeeded, the PSource will never
881 + * be freed. So PSource can be freed only in psource_new.
882 + * Note pnode_monitor_remove_all can also free PSource, but currently no one
888 + GSource *source = NULL;
891 + if ((fd = port_create()) >= 0) {
892 + source = g_source_new(&fen_source_func, sizeof(PSource));
893 + PGPFD(source)->fd = fd;
894 + PGPFD(source)->events = G_IO_IN | G_IO_HUP | G_IO_ERR;
895 + g_source_set_callback(source, port_events_read_cb, NULL, NULL);
896 + g_source_attach(source, NULL);
897 + g_source_unref(source);
898 + g_source_add_poll(source, PGPFD(source));
900 + FK_W ("%s 0x%p fd %d\n", __func__, source, PGPFD(source)->fd);
902 + FK_W ("PORT_CREATE %s\n", g_strerror(errno));
903 + g_return_val_if_reached(NULL);
913 + * Unsafe, need lock fen_lock.
914 + * port_add will associate a GSource to @f->source
919 + GSource *source = f->source;
921 + FK_W ("%s [0x%p] %s\n", __func__, f, NODE_NAME(f));
924 + g_assert(NODE_HAS_FLAG(f, NODE_FLAG_STAT_UPDATED));
926 + /* if (!NODE_HAS_FLAG(f, NODE_FLAG_STAT_DONE)) { */
927 + /* if (NODE_STAT(f) != 0) { */
928 + /* return errno; */
932 + /* Try re-use f->pn. f->pn may be used by other request, e.g. f is deleted
933 + * for a long time. So if pn is full, we try to open a new one.
937 + /* Try the next visible source. */
938 + if (pn_visible_list) {
939 + source = (GSource *)pn_visible_list->data;
941 + if ((source = psource_new()) != NULL) {
942 + g_assert (g_list_find (pn_visible_list, source) == NULL);
943 + pn_visible_list = g_list_prepend (pn_visible_list, source);
948 + if (port_associate(PGPFD(source)->fd, PORT_SOURCE_FILE, (uintptr_t)FILE_OBJECT(f),
951 + f->source = source;
952 + NODE_SET_STATE(f, NODE_STATE_ASSOCIATED);
953 + NODE_CLE_FLAG(f, NODE_FLAG_STAT_UPDATED);
954 + FK_W ("PORT_ASSOCIATE 0x%p OK\n", f);
956 + } else if (errno == EAGAIN) {
957 + /* Full, remove it. */
958 + pn_visible_list = g_list_remove (pn_visible_list, source);
959 + /* Re-add to port */
962 + } else if (errno == ENOENT) {
963 + /* File is not exist */
964 + } else if (errno == ENOTSUP) {
965 + /* FS is not supported. Currently we think it no longer make sense to
966 + * monitor it, so clean the stat info and return 0 to ignore this
967 + * node. If there are requirement, we can consider to add polling
970 + NODE_CLE_FLAG(f, NODE_FLAG_STAT_UPDATED);
973 + FK_W ("PORT_ASSOCIATE 0x%p %s\n", f, g_strerror (errno));
976 + /* No matter if associated successfully, stat info is out-of-date, so clean it. */
977 + NODE_CLE_FLAG(f, NODE_FLAG_STAT_UPDATED);
985 + * Unsafe, need lock fen_lock.
988 +port_remove (node_t *f)
990 + /* g_assert(f->source); */
992 + if (NODE_HAS_STATE(f, NODE_STATE_ASSOCIATED)) {
993 + /* Mark unregisted. */
994 + if (port_dissociate(PGPFD(f->source)->fd, PORT_SOURCE_FILE, (uintptr_t)FILE_OBJECT(f)) == 0) {
996 + * Note, we can run foode_delete if dissociating is failed,
997 + * because there may be some pending events (mostly like
998 + * FILE_DELETE) in the port_get. If we delete the foode
999 + * the fnode may be deleted, then port_get will run on an invalid
1002 + NODE_CLE_STATE(f, NODE_STATE_ASSOCIATED);
1003 + FK_W ("PORT_DISSOCIATE 0x%p OK\n", f);
1004 + } else if (errno == ENOENT) {
1005 + /* The file has been removed from port, after port_get or before
1006 + * port_get but DELETED event has been generated.
1009 + FK_W ("PORT_DISSOCIATE 0x%p %s\n", f, g_strerror (errno));
1010 + g_return_if_reached();
1016 + * When a node is deleted, we need to remove
1017 + * all events referencing this node from event queue.
1019 + * Unsafe, need lock fen_lock.
1021 +void prune_queue (node_t *f)
1024 + GQueue *c = g_queue_copy(g_eventq);
1025 + while (ev = (node_event_t*) g_queue_pop_head(c)) {
1026 + if (ev->user_data == f || ev->pair_data == f)
1027 + g_queue_remove(g_eventq, ev);
1033 + * Get Solaris resouce values.
1038 +port_class_init (void (*user_process_events_callback) (gpointer, node_event_t*))
1042 + if ((rblk = malloc (rctlblk_size ())) == NULL) {
1043 + FK_W ("[kernel] rblk malloc %s\n", g_strerror (errno));
1046 + if (getrctl ("process.max-port-events", NULL, rblk, RCTL_FIRST) == -1) {
1047 + FK_W ("[kernel] getrctl %s\n", g_strerror (errno));
1051 + max_port_events = rctlblk_get_value(rblk);
1052 + FK_W ("max_port_events = %u\n", max_port_events);
1055 + renamed_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
1057 + if (renamed_hash == NULL) {
1058 + FK_W ("[kernel] FEN global renamed queue initializing faild\n");
1061 + if ((g_eventq = g_queue_new ()) == NULL) {
1062 + FK_W ("[kernel] FEN global event queue initializing faild\n");
1065 + if (user_process_events_callback == NULL) {
1066 + FK_W ("[kernel] FEN global no user_process_events_callback\n");
1069 + user_process_events_cb = user_process_events_callback;
1070 + memset (&zero_wait, 0, sizeof (timespec_t));
1072 + pevents = g_malloc(PE_ALLOC * sizeof(port_event_t));
1073 + if (pevents == NULL) {
1074 + FK_W ("[kernel] FEN global alloc pevents failed\n");
1082 +printevent (const char *pname, int event, const char *tag)
1084 + static gchar *event_string = NULL;
1087 + if (event_string) {
1088 + g_free(event_string);
1091 + str = g_string_new ("");
1092 + g_string_printf (str, "[%s] [%-20s]", tag, pname);
1093 + if (event & FILE_ACCESS) {
1094 + str = g_string_append (str, " ACCESS");
1096 + if (event & FILE_MODIFIED) {
1097 + str = g_string_append (str, " MODIFIED");
1099 + if (event & FILE_ATTRIB) {
1100 + str = g_string_append (str, " ATTRIB");
1102 + if (event & FILE_DELETE) {
1103 + str = g_string_append (str, " DELETE");
1105 + if (event & FILE_RENAME_TO) {
1106 + str = g_string_append (str, " RENAME_TO");
1108 + if (event & FILE_RENAME_FROM) {
1109 + str = g_string_append (str, " RENAME_FROM");
1111 + if (event & UNMOUNTED) {
1112 + str = g_string_append (str, " UNMOUNTED");
1114 + if (event & MOUNTEDOVER) {
1115 + str = g_string_append (str, " MOUNTEDOVER");
1117 + event_string = str->str;
1118 + g_string_free (str, FALSE);
1119 + return event_string;
1123 +_event_strings(int event)
1125 + GString *str = g_string_sized_new(80);
1127 + if (event & FILE_DELETE)
1128 + g_string_append(str, " FILE_DELETE");
1130 + if (event & FILE_RENAME_FROM)
1131 + g_string_append(str, " FILE_RENAME_FROM");
1133 + if (event & FILE_MODIFIED)
1134 + g_string_append(str, " FILE_MODIFIED");
1136 + if (event & FILE_RENAME_TO)
1137 + g_string_append(str, " FILE_RENAME_TO");
1139 + if (event & MOUNTEDOVER)
1140 + g_string_append(str, " MOUNTEDOVER");
1142 + if (event & FILE_ATTRIB)
1143 + g_string_append(str, " FILE_ATTRIB");
1145 + if (event & UNMOUNTED)
1146 + g_string_append(str, " UNMOUNTED");
1148 + if (event & FILE_ACCESS)
1149 + g_string_append(str, " FILE_ACCESS");
1151 + return g_string_free(str, FALSE);
1154 +static const gchar *
1155 +_event_string (int event)
1159 + return "FILE_DELETE";
1160 + case FILE_RENAME_FROM:
1161 + return "FILE_RENAME_FROM";
1162 + case FILE_MODIFIED:
1163 + return "FILE_MODIFIED";
1164 + case FILE_RENAME_TO:
1165 + return "FILE_RENAME_TO";
1167 + return "MOUNTEDOVER";
1169 + return "FILE_ATTRIB";
1171 + return "UNMOUNTED";
1173 + return "FILE_ACCESS";
1175 + return "EVENT_UNKNOWN";
1179 diff --git a/server/fen-kernel.h b/server/fen-kernel.h
1180 new file mode 100644
1181 index 0000000..6d2c49b
1182 --- /dev/null 2019-12-10 11:10:35.000000000 +0000
1183 +++ gamin-0.1.10/server/fen-kernel.h 2019-12-10 11:10:22.999527865 +0000
1185 +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
1186 +/* vim:set expandtab ts=4 shiftwidth=4: */
1188 + * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
1191 + * This library is free software; you can redistribute it and/or
1192 + * modify it under the terms of the GNU Lesser General Public
1193 + * License as published by the Free Software Foundation; either
1194 + * version 2 of the License, or (at your option) any later version.
1196 + * This library is distributed in the hope that it will be useful,
1197 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1198 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1199 + * Lesser General Public License for more details.
1201 + * You should have received a copy of the GNU Lesser General
1202 + * Public License along with this library; if not, write to the
1203 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
1204 + * Boston, MA 02111-1307, USA.
1206 + * Authors: Lin Ma <lin.ma@sun.com>
1209 +#include <sys/types.h>
1212 +#include "fen-node.h"
1214 +#ifndef _FEN_KERNEL_H_
1215 +#define _FEN_KERNEL_H_
1217 +#define CONCERNED_EVENTS (FILE_MODIFIED | FILE_ATTRIB | FILE_NOFOLLOW)
1218 +#define EXCEPTION_EVENTS (FILE_DELETE | FILE_RENAME_FROM)
1219 +#define HAS_EXCEPTION_EVENTS(e) ((e & EXCEPTION_EVENTS) != 0)
1220 +#define HAS_NO_EXCEPTION_EVENTS(e) ((e & EXCEPTION_EVENTS) == 0)
1222 +gint port_add (node_t* f);
1223 +void port_remove (node_t *f);
1224 +void prune_queue (node_t *f);
1226 +gboolean port_class_init ();
1228 +#endif /* _FEN_KERNEL_H_ */
1229 diff --git a/server/fen-node.c b/server/fen-node.c
1230 new file mode 100644
1231 index 0000000..d4d7ddb
1232 --- /dev/null 2019-12-10 11:10:35.000000000 +0000
1233 +++ gamin-0.1.10/server/fen-node.c 2019-12-10 11:10:23.002327705 +0000
1235 +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
1236 +/* vim:set expandtab ts=4 shiftwidth=4: */
1238 + * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
1241 + * This library is free software; you can redistribute it and/or
1242 + * modify it under the terms of the GNU Lesser General Public
1243 + * License as published by the Free Software Foundation; either
1244 + * version 2 of the License, or (at your option) any later version.
1246 + * This library is distributed in the hope that it will be useful,
1247 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1248 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1249 + * Lesser General Public License for more details.
1251 + * You should have received a copy of the GNU Lesser General
1252 + * Public License along with this library; if not, write to the
1253 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
1254 + * Boston, MA 02111-1307, USA.
1256 + * Authors: Lin Ma <lin.ma@sun.com>
1259 +#include "config.h"
1260 +#include <sys/stat.h>
1262 +#include <strings.h>
1264 +#include "fen-kernel.h"
1265 +#include "fen-node.h"
1266 +#include "fen-dump.h"
1268 +#ifdef GIO_COMPILATION
1269 +#include "gfilemonitor.h"
1271 +#include "gam_event.h"
1272 +#include "gam_server.h"
1273 +#include "gam_protocol.h"
1276 +#ifdef GIO_COMPILATION
1277 +#define FN_W if (fn_debug_enabled) g_debug
1278 +static gboolean fn_debug_enabled = FALSE;
1280 +#include "gam_error.h"
1281 +#define FN_W(...) GAM_DEBUG(DEBUG_INFO, __VA_ARGS__)
1284 +G_LOCK_EXTERN (fen_lock);
1286 +/* Must continue monitoring if:
1287 + * 1) I'm subscribed,
1288 + * 2) The subscribed children (one of the children has subs) are missing,
1289 + * 3) my parent is subscribed (monitoring directory).
1291 +#define NODE_NEED_MONITOR(f) \
1292 + (NODE_IS_ACTIVE(f) || node_children_num(f) > 0 || NODE_IS_REQUIRED_BY_PARENT(f))
1294 +static int concern_events[] = {
1299 +#ifdef GIO_COMPILATION
1303 + FILE_MODIFIED | FILE_ATTRIB,
1308 +node_t *ROOT = NULL;
1310 +static void node_emit_one_event(node_t *f, GList *subs, node_t *other, int event);
1311 +static void node_emit_events(node_t *f, const node_event_t *ne);
1312 +static int node_event_translate(int event, gboolean pair);
1313 +static void node_add_event (node_t *f, node_event_t *ev);
1314 +static node_t* node_new (node_t* parent, const gchar* basename);
1315 +static void node_delete (node_t* parent);
1316 +static node_t* node_get_child (node_t *f, const gchar *basename);
1317 +static void children_add (node_t *p, node_t *f);
1318 +static void children_remove (node_t *p, node_t *f);
1319 +static gboolean children_remove_cb (gpointer key, gpointer value, gpointer user_data);
1320 +static guint node_children_num (node_t *f);
1323 +node_timeval_lt(const GTimeVal *val1, const GTimeVal *val2)
1325 + if (val1->tv_sec < val2->tv_sec)
1328 + if (val1->tv_sec > val2->tv_sec)
1331 + /* val1->tv_sec == val2->tv_sec */
1332 + if (val1->tv_usec < val2->tv_usec)
1339 +node_traverse (node_t* node, void(*traverse_cb)(node_t*, gpointer), gpointer user_data)
1341 + GHashTableIter iter;
1344 + g_assert(traverse_cb);
1345 + if (node == NULL) {
1350 + traverse_cb(node, user_data);
1353 + g_hash_table_iter_init (&iter, node->children);
1354 + while (g_hash_table_iter_next (&iter, NULL, &value)) {
1355 + node_traverse((node_t *)value, traverse_cb, user_data);
1360 +node_find(node_t* node, const gchar* filename, gboolean create_on_missing)
1368 + g_assert (filename && filename[0] == '/');
1370 + if (node == NULL) {
1374 + FN_W ("%s %s\n", __func__, filename);
1376 + parent = child = node;
1377 + str = g_strdup (filename);
1379 + for (token = strtok_r (str, G_DIR_SEPARATOR_S, &lasts);
1380 + token != NULL && child != NULL;
1381 + token = strtok_r (NULL, G_DIR_SEPARATOR_S, &lasts)) {
1382 + FN_W ("%s %s + %s\n", __func__, NODE_NAME(parent), token);
1383 + child = node_get_child(parent, token);
1386 + } else if (create_on_missing) {
1387 + child = node_new (parent, token);
1389 + children_add (parent, child);
1393 + FN_W ("%s create %s failed", __func__, token);
1405 +node_lstat(node_t *f)
1409 + g_assert(!NODE_HAS_STATE(f, NODE_STATE_ASSOCIATED));
1411 + if (lstat(NODE_NAME(f), &buf) == 0) {
1412 + FN_W ("%s %s\n", __func__, NODE_NAME(f));
1413 + FILE_OBJECT(f)->fo_atime = buf.st_atim;
1414 + FILE_OBJECT(f)->fo_mtime = buf.st_mtim;
1415 + FILE_OBJECT(f)->fo_ctime = buf.st_ctim;
1416 + NODE_SET_FLAG(f, NODE_FLAG_STAT_UPDATED |
1417 + (S_ISDIR (buf.st_mode) ? NODE_FLAG_DIR : NODE_FLAG_NONE));
1420 + FN_W ("%s(lstat) %s %s\n", __func__, NODE_NAME(f), g_strerror (errno));
1426 +node_create_children_snapshot(node_t *f, gint created_event, gboolean emit)
1429 + GError *err = NULL;
1431 + FN_W ("%s %s [0x%p]\n", __func__, NODE_NAME(f), f);
1433 + dir = g_dir_open (NODE_NAME(f), 0, &err);
1435 + const char *basename;
1436 + node_t *child = NULL;
1438 + while ((basename = g_dir_read_name (dir))) {
1442 + child = node_get_child (f, basename);
1443 + if (child == NULL) {
1446 + child = node_new (f, basename);
1447 + children_add (f, child);
1450 + if (f->dir_subs) {
1451 + /* We need monitor the new children, or the existed child which
1452 + * is in the DELETED mode.
1454 + if (!NODE_HAS_STATE(child, NODE_STATE_ASSOCIATED) &&
1455 + node_lstat(child) == 0 && port_add(child) == 0) {
1457 + /* Emit the whatever event for the new found file. */
1458 + node_emit_one_event(child, child->dir_subs, NULL, created_event);
1459 + node_emit_one_event(child, child->subs, NULL, created_event);
1460 + node_emit_one_event(child, f->dir_subs, NULL, created_event);
1461 + node_emit_one_event(child, f->subs, NULL, created_event);
1464 + /* else ignore, because it may be deleted. */
1467 + g_dir_close (dir);
1469 + /* We have finished children snapshot. Any other new added subs should
1470 + * directory iterate the snapshot instead of scan directory again.
1472 + NODE_SET_FLAG(f, NODE_FLAG_SNAPSHOT_UPDATED);
1475 + FN_W (err->message);
1476 + g_error_free (err);
1481 + * If all active children nodes are ported, then cancel monitor the parent
1482 + * node. If we know how many children are created, then we can stop accordingly.
1484 + * Unsafe, need lock.
1487 +foreach_known_children_scan(gpointer key, gpointer value, gpointer user_data)
1489 + node_t* f = (node_t*)value;
1491 + FN_W ("%s 0x%p %s\n", __func__, f, NODE_NAME(f));
1493 + if (!NODE_HAS_STATE(f, NODE_STATE_ASSOCIATED)) {
1494 + if (node_lstat(f) == 0 && port_add(f) == 0) {
1495 + node_emit_one_event(f, f->dir_subs, NULL, FN_EVENT_CREATED);
1496 + node_emit_one_event(f, f->subs, NULL, FN_EVENT_CREATED);
1497 + if (NODE_PARENT(f)) {
1498 + node_emit_one_event(f, NODE_PARENT(f)->dir_subs, NULL, FN_EVENT_CREATED);
1499 + node_emit_one_event(f, NODE_PARENT(f)->subs, NULL, FN_EVENT_CREATED);
1506 +node_try_delete(node_t* node)
1510 + FN_W ("%s 0x%p %s\n", __func__, node, NODE_NAME(node));
1512 + /* Try clean children */
1513 + if (node_children_num (node) > 0) {
1514 + g_hash_table_foreach_remove(node->children, children_remove_cb, NULL);
1516 + if (!NODE_NEED_MONITOR(node)) {
1517 + /* Clean some flags. */
1518 + /* NODE_CLE_FLAG(node, NODE_FLAG_HAS_SNAPSHOT | NODE_FLAG_STAT_DONE); */
1521 + /* Now we handle the state. */
1522 + if (NODE_HAS_STATE(node, NODE_STATE_ASSOCIATED)) {
1523 + port_remove(node);
1525 + /* Actually ignore the ROOT node. */
1526 + if (node->state == 0 && NODE_PARENT(node)) {
1527 + children_remove(NODE_PARENT(node), node);
1528 + /* Remove the pending events in the queue. */
1529 + prune_queue(node);
1530 + /* Do clean instead of returning TRUE. */
1531 + node_delete (node);
1538 +node_new (node_t* parent, const gchar* basename)
1542 + g_assert (basename && basename[0]);
1544 + if ((f = g_new0(node_t, 1)) != NULL) {
1546 + NODE_NAME(f) = g_build_filename(NODE_NAME(parent), basename, NULL);
1548 + NODE_NAME(f) = g_strdup(G_DIR_SEPARATOR_S);
1550 + f->basename = g_strdup (basename);
1551 + /* f->children = g_hash_table_new_full (g_str_hash, g_str_equal, */
1552 + /* NULL, (GDestroyNotify)node_delete); */
1553 + f->children = g_hash_table_new_full (g_str_hash, g_str_equal,
1555 +#ifdef GIO_COMPILATION
1556 + f->gfile = g_file_new_for_path (NODE_NAME(f));
1558 + FN_W ("%s 0x%p %s\n", __func__, f, NODE_NAME(f));
1564 +node_delete (node_t *f)
1566 + FN_W ("%s 0x%p %s\n", __func__, f, NODE_NAME(f));
1567 + g_assert(f->state == 0);
1568 + g_assert(!NODE_IS_ACTIVE(f));
1569 + g_assert(g_hash_table_size (f->children) == 0);
1570 + g_assert(NODE_PARENT(f) == NULL);
1571 + g_hash_table_unref(f->children);
1572 +#ifdef GIO_COMPILATION
1573 + g_object_unref (f->gfile);
1575 + g_free(f->basename);
1576 + g_free(NODE_NAME(f));
1581 +children_add (node_t *p, node_t *f)
1583 + FN_W ("%s %s %s\n", __func__, NODE_NAME(p), f->basename);
1584 + g_hash_table_insert (p->children, f->basename, f);
1585 + NODE_PARENT(f) = p;
1589 +children_remove (node_t *p, node_t *f)
1591 + FN_W ("%s %s %s\n", __func__, NODE_NAME(p), f->basename);
1592 + g_hash_table_steal (p->children, f->basename);
1593 + NODE_PARENT(f) = NULL;
1597 +node_get_child (node_t *f, const gchar *basename)
1599 + if (f->children) {
1600 + return (node_t *) g_hash_table_lookup (f->children, (gpointer)basename);
1606 +node_children_num (node_t *f)
1608 + return g_hash_table_size (f->children);
1612 + * depth first delete recursively
1615 +children_remove_cb (gpointer key, gpointer value, gpointer user_data)
1617 + return node_try_delete ((node_t*)value);
1623 + ROOT = node_new (NULL, G_DIR_SEPARATOR_S);
1624 + if (ROOT == NULL) {
1625 + FN_W ("[node] Create ROOT node failed.\n");
1629 + return port_class_init (node_add_event);
1633 + * Adjust self on failing to Port
1636 +node_adjust_deleted(node_t* f)
1640 + FN_W ("%s %s\n", __func__, NODE_NAME(f));
1642 + for (ancestor = NODE_PARENT(f);
1644 + ancestor = NODE_PARENT(ancestor)) {
1645 + /* Stop if we find a node which been already associated or is existed
1646 + * and can be associated.
1648 + if (NODE_HAS_STATE(ancestor, NODE_STATE_ASSOCIATED) ||
1649 + (node_lstat(ancestor) == 0 && port_add(ancestor) == 0)) {
1654 + /* We assume we shouldn't reach here, because Root is always existed and
1655 + * associated. But given bugster#6955199, if PORT FS has problems on root,
1656 + * we may reach here. So just return ROOT and the whole GIO fen backend will
1659 + /* g_assert(ancestor != NULL); */
1664 +node_emit_events(node_t *f, const node_event_t *ne)
1666 + gsize num = sizeof(concern_events)/sizeof(int);
1671 + if (node_timeval_lt(&f->atv, &ne->ctv)) {
1672 + int event = ne->e;
1674 + /* Emit DELETED on the pair_data */
1675 + if (ne->pair_data) {
1676 + node_t *from = ne->pair_data;
1677 + node_emit_one_event(from, from->dir_subs, NULL, node_event_translate(FILE_DELETE, FALSE));
1678 + node_emit_one_event(from, from->subs, NULL, node_event_translate(FILE_DELETE, FALSE));
1681 + for (i = 0; i < num; i++) {
1682 + if (event & concern_events[i]) {
1683 + translated_e = node_event_translate(concern_events[i], FALSE);
1684 + /* Neither GIO or gamin cares about modified events on a
1687 +#ifdef GIO_COMPILATION
1688 + if ((concern_events[i] & FILE_MODIFIED) == 0) {
1689 + node_emit_one_event(f, f->dir_subs, NULL, translated_e);
1692 + /* Gamin doesn't care about attrib changed events on a directory
1695 + if ((concern_events[i] & (FILE_MODIFIED | FILE_ATTRIB)) == 0) {
1696 + node_emit_one_event(f, f->dir_subs, NULL, translated_e);
1699 + node_emit_one_event(f, f->subs, NULL, translated_e);
1701 + event &= ~concern_events[i];
1705 + p = NODE_PARENT(f);
1706 + if (p != NULL && node_timeval_lt(&p->atv, &ne->ctv)) {
1707 + int event = ne->e;
1708 + for (i = 0; i < num; i++) {
1709 + if (event & concern_events[i]) {
1710 + translated_e = node_event_translate(concern_events[i], ne->pair_data != NULL);
1711 + node_emit_one_event(f, p->dir_subs, ne->pair_data, translated_e);
1712 + node_emit_one_event(f, p->subs, ne->pair_data, translated_e);
1714 + event &= ~concern_events[i];
1724 +node_add_event (node_t *f, node_event_t *ev)
1726 + FN_W ("%s %d\n", __func__, ev->e);
1728 + /* Clean the events flag early, because all received events need be
1729 + * processed in this function.
1731 + NODE_CLE_STATE(f, NODE_STATE_HAS_EVENTS);
1734 + * Node the node has been created, so we can delete create event in
1735 + * optimizing. To reduce the statings, we add it to Port on discoving
1736 + * it then emit CREATED event. So we don't need to do anything here.
1738 + if (NODE_NEED_MONITOR(f)) {
1739 + if (HAS_NO_EXCEPTION_EVENTS(ev->e)) {
1740 + if (NODE_HAS_STATE(f, NODE_STATE_ASSOCIATED) || (node_lstat(f) == 0 && port_add(f) == 0)) {
1741 + if ((ev->e & FILE_MODIFIED) && NODE_HAS_FLAG(f, NODE_FLAG_DIR)) {
1742 + if (f->dir_subs) {
1743 + node_create_children_snapshot(f, FN_EVENT_CREATED, TRUE);
1745 + g_hash_table_foreach(f->children, foreach_known_children_scan, NULL);
1749 + /* Emit delete event */
1750 + ev->e |= FILE_DELETE;
1752 + node_adjust_deleted(f);
1756 + node_adjust_deleted(f);
1759 + /* Send events to clients. */
1760 + node_emit_events (f, ev);
1763 + /* Send events to clients. */
1764 + node_emit_events (f, ev);
1766 + node_try_delete(f);
1769 + if (ev->pair_data) {
1770 + node_t *from = ev->pair_data;
1771 + g_assert(ev->e == FILE_RENAME_TO);
1773 + if (NODE_NEED_MONITOR(from)) {
1774 + /* Clean the events flag, since it may block free this node. */
1775 + NODE_CLE_STATE(from, NODE_STATE_HAS_EVENTS);
1776 + node_adjust_deleted(from);
1778 + node_try_delete(from);
1782 + node_event_delete (ev);
1786 +node_emit_one_event(node_t *f, GList *subs, node_t *other, int event)
1790 + FN_W ("%s %s %d\n", __func__, NODE_NAME(f), event);
1792 +#ifdef GIO_COMPILATION
1793 + for (idx = subs; idx; idx = idx->next) {
1794 + g_file_monitor_emit_event(G_FILE_MONITOR(idx->data), f->gfile,
1795 + (other == NULL ? NULL : other->gfile), event);
1798 + for (idx = subs; idx; idx = idx->next) {
1799 + gam_server_emit_one_event(NODE_NAME(f), gam_subscription_is_dir(idx->data), event, idx->data, 1);
1805 +node_event_translate(int event, gboolean pair)
1807 +#ifdef GIO_COMPILATION
1810 + case FILE_RENAME_FROM:
1811 + return G_FILE_MONITOR_EVENT_DELETED;
1813 + return G_FILE_MONITOR_EVENT_UNMOUNTED;
1815 + return G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED;
1817 + case FILE_MODIFIED:
1818 + return G_FILE_MONITOR_EVENT_CHANGED;
1819 + case FILE_RENAME_TO:
1821 + return G_FILE_MONITOR_EVENT_MOVED;
1823 + return G_FILE_MONITOR_EVENT_CREATED;
1826 + /* case FILE_ACCESS: */
1827 + g_assert_not_reached ();
1833 + case FILE_RENAME_FROM:
1834 + return GAMIN_EVENT_DELETED;
1837 + return GAMIN_EVENT_CHANGED;
1838 + case FILE_RENAME_TO:
1840 + return GAMIN_EVENT_MOVED;
1842 + return GAMIN_EVENT_CREATED;
1845 + if (event & (FILE_ATTRIB | FILE_MODIFIED)) {
1846 + return GAMIN_EVENT_CHANGED;
1848 + /* case FILE_ACCESS: */
1849 + g_assert_not_reached ();
1856 +node_event_new (int event, gpointer user_data)
1860 + if ((ev = g_new (node_event_t, 1)) != NULL) {
1863 + ev->user_data = user_data;
1864 + ev->pair_data = NULL; /* For renamed file. */
1865 + /* Created timestamp */
1866 + g_get_current_time(&ev->ctv);
1867 + ev->rename_tv = ev->ctv;
1873 +node_event_delete (node_event_t* ev)
1878 diff --git a/server/fen-node.h b/server/fen-node.h
1879 new file mode 100644
1880 index 0000000..7e99032
1882 +++ b/server/fen-node.h
1884 +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
1885 +/* vim:set expandtab ts=4 shiftwidth=4: */
1887 + * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
1890 + * This library is free software; you can redistribute it and/or
1891 + * modify it under the terms of the GNU Lesser General Public
1892 + * License as published by the Free Software Foundation; either
1893 + * version 2 of the License, or (at your option) any later version.
1895 + * This library is distributed in the hope that it will be useful,
1896 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1897 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1898 + * Lesser General Public License for more details.
1900 + * You should have received a copy of the GNU Lesser General
1901 + * Public License along with this library; if not, write to the
1902 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
1903 + * Boston, MA 02111-1307, USA.
1905 + * Authors: Lin Ma <lin.ma@sun.com>
1909 +#include <gio/gio.h>
1911 +#ifndef _FEN_NODE_H_
1912 +#define _FEN_NODE_H_
1914 +#ifdef GIO_COMPILATION
1915 +#define FN_EVENT_CREATED G_FILE_MONITOR_EVENT_CREATED
1917 +#define FN_EVENT_CREATED GAMIN_EVENT_CREATED
1920 +#define NODE_STATE_NONE 0x00000000
1921 +#define NODE_STATE_ASSOCIATED 0x00000001 /* This is a confilct to NODE_FLAG_STAT_DONE */
1922 +#define NODE_STATE_HAS_EVENTS 0x00000002
1924 +#define NODE_FLAG_NONE 0x00000000
1925 +#define NODE_FLAG_SNAPSHOT_UPDATED 0x00000001
1926 +#define NODE_FLAG_DIR 0x00000002
1927 +#define NODE_FLAG_STAT_UPDATED 0x00000004
1929 +#define NODE_CLE_STATE(f, st) (f->state &= ~(st))
1930 +#define NODE_SET_STATE(f, st) (f->state = ((f->state & ~(st)) | (st)))
1931 +#define NODE_HAS_STATE(f, st) (f->state & (st))
1933 +#define NODE_CLE_FLAG(f, fl) (f->flag &= ~(fl))
1934 +#define NODE_SET_FLAG(f, fl) (f->flag = ((f->flag & ~(fl)) | (fl)))
1935 +#define NODE_HAS_FLAG(f, fl) (f->flag & (fl))
1937 +typedef struct node node_t;
1940 + file_obj_t fobj; /* Inherit from file_obj_t, must be the first. */
1945 + GTimeVal atv; /* Timestamp for the first added sub. */
1947 + /* the parent and children of node */
1949 + GHashTable *children; /* children in basename */
1951 + /* List of subscriptions monitoring this fdata/path */
1955 +#ifdef GIO_COMPILATION
1960 +#define FILE_OBJECT(f) ((file_obj_t *)(f))
1961 +#define NODE_NAME(f) (FILE_OBJECT(f)->fo_name)
1962 +#define NODE_PARENT(f) (((node_t *)f)->parent)
1963 +#define NODE_IS_ACTIVE(f) (f->dir_subs || f->subs)
1964 +#define NODE_IS_REQUIRED_BY_PARENT(f) (NODE_PARENT(f) && NODE_PARENT(f)->dir_subs)
1966 +gboolean node_timeval_lt(const GTimeVal *val1, const GTimeVal *val2);
1967 +gboolean node_try_delete(node_t* node);
1968 +void node_traverse(node_t* node, void(*traverse_cb)(node_t*, gpointer), gpointer user_data);
1969 +node_t* node_find(node_t* node, const gchar* filename, gboolean create_on_missing);
1970 +gint node_lstat(node_t *f);
1971 +void node_create_children_snapshot(node_t *f, gint created_event, gboolean emit);
1972 +void node_adjust_deleted(node_t *f);
1973 +gboolean node_class_init();
1975 +typedef struct node_event
1978 + gpointer user_data;
1979 + gpointer pair_data;
1980 + GTimeVal ctv; /* Created timestamp */
1981 + GTimeVal rename_tv; /* Possible rename timestamp */
1984 +node_event_t* node_event_new (int event, gpointer user_data);
1985 +void node_event_delete (node_event_t* ev);
1987 +#endif /* _FEN_NODE_H_ */
1988 diff --git a/server/gam_channel.c b/server/gam_channel.c
1989 index 56c3ea7..6db1692 100644
1990 --- a/server/gam_channel.c
1991 +++ b/server/gam_channel.c
1993 #include <sys/stat.h>
1995 #include <sys/uio.h>
1997 +#include <string.h>
1999 +#if defined(HAVE_UCRED_H)
2001 +#endif defined(HAVE_UCRED_H)
2002 #include "gam_error.h"
2003 #include "gam_connection.h"
2004 #include "gam_channel.h"
2005 @@ -101,6 +107,10 @@ gam_client_conn_check_cred(GIOChannel * source, int fd,
2009 +#if defined(HAVE_GETPEERUCRED)
2015 #if defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED)
2016 @@ -167,11 +177,25 @@ gam_client_conn_check_cred(GIOChannel * source, int fd,
2017 fd, cr_len, (int) sizeof(cr));
2020 +#elif defined(HAVE_GETPEERUCRED)
2021 + if ((creds = (ucred_t *)malloc(ucred_size()))==(ucred_t *)NULL){
2022 + GAM_DEBUG(DEBUG_INFO,"Malloc failed for ucreds");
2026 + if (getpeerucred(fd, &creds)!=0){
2027 + GAM_DEBUG(DEBUG_INFO,"getpeerucred call failed");
2030 + c_uid = ucred_getruid(creds);
2031 + c_gid = ucred_getrgid(creds);
2032 + c_pid = ucred_getpid(creds);
2033 + ucred_free(creds);
2034 #elif defined(HAVE_CMSGCRED)
2035 c_pid = cmsg.cred.cmcred_pid;
2036 c_uid = cmsg.cred.cmcred_euid;
2037 c_gid = cmsg.cred.cmcred_groups[0];
2038 -#else /* !SO_PEERCRED && !HAVE_CMSGCRED */
2039 +#else /* !SO_PEERCRED && !HAVE_CMSGCRED && !HAVE_GETPEERUCRED */
2040 GAM_DEBUG(DEBUG_INFO,
2041 "Socket credentials not supported on this OS\n");
2043 diff --git a/server/gam_fen.c b/server/gam_fen.c
2044 new file mode 100644
2045 index 0000000..21476e1
2047 +++ b/server/gam_fen.c
2049 +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2050 +/* vim:set expandtab ts=4 shiftwidth=4: */
2052 + * Copyright (C) 2008 Sun Microsystems, Inc. All rights reserved.
2053 + * Use is subject to license terms.
2055 + * This library is free software; you can redistribute it and/or
2056 + * modify it under the terms of the GNU Lesser General Public
2057 + * License as published by the Free Software Foundation; either
2058 + * version 2 of the License, or (at your option) any later version.
2060 + * This library is distributed in the hope that it will be useful,
2061 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2062 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2063 + * Lesser General Public License for more details.
2065 + * You should have received a copy of the GNU Lesser General
2066 + * Public License along with this library; if not, write to the
2067 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
2068 + * Boston, MA 02111-1307, USA.
2070 + * Authors: Lin Ma <lin.ma@sun.com>
2074 + * A Solaris port has a resource limit of events (port_max_events) which
2075 + * limits the number of objects (fds) that can be actively associated objects
2076 + * whith the port. The default is (65536), but can be changed.
2078 + * project.max-port-ids identify the max number of ports
2079 + * process.max-port-events identify the max objs of a port
2080 + * process.max-file-descriptor identify the max fds of a process
2082 + * For a user server process, process.max-file-descriptor seems a bottleneck.
2083 + * I will use a port list for monitor fds to avoid process.max-file-descriptor
2084 + * is greater than process.max-port-events.
2086 +#include "config.h"
2087 +#include "gam_error.h"
2088 +#include "gam_fen.h"
2089 +#include "gam_event.h"
2090 +#include "gam_server.h"
2091 +#include "gam_protocol.h"
2093 +#include "fen-helper.h"
2096 + * Initializes the FEN system. This must be called before
2097 + * any other functions in this module.
2099 + * @returns TRUE if initialization succeeded, FALSE otherwise
2103 +gam_fen_init (void)
2108 + gam_server_install_kernel_hooks (GAMIN_K_FEN,
2109 + gam_fen_add_subscription,
2110 + gam_fen_remove_subscription,
2111 + gam_fen_remove_all_for,
2117 + * Adds a subscription to be monitored.
2119 + * @param sub a #GamSubscription to be polled
2120 + * @returns TRUE if adding the subscription succeeded, FALSE otherwise
2124 +gam_fen_add_subscription (GamSubscription *sub)
2126 + g_debug ("[ %s ] sub[0x%p]\n", __func__, sub);
2128 + gam_listener_add_subscription (gam_subscription_get_listener (sub), sub);
2129 + fen_add (gam_subscription_get_path(sub),
2131 + gam_subscription_is_dir (sub));
2136 + * Removes a subscription which was being monitored.
2138 + * @param sub a #GamSubscription to remove
2139 + * @returns TRUE if removing the subscription succeeded, FALSE otherwise
2143 +gam_fen_remove_subscription (GamSubscription *sub)
2145 + g_debug ("[ %s ] sub[0x%p]\n", __func__, sub);
2147 + fen_remove (gam_subscription_get_path(sub),
2149 + gam_subscription_is_dir (sub));
2150 + /* free subscription */
2151 + gam_subscription_cancel(sub);
2152 + gam_subscription_free(sub);
2157 + * Stop monitoring all subscriptions for a given listener.
2159 + * @param listener a #GamListener
2160 + * @returns TRUE if removing the subscriptions succeeded, FALSE otherwise
2164 +gam_fen_remove_all_for (GamListener *listener)
2168 + gboolean success = TRUE;
2170 + subs = gam_listener_get_subscriptions (listener);
2175 + for (idx = subs; idx != NULL; idx = idx->next) {
2176 + GamSubscription *sub = (GamSubscription *)idx->data;
2178 + if (!gam_fen_remove_subscription (sub))
2183 + g_list_free (subs);
2189 diff --git a/server/gam_fen.h b/server/gam_fen.h
2190 new file mode 100644
2191 index 0000000..47e952d
2193 +++ b/server/gam_fen.h
2195 +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2196 +/* vim:set expandtab ts=4 shiftwidth=4: */
2198 + * Copyright (C) 2008 Sun Microsystems, Inc. All rights reserved.
2199 + * Use is subject to license terms.
2201 + * This library is free software; you can redistribute it and/or
2202 + * modify it under the terms of the GNU Lesser General Public
2203 + * License as published by the Free Software Foundation; either
2204 + * version 2 of the License, or (at your option) any later version.
2206 + * This library is distributed in the hope that it will be useful,
2207 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2208 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2209 + * Lesser General Public License for more details.
2211 + * You should have received a copy of the GNU Lesser General
2212 + * Public License along with this library; if not, write to the
2213 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
2214 + * Boston, MA 02111-1307, USA.
2216 + * Authors: Lin Ma <lin.ma@sun.com>
2219 +#ifndef __GAM_FEN_H__
2220 +#define __GAM_FEN_H__
2223 +#include "gam_subscription.h"
2227 +gboolean gam_fen_init (void);
2228 +gboolean gam_fen_add_subscription (GamSubscription *sub);
2229 +gboolean gam_fen_remove_subscription (GamSubscription *sub);
2230 +gboolean gam_fen_remove_all_for (GamListener *listener);
2234 +#endif /* __GAM_FEN_H__ */
2235 diff --git a/server/gam_fs.c b/server/gam_fs.c
2236 index c8ca704..1d2f2c8 100644
2237 --- a/server/gam_fs.c
2238 +++ b/server/gam_fs.c
2243 +#ifdef HAVE_SYS_MNTTAB_H
2244 +#include <sys/mnttab.h>
2246 #include "gam_error.h"
2249 +#ifdef HAVE_SYS_MNTTAB_H
2250 +#define MTAB MNTTAB
2251 +#define MTABDEL "\t"
2253 +#define MTAB "/etc/mtab"
2254 +#define MTABDEL "\t"
2257 #define DEFAULT_POLL_TIMEOUT 0
2259 typedef struct _gam_fs_properties {
2260 @@ -119,7 +130,7 @@ gam_fs_scan_mtab (void)
2264 - g_file_get_contents ("/etc/mtab", &contents, &len, NULL);
2265 + g_file_get_contents (MTAB, &contents, &len, NULL);
2266 if (contents == NULL)
2269 @@ -133,7 +144,7 @@ gam_fs_scan_mtab (void)
2270 if (line[0] == '\0')
2273 - words = g_strsplit (line, " ", 0);
2274 + words = g_strsplit (line, MTABDEL, 0);
2278 @@ -176,19 +187,25 @@ gam_fs_init (void)
2279 gam_fs_set ("ext2", GFS_MT_DEFAULT, 0);
2280 gam_fs_set ("reiser4", GFS_MT_DEFAULT, 0);
2281 gam_fs_set ("reiserfs", GFS_MT_DEFAULT, 0);
2282 + gam_fs_set ("zfs", GFS_MT_DEFAULT, 0);
2283 + gam_fs_set ("ufs", GFS_MT_DEFAULT, 0);
2284 gam_fs_set ("novfs", GFS_MT_POLL, 30);
2286 + gam_fs_set ("nfs", GFS_MT_DEFAULT, 0);
2288 gam_fs_set ("nfs", GFS_MT_POLL, 5);
2289 - if (stat("/etc/mtab", &mtab_sbuf) != 0)
2291 + if (stat(MTAB, &mtab_sbuf) != 0)
2293 - GAM_DEBUG(DEBUG_INFO, "Could not stat /etc/mtab\n");
2294 + GAM_DEBUG(DEBUG_INFO, "Could not stat %s\n",MTAB);
2296 gam_fs_scan_mtab ();
2300 - if (stat("/etc/mtab", &sbuf) != 0)
2301 + if (stat(MTAB, &sbuf) != 0)
2303 - GAM_DEBUG(DEBUG_INFO, "Could not stat /etc/mtab\n");
2304 + GAM_DEBUG(DEBUG_INFO, "Could not stat %s\n",MTAB);
2307 /* /etc/mtab has changed */
2308 diff --git a/server/gam_fs.h b/server/gam_fs.h
2309 index bc2d538..94e70fd 100644
2310 --- a/server/gam_fs.h
2311 +++ b/server/gam_fs.h
2312 @@ -8,6 +8,7 @@ typedef enum {
2313 #if !defined(ENABLE_DNOTIFY) && \
2314 !defined(ENABLE_INOTIFY) && \
2315 !defined(ENABLE_KQUEUE) && \
2316 + !defined(ENABLE_FEN) && \
2317 !defined(ENABLE_HURD_MACH_NOTIFY)
2318 GFS_MT_DEFAULT = GFS_MT_POLL,
2320 diff --git a/server/gam_server.c b/server/gam_server.c
2321 index f92a691..e5da29f 100644
2322 --- a/server/gam_server.c
2323 +++ b/server/gam_server.c
2325 #ifdef ENABLE_HURD_MACH_NOTIFY
2326 #include "gam_hurd_mach_notify.h"
2329 +#include "gam_fen.h"
2331 #include "gam_excludes.h"
2333 #include "gam_conf.h"
2334 @@ -162,6 +165,12 @@ gam_init_subscriptions(void)
2339 + if (gam_fen_init()) {
2340 + GAM_DEBUG(DEBUG_INFO, "Using fen as backend\n");
2346 if (gam_poll_basic_init()) {
2347 @@ -627,6 +636,10 @@ main(int argc, const char *argv[])
2348 signal(SIGQUIT, gam_exit);
2349 signal(SIGTERM, gam_exit);
2350 signal(SIGPIPE, SIG_IGN);
2352 + signal(SIGUSR1, SIG_IGN);
2353 + signal(SIGUSR2, SIG_IGN);
2356 if (!gam_init_subscriptions()) {
2357 GAM_DEBUG(DEBUG_INFO, "Could not initialize the subscription system.\n");
2358 diff --git a/server/gam_server.h b/server/gam_server.h
2359 index bc99e09..313dd84 100644
2360 --- a/server/gam_server.h
2361 +++ b/server/gam_server.h
2362 @@ -16,7 +16,8 @@ typedef enum {
2363 GAMIN_K_INOTIFY = 2,
2366 - GAMIN_K_INOTIFY2 = 5
2367 + GAMIN_K_INOTIFY2 = 5,
2372 diff --git a/tests/testing.c b/tests/testing.c
2373 index 9926c0a..4c08740 100644
2374 --- a/tests/testing.c
2375 +++ b/tests/testing.c
2377 +#include "config.h"
2381 @@ -31,6 +32,11 @@ static struct testState {
2383 #define IS_BLANK(p) ((*(p) == ' ') || (*(p) == '\t') || \
2384 (*(p) == '\n') || (*(p) == '\r'))
2386 +#define KILLCMD "pkill"
2388 +#define KILLCMD "killall"
2392 scanCommand(char *line, char **command, char **arg, char **arg2)
2393 @@ -268,7 +274,7 @@ processCommand(char *line, int no)
2394 * okay, it's heavy but that's the simplest way since we do not have
2395 * the pid(s) of the servers running.
2397 - ret = system("killall gam_server");
2398 + ret = system(KILLCMD" gam_server");
2400 fprintf(stderr, "kill line %d: failed to killall gam_server\n",