glib r6702 - in trunk: . gio gio/fen
- From: alexl svn gnome org
- To: svn-commits-list gnome org
- Subject: glib r6702 - in trunk: . gio gio/fen
- Date: Fri, 14 Mar 2008 08:58:24 +0000 (GMT)
Author: alexl
Date: Fri Mar 14 08:58:24 2008
New Revision: 6702
URL: http://svn.gnome.org/viewvc/glib?rev=6702&view=rev
Log:
2008-03-14 Alexander Larsson <alexl redhat com>
* Makefile.am:
* fen/Makefile.am: Added.
* fen/fen-data.[ch]: Added.
* fen/fen-dump.[ch]: Added.
* fen/fen-helper.[ch]: Added.
* fen/fen-kernel.[ch]: Added.
* fen/fen-missing.[ch]: Added.
* fen/fen-node.[ch]: Added.
* fen/fen-sub.[ch]: Added.
* fen/gfendirectorymonitor.[ch]: Added.
* fen/gfenfilemonitor.[ch]: Added.
* giomodule.c:
Added Solaris FEN file notification backend.
Patch from Lin Ma <Lin Ma Sun COM>
Added:
trunk/gio/fen/
trunk/gio/fen/Makefile.am
trunk/gio/fen/fen-data.c
trunk/gio/fen/fen-data.h
trunk/gio/fen/fen-dump.c
trunk/gio/fen/fen-dump.h
trunk/gio/fen/fen-helper.c
trunk/gio/fen/fen-helper.h
trunk/gio/fen/fen-kernel.c
trunk/gio/fen/fen-kernel.h
trunk/gio/fen/fen-missing.c
trunk/gio/fen/fen-missing.h
trunk/gio/fen/fen-node.c
trunk/gio/fen/fen-node.h
trunk/gio/fen/fen-sub.c
trunk/gio/fen/fen-sub.h
trunk/gio/fen/gfendirectorymonitor.c
trunk/gio/fen/gfendirectorymonitor.h
trunk/gio/fen/gfenfilemonitor.c
trunk/gio/fen/gfenfilemonitor.h
Modified:
trunk/ChangeLog
trunk/configure.in
trunk/gio/ChangeLog
trunk/gio/Makefile.am
trunk/gio/giomodule.c
Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in (original)
+++ trunk/configure.in Fri Mar 14 08:58:24 2008
@@ -1502,6 +1502,22 @@
AM_CONDITIONAL(HAVE_INOTIFY, [test "$inotify_support" = "yes"])
+dnl *********************************
+dnl ** Check for Solaris FEN (GIO) **
+dnl *********************************
+fen_support=no
+AC_COMPILE_IFELSE([
+#include <port.h>
+#ifndef PORT_SOURCE_FILE
+#error "Please upgrade to Nevada 72 or above to suppoert FEN"
+#endif
+int main() { return 0; } ],
+[
+ fen_support=yes
+],)
+
+AM_CONDITIONAL(HAVE_FEN, [test "$fen_support" = "yes"])
+
dnl ****************************
dnl *** Checks for FAM (GIO) ***
dnl ****************************
@@ -3234,6 +3250,7 @@
gio/Makefile
gio/xdgmime/Makefile
gio/inotify/Makefile
+gio/fen/Makefile
gio/fam/Makefile
gio/win32/Makefile
gio/tests/Makefile
Modified: trunk/gio/Makefile.am
==============================================================================
--- trunk/gio/Makefile.am (original)
+++ trunk/gio/Makefile.am Fri Mar 14 08:58:24 2008
@@ -99,6 +99,12 @@
platform_libadd += inotify/libinotify.la
endif
+if HAVE_FEN
+AM_CPPFLAGS += -DHAVE_FEN
+SUBDIRS += fen
+platform_libadd += fen/libfen.la
+endif
+
if OS_WIN32
SUBDIRS += win32
platform_libadd += win32/libgiowin32.la
Added: trunk/gio/fen/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/gio/fen/Makefile.am Fri Mar 14 08:58:24 2008
@@ -0,0 +1,38 @@
+include $(top_srcdir)/Makefile.decl
+
+NULL =
+
+noinst_LTLIBRARIES = libfen.la
+
+libfen_la_SOURCES = \
+ fen-dump.c \
+ fen-dump.h \
+ fen-kernel.c \
+ fen-kernel.h \
+ fen-node.c \
+ fen-node.h \
+ fen-missing.c \
+ fen-missing.h \
+ fen-helper.c \
+ fen-helper.h \
+ fen-data.c \
+ fen-data.h \
+ fen-sub.c \
+ fen-sub.h \
+ gfenfilemonitor.c \
+ gfenfilemonitor.h \
+ gfendirectorymonitor.c \
+ gfendirectorymonitor.h \
+ $(NULL)
+
+libfen_la_CFLAGS = \
+ -DG_LOG_DOMAIN=\"GLib-GIO\" \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/glib \
+ -I$(top_srcdir)/gmodule \
+ -I$(top_srcdir)/gio \
+ -I$(top_builddir)/gio \
+ $(GLIB_DEBUG_FLAGS) \
+ -DGIO_MODULE_DIR=\"$(GIO_MODULE_DIR)\" \
+ -DGIO_COMPILATION \
+ -DG_DISABLE_DEPRECATED
Added: trunk/gio/fen/fen-data.c
==============================================================================
--- (empty file)
+++ trunk/gio/fen/fen-data.c Fri Mar 14 08:58:24 2008
@@ -0,0 +1,708 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set expandtab ts=4 shiftwidth=4: */
+/*
+ * Copyright (C) 2008 Sun Microsystem.
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Lin Ma <lin ma sun com>
+ */
+
+#include "config.h"
+#include <port.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <glib.h>
+#include "fen-data.h"
+#include "fen-kernel.h"
+#include "fen-missing.h"
+#include "fen-dump.h"
+
+#define PROCESS_EVENTQ_TIME 10 /* in milliseconds */
+#define PAIR_EVENTS_TIMEVAL 00000 /* in microseconds */
+#define PAIR_EVENTS_INC_TIMEVAL 0000 /* in microseconds */
+#define SCAN_CHANGINGS_TIME 50 /* in milliseconds */
+#define SCAN_CHANGINGS_MAX_TIME (4*100) /* in milliseconds */
+#define SCAN_CHANGINGS_MIN_TIME (4*100) /* in milliseconds */
+#define INIT_CHANGES_NUM 2
+#define BASE_NUM 2
+
+#define FD_W if (fd_debug_enabled) g_warning
+static gboolean fd_debug_enabled = FALSE;
+
+G_LOCK_EXTERN (fen_lock);
+static GList *deleting_data = NULL;
+static guint deleting_data_id = 0;
+
+static void (*emit_once_cb) (fdata *f, int events, gpointer sub);
+static void (*emit_cb) (fdata *f, int events);
+static int (*_event_converter) (int event);
+
+static gboolean fdata_delete (fdata* f);
+static gint fdata_sub_find (gpointer a, gpointer b);
+static void scan_children (node_t *f);
+static void scan_known_children (node_t* f);
+
+node_t*
+add_missing_cb (node_t* parent, gpointer user_data)
+{
+ g_assert (parent);
+ FD_W ("%s p:0x%p %s\n", __func__, parent, (gchar*)user_data);
+ return add_node (parent, (gchar*)user_data);
+}
+
+gboolean
+pre_del_cb (node_t* node, gpointer user_data)
+{
+ fdata* data;
+
+ g_assert (node);
+ data = node_get_data (node);
+ FD_W ("%s node:0x%p %s\n", __func__, node, NODE_NAME(node));
+ if (data != NULL) {
+ if (!FN_IS_PASSIVE(data)) {
+ return FALSE;
+ }
+ fdata_delete (data);
+ }
+ return TRUE;
+}
+
+static guint
+_pow (guint x, guint y)
+{
+ guint z = 1;
+ g_assert (x >= 0 && y >= 0);
+ for (; y > 0; y--) {
+ z *= x;
+ }
+ return z;
+}
+
+static guint
+get_scalable_scan_time (fdata* data)
+{
+ guint sleep_time;
+ /* Caculate from num = 0 */
+ sleep_time = _pow (BASE_NUM, data->changed_event_num) * SCAN_CHANGINGS_TIME;
+ if (sleep_time < SCAN_CHANGINGS_MIN_TIME) {
+ sleep_time = SCAN_CHANGINGS_MIN_TIME;
+ } else if (sleep_time > SCAN_CHANGINGS_MAX_TIME) {
+ sleep_time = SCAN_CHANGINGS_MAX_TIME;
+ data->change_update_id = INIT_CHANGES_NUM;
+ }
+ FD_W ("SCALABE SCAN num:time [ %4u : %4u ] %s\n", data->changed_event_num, sleep_time, FN_NAME(data));
+ return sleep_time;
+}
+
+static gboolean
+g_timeval_lt (GTimeVal *val1, GTimeVal *val2)
+{
+ if (val1->tv_sec < val2->tv_sec)
+ return TRUE;
+
+ if (val1->tv_sec > val2->tv_sec)
+ return FALSE;
+
+ /* val1->tv_sec == val2->tv_sec */
+ if (val1->tv_usec < val2->tv_usec)
+ return TRUE;
+
+ return FALSE;
+}
+
+/**
+ * If all active children nodes are ported, then cancel monitor the parent node
+ *
+ * Unsafe, need lock.
+ */
+static void
+scan_known_children (node_t* f)
+{
+ GDir *dir;
+ GError *err = NULL;
+ fdata* pdata;
+
+ FD_W ("%s %s [0x%p]\n", __func__, NODE_NAME(f), f);
+ pdata = node_get_data (f);
+ /*
+ * Currect fdata must is directly monitored. Be sure it is 1 level monitor.
+ */
+ dir = g_dir_open (NODE_NAME(f), 0, &err);
+ if (dir) {
+ const char *basename;
+
+ while ((basename = g_dir_read_name (dir)))
+ {
+ node_t* childf = NULL;
+ fdata* data;
+ GList *idx;
+ /*
+ * If the node is existed, and isn't ported, then emit created
+ * event. Ignore others.
+ */
+ childf = children_find (f, basename);
+ if (childf &&
+ (data = node_get_data (childf)) != NULL &&
+ !FN_IS_PASSIVE (data)) {
+ if (!is_monitoring (data) &&
+ port_add (&data->fobj, &data->len, data)) {
+ fdata_emit_events (data, FN_EVENT_CREATED);
+ }
+ }
+ }
+ g_dir_close (dir);
+ } else {
+ FD_W (err->message);
+ g_error_free (err);
+ }
+}
+
+static void
+scan_children (node_t *f)
+{
+ GDir *dir;
+ GError *err = NULL;
+ fdata* pdata;
+
+ FD_W ("%s %s [0x%p]\n", __func__, NODE_NAME(f), f);
+ pdata = node_get_data (f);
+ /*
+ * Currect fdata must is directly monitored. Be sure it is 1 level monitor.
+ */
+ dir = g_dir_open (NODE_NAME(f), 0, &err);
+ if (dir) {
+ const char *basename;
+
+ while ((basename = g_dir_read_name (dir)))
+ {
+ node_t* childf = NULL;
+ fdata* data;
+ GList *idx;
+
+ childf = children_find (f, basename);
+ if (childf == NULL) {
+ gchar *filename;
+
+ filename = g_build_filename (NODE_NAME(f), basename, NULL);
+ childf = add_node (f, filename);
+ g_assert (childf);
+ data = fdata_new (childf, FALSE);
+ g_free (filename);
+ }
+ if ((data = node_get_data (childf)) == NULL) {
+ data = fdata_new (childf, FALSE);
+ }
+ /* Be sure data isn't ported and add to port successfully */
+ /* Don't need delete it, it will be deleted by the parent */
+ if (is_monitoring (data)) {
+ /* Ignored */
+ } else if (/* !is_ported (data) && */
+ port_add (&data->fobj, &data->len, data)) {
+ fdata_emit_events (data, FN_EVENT_CREATED);
+ }
+ }
+ g_dir_close (dir);
+ } else {
+ FD_W (err->message);
+ g_error_free (err);
+ }
+}
+
+static gboolean
+scan_deleting_data (gpointer data)
+{
+ fdata *f;
+ GList* i;
+ GList* deleted_list = NULL;
+ gboolean ret = TRUE;
+
+ if (G_TRYLOCK (fen_lock)) {
+ for (i = deleting_data; i; i = i->next) {
+ f = (fdata*)i->data;
+ if (fdata_delete (f)) {
+ deleted_list = g_list_prepend (deleted_list, i);
+ }
+ }
+
+ for (i = deleted_list; i; i = i->next) {
+ deleting_data = g_list_remove_link (deleting_data,
+ (GList *)i->data);
+ g_list_free_1 ((GList *)i->data);
+ }
+ g_list_free (deleted_list);
+
+ if (deleting_data == NULL) {
+ deleting_data_id = 0;
+ ret = FALSE;
+ }
+ G_UNLOCK (fen_lock);
+ }
+ return ret;
+}
+
+gboolean
+is_monitoring (fdata* data)
+{
+ return is_ported (data) || data->change_update_id > 0;
+}
+
+fdata*
+get_parent_data (fdata* data)
+{
+ if (FN_NODE(data) && !IS_TOPNODE(FN_NODE(data))) {
+ return node_get_data (FN_NODE(data)->parent);
+ }
+ return NULL;
+}
+
+node_t*
+get_parent_node (fdata* data)
+{
+ if (FN_NODE(data)) {
+ return (FN_NODE(data)->parent);
+ }
+ return NULL;
+}
+
+fdata *
+fdata_new (node_t* node, gboolean is_mondir)
+{
+ fdata *f = NULL;
+
+ g_assert (node);
+ if ((f = g_new0 (fdata, 1)) != NULL) {
+ FN_NODE(f) = node;
+ FN_NAME(f) = g_strdup (NODE_NAME(node));
+ f->is_dir = is_mondir;
+ f->eventq = g_queue_new ();
+ FD_W ("[ %s ] 0x%p %s\n", __func__, f, FN_NAME(f));
+ node_set_data (node, f);
+ }
+ return f;
+}
+
+static gboolean
+fdata_delete (fdata *f)
+{
+ fnode_event_t *ev;
+
+ FD_W ("[ TRY %s ] 0x%p id[%4d:%4d] %s\n", __func__, f, f->eventq_id, f->change_update_id, FN_NAME(f));
+ g_assert (FN_IS_PASSIVE(f));
+
+ port_remove (f);
+ /* missing_remove (f); */
+
+ if (f->node != NULL) {
+ node_set_data (f->node, NULL);
+ f->node = NULL;
+ }
+
+ if (f->change_update_id > 0 || f->eventq_id > 0) {
+ if (FN_IS_LIVING(f)) {
+ f->is_cancelled = TRUE;
+ deleting_data = g_list_prepend (deleting_data, f);
+ if (deleting_data_id == 0) {
+ deleting_data_id = g_idle_add (scan_deleting_data, NULL);
+ g_assert (deleting_data_id > 0);
+ }
+ }
+ return FALSE;
+ }
+ FD_W ("[ %s ] 0x%p %s\n", __func__, f, FN_NAME(f));
+
+ while ((ev = g_queue_pop_head (f->eventq)) != NULL) {
+ fnode_event_delete (ev);
+ }
+
+ g_queue_free (f->eventq);
+ g_free (FN_NAME(f));
+ g_free (f);
+ return TRUE;
+}
+
+void
+fdata_reset (fdata* data)
+{
+ fnode_event_t *ev;
+
+ g_assert (data);
+
+ while ((ev = g_queue_pop_head (data->eventq)) != NULL) {
+ fnode_event_delete (ev);
+ }
+}
+
+static gint
+fdata_sub_find (gpointer a, gpointer b)
+{
+ if (a != b) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+void
+fdata_sub_add (fdata *f, gpointer sub)
+{
+ FD_W ("[%s] [data: 0x%p ] [s: 0x%p ] %s\n", __func__, f, sub, FN_NAME(f));
+ g_assert (g_list_find_custom (f->subs, sub, (GCompareFunc)fdata_sub_find) == NULL);
+ f->subs = g_list_prepend (f->subs, sub);
+}
+
+void
+fdata_sub_remove (fdata *f, gpointer sub)
+{
+ GList *l;
+ FD_W ("[%s] [data: 0x%p ] [s: 0x%p ] %s\n", __func__, f, sub, FN_NAME(f));
+ g_assert (g_list_find_custom (f->subs, sub, (GCompareFunc)fdata_sub_find) != NULL);
+ l = g_list_find_custom (f->subs, sub, (GCompareFunc)fdata_sub_find);
+ g_assert (l);
+ g_assert (sub == l->data);
+ f->subs = g_list_delete_link (f->subs, l);
+}
+
+/**
+ * Adjust self on failing to Port
+ */
+void
+fdata_adjust_deleted (fdata* f)
+{
+ node_t* parent;
+ fdata* pdata;
+ node_op_t op = {NULL, NULL, pre_del_cb, NULL};
+
+ /*
+ * It's a top node. We move it to missing list.
+ */
+ parent = get_parent_node (f);
+ pdata = get_parent_data (f);
+ if (!FN_IS_PASSIVE(f) ||
+ children_num (FN_NODE(f)) > 0 ||
+ (pdata && !FN_IS_PASSIVE(pdata))) {
+ if (parent) {
+ if (pdata == NULL) {
+ pdata = fdata_new (parent, FALSE);
+ }
+ g_assert (pdata);
+ if (!port_add (&pdata->fobj, &pdata->len, pdata)) {
+ fdata_adjust_deleted (pdata);
+ }
+ } else {
+ /* f is root */
+ g_assert (IS_TOPNODE(FN_NODE(f)));
+ missing_add (f);
+ }
+ } else {
+#ifdef GIO_COMPILATION
+ pending_remove_node (FN_NODE(f), &op);
+#else
+ remove_node (FN_NODE(f), &op);
+#endif
+ }
+}
+
+static gboolean
+fdata_adjust_changed (fdata *f)
+{
+ fnode_event_t *ev;
+ struct stat buf;
+ node_t* parent;
+ fdata* pdata;
+
+ G_LOCK (fen_lock);
+ parent = get_parent_node (f);
+ pdata = get_parent_data (f);
+
+ if (!FN_IS_LIVING(f) ||
+ (children_num (FN_NODE(f)) == 0 &&
+ FN_IS_PASSIVE(f) &&
+ pdata && FN_IS_PASSIVE(pdata))) {
+ f->change_update_id = 0;
+ G_UNLOCK (fen_lock);
+ return FALSE;
+ }
+
+ FD_W ("[ %s ] %s\n", __func__, FN_NAME(f));
+ if (FN_STAT (FN_NAME(f), &buf) != 0) {
+ FD_W ("LSTAT [%-20s] %s\n", FN_NAME(f), g_strerror (errno));
+ goto L_delete;
+ }
+ f->is_dir = S_ISDIR (buf.st_mode) ? TRUE : FALSE;
+ if (f->len != buf.st_size) {
+ FD_W ("LEN [%lld:%lld] %s\n", f->len, buf.st_size, FN_NAME(f));
+ f->len = buf.st_size;
+ ev = fnode_event_new (FILE_MODIFIED, TRUE, f);
+ if (ev != NULL) {
+ ev->is_pending = TRUE;
+ fdata_add_event (f, ev);
+ }
+ /* Fdata is still changing, so scalable scan */
+ f->change_update_id = g_timeout_add (get_scalable_scan_time (f),
+ (GSourceFunc)fdata_adjust_changed,
+ (gpointer)f);
+ G_UNLOCK (fen_lock);
+ return FALSE;
+ } else {
+ f->changed_event_num = 0;
+ f->fobj.fo_atime = buf.st_atim;
+ f->fobj.fo_mtime = buf.st_mtim;
+ f->fobj.fo_ctime = buf.st_ctim;
+ if (FN_IS_DIR(f)) {
+ if (FN_IS_MONDIR(f)) {
+ scan_children (FN_NODE(f));
+ } else {
+ scan_known_children (FN_NODE(f));
+ if ((children_num (FN_NODE(f)) == 0 &&
+ FN_IS_PASSIVE(f) &&
+ pdata && FN_IS_PASSIVE(pdata))) {
+ port_remove (f);
+ goto L_exit;
+ }
+ }
+ }
+ if (!port_add_simple (&f->fobj, f)) {
+ L_delete:
+ ev = fnode_event_new (FILE_DELETE, FALSE, f);
+ if (ev != NULL) {
+ fdata_add_event (f, ev);
+ }
+ }
+ }
+L_exit:
+ f->change_update_id = 0;
+ G_UNLOCK (fen_lock);
+ return FALSE;
+}
+
+void
+fdata_emit_events_once (fdata *f, int event, gpointer sub)
+{
+ emit_once_cb (f, _event_converter (event), sub);
+}
+
+void
+fdata_emit_events (fdata *f, int event)
+{
+ emit_cb (f, _event_converter (event));
+}
+
+static gboolean
+process_events (gpointer udata)
+{
+ node_op_t op = {NULL, NULL, pre_del_cb, NULL};
+ fdata* f;
+ fnode_event_t* ev;
+ int e;
+
+ /* FD_W ("IN <======== %s\n", __func__); */
+
+ f = (fdata*)udata;
+ FD_W ("%s 0x%p id:%-4d %s\n", __func__, f, f->eventq_id, FN_NAME(f));
+
+ G_LOCK (fen_lock);
+
+ if (!FN_IS_LIVING(f)) {
+ f->eventq_id = 0;
+ G_UNLOCK (fen_lock);
+ return FALSE;
+ }
+
+ if ((ev = (fnode_event_t*)g_queue_pop_head (f->eventq)) != NULL) {
+ /* Send events to clients. */
+ e = ev->e;
+ if (!ev->is_pending) {
+#ifdef GIO_COMPILATION
+ if (ev->has_twin) {
+ fdata_emit_events (f, FILE_ATTRIB);
+ }
+#endif
+ fdata_emit_events (f, ev->e);
+ }
+
+ fnode_event_delete (ev);
+ ev = NULL;
+
+ /* Adjust node state. */
+ /*
+ * Node the node has been created, so we can delete create event in
+ * optimizing. To reduce the statings, we add it to Port on discoving
+ * it then emit CREATED event. So we don't need to do anything here.
+ */
+ switch (e) {
+ case FILE_MODIFIED:
+ case MOUNTEDOVER:
+ case UNMOUNTED:
+ /* If the event is a changed event, then pending process it */
+ if (f->change_update_id == 0) {
+ f->change_update_id = g_timeout_add (get_scalable_scan_time(f),
+ (GSourceFunc)fdata_adjust_changed,
+ (gpointer)f);
+ g_assert (f->change_update_id > 0);
+ }
+ break;
+ case FILE_ATTRIB: /* Ignored */
+ case FILE_DELETE:
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ /* Process one event a time */
+ G_UNLOCK (fen_lock);
+ return TRUE;
+ }
+ f->eventq_id = 0;
+ G_UNLOCK (fen_lock);
+ /* FD_W ("OUT ========> %s\n", __func__); */
+ return FALSE;
+}
+
+/**
+ * fdata_add_event:
+ *
+ */
+void
+fdata_add_event (fdata *f, fnode_event_t *ev)
+{
+ node_op_t op = {NULL, NULL, pre_del_cb, NULL};
+ fnode_event_t *tail;
+
+ if (!FN_IS_LIVING(f)) {
+ fnode_event_delete (ev);
+ return;
+ }
+
+ FD_W ("%s %d\n", __func__, ev->e);
+ g_get_current_time (&ev->t);
+ /*
+ * If created/deleted events of child node happened, then we use parent
+ * event queue to handle.
+ * If child node emits deleted event, it seems no changes for the parent
+ * node, but the attr is changed. So we may try to cancel processing the
+ * coming changed events of the parent node.
+ */
+ tail = (fnode_event_t*)g_queue_peek_tail (f->eventq);
+ switch (ev->e) {
+ case FILE_RENAME_FROM:
+ case FILE_RENAME_TO:
+ case FILE_ACCESS:
+ fnode_event_delete (ev);
+ g_assert_not_reached ();
+ return;
+ case FILE_DELETE:
+ /* clear changed event number */
+ f->changed_event_num = 0;
+ /*
+ * We will cancel all previous events.
+ */
+ if (tail) {
+ g_queue_pop_tail (f->eventq);
+ do {
+ fnode_event_delete (tail);
+ } while ((tail = (fnode_event_t*)g_queue_pop_tail (f->eventq)) != NULL);
+ }
+ /*
+ * Given a node "f" is deleted, process it ASAP.
+ */
+ fdata_emit_events (f, ev->e);
+ fnode_event_delete (ev);
+ fdata_adjust_deleted (f);
+ return;
+ case FILE_MODIFIED:
+ case UNMOUNTED:
+ case MOUNTEDOVER:
+ /* clear changed event number */
+ f->changed_event_num ++;
+ case FILE_ATTRIB:
+ default:
+ /*
+ * If in the time range, we will try optimizing
+ * (changed+) to (changed)
+ * (attrchanged changed) to ([changed, attrchanged])
+ * (event attrchanged) to ([event, attrchanged])
+ */
+ if (tail) {
+ do {
+ if (tail->e == ev->e) {
+ if (g_timeval_lt (&ev->t, &tail->t)) {
+ g_queue_peek_tail (f->eventq);
+ /* Add the increment */
+ g_time_val_add (&ev->t, PAIR_EVENTS_INC_TIMEVAL);
+ /* skip the previous event */
+ FD_W ("SKIPPED -- %s\n", _event_string (tail->e));
+ fnode_event_delete (tail);
+ } else {
+ break;
+ }
+ } else if (tail->e == FILE_ATTRIB && ev->e == FILE_MODIFIED) {
+ ev->has_twin = TRUE;
+ fnode_event_delete (tail);
+ } else if (ev->e == FILE_ATTRIB) {
+ tail->has_twin = TRUE;
+ /* skip the current event */
+ fnode_event_delete (ev);
+ return;
+ } else {
+ break;
+ }
+ } while ((tail = (fnode_event_t*)g_queue_peek_tail (f->eventq)) != NULL);
+ }
+ }
+
+ /* must add the threshold time */
+ g_time_val_add (&ev->t, PAIR_EVENTS_TIMEVAL);
+
+ g_queue_push_tail (f->eventq, ev);
+
+ /* starting process_events */
+ if (f->eventq_id == 0) {
+ f->eventq_id = g_timeout_add (PROCESS_EVENTQ_TIME,
+ process_events,
+ (gpointer)f);
+ g_assert (f->eventq_id > 0);
+ }
+ FD_W ("%s 0x%p id:%-4d %s\n", __func__, f, f->eventq_id, FN_NAME(f));
+}
+
+gboolean
+fdata_class_init (void (*user_emit_cb) (fdata*, int),
+ void (*user_emit_once_cb) (fdata*, int, gpointer),
+ int (*user_event_converter) (int event))
+{
+ FD_W ("%s\n", __func__);
+ if (user_emit_cb == NULL) {
+ return FALSE;
+ }
+ if (user_emit_once_cb == NULL) {
+ return FALSE;
+ }
+ if (user_event_converter == NULL) {
+ return FALSE;
+ }
+ emit_cb = user_emit_cb;
+ emit_once_cb = user_emit_once_cb;
+ _event_converter = user_event_converter;
+
+ if (!port_class_init (fdata_add_event)) {
+ FD_W ("port_class_init failed.");
+ return FALSE;
+ }
+ return TRUE;
+}
Added: trunk/gio/fen/fen-data.h
==============================================================================
--- (empty file)
+++ trunk/gio/fen/fen-data.h Fri Mar 14 08:58:24 2008
@@ -0,0 +1,88 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set expandtab ts=4 shiftwidth=4: */
+/*
+ * Copyright (C) 2008 Sun Microsystem.
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Lin Ma <lin ma sun com>
+ */
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "fen-node.h"
+#include "fen-kernel.h"
+
+#ifndef _FEN_DATA_H_
+#define _FEN_DATA_H_
+
+#define FN_EVENT_CREATED 0
+#define FN_NAME(fp) (((fdata*)(fp))->fobj.fo_name)
+#define FN_NODE(fp) (((fdata*)(fp))->node)
+#define FN_IS_DIR(fp) (((fdata*)(fp))->is_dir)
+#define FN_IS_PASSIVE(fp) (((fdata*)(fp))->subs == NULL)
+#define FN_IS_MONDIR(fp) (((fdata*)(fp))->mon_dir_num > 0)
+#define FN_IS_LIVING(fp) (!((fdata*)(fp))->is_cancelled)
+
+typedef struct
+{
+ file_obj_t fobj;
+ off_t len;
+ gboolean is_cancelled;
+
+ node_t* node;
+ /* to identify if the path is dir */
+ gboolean is_dir;
+ guint mon_dir_num;
+
+ /* List of subscriptions monitoring this fdata/path */
+ GList *subs;
+
+ /* prcessed changed events num */
+ guint changed_event_num;
+
+ /* process events source id */
+ GQueue* eventq;
+ guint eventq_id;
+ guint change_update_id;
+} fdata;
+
+/* fdata functions */
+fdata* fdata_new (node_t* node, gboolean is_mondir);
+void fdata_reset (fdata* data);
+void fdata_emit_events_once (fdata *f, int event, gpointer sub);
+void fdata_emit_events (fdata *f, int event);
+void fdata_add_event (fdata *f, fnode_event_t *ev);
+void fdata_adjust_deleted (fdata *f);
+fdata* get_parent_data (fdata* data);
+node_t* get_parent_node (fdata* data);
+gboolean is_monitoring (fdata* data);
+
+/* sub */
+void fdata_sub_add (fdata *f, gpointer sub);
+void fdata_sub_remove (fdata *f, gpointer sub);
+
+/* misc */
+node_t* add_missing_cb (node_t* parent, gpointer user_data);
+gboolean pre_del_cb (node_t* node, gpointer user_data);
+
+/* init */
+gboolean fdata_class_init (void (*user_emit_cb) (fdata*, int),
+ void (*user_emit_once_cb) (fdata*, int, gpointer),
+ int (*user_event_converter) (int event));
+
+#endif /* _FEN_DATA_H_ */
Added: trunk/gio/fen/fen-dump.c
==============================================================================
--- (empty file)
+++ trunk/gio/fen/fen-dump.c Fri Mar 14 08:58:24 2008
@@ -0,0 +1,99 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set expandtab ts=4 shiftwidth=4: */
+/*
+ * Copyright (C) 2008 Sun Microsystem.
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Lin Ma <lin ma sun com>
+ */
+
+#include "config.h"
+#include <glib.h>
+#include <glib/gprintf.h>
+#include "fen-node.h"
+#include "fen-data.h"
+#include "fen-kernel.h"
+#include "fen-missing.h"
+#include "fen-dump.h"
+
+G_LOCK_EXTERN (fen_lock);
+
+/*-------------------- node ------------------*/
+static void
+dump_node (node_t* node, gpointer data)
+{
+ if (data && node->user_data) {
+ return;
+ }
+ g_printf ("[%s] < 0x%p : 0x%p > %s\n", __func__, node, node->user_data, NODE_NAME(node));
+}
+
+static gboolean
+dump_node_tree (node_t* node, gpointer user_data)
+{
+ node_op_t op = {dump_node, NULL, NULL, user_data};
+ GList* children;
+ GList* i;
+ if (G_TRYLOCK (fen_lock)) {
+ if (node) {
+ travel_nodes (node, &op);
+ }
+ G_UNLOCK (fen_lock);
+ }
+ return TRUE;
+}
+
+/* ------------------ fdata port hash --------------------*/
+void
+dump_hash_cb (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ g_printf ("[%s] < 0x%p : 0x%p >\n", __func__, key, value);
+}
+
+gboolean
+dump_hash (GHashTable* hash, gpointer user_data)
+{
+ if (G_TRYLOCK (fen_lock)) {
+ if (g_hash_table_size (hash) > 0) {
+ g_hash_table_foreach (hash, dump_hash_cb, user_data);
+ }
+ G_UNLOCK (fen_lock);
+ }
+ return TRUE;
+}
+
+/* ------------------ event --------------------*/
+void
+dump_event (fnode_event_t* ev, gpointer user_data)
+{
+ fdata* data = ev->user_data;
+ g_printf ("[%s] < 0x%p : 0x%p > [ %10s ] %s\n", __func__, ev, ev->user_data, _event_string (ev->e), FN_NAME(data));
+}
+
+void
+dump_event_queue (fdata* data, gpointer user_data)
+{
+ if (G_TRYLOCK (fen_lock)) {
+ if (data->eventq) {
+ g_queue_foreach (data->eventq, (GFunc)dump_event, user_data);
+ }
+ G_UNLOCK (fen_lock);
+ }
+}
+
Added: trunk/gio/fen/fen-dump.h
==============================================================================
--- (empty file)
+++ trunk/gio/fen/fen-dump.h Fri Mar 14 08:58:24 2008
@@ -0,0 +1,28 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set expandtab ts=4 shiftwidth=4: */
+/*
+ * Copyright (C) 2008 Sun Microsystem.
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Lin Ma <lin ma sun com>
+ */
+
+#ifndef _FEN_DUMP_H_
+#define _FEN_DUMP_H_
+
+
+#endif /* _FEN_DUMP_H_ */
Added: trunk/gio/fen/fen-helper.c
==============================================================================
--- (empty file)
+++ trunk/gio/fen/fen-helper.c Fri Mar 14 08:58:24 2008
@@ -0,0 +1,330 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set expandtab ts=4 shiftwidth=4: */
+/*
+ * Copyright (C) 2008 Sun Microsystem.
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Lin Ma <lin ma sun com>
+ */
+
+#include "config.h"
+#include <glib.h>
+#include "fen-data.h"
+#include "fen-helper.h"
+#include "fen-kernel.h"
+#ifdef GIO_COMPILATION
+#include "gfilemonitor.h"
+#else
+#include "gam_event.h"
+#include "gam_server.h"
+#include "gam_protocol.h"
+#endif
+
+#define FH_W if (fh_debug_enabled) g_warning
+static gboolean fh_debug_enabled = FALSE;
+
+G_LOCK_EXTERN (fen_lock);
+
+static void default_emit_event_cb (fdata *f, int events);
+static void default_emit_once_event_cb (fdata *f, int events, gpointer sub);
+static int default_event_converter (int event);
+
+static void
+scan_children_init (node_t *f, gpointer sub)
+{
+ GDir *dir;
+ GError *err = NULL;
+ node_op_t op = {NULL, NULL, pre_del_cb, NULL};
+ fdata* pdata;
+
+ FH_W ("%s %s [0x%p]\n", __func__, NODE_NAME(f), f);
+ pdata = node_get_data (f);
+
+ dir = g_dir_open (NODE_NAME(f), 0, &err);
+ if (dir) {
+ const char *basename;
+
+ while ((basename = g_dir_read_name (dir)))
+ {
+ node_t *childf = NULL;
+ fdata* data;
+ GList *idx;
+
+ childf = children_find (f, basename);
+ if (childf == NULL) {
+ gchar *filename;
+
+ filename = g_build_filename (NODE_NAME(f), basename, NULL);
+ childf = add_node (f, filename);
+ g_assert (childf);
+ g_free (filename);
+ }
+ if ((data = node_get_data (childf)) == NULL) {
+ data = fdata_new (childf, FALSE);
+ }
+
+ if (is_monitoring (data)) {
+ /* Ignored */
+ } else if (/* !is_ported (data) && */
+ port_add (&data->fobj, &data->len, data)) {
+ /* Emit created to all other subs */
+ fdata_emit_events (data, FN_EVENT_CREATED);
+ }
+ /* Emit created to the new sub */
+#ifdef GIO_COMPILATION
+ /* fdata_emit_events_once (data, FN_EVENT_CREATED, sub); */
+#else
+ gam_server_emit_one_event (NODE_NAME(childf),
+ gam_subscription_is_dir (sub), GAMIN_EVENT_EXISTS, sub, 1);
+#endif
+ }
+ g_dir_close (dir);
+ } else {
+ FH_W (err->message);
+ g_error_free (err);
+ }
+}
+
+/**
+ * fen_add
+ *
+ * Won't hold a ref, we have a timout callback to clean unused fdata.
+ * If there is no value for a key, add it and return it; else return the old
+ * one.
+ */
+void
+fen_add (const gchar *filename, gpointer sub, gboolean is_mondir)
+{
+ node_op_t op = {NULL, add_missing_cb, pre_del_cb, (gpointer)filename};
+ node_t* f;
+ fdata* data;
+
+ g_assert (filename);
+ g_assert (sub);
+
+ G_LOCK (fen_lock);
+ f = find_node_full (filename, &op);
+ FH_W ("[ %s ] f[0x%p] sub[0x%p] %s\n", __func__, f, sub, filename);
+ g_assert (f);
+ data = node_get_data (f);
+ if (data == NULL) {
+ data = fdata_new (f, is_mondir);
+ }
+
+ if (is_mondir) {
+ data->mon_dir_num ++;
+ }
+
+ /* Change to active */
+#ifdef GIO_COMPILATION
+ if (port_add (&data->fobj, &data->len, data) ||
+ g_file_test (FN_NAME(data), G_FILE_TEST_EXISTS)) {
+ if (is_mondir) {
+ scan_children_init (f, sub);
+ }
+ fdata_sub_add (data, sub);
+ } else {
+ fdata_sub_add (data, sub);
+ fdata_adjust_deleted (data);
+ }
+#else
+ if (port_add (&data->fobj, &data->len, data) ||
+ g_file_test (FN_NAME(data), G_FILE_TEST_EXISTS)) {
+ gam_server_emit_one_event (FN_NAME(data),
+ gam_subscription_is_dir (sub), GAMIN_EVENT_EXISTS, sub, 1);
+ if (is_mondir) {
+ scan_children_init (f, sub);
+ }
+ gam_server_emit_one_event (FN_NAME(data),
+ gam_subscription_is_dir (sub), GAMIN_EVENT_ENDEXISTS, sub, 1);
+ fdata_sub_add (data, sub);
+ } else {
+ fdata_sub_add (data, sub);
+ gam_server_emit_one_event (FN_NAME(data),
+ gam_subscription_is_dir (sub), GAMIN_EVENT_DELETED, sub, 1);
+ fdata_adjust_deleted (data);
+ gam_server_emit_one_event (FN_NAME(data),
+ gam_subscription_is_dir (sub), GAMIN_EVENT_ENDEXISTS, sub, 1);
+ }
+#endif
+ G_UNLOCK (fen_lock);
+}
+
+void
+fen_remove (const gchar *filename, gpointer sub, gboolean is_mondir)
+{
+ node_op_t op = {NULL, add_missing_cb, pre_del_cb, (gpointer)filename};
+ node_t* f;
+ fdata* data;
+
+ g_assert (filename);
+ g_assert (sub);
+
+ G_LOCK (fen_lock);
+ f = find_node (filename);
+ FH_W ("[ %s ] f[0x%p] sub[0x%p] %s\n", __func__, f, sub, filename);
+
+ g_assert (f);
+ data = node_get_data (f);
+ g_assert (data);
+
+ if (is_mondir) {
+ data->mon_dir_num --;
+ }
+ fdata_sub_remove (data, sub);
+ if (FN_IS_PASSIVE(data)) {
+#ifdef GIO_COMPILATION
+ pending_remove_node (f, &op);
+#else
+ remove_node (f, &op);
+#endif
+ }
+ G_UNLOCK (fen_lock);
+}
+
+static gboolean
+fen_init_once_func (gpointer data)
+{
+ FH_W ("%s\n", __func__);
+ if (!node_class_init ()) {
+ FH_W ("node_class_init failed.");
+ return FALSE;
+ }
+ if (!fdata_class_init (default_emit_event_cb,
+ default_emit_once_event_cb,
+ default_event_converter)) {
+ FH_W ("fdata_class_init failed.");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+gboolean
+fen_init ()
+{
+#ifdef GIO_COMPILATION
+ static GOnce fen_init_once = G_ONCE_INIT;
+ g_once (&fen_init_once, (GThreadFunc)fen_init_once_func, NULL);
+ return (gboolean)fen_init_once.retval;
+#else
+ return fen_init_once_func (NULL);
+#endif
+}
+
+static void
+default_emit_once_event_cb (fdata *f, int events, gpointer sub)
+{
+#ifdef GIO_COMPILATION
+ GFile* child;
+ fen_sub* _sub = (fen_sub*)sub;
+ child = g_file_new_for_path (FN_NAME(f));
+ g_file_monitor_emit_event (G_FILE_MONITOR (_sub->user_data),
+ child, NULL, events);
+ g_object_unref (child);
+#else
+ gam_server_emit_one_event (FN_NAME(f),
+ gam_subscription_is_dir (sub), events, sub, 1);
+#endif
+}
+
+static void
+default_emit_event_cb (fdata *f, int events)
+{
+ GList* i;
+ fdata* pdata;
+
+#ifdef GIO_COMPILATION
+ GFile* child;
+ child = g_file_new_for_path (FN_NAME(f));
+ for (i = f->subs; i; i = i->next) {
+ fen_sub* sub = (fen_sub*)i->data;
+ gboolean file_is_dir = sub->is_mondir;
+ if ((events != G_FILE_MONITOR_EVENT_CHANGED &&
+ events != G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED) ||
+ !file_is_dir) {
+ g_file_monitor_emit_event (G_FILE_MONITOR (sub->user_data),
+ child, NULL, events);
+ }
+ }
+ if ((pdata = get_parent_data (f)) != NULL) {
+ for (i = pdata->subs; i; i = i->next) {
+ fen_sub* sub = (fen_sub*)i->data;
+ gboolean file_is_dir = sub->is_mondir;
+ g_file_monitor_emit_event (G_FILE_MONITOR (sub->user_data),
+ child, NULL, events);
+ }
+ }
+ g_object_unref (child);
+#else
+ for (i = f->subs; i; i = i->next) {
+ gboolean file_is_dir = gam_subscription_is_dir (i->data);
+ if (events != GAMIN_EVENT_CHANGED || !file_is_dir) {
+ gam_server_emit_one_event (FN_NAME(f), file_is_dir, events, i->data, 1);
+ }
+ }
+ if ((pdata = get_parent_data (f)) != NULL) {
+ for (i = pdata->subs; i; i = i->next) {
+ gboolean file_is_dir = gam_subscription_is_dir (i->data);
+ gam_server_emit_one_event (FN_NAME(f), file_is_dir, events, i->data, 1);
+ }
+ }
+#endif
+}
+
+static int
+default_event_converter (int event)
+{
+#ifdef GIO_COMPILATION
+ switch (event) {
+ case FN_EVENT_CREATED:
+ return G_FILE_MONITOR_EVENT_CREATED;
+ case FILE_DELETE:
+ case FILE_RENAME_FROM:
+ return G_FILE_MONITOR_EVENT_DELETED;
+ case UNMOUNTED:
+ return G_FILE_MONITOR_EVENT_UNMOUNTED;
+ case FILE_ATTRIB:
+ return G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED;
+ case MOUNTEDOVER:
+ case FILE_MODIFIED:
+ case FILE_RENAME_TO:
+ return G_FILE_MONITOR_EVENT_CHANGED;
+ default:
+ /* case FILE_ACCESS: */
+ g_assert_not_reached ();
+ return -1;
+ }
+#else
+ switch (event) {
+ case FN_EVENT_CREATED:
+ return GAMIN_EVENT_CREATED;
+ case FILE_DELETE:
+ case FILE_RENAME_FROM:
+ return GAMIN_EVENT_DELETED;
+ case FILE_ATTRIB:
+ case MOUNTEDOVER:
+ case UNMOUNTED:
+ case FILE_MODIFIED:
+ case FILE_RENAME_TO:
+ return GAMIN_EVENT_CHANGED;
+ default:
+ /* case FILE_ACCESS: */
+ g_assert_not_reached ();
+ return -1;
+ }
+#endif
+}
Added: trunk/gio/fen/fen-helper.h
==============================================================================
--- (empty file)
+++ trunk/gio/fen/fen-helper.h Fri Mar 14 08:58:24 2008
@@ -0,0 +1,35 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set expandtab ts=4 shiftwidth=4: */
+/*
+ * Copyright (C) 2008 Sun Microsystem.
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Lin Ma <lin ma sun com>
+ */
+
+#include "fen-sub.h"
+
+#ifndef _FEN_HELPER_H_
+#define _FEN_HELPER_H_
+
+void fen_add (const gchar *filename, gpointer sub, gboolean is_mondir);
+void fen_remove (const gchar *filename, gpointer sub, gboolean is_mondir);
+
+/* FEN subsystem initializing */
+gboolean fen_init ();
+
+#endif /* _FEN_HELPER_H_ */
Added: trunk/gio/fen/fen-kernel.c
==============================================================================
--- (empty file)
+++ trunk/gio/fen/fen-kernel.c Fri Mar 14 08:58:24 2008
@@ -0,0 +1,523 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set expandtab ts=4 shiftwidth=4: */
+/*
+ * Copyright (C) 2008 Sun Microsystem.
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Lin Ma <lin ma sun com>
+ */
+
+#include "config.h"
+#include <rctl.h>
+#include <strings.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <glib.h>
+#include "fen-kernel.h"
+#include "fen-dump.h"
+
+#define FK_W if (fk_debug_enabled) g_warning
+static gboolean fk_debug_enabled = FALSE;
+
+G_GNUC_INTERNAL G_LOCK_DEFINE (fen_lock);
+#define PE_ALLOC 64
+#define F_PORT(pp) (((_f *)(fo))->port->port)
+#define F_NAME(pp) (((_f *)(fo))->fobj->fo_name)
+#define FEN_ALL_EVENTS (FILE_MODIFIED | FILE_ATTRIB | FILE_NOFOLLOW)
+#define FEN_IGNORE_EVENTS (FILE_ACCESS)
+#define PROCESS_PORT_EVENTS_TIME 400 /* in milliseconds */
+
+static GHashTable *_obj_fen_hash = NULL; /* <user_data, port> */
+static ulong max_port_events = 512;
+static GList *pn_vq; /* the queue of ports which don't have the max objs */
+static GList *pn_fq; /* the queue of ports which have the max objs */
+static GQueue *g_eventq = NULL;
+static void (*add_event_cb) (gpointer, fnode_event_t*);
+
+typedef struct pnode
+{
+ long ref; /* how many fds are associated to this port */
+ int port;
+ guint port_source_id;
+} pnode_t;
+
+typedef struct {
+ pnode_t* port;
+ file_obj_t* fobj;
+
+ gboolean is_active;
+ gpointer user_data;
+} _f;
+
+static gboolean port_fetch_event_cb (void *arg);
+static pnode_t *pnode_new ();
+static void pnode_delete (pnode_t *pn);
+
+gboolean
+is_ported (gpointer f)
+{
+ _f* fo = g_hash_table_lookup (_obj_fen_hash, f);
+
+ if (fo) {
+ return fo->is_active;
+ }
+ return FALSE;
+}
+
+static void
+printevent (const char *pname, int event, const char *tag)
+{
+ GString* str;
+ str = g_string_new ("");
+
+ g_string_printf (str, "[%s] [%-20s]", tag, pname);
+ if (event & FILE_ACCESS) {
+ str = g_string_append (str, " ACCESS");
+ }
+ if (event & FILE_MODIFIED) {
+ str = g_string_append (str, " MODIFIED");
+ }
+ if (event & FILE_ATTRIB) {
+ str = g_string_append (str, " ATTRIB");
+ }
+ if (event & FILE_DELETE) {
+ str = g_string_append (str, " DELETE");
+ }
+ if (event & FILE_RENAME_TO) {
+ str = g_string_append (str, " RENAME_TO");
+ }
+ if (event & FILE_RENAME_FROM) {
+ str = g_string_append (str, " RENAME_FROM");
+ }
+ if (event & UNMOUNTED) {
+ str = g_string_append (str, " UNMOUNTED");
+ }
+ if (event & MOUNTEDOVER) {
+ str = g_string_append (str, " MOUNTEDOVER");
+ }
+
+ FK_W ("%s\n", str->str);
+ g_string_free (str, TRUE);
+}
+
+static void
+port_add_kevent (int e, gpointer f)
+{
+ fnode_event_t *ev, *tail;
+ GTimeVal t;
+ gboolean has_twin = FALSE;
+
+ /* printevent (F_NAME(f), e, "org"); */
+ /*
+ * Child FILE_DELETE | FILE_RENAME_FROM will trigger parent FILE_MODIFIED.
+ * FILE_MODIFIED will trigger FILE_ATTRIB.
+ */
+
+ if ((e & FILE_ATTRIB) && e != FILE_ATTRIB) {
+ e ^= FILE_ATTRIB;
+ has_twin = TRUE;
+ }
+ if (e == FILE_RENAME_FROM) {
+ e = FILE_DELETE;
+ }
+ if (e == FILE_RENAME_TO) {
+ e = FILE_MODIFIED;
+ }
+
+ switch (e) {
+ case FILE_DELETE:
+ case FILE_RENAME_FROM:
+ case FILE_MODIFIED:
+ case FILE_ATTRIB:
+ case UNMOUNTED:
+ case MOUNTEDOVER:
+ break;
+ case FILE_RENAME_TO:
+ case FILE_ACCESS:
+ default:
+ g_assert_not_reached ();
+ return;
+ }
+
+ tail = (fnode_event_t*) g_queue_peek_tail (g_eventq);
+ if (tail) {
+ if (tail->user_data == f) {
+ if (tail->e == e) {
+ tail->has_twin = (has_twin | (tail->has_twin ^ has_twin));
+ /* skip the current */
+ return;
+ } else if (e == FILE_MODIFIED && !has_twin
+ && tail->e == FILE_ATTRIB) {
+ tail->e = FILE_MODIFIED;
+ tail->has_twin = TRUE;
+ return;
+ } else if (e == FILE_ATTRIB
+ && tail->e == FILE_MODIFIED && !tail->has_twin) {
+ tail->has_twin = TRUE;
+ return;
+ }
+ }
+ }
+
+ if ((ev = fnode_event_new (e, has_twin, f)) != NULL) {
+ g_queue_push_tail (g_eventq, ev);
+ }
+}
+
+static void
+port_process_kevents ()
+{
+ fnode_event_t *ev;
+
+ while ((ev = (fnode_event_t*)g_queue_pop_head (g_eventq)) != NULL) {
+ FK_W ("[%s] 0x%p %s\n", __func__, ev, _event_string (ev->e));
+ add_event_cb (ev->user_data, ev);
+ }
+}
+
+static gboolean
+port_fetch_event_cb (void *arg)
+{
+ pnode_t *pn = (pnode_t *)arg;
+ _f* fo;
+ uint_t nget = 0;
+ port_event_t pe[PE_ALLOC];
+ timespec_t timeout;
+ gpointer f;
+ gboolean ret = TRUE;
+
+ /* FK_W ("IN <======== %s\n", __func__); */
+ G_LOCK (fen_lock);
+
+ memset (&timeout, 0, sizeof (timespec_t));
+ do {
+ nget = 1;
+ if (port_getn (pn->port, pe, PE_ALLOC, &nget, &timeout) == 0) {
+ int i;
+ for (i = 0; i < nget; i++) {
+ fo = (_f*)pe[i].portev_user;
+ /* handle event */
+ switch (pe[i].portev_source) {
+ case PORT_SOURCE_FILE:
+ /* If got FILE_EXCEPTION or add to port failed,
+ delete the pnode */
+ fo->is_active = FALSE;
+ if (fo->user_data) {
+ printevent (F_NAME(fo), pe[i].portev_events, "RAW");
+ port_add_kevent (pe[i].portev_events, fo->user_data);
+ } else {
+ /* fnode is deleted */
+ goto L_delete;
+ }
+ if (pe[i].portev_events & FILE_EXCEPTION) {
+ g_hash_table_remove (_obj_fen_hash, fo->user_data);
+ L_delete:
+ FK_W ("[ FREE_FO ] [0x%p]\n", fo);
+ pnode_delete (fo->port);
+ g_free (fo);
+ }
+ break;
+ default:
+ /* case PORT_SOURCE_TIMER: */
+ FK_W ("[kernel] unknown portev_source %d\n", pe[i].portev_source);
+ }
+ }
+ } else {
+ FK_W ("[kernel] port_getn %s\n", g_strerror (errno));
+ nget = 0;
+ }
+ } while (nget == PE_ALLOC);
+
+ /* Processing g_eventq */
+ port_process_kevents ();
+
+ if (pn->ref == 0) {
+ pn->port_source_id = 0;
+ ret = FALSE;
+ }
+ G_UNLOCK (fen_lock);
+ /* FK_W ("OUT ========> %s\n", __func__); */
+ return ret;
+}
+
+/*
+ * ref - 1 if remove a watching file succeeded.
+ */
+static void
+pnode_delete (pnode_t *pn)
+{
+ g_assert (pn->ref <= max_port_events);
+
+ if (pn->ref == max_port_events) {
+ FK_W ("PORT : move to visible queue - [pn] 0x%p [ref] %d\n", pn, pn->ref);
+ pn_fq = g_list_remove (pn_fq, pn);
+ pn_vq = g_list_prepend (pn_vq, pn);
+ }
+ if ((-- pn->ref) == 0) {
+ /* Should dispatch the source */
+ }
+ FK_W ("%s [pn] 0x%p [ref] %d\n", __func__, pn, pn->ref);
+}
+
+/*
+ * malloc pnode_t and port_create, start thread at pnode_ref.
+ * if pnode_new succeeded, the pnode_t will never
+ * be freed. So pnode_t can be freed only in pnode_new.
+ * Note pnode_monitor_remove_all can also free pnode_t, but currently no one
+ * invork it.
+ */
+static pnode_t *
+pnode_new ()
+{
+ pnode_t *pn = NULL;
+
+ if (pn_vq) {
+ pn = (pnode_t*)pn_vq->data;
+ g_assert (pn->ref < max_port_events);
+ } else {
+ pn = g_new0 (pnode_t, 1);
+ if (pn != NULL) {
+ if ((pn->port = port_create ()) >= 0) {
+ g_assert (g_list_find (pn_vq, pn) == NULL);
+ pn_vq = g_list_prepend (pn_vq, pn);
+ } else {
+ FK_W ("PORT_CREATE %s\n", g_strerror (errno));
+ g_free (pn);
+ pn = NULL;
+ }
+ }
+ }
+ if (pn) {
+ FK_W ("%s [pn] 0x%p [ref] %d\n", __func__, pn, pn->ref);
+ pn->ref++;
+ if (pn->ref == max_port_events) {
+ FK_W ("PORT : move to full queue - [pn] 0x%p [ref] %d\n", pn, pn->ref);
+ pn_vq = g_list_remove (pn_vq, pn);
+ pn_fq = g_list_prepend (pn_fq, pn);
+ g_assert (g_list_find (pn_vq, pn) == NULL);
+ }
+ /* attach the source */
+ if (pn->port_source_id == 0) {
+ pn->port_source_id = g_timeout_add (PROCESS_PORT_EVENTS_TIME,
+ port_fetch_event_cb,
+ (void *)pn);
+ g_assert (pn->port_source_id > 0);
+ }
+ }
+
+ return pn;
+}
+
+/**
+ * port_add_internal
+ *
+ * < private >
+ * Unsafe, need lock fen_lock.
+ */
+static gboolean
+port_add_internal (file_obj_t* fobj, off_t* len,
+ gpointer f, gboolean need_stat)
+{
+ int ret;
+ struct stat buf;
+ _f* fo = NULL;
+
+ g_assert (f && fobj);
+ FK_W ("%s [0x%p] %s\n", __func__, f, fobj->fo_name);
+
+ if ((fo = g_hash_table_lookup (_obj_fen_hash, f)) == NULL) {
+ fo = g_new0 (_f, 1);
+ fo->fobj = fobj;
+ fo->user_data = f;
+ g_assert (fo);
+ FK_W ("[ NEW_FO ] [0x%p] %s\n", fo, F_NAME(fo));
+ g_hash_table_insert (_obj_fen_hash, f, fo);
+ }
+
+ if (fo->is_active) {
+ return TRUE;
+ }
+
+ if (fo->port == NULL) {
+ fo->port = pnode_new ();
+ }
+
+ if (need_stat) {
+ if (FN_STAT (F_NAME(fo), &buf) != 0) {
+ FK_W ("LSTAT [%-20s] %s\n", F_NAME(fo), g_strerror (errno));
+ goto L_exit;
+ }
+ g_assert (len);
+ fo->fobj->fo_atime = buf.st_atim;
+ fo->fobj->fo_mtime = buf.st_mtim;
+ fo->fobj->fo_ctime = buf.st_ctim;
+ *len = buf.st_size;
+ }
+
+ if (port_associate (F_PORT(fo),
+ PORT_SOURCE_FILE,
+ (uintptr_t)fo->fobj,
+ FEN_ALL_EVENTS,
+ (void *)fo) == 0) {
+ fo->is_active = TRUE;
+ FK_W ("%s %s\n", "PORT_ASSOCIATE", F_NAME(fo));
+ return TRUE;
+ } else {
+ FK_W ("PORT_ASSOCIATE [%-20s] %s\n", F_NAME(fo), g_strerror (errno));
+ L_exit:
+ FK_W ("[ FREE_FO ] [0x%p]\n", fo);
+ g_hash_table_remove (_obj_fen_hash, f);
+ pnode_delete (fo->port);
+ g_free (fo);
+ }
+ return FALSE;
+}
+
+gboolean
+port_add (file_obj_t* fobj, off_t* len, gpointer f)
+{
+ return port_add_internal (fobj, len, f, TRUE);
+}
+
+gboolean
+port_add_simple (file_obj_t* fobj, gpointer f)
+{
+ return port_add_internal (fobj, NULL, f, FALSE);
+}
+
+/**
+ * port_remove
+ *
+ * < private >
+ * Unsafe, need lock fen_lock.
+ */
+void
+port_remove (gpointer f)
+{
+ _f* fo = NULL;
+
+ FK_W ("%s\n", __func__);
+ if ((fo = g_hash_table_lookup (_obj_fen_hash, f)) != NULL) {
+ /* Marked */
+ fo->user_data = NULL;
+ g_hash_table_remove (_obj_fen_hash, f);
+
+ if (port_dissociate (F_PORT(fo),
+ PORT_SOURCE_FILE,
+ (uintptr_t)fo->fobj) == 0) {
+ /*
+ * Note, we can run foode_delete if dissociating is failed,
+ * because there may be some pending events (mostly like
+ * FILE_DELETE) in the port_get. If we delete the foode
+ * the fnode may be deleted, then port_get will run on an invalid
+ * address.
+ */
+ FK_W ("[ FREE_FO ] [0x%p]\n", fo);
+ pnode_delete (fo->port);
+ g_free (fo);
+ } else {
+ FK_W ("PORT_DISSOCIATE [%-20s] %s\n", F_NAME(fo), g_strerror (errno));
+ }
+ }
+}
+
+const gchar *
+_event_string (int event)
+{
+ switch (event) {
+ case FILE_DELETE:
+ return "FILE_DELETE";
+ case FILE_RENAME_FROM:
+ return "FILE_RENAME_FROM";
+ case FILE_MODIFIED:
+ return "FILE_MODIFIED";
+ case FILE_RENAME_TO:
+ return "FILE_RENAME_TO";
+ case MOUNTEDOVER:
+ return "MOUNTEDOVER";
+ case FILE_ATTRIB:
+ return "FILE_ATTRIB";
+ case UNMOUNTED:
+ return "UNMOUNTED";
+ case FILE_ACCESS:
+ return "FILE_ACCESS";
+ default:
+ return "EVENT_UNKNOWN";
+ }
+}
+
+/**
+ * Get Solaris resouce values.
+ *
+ */
+
+extern gboolean
+port_class_init (void (*user_add_event) (gpointer, fnode_event_t*))
+{
+ rctlblk_t *rblk;
+ FK_W ("%s\n", __func__);
+ if ((rblk = malloc (rctlblk_size ())) == NULL) {
+ FK_W ("[kernel] rblk malloc %s\n", g_strerror (errno));
+ return FALSE;
+ }
+ if (getrctl ("process.max-port-events", NULL, rblk, RCTL_FIRST) == -1) {
+ FK_W ("[kernel] getrctl %s\n", g_strerror (errno));
+ free (rblk);
+ return FALSE;
+ } else {
+ max_port_events = rctlblk_get_value(rblk);
+ FK_W ("[kernel] max_port_events = %u\n", max_port_events);
+ free (rblk);
+ }
+ if ((_obj_fen_hash = g_hash_table_new(g_direct_hash,
+ g_direct_equal)) == NULL) {
+ FK_W ("[kernel] fobj hash initializing faild\n");
+ return FALSE;
+ }
+ if ((g_eventq = g_queue_new ()) == NULL) {
+ FK_W ("[kernel] FEN global event queue initializing faild\n");
+ }
+ if (user_add_event == NULL) {
+ return FALSE;
+ }
+ add_event_cb = user_add_event;
+ return TRUE;
+}
+
+fnode_event_t*
+fnode_event_new (int event, gboolean has_twin, gpointer user_data)
+{
+ fnode_event_t *ev;
+
+ if ((ev = g_new (fnode_event_t, 1)) != NULL) {
+ g_assert (ev);
+ ev->e = event;
+ ev->user_data = user_data;
+ ev->has_twin = has_twin;
+ /* Default isn't a pending event. */
+ ev->is_pending = FALSE;
+ }
+ return ev;
+}
+
+void
+fnode_event_delete (fnode_event_t* ev)
+{
+ g_free (ev);
+}
Added: trunk/gio/fen/fen-kernel.h
==============================================================================
--- (empty file)
+++ trunk/gio/fen/fen-kernel.h Fri Mar 14 08:58:24 2008
@@ -0,0 +1,53 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set expandtab ts=4 shiftwidth=4: */
+/*
+ * Copyright (C) 2008 Sun Microsystem.
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Lin Ma <lin ma sun com>
+ */
+
+#include <port.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifndef _FEN_KERNEL_H_
+#define _FEN_KERNEL_H_
+
+#define FN_STAT lstat
+
+typedef struct fnode_event
+{
+ int e;
+ gboolean has_twin;
+ gboolean is_pending;
+ gpointer user_data;
+ GTimeVal t;
+} fnode_event_t;
+
+gboolean port_add (file_obj_t* fobj, off_t* len, gpointer f);
+gboolean port_add_simple (file_obj_t* fobj, gpointer f);
+void port_remove (gpointer f);
+gboolean is_ported (gpointer f);
+
+fnode_event_t* fnode_event_new (int event, gboolean has_twin, gpointer user_data);
+void fnode_event_delete (fnode_event_t* ev);
+const gchar * _event_string (int event);
+
+extern gboolean port_class_init ();
+
+#endif /* _FEN_KERNEL_H_ */
Added: trunk/gio/fen/fen-missing.c
==============================================================================
--- (empty file)
+++ trunk/gio/fen/fen-missing.c Fri Mar 14 08:58:24 2008
@@ -0,0 +1,114 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set expandtab ts=4 shiftwidth=4: */
+/*
+ * Copyright (C) 2008 Sun Microsystem.
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Lin Ma <lin ma sun com>
+ */
+
+#include "config.h"
+#include <glib.h>
+#include "fen-data.h"
+#include "fen-missing.h"
+
+G_LOCK_EXTERN (fen_lock);
+#define SCAN_MISSING_INTERVAL 4000 /* in milliseconds */
+#define FM_W if (fm_debug_enabled) g_warning
+
+/* global data structure for scan missing files */
+gboolean fm_debug_enabled = TRUE;
+static GList *missing_list = NULL;
+static guint scan_missing_source_id = 0;
+
+static gboolean scan_missing_list (gpointer data);
+
+static gboolean
+scan_missing_list (gpointer data)
+{
+ GList *existing_list = NULL;
+ GList *idx = NULL;
+ fdata *f;
+ gboolean ret = TRUE;
+
+ G_LOCK (fen_lock);
+
+ for (idx = missing_list; idx; idx = idx->next) {
+ f = (fdata*)idx->data;
+
+ if (port_add (&f->fobj, &f->len, f)) {
+ /* TODO - emit CREATE event */
+ fdata_emit_events (f, FN_EVENT_CREATED);
+ existing_list = g_list_prepend (existing_list, idx);
+ }
+ }
+
+ for (idx = existing_list; idx; idx = idx->next) {
+ missing_list = g_list_remove_link (missing_list, (GList *)idx->data);
+ g_list_free_1 ((GList *)idx->data);
+ }
+ g_list_free (existing_list);
+
+ if (missing_list == NULL) {
+ scan_missing_source_id = 0;
+ ret = FALSE;
+ }
+
+ G_UNLOCK (fen_lock);
+ return ret;
+}
+
+/**
+ * missing_add
+ *
+ * Unsafe, need lock fen_lock.
+ */
+void
+missing_add (fdata *f)
+{
+ GList *idx;
+
+ g_assert (!is_ported (f));
+
+ if (g_list_find (missing_list, f) != NULL) {
+ FM_W ("%s is ALREADY added %s\n", __func__, FN_NAME(f));
+ return;
+ }
+ FM_W ("%s is added %s\n", __func__, FN_NAME(f));
+
+ missing_list = g_list_prepend (missing_list, f);
+
+ /* if doesn't scan, then start */
+ if (scan_missing_source_id == 0) {
+ scan_missing_source_id = g_timeout_add (SCAN_MISSING_INTERVAL,
+ scan_missing_list,
+ NULL);
+ g_assert (scan_missing_source_id > 0);
+ }
+}
+
+/**
+ * missing_remove
+ *
+ * Unsafe, need lock fen_lock.
+ */
+void
+missing_remove (fdata *f)
+{
+ FM_W ("%s %s\n", __func__, FN_NAME(f));
+ missing_list = g_list_remove (missing_list, f);
+}
Added: trunk/gio/fen/fen-missing.h
==============================================================================
--- (empty file)
+++ trunk/gio/fen/fen-missing.h Fri Mar 14 08:58:24 2008
@@ -0,0 +1,37 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set expandtab ts=4 shiftwidth=4: */
+/*
+ * Copyright (C) 2008 Sun Microsystem.
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Lin Ma <lin ma sun com>
+ */
+
+#ifndef __GAM_FEN_H__
+#define __GAM_FEN_H__
+
+#include "fen-data.h"
+
+G_BEGIN_DECLS
+
+extern void missing_add (fdata *f);
+extern void missing_remove (fdata *f);
+
+G_END_DECLS
+
+#endif /* __GAM_FEN_H__ */
+
Added: trunk/gio/fen/fen-node.c
==============================================================================
--- (empty file)
+++ trunk/gio/fen/fen-node.c Fri Mar 14 08:58:24 2008
@@ -0,0 +1,460 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set expandtab ts=4 shiftwidth=4: */
+/*
+ * Copyright (C) 2008 Sun Microsystem.
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Lin Ma <lin ma sun com>
+ */
+
+#include "config.h"
+#include <errno.h>
+#include <strings.h>
+#include <glib.h>
+#include "fen-node.h"
+#include "fen-dump.h"
+
+#define NODE_STAT(n) (((node_t*)(n))->stat)
+
+struct _dnode {
+ gchar* filename;
+ node_op_t* op;
+ GTimeVal tv;
+};
+
+#define FN_W if (fn_debug_enabled) g_warning
+static gboolean fn_debug_enabled = FALSE;
+
+G_LOCK_EXTERN (fen_lock);
+#define PROCESS_DELETING_INTERVAL 900 /* in second */
+
+static node_t* _head = NULL;
+static GList *deleting_nodes = NULL;
+static guint deleting_nodes_id = 0;
+
+static node_t* node_new (node_t* parent, const gchar* basename);
+static void node_delete (node_t* parent);
+static gboolean remove_node_internal (node_t* node, node_op_t* op);
+static void children_add (node_t *p, node_t *f);
+static void children_remove (node_t *p, node_t *f);
+static guint children_foreach_remove (node_t *f, GHRFunc func, gpointer user_data);
+static void children_foreach (node_t *f, GHFunc func, gpointer user_data);
+static gboolean children_remove_cb (gpointer key,
+ gpointer value,
+ gpointer user_data);
+
+static struct _dnode*
+_dnode_new (const gchar* filename, node_op_t* op)
+{
+ struct _dnode* d;
+
+ g_assert (op);
+ if ((d = g_new (struct _dnode, 1)) != NULL) {
+ d->filename = g_strdup (filename);
+ d->op = g_memdup (op, sizeof (node_op_t));
+ g_assert (d->op);
+ g_get_current_time (&d->tv);
+ g_time_val_add (&d->tv, PROCESS_DELETING_INTERVAL);
+ }
+ return d;
+}
+
+static void
+_dnode_free (struct _dnode* d)
+{
+ g_assert (d);
+ g_free (d->filename);
+ g_free (d->op);
+ g_free (d);
+}
+
+static gboolean
+g_timeval_lt (GTimeVal *val1, GTimeVal *val2)
+{
+ if (val1->tv_sec < val2->tv_sec)
+ return TRUE;
+
+ if (val1->tv_sec > val2->tv_sec)
+ return FALSE;
+
+ /* val1->tv_sec == val2->tv_sec */
+ if (val1->tv_usec < val2->tv_usec)
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+scan_deleting_nodes (gpointer data)
+{
+ struct _dnode* d;
+ GTimeVal tv_now;
+ GList* i;
+ GList* deleted_list = NULL;
+ gboolean ret = TRUE;
+ node_t* node;
+
+ g_get_current_time (&tv_now);
+
+ if (G_TRYLOCK (fen_lock)) {
+ for (i = deleting_nodes; i; i = i->next) {
+ d = (struct _dnode*)i->data;
+ /* Time to free, try only once */
+ if (g_timeval_lt (&d->tv, &tv_now)) {
+ if ((node = find_node (d->filename)) != NULL) {
+ remove_node_internal (node, d->op);
+ }
+ _dnode_free (d);
+ deleted_list = g_list_prepend (deleted_list, i);
+ }
+ }
+
+ for (i = deleted_list; i; i = i->next) {
+ deleting_nodes = g_list_remove_link (deleting_nodes,
+ (GList *)i->data);
+ g_list_free_1 ((GList *)i->data);
+ }
+ g_list_free (deleted_list);
+
+ if (deleting_nodes == NULL) {
+ deleting_nodes_id = 0;
+ ret = FALSE;
+ }
+ G_UNLOCK (fen_lock);
+ }
+ return ret;
+}
+
+gpointer
+node_get_data (node_t* node)
+{
+ g_assert (node);
+ return node->user_data;
+}
+
+gpointer
+node_set_data (node_t* node, gpointer user_data)
+{
+ gpointer data = node->user_data;
+ g_assert (node);
+ node->user_data = user_data;
+ return data;
+}
+
+void
+travel_nodes (node_t* node, node_op_t* op)
+{
+ GList* children;
+ GList* i;
+
+ if (node) {
+ if (op && op->hit) {
+ op->hit (node, op->user_data);
+ }
+ }
+ children = g_hash_table_get_values (node->children);
+ if (children) {
+ for (i = children; i; i = i->next) {
+ travel_nodes (i->data, op);
+ }
+ g_list_free (children);
+ }
+}
+
+static node_t*
+find_node_internal (node_t* node, const gchar* filename, node_op_t* op)
+{
+ gchar* str;
+ gchar* token;
+ gchar* lasts;
+ node_t* parent;
+ node_t* child;
+
+ g_assert (filename && filename[0] == '/');
+ g_assert (node);
+
+ parent = node;
+ str = g_strdup (filename + strlen (NODE_NAME(parent)));
+
+ if ((token = strtok_r (str, G_DIR_SEPARATOR_S, &lasts)) != NULL) {
+ do {
+ FN_W ("%s %s + %s\n", __func__, NODE_NAME(parent), token);
+ child = children_find (parent, token);
+ if (child) {
+ parent = child;
+ } else {
+ if (op && op->add_missing) {
+ child = op->add_missing (parent, op->user_data);
+ goto L_hit;
+ }
+ break;
+ }
+ } while ((token = strtok_r (NULL, G_DIR_SEPARATOR_S, &lasts)) != NULL);
+ } else {
+ /* It's the head */
+ g_assert (parent == _head);
+ child = _head;
+ }
+
+ if (token == NULL && child) {
+ L_hit:
+ if (op && op->hit) {
+ op->hit (child, op->user_data);
+ }
+ }
+ g_free (str);
+ return child;
+}
+
+node_t*
+find_node (const gchar *filename)
+{
+ return find_node_internal (_head, filename, NULL);
+}
+
+node_t*
+find_node_full (const gchar* filename, node_op_t* op)
+{
+ return find_node_internal (_head, filename, op);
+}
+
+node_t*
+add_node (node_t* parent, const gchar* filename)
+{
+ gchar* str;
+ gchar* token;
+ gchar* lasts;
+ node_t* child = NULL;
+
+ g_assert (_head);
+ g_assert (filename && filename[0] == '/');
+
+ if (parent == NULL) {
+ parent = _head;
+ }
+
+ str = g_strdup (filename + strlen (NODE_NAME(parent)));
+
+ if ((token = strtok_r (str, G_DIR_SEPARATOR_S, &lasts)) != NULL) {
+ do {
+ FN_W ("%s %s + %s\n", __func__, NODE_NAME(parent), token);
+ child = node_new (parent, token);
+ if (child) {
+ children_add (parent, child);
+ parent = child;
+ } else {
+ break;
+ }
+ } while ((token = strtok_r (NULL, G_DIR_SEPARATOR_S, &lasts)) != NULL);
+ }
+ g_free (str);
+ if (token == NULL) {
+ return child;
+ } else {
+ return NULL;
+ }
+}
+
+/**
+ * delete recursively
+ */
+static gboolean
+remove_children (node_t* node, node_op_t* op)
+{
+ FN_W ("%s 0x%p %s\n", __func__, node, NODE_NAME(node));
+ if (children_num (node) > 0) {
+ children_foreach_remove (node, children_remove_cb,
+ (gpointer)op);
+ }
+ if (children_num (node) == 0) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+remove_node_internal (node_t* node, node_op_t* op)
+{
+ node_t* parent = NULL;
+ /*
+ * If the parent is passive and doesn't have children, delete it.
+ * NOTE node_delete_deep is a depth first delete recursively.
+ * Top node is deleted in node_cancel_sub
+ */
+ g_assert (node);
+ g_assert (op && op->pre_del);
+ if (node != _head) {
+ if (remove_children (node, op)) {
+ if (node->user_data) {
+ if (!op->pre_del (node, op->user_data)) {
+ return FALSE;
+ }
+ }
+ parent = node->parent;
+ children_remove (parent, node);
+ node_delete (node);
+ if (children_num (parent) == 0) {
+ remove_node_internal (parent, op);
+ }
+ return TRUE;
+ }
+ return FALSE;
+ }
+ return TRUE;
+}
+
+void
+pending_remove_node (node_t* node, node_op_t* op)
+{
+ struct _dnode* d;
+ GList* l;
+
+ for (l = deleting_nodes; l; l=l->next) {
+ d = (struct _dnode*) l->data;
+ if (g_ascii_strcasecmp (d->filename, NODE_NAME(node)) == 0) {
+ return;
+ }
+ }
+
+ d = _dnode_new (NODE_NAME(node), op);
+ g_assert (d);
+ deleting_nodes = g_list_prepend (deleting_nodes, d);
+ if (deleting_nodes_id == 0) {
+ deleting_nodes_id = g_timeout_add_seconds (PROCESS_DELETING_INTERVAL,
+ scan_deleting_nodes,
+ NULL);
+ g_assert (deleting_nodes_id > 0);
+ }
+}
+
+void
+remove_node (node_t* node, node_op_t* op)
+{
+ remove_node_internal (node, op);
+}
+
+static node_t*
+node_new (node_t* parent, const gchar* basename)
+{
+ node_t *f = NULL;
+
+ g_assert (basename && basename[0]);
+ if ((f = g_new0 (node_t, 1)) != NULL) {
+ if (parent) {
+ f->basename = g_strdup (basename);
+ f->filename = g_build_filename (G_DIR_SEPARATOR_S,
+ NODE_NAME(parent), basename, NULL);
+ } else {
+ f->basename = g_strdup (basename);
+ f->filename = g_strdup (basename);
+ }
+ f->children = g_hash_table_new_full (g_str_hash, g_str_equal,
+ NULL, (GDestroyNotify)node_delete);
+ FN_W ("[ %s ] 0x%p %s\n", __func__, f, NODE_NAME(f));
+ }
+ return f;
+}
+
+static void
+node_delete (node_t *f)
+{
+ FN_W ("[ %s ] 0x%p %s\n", __func__, f, NODE_NAME(f));
+ g_assert (g_hash_table_size (f->children) == 0);
+ g_assert (f->user_data == NULL);
+
+ g_hash_table_unref (f->children);
+ g_free (f->basename);
+ g_free (f->filename);
+ g_free (f);
+}
+
+static void
+children_add (node_t *p, node_t *f)
+{
+ FN_W ("%s [p] %8s [c] %8s\n", __func__, p->basename, f->basename);
+ g_hash_table_insert (p->children, f->basename, f);
+ f->parent = p;
+}
+
+static void
+children_remove (node_t *p, node_t *f)
+{
+ FN_W ("%s [p] %8s [c] %8s\n", __func__, p->basename, f->basename);
+ g_hash_table_steal (p->children, f->basename);
+ f->parent = NULL;
+}
+
+guint
+children_num (node_t *f)
+{
+ return g_hash_table_size (f->children);
+}
+
+node_t *
+children_find (node_t *f, const gchar *basename)
+{
+ return (node_t *) g_hash_table_lookup (f->children, (gpointer)basename);
+}
+
+/**
+ * depth first delete recursively
+ */
+static gboolean
+children_remove_cb (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ node_t* f = (node_t*)value;
+ node_op_t* op = (node_op_t*) user_data;
+
+ g_assert (f->parent);
+
+ FN_W ("%s [p] %8s [c] %8s\n", __func__, f->parent->basename, f->basename);
+ if (remove_children (f, op)) {
+ if (f->user_data != NULL) {
+ return op->pre_del (f, op->user_data);
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static guint
+children_foreach_remove (node_t *f, GHRFunc func, gpointer user_data)
+{
+ g_assert (f);
+
+ return g_hash_table_foreach_remove (f->children, func, user_data);
+}
+
+static void
+children_foreach (node_t *f, GHFunc func, gpointer user_data)
+{
+ g_assert (f);
+
+ g_hash_table_foreach (f->children, func, user_data);
+}
+
+gboolean
+node_class_init ()
+{
+ FN_W ("%s\n", __func__);
+ if (_head == NULL) {
+ _head = node_new (NULL, G_DIR_SEPARATOR_S);
+ }
+ return _head != NULL;
+}
Added: trunk/gio/fen/fen-node.h
==============================================================================
--- (empty file)
+++ trunk/gio/fen/fen-node.h Fri Mar 14 08:58:24 2008
@@ -0,0 +1,72 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set expandtab ts=4 shiftwidth=4: */
+/*
+ * Copyright (C) 2008 Sun Microsystem.
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Lin Ma <lin ma sun com>
+ */
+
+#ifndef _FEN_NODE_H_
+#define _FEN_NODE_H_
+
+typedef struct node node_t;
+
+struct node
+{
+ gchar *filename;
+ gchar *basename;
+ gint stat;
+
+ /* the parent and children of node */
+ node_t *parent;
+ GHashTable *children; /* children in basename */
+
+ gpointer user_data;
+};
+
+#define IS_TOPNODE(fp) (((node_t *)(fp))->parent == NULL)
+#define NODE_NAME(fp) (((node_t *)(fp))->filename)
+
+typedef struct node_op
+{
+ /* find */
+ void (*hit) (node_t* node, gpointer user_data);
+ node_t* (*add_missing) (node_t* parent, gpointer user_data);
+ /* delete */
+ gboolean (*pre_del) (node_t* node, gpointer user_data);
+ /* data */
+ gpointer user_data;
+} node_op_t;
+
+node_t* add_node (node_t* parent, const gchar* filename);
+void remove_node (node_t* node, node_op_t* op);
+void pending_remove_node (node_t* node, node_op_t* op);
+
+void travel_nodes (node_t* node, node_op_t* op);
+node_t* find_node_full (const gchar* filename, node_op_t* op);
+node_t* find_node (const gchar *filename);
+
+node_t* children_find (node_t *f, const gchar *basename);
+guint children_num (node_t *f);
+
+gpointer node_get_data (node_t* node);
+gpointer node_set_data (node_t* node, gpointer user_data);
+
+gboolean node_class_init ();
+
+#endif /* _FEN_NODE_H_ */
Added: trunk/gio/fen/fen-sub.c
==============================================================================
--- (empty file)
+++ trunk/gio/fen/fen-sub.c Fri Mar 14 08:58:24 2008
@@ -0,0 +1,41 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set expandtab ts=4 shiftwidth=4: */
+/*
+ * Copyright (C) 2008 Sun Microsystem.
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Lin Ma <lin ma sun com>
+ */
+
+#include "config.h"
+#include "fen-sub.h"
+
+fen_sub*
+fen_sub_new (gpointer udata, gboolean is_mondir)
+{
+ fen_sub *sub;
+ sub = g_new (fen_sub, 1);
+ sub->user_data = udata;
+ sub->is_mondir = is_mondir;
+ return sub;
+}
+
+void
+fen_sub_delete (fen_sub *sub)
+{
+ g_free (sub);
+}
Added: trunk/gio/fen/fen-sub.h
==============================================================================
--- (empty file)
+++ trunk/gio/fen/fen-sub.h Fri Mar 14 08:58:24 2008
@@ -0,0 +1,38 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set expandtab ts=4 shiftwidth=4: */
+/*
+ * Copyright (C) 2008 Sun Microsystem.
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Lin Ma <lin ma sun com>
+ */
+
+#include <glib.h>
+
+#ifndef _FEN_SUB_H_
+#define _FEN_SUB_H_
+
+typedef struct _fen_sub
+{
+ gpointer user_data;
+ gboolean is_mondir;
+} fen_sub;
+
+fen_sub* fen_sub_new (gpointer udata, gboolean is_mondir);
+void fen_sub_delete (fen_sub *sub);
+
+#endif _FEN_SUB_H_
Added: trunk/gio/fen/gfendirectorymonitor.c
==============================================================================
--- (empty file)
+++ trunk/gio/fen/gfendirectorymonitor.c Fri Mar 14 08:58:24 2008
@@ -0,0 +1,149 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set expandtab ts=4 shiftwidth=4: */
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ * Copyright (C) 2007 Sebastian DrÃge.
+ * Copyright (C) 2008 Sun Microsystem.
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Alexander Larsson <alexl redhat com>
+ * John McCutchan <john johnmccutchan com>
+ * Sebastian DrÃge <slomo circular-chaos org>
+ * Lin Ma <lin ma sun com>
+ */
+
+#include <config.h>
+
+#include "gfendirectorymonitor.h"
+#include "giomodule.h"
+
+#include "fen-helper.h"
+
+#include "gioalias.h"
+
+struct _GFenDirectoryMonitor
+{
+ GLocalDirectoryMonitor parent_instance;
+ gboolean cancelled;
+ fen_sub* sub;
+};
+
+static gboolean g_fen_directory_monitor_cancel (GFileMonitor* monitor);
+
+#define g_fen_directory_monitor_get_type _g_fen_directory_monitor_get_type
+G_DEFINE_TYPE_WITH_CODE (GFenDirectoryMonitor, g_fen_directory_monitor, G_TYPE_LOCAL_DIRECTORY_MONITOR,
+ g_io_extension_point_implement (G_LOCAL_DIRECTORY_MONITOR_EXTENSION_POINT_NAME,
+ g_define_type_id,
+ "fen",
+ 20))
+
+static void
+g_fen_directory_monitor_finalize (GObject *object)
+{
+ GFenDirectoryMonitor *self = G_FEN_DIRECTORY_MONITOR (object);
+
+ if (self->sub) {
+ fen_remove (G_LOCAL_DIRECTORY_MONITOR (self)->dirname, self->sub, TRUE);
+ fen_sub_delete (self->sub);
+ self->sub = NULL;
+ }
+
+ if (G_OBJECT_CLASS (g_fen_directory_monitor_parent_class)->finalize)
+ (*G_OBJECT_CLASS (g_fen_directory_monitor_parent_class)->finalize) (object);
+}
+
+static GObject *
+g_fen_directory_monitor_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GObject *obj;
+ GFenDirectoryMonitorClass *klass;
+ GObjectClass *parent_class;
+ GFenDirectoryMonitor *self;
+ const gchar *dirname = NULL;
+
+ klass = G_FEN_DIRECTORY_MONITOR_CLASS (g_type_class_peek (G_TYPE_FEN_DIRECTORY_MONITOR));
+ parent_class = g_fen_directory_monitor_parent_class;
+ obj = parent_class->constructor (type,
+ n_construct_properties,
+ construct_properties);
+
+ self = G_FEN_DIRECTORY_MONITOR (obj);
+
+ dirname = G_LOCAL_DIRECTORY_MONITOR (self)->dirname;
+ g_assert (dirname != NULL);
+
+ /* Will never fail as is_supported() should be called before instanciating
+ * anyway */
+ if (!fen_init ())
+ g_assert_not_reached ();
+
+ /* FIXME: what to do about errors here? we can't return NULL or another
+ * kind of error and an assertion is probably too hard */
+ self->sub = fen_sub_new (self, TRUE);
+ g_assert (self->sub);
+
+ fen_add (dirname, self->sub, TRUE);
+
+ return obj;
+}
+
+static gboolean
+g_fen_directory_monitor_is_supported (void)
+{
+ return fen_init ();
+}
+
+static void
+g_fen_directory_monitor_class_init (GFenDirectoryMonitorClass* klass)
+{
+ GObjectClass* gobject_class = G_OBJECT_CLASS (klass);
+ GFileMonitorClass *directory_monitor_class = G_FILE_MONITOR_CLASS (klass);
+ GLocalDirectoryMonitorClass *local_directory_monitor_class = G_LOCAL_DIRECTORY_MONITOR_CLASS (klass);
+
+ gobject_class->finalize = g_fen_directory_monitor_finalize;
+ gobject_class->constructor = g_fen_directory_monitor_constructor;
+ directory_monitor_class->cancel = g_fen_directory_monitor_cancel;
+
+ local_directory_monitor_class->mount_notify = TRUE;
+ local_directory_monitor_class->is_supported = g_fen_directory_monitor_is_supported;
+}
+
+static void
+g_fen_directory_monitor_init (GFenDirectoryMonitor* monitor)
+{
+}
+
+static gboolean
+g_fen_directory_monitor_cancel (GFileMonitor* monitor)
+{
+ GFenDirectoryMonitor *self = G_FEN_DIRECTORY_MONITOR (monitor);
+
+ if (self->sub) {
+ fen_remove (G_LOCAL_DIRECTORY_MONITOR (self)->dirname, self->sub, TRUE);
+ fen_sub_delete (self->sub);
+ self->sub = NULL;
+ }
+
+ if (G_FILE_MONITOR_CLASS (g_fen_directory_monitor_parent_class)->cancel)
+ (*G_FILE_MONITOR_CLASS (g_fen_directory_monitor_parent_class)->cancel) (monitor);
+
+ return TRUE;
+}
+
Added: trunk/gio/fen/gfendirectorymonitor.h
==============================================================================
--- (empty file)
+++ trunk/gio/fen/gfendirectorymonitor.h Fri Mar 14 08:58:24 2008
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set expandtab ts=4 shiftwidth=4: */
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ * Copyright (C) 2007 Sebastian DrÃge.
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Alexander Larsson <alexl redhat com>
+ * John McCutchan <john johnmccutchan com>
+ * Sebastian DrÃge <slomo circular-chaos org>
+ */
+
+#ifndef __G_FEN_DIRECTORY_MONITOR_H__
+#define __G_FEN_DIRECTORY_MONITOR_H__
+
+#include <glib-object.h>
+#include <string.h>
+#include "glocaldirectorymonitor.h"
+#include "giomodule.h"
+
+G_BEGIN_DECLS
+
+#define G_TYPE_FEN_DIRECTORY_MONITOR (_g_fen_directory_monitor_get_type ())
+#define G_FEN_DIRECTORY_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_FEN_DIRECTORY_MONITOR, GFenDirectoryMonitor))
+#define G_FEN_DIRECTORY_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), G_TYPE_FEN_DIRECTORY_MONITOR, GFenDirectoryMonitorClass))
+#define G_IS_FEN_DIRECTORY_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_FEN_DIRECTORY_MONITOR))
+#define G_IS_FEN_DIRECTORY_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_FEN_DIRECTORY_MONITOR))
+
+typedef struct _GFenDirectoryMonitor GFenDirectoryMonitor;
+typedef struct _GFenDirectoryMonitorClass GFenDirectoryMonitorClass;
+
+struct _GFenDirectoryMonitorClass {
+ GLocalDirectoryMonitorClass parent_class;
+};
+
+GType _g_fen_directory_monitor_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __G_FEN_DIRECTORY_MONITOR_H__ */
Added: trunk/gio/fen/gfenfilemonitor.c
==============================================================================
--- (empty file)
+++ trunk/gio/fen/gfenfilemonitor.c Fri Mar 14 08:58:24 2008
@@ -0,0 +1,148 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set expandtab ts=4 shiftwidth=4: */
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ * Copyright (C) 2007 Sebastian DrÃge.
+ * Copyright (C) 2008 Sun Microsystem.
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Alexander Larsson <alexl redhat com>
+ * John McCutchan <john johnmccutchan com>
+ * Sebastian DrÃge <slomo circular-chaos org>
+ * Lin Ma <lin ma sun com>
+ */
+
+#include <config.h>
+
+#include "gfenfilemonitor.h"
+#include <gio/giomodule.h>
+
+#include "fen-helper.h"
+
+#include "gioalias.h"
+
+struct _GFenFileMonitor
+{
+ GLocalFileMonitor parent_instance;
+ fen_sub* sub;
+};
+
+static gboolean g_fen_file_monitor_cancel (GFileMonitor* monitor);
+
+#define g_fen_file_monitor_get_type _g_fen_file_monitor_get_type
+G_DEFINE_TYPE_WITH_CODE (GFenFileMonitor, g_fen_file_monitor, G_TYPE_LOCAL_FILE_MONITOR,
+ g_io_extension_point_implement (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
+ g_define_type_id,
+ "fen",
+ 20))
+
+static void
+g_fen_file_monitor_finalize (GObject *object)
+{
+ GFenFileMonitor *self = G_FEN_FILE_MONITOR (object);
+
+ if (self->sub) {
+ fen_remove (G_LOCAL_FILE_MONITOR (self)->filename, self->sub, FALSE);
+ fen_sub_delete (self->sub);
+ self->sub = NULL;
+ }
+
+ if (G_OBJECT_CLASS (g_fen_file_monitor_parent_class)->finalize)
+ (*G_OBJECT_CLASS (g_fen_file_monitor_parent_class)->finalize) (object);
+}
+
+static GObject *
+g_fen_file_monitor_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GObject *obj;
+ GFenFileMonitorClass *klass;
+ GObjectClass *parent_class;
+ GFenFileMonitor *self;
+ const gchar *filename = NULL;
+
+ klass = G_FEN_FILE_MONITOR_CLASS (g_type_class_peek (G_TYPE_FEN_FILE_MONITOR));
+ parent_class = g_fen_file_monitor_parent_class;
+ obj = parent_class->constructor (type,
+ n_construct_properties,
+ construct_properties);
+
+ self = G_FEN_FILE_MONITOR (obj);
+
+ filename = G_LOCAL_FILE_MONITOR (obj)->filename;
+
+ g_assert (filename != NULL);
+
+ /* Will never fail as is_supported() should be called before instanciating
+ * anyway */
+ if (!fen_init ())
+ g_assert_not_reached ();
+
+ /* FIXME: what to do about errors here? we can't return NULL or another
+ * kind of error and an assertion is probably too hard */
+ self->sub = fen_sub_new (self, FALSE);
+ g_assert (self->sub);
+
+ fen_add (filename, self->sub, FALSE);
+
+ return obj;
+}
+
+static gboolean
+g_fen_file_monitor_is_supported (void)
+{
+ return fen_init ();
+}
+
+static void
+g_fen_file_monitor_class_init (GFenFileMonitorClass* 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);
+
+ gobject_class->finalize = g_fen_file_monitor_finalize;
+ gobject_class->constructor = g_fen_file_monitor_constructor;
+ file_monitor_class->cancel = g_fen_file_monitor_cancel;
+
+ local_file_monitor_class->is_supported = g_fen_file_monitor_is_supported;
+}
+
+static void
+g_fen_file_monitor_init (GFenFileMonitor* monitor)
+{
+}
+
+static gboolean
+g_fen_file_monitor_cancel (GFileMonitor* monitor)
+{
+ GFenFileMonitor *self = G_FEN_FILE_MONITOR (monitor);
+
+ if (self->sub) {
+ fen_remove (G_LOCAL_FILE_MONITOR (self)->filename, self->sub, FALSE);
+ fen_sub_delete (self->sub);
+ self->sub = NULL;
+ }
+
+ if (G_FILE_MONITOR_CLASS (g_fen_file_monitor_parent_class)->cancel)
+ (*G_FILE_MONITOR_CLASS (g_fen_file_monitor_parent_class)->cancel) (monitor);
+
+ return TRUE;
+}
+
Added: trunk/gio/fen/gfenfilemonitor.h
==============================================================================
--- (empty file)
+++ trunk/gio/fen/gfenfilemonitor.h Fri Mar 14 08:58:24 2008
@@ -0,0 +1,56 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set expandtab ts=4 shiftwidth=4: */
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ * Copyright (C) 2007 Sebastian DrÃge.
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Alexander Larsson <alexl redhat com>
+ * John McCutchan <john johnmccutchan com>
+ * Sebastian DrÃge <slomo circular-chaos org>
+ */
+
+#ifndef __G_FEN_FILE_MONITOR_H__
+#define __G_FEN_FILE_MONITOR_H__
+
+#include <glib-object.h>
+#include <string.h>
+#include <gio/gfilemonitor.h>
+#include <gio/glocalfilemonitor.h>
+#include <gio/giomodule.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_FEN_FILE_MONITOR (_g_fen_file_monitor_get_type ())
+#define G_FEN_FILE_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_FEN_FILE_MONITOR, GFenFileMonitor))
+#define G_FEN_FILE_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), G_TYPE_FEN_FILE_MONITOR, GFenFileMonitorClass))
+#define G_IS_FEN_FILE_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_FEN_FILE_MONITOR))
+#define G_IS_FEN_FILE_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_FEN_FILE_MONITOR))
+
+typedef struct _GFenFileMonitor GFenFileMonitor;
+typedef struct _GFenFileMonitorClass GFenFileMonitorClass;
+
+struct _GFenFileMonitorClass {
+ GLocalFileMonitorClass parent_class;
+};
+
+GType _g_fen_file_monitor_get_type (void);
+
+G_END_DECLS
+
+#endif /* __G_FEN_FILE_MONITOR_H__ */
Modified: trunk/gio/giomodule.c
==============================================================================
--- trunk/gio/giomodule.c (original)
+++ trunk/gio/giomodule.c Fri Mar 14 08:58:24 2008
@@ -285,6 +285,8 @@
G_LOCK_DEFINE_STATIC (loaded_dirs);
+extern GType _g_fen_directory_monitor_get_type (void);
+extern GType _g_fen_file_monitor_get_type (void);
extern GType _g_inotify_directory_monitor_get_type (void);
extern GType _g_inotify_file_monitor_get_type (void);
extern GType _g_unix_volume_monitor_get_type (void);
@@ -331,9 +333,9 @@
#if defined(HAVE_SYS_INOTIFY_H) || defined(HAVE_LINUX_INOTIFY_H)
_g_inotify_directory_monitor_get_type ();
_g_inotify_file_monitor_get_type ();
-#endif
-#ifdef G_OS_WIN32
- g_win32_directory_monitor_get_type ();
+#elif defined(HAVE_FEN)
+ _g_fen_directory_monitor_get_type ();
+ _g_fen_file_monitor_get_type ();
#endif
#ifdef G_OS_UNIX
_g_unix_volume_monitor_get_type ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]