[glib] Reworked Solaris file event notification for GIO. See https://defect.opensolaris.org/bz/show_bug.cgi
- From: Lin Ma <linma src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] Reworked Solaris file event notification for GIO. See https://defect.opensolaris.org/bz/show_bug.cgi
- Date: Mon, 17 May 2010 06:46:17 +0000 (UTC)
commit e5440f865d79795061cf5e64d8ed7300222c4a79
Author: Lin Ma <lin ma sun com>
Date: Mon May 17 14:42:52 2010 +0800
Reworked Solaris file event notification for GIO. See
https://defect.opensolaris.org/bz/show_bug.cgi?id=10194
Updated copyright.
gio/fen/Makefile.am | 6 -
gio/fen/fen-data.c | 718 -------------------------------------
gio/fen/fen-data.h | 89 -----
gio/fen/fen-dump.c | 43 +--
gio/fen/fen-dump.h | 4 +-
gio/fen/fen-helper.c | 326 +++++------------
gio/fen/fen-helper.h | 13 +-
gio/fen/fen-kernel.c | 775 ++++++++++++++++++++--------------------
gio/fen/fen-kernel.h | 35 +--
gio/fen/fen-missing.c | 121 -------
gio/fen/fen-missing.h | 38 --
gio/fen/fen-node.c | 762 ++++++++++++++++++++++++---------------
gio/fen/fen-node.h | 97 ++++--
gio/fen/fen-sub.c | 42 ---
gio/fen/fen-sub.h | 39 --
gio/fen/gfendirectorymonitor.c | 95 +++---
gio/fen/gfendirectorymonitor.h | 3 +
gio/fen/gfenfilemonitor.c | 32 +-
gio/fen/gfenfilemonitor.h | 3 +
19 files changed, 1114 insertions(+), 2127 deletions(-)
---
diff --git a/gio/fen/Makefile.am b/gio/fen/Makefile.am
index 1acaa44..d96da45 100644
--- a/gio/fen/Makefile.am
+++ b/gio/fen/Makefile.am
@@ -11,14 +11,8 @@ libfen_la_SOURCES = \
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 \
diff --git a/gio/fen/fen-dump.c b/gio/fen/fen-dump.c
index d9ac363..98d20eb 100644
--- a/gio/fen/fen-dump.c
+++ b/gio/fen/fen-dump.c
@@ -1,8 +1,8 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim:set expandtab ts=4 shiftwidth=4: */
/*
- * Copyright (C) 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
+ * reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -26,9 +26,6 @@
#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);
@@ -37,25 +34,16 @@ G_LOCK_EXTERN (fen_lock);
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));
+ g_printf ("n:0x%p ds:0x%p s:0x%p %s\n", node, node->dir_subs, node->subs, NODE_NAME(node));
}
-static gboolean
-dump_node_tree (node_t* node, gpointer user_data)
+static void
+dump_tree (node_t* node)
{
- 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);
- }
+ node_traverse(NULL, dump_node, NULL);
G_UNLOCK (fen_lock);
}
- return TRUE;
}
/* ------------------ fdata port hash --------------------*/
@@ -64,7 +52,7 @@ dump_hash_cb (gpointer key,
gpointer value,
gpointer user_data)
{
- g_printf ("[%s] < 0x%p : 0x%p >\n", __func__, key, value);
+ g_printf ("k:0x%p v:0x%p >\n", key, value);
}
gboolean
@@ -81,20 +69,9 @@ dump_hash (GHashTable* hash, gpointer user_data)
/* ------------------ 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)
+dump_event (node_event_t* ev, 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);
- }
+ node_t* node = ev->user_data;
+ 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));
}
diff --git a/gio/fen/fen-dump.h b/gio/fen/fen-dump.h
index 0e866fa..ffac822 100644
--- a/gio/fen/fen-dump.h
+++ b/gio/fen/fen-dump.h
@@ -1,8 +1,8 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim:set expandtab ts=4 shiftwidth=4: */
/*
- * Copyright (C) 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
+ * reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
diff --git a/gio/fen/fen-helper.c b/gio/fen/fen-helper.c
index c05cb41..e68e7c3 100644
--- a/gio/fen/fen-helper.c
+++ b/gio/fen/fen-helper.c
@@ -1,8 +1,8 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim:set expandtab ts=4 shiftwidth=4: */
/*
- * Copyright (C) 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
+ * reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -24,11 +24,9 @@
#include "config.h"
#include <glib.h>
-#include "fen-data.h"
#include "fen-helper.h"
#include "fen-kernel.h"
#ifdef GIO_COMPILATION
-#include "gfile.h"
#include "gfilemonitor.h"
#else
#include "gam_event.h"
@@ -37,7 +35,7 @@
#endif
#ifdef GIO_COMPILATION
-#define FH_W if (fh_debug_enabled) g_warning
+#define FH_W if (fh_debug_enabled) g_debug
static gboolean fh_debug_enabled = FALSE;
#else
#include "gam_error.h"
@@ -46,292 +44,154 @@ 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);
-
+/* misc */
static void
-scan_children_init (node_t *f, gpointer sub)
+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;
-
+ gboolean emit;
+ gint event;
+
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;
+#ifdef GIO_COMPILATION
+ emit = FALSE;
+ event = G_FILE_MONITOR_EVENT_CREATED;
+#else
+ emit = TRUE;
+ event = GAMIN_EVENT_EXISTS;
+#endif
+
+ if (!NODE_HAS_FLAG(f, NODE_FLAG_SNAPSHOT_UPDATED)) {
+ /* TODO snapshot should also compare to the sub created timestamp. */
+ /* GIO initially doesn't emit created/existed events. */
+ node_create_children_snapshot(f, event, emit);
+ } else {
+ GHashTableIter iter;
+ gpointer value;
+
+ g_hash_table_iter_init (&iter, f->children);
+ while (g_hash_table_iter_next (&iter, NULL, &value)) {
+ node_t *child = (node_t *)value;
- 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); */
+ /* GIO initially doesn't emit created/existed events. */
+ /* g_file_monitor_emit_event(G_FILE_MONITOR(sub), child->gfile, NULL, event); */
#else
- gam_server_emit_one_event (NODE_NAME(childf),
- gam_subscription_is_dir (sub), GAMIN_EVENT_EXISTS, sub, 1);
+ gam_server_emit_one_event(NODE_NAME(child), gam_subscription_is_dir(sub), event, sub, 1);
#endif
}
- g_dir_close (dir);
- } else {
- FH_W (err->message);
- g_error_free (err);
}
}
/**
- * _fen_add
+ * fen_add
*
- * Won't hold a ref, we have a timout callback to clean unused fdata.
+ * Won't hold a ref, we have a timout callback to clean unused node_t.
* 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)
+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);
+ f = node_find(NULL, filename, TRUE);
+ FH_W ("%s 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);
+
+ /* Update timestamp, the events in global queue will compare itself to this
+ * timestamp to decide if be emitted. TODO, timestamp should be per sub.
+ */
+ if (!NODE_IS_ACTIVE(f)) {
+ g_get_current_time(&f->atv);
}
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);
+ f->dir_subs = g_list_prepend(f->dir_subs, sub);
} else {
- _fdata_sub_add (data, sub);
- _fdata_adjust_deleted (data);
+ f->subs = g_list_prepend(f->subs, sub);
}
-#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),
+
+ if (NODE_HAS_STATE(f, NODE_STATE_ASSOCIATED) ||
+ (node_lstat(f) == 0 && port_add(f) == 0)) {
+#ifndef GIO_COMPILATION
+ gam_server_emit_one_event (NODE_NAME(f),
gam_subscription_is_dir (sub), GAMIN_EVENT_EXISTS, sub, 1);
+#endif
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),
+#ifndef GIO_COMPILATION
+ gam_server_emit_one_event (NODE_NAME(f),
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
+ node_adjust_deleted (f);
}
+#ifndef GIO_COMPILATION
+ gam_server_emit_one_event (NODE_NAME(f),
+ 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)
+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);
+ f = node_find(NULL, filename, FALSE);
+ FH_W ("%s 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);
-}
+ if (f) {
+ if (is_mondir) {
+ f->dir_subs = g_list_remove(f->dir_subs, sub);
+ } else {
+ f->subs = g_list_remove(f->subs, sub);
+ }
-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;
+ if (!NODE_IS_ACTIVE(f)) {
+ node_try_delete (f);
+ }
}
- return TRUE;
+ G_UNLOCK (fen_lock);
}
+/**
+ * fen_init:
+ *
+ * FEN subsystem initializing.
+ */
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)
+fen_init ()
{
-#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 gboolean initialized = FALSE;
+ static gboolean result = FALSE;
-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);
- }
+ G_LOCK (fen_lock);
+ if (initialized) {
+ G_UNLOCK (fen_lock);
+ return result;
}
-#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;
+ result = node_class_init();
+
+ if (!result) {
+ G_UNLOCK (fen_lock);
+ return result;
}
-#endif
+
+ initialized = TRUE;
+
+ G_UNLOCK (fen_lock);
+ return result;
}
+
diff --git a/gio/fen/fen-helper.h b/gio/fen/fen-helper.h
index 330d007..25df38f 100644
--- a/gio/fen/fen-helper.h
+++ b/gio/fen/fen-helper.h
@@ -1,8 +1,8 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim:set expandtab ts=4 shiftwidth=4: */
/*
- * Copyright (C) 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
+ * reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -22,15 +22,12 @@
* 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);
+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 ();
+gboolean fen_init ();
#endif /* _FEN_HELPER_H_ */
diff --git a/gio/fen/fen-kernel.c b/gio/fen/fen-kernel.c
index 1747d8f..64ec910 100644
--- a/gio/fen/fen-kernel.c
+++ b/gio/fen/fen-kernel.c
@@ -1,8 +1,8 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim:set expandtab ts=4 shiftwidth=4: */
/*
- * Copyright (C) 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
+ * reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -25,7 +25,6 @@
#include "config.h"
#include <rctl.h>
#include <strings.h>
-#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -34,7 +33,7 @@
#include "fen-dump.h"
#ifdef GIO_COMPILATION
-#define FK_W if (fk_debug_enabled) g_warning
+#define FK_W if (fk_debug_enabled) g_debug
static gboolean fk_debug_enabled = FALSE;
#else
#include "gam_error.h"
@@ -42,396 +41,345 @@ static gboolean fk_debug_enabled = FALSE;
#endif
G_GNUC_INTERNAL G_LOCK_DEFINE (fen_lock);
-#define PE_ALLOC 64
-#define F_PORT(pfo) (((_f *)(pfo))->port->port)
-#define F_NAME(pfo) (((_f *)(pfo))->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 GList *pn_visible_list; /* the queue of ports which don't 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 timespec_t zero_wait;
+static void (*user_process_events_cb) (gpointer, node_event_t*);
+static port_event_t *pevents = NULL;
+static gint PE_ALLOC = 2048;
+static GHashTable *renamed_hash = NULL; /* <parent node, ev> */
+
+typedef struct _PSource {
+ GSource source; /* Inherit from GSource, must be the first. */
+ GPollFD gfd;
+ gboolean pending;
+ uint_t event_growing_factor;
+ uint_t pending_events;
+} PSource;
+
+#define PGPFD(s) (&((PSource *)(s))->gfd)
+#define SLEEP_BASE_TIME 10 /* in milliseconds */
+#define EXPECT_INC_EVENTS(pn) (1 << (pn->event_growing_factor))
+
+#define RENAME_EVENTS_INTERVAL 500 /* in milliseconds */
+#define PROCESS_PORT_EVENTS_TIME 1000 /* in milliseconds */
+guint process_port_event_id = 0;
+
+static gchar* _event_strings(int event);
+static const gchar* _event_string (int event);
+static GSource *psource_new();
+
+static gboolean port_prepare(GSource *source, gint *timeout_);
+static gboolean port_check(GSource *source);
+static gboolean port_dispatch(GSource *source, GSourceFunc callback, gpointer user_data);
+static GSourceFuncs fen_source_func = {
+ port_prepare,
+ port_check,
+ port_dispatch,
+ NULL
+};
-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)
+static gboolean
+port_prepare(GSource *source, gint *timeout_)
{
- _f* fo = g_hash_table_lookup (_obj_fen_hash, f);
-
- if (fo) {
- return fo->is_active;
- }
return FALSE;
}
-static gchar*
-printevent (const char *pname, int event, const char *tag)
-{
- static gchar *event_string = NULL;
- GString *str;
-
- if (event_string) {
- g_free(event_string);
- }
-
- 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");
- }
- event_string = str->str;
- g_string_free (str, FALSE);
- return event_string;
-}
-
-static void
-port_add_kevent (int e, gpointer f)
+static gboolean
+port_check(GSource *source)
{
- fnode_event_t *ev, *tail;
- GTimeVal t;
- gboolean has_twin = FALSE;
+ PSource *pn = (PSource *)source;
+ uint_t nget;
- /*
- * 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;
+ if (pn->pending) {
+ pn->pending = FALSE;
+ g_source_add_poll(source, PGPFD(source));
+ g_source_unref(source);
+ return FALSE;
}
- 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 (!(PGPFD(pn)->revents & G_IO_IN))
+ return FALSE;
+
+ if (port_getn(PGPFD(source)->fd, NULL, 0, &nget, 0) == 0) {
+ if (nget - pn->pending_events > EXPECT_INC_EVENTS(pn)) {
+ /* Sleep for a while. */
+ pn->pending_events = nget;
+ pn->event_growing_factor ++;
+
+ pn->pending = TRUE;
+ g_source_ref(source);
+ g_source_remove_poll(source, PGPFD(source));
+ g_timeout_add(SLEEP_BASE_TIME,
+ (GSourceFunc)port_check,
+ (gpointer)pn);
+ return FALSE;
}
}
-
- 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);
- }
+ pn->pending_events = 0;
+ pn->event_growing_factor = 0;
+
+ return TRUE;
}
static gboolean
-port_fetch_event_cb (void *arg)
+port_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
{
- pnode_t *pn = (pnode_t *)arg;
- _f* fo;
+ node_t *f;
uint_t nget = 0;
- port_event_t pe[PE_ALLOC];
- timespec_t timeout;
- gpointer f;
- gboolean ret = TRUE;
-
- /* FK_W ("IN <======== %s\n", __func__); */
+ uint_t total = 0;
+
+ FK_W ("%s 0x%p fd %d\n", __func__, source, PGPFD(source)->fd);
+
G_LOCK (fen_lock);
-
- memset (&timeout, 0, sizeof (timespec_t));
do {
nget = 1;
- if (port_getn (pn->port, pe, PE_ALLOC, &nget, &timeout) == 0) {
+ if (port_getn(PGPFD(source)->fd, pevents, PE_ALLOC, &nget, &zero_wait) == 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) {
- FK_W("%s\n",
- 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);
+ f = (node_t *)pevents[i].portev_user;
+
+ if (pevents[i].portev_source == PORT_SOURCE_FILE) {
+
+ NODE_CLE_STATE(f, NODE_STATE_ASSOCIATED);
+ NODE_SET_STATE(f, NODE_STATE_HAS_EVENTS);
+
+ if (HAS_NO_EXCEPTION_EVENTS(pevents[i].portev_events)) {
+ /* If the events do not show it's deleted, update
+ * file timestamp to avoid missing events next time.
+ */
+ if (node_lstat(f) != 0 /* || port_add(f) != 0 */) {
+ /* Included deleted event. */
+ pevents[i].portev_events |= FILE_DELETE;
+ }
}
- break;
- default:
- /* case PORT_SOURCE_TIMER: */
- FK_W ("[kernel] unknown portev_source %d\n", pe[i].portev_source);
+
+ /* Queue it and waiting for processing. */
+ g_queue_push_tail(g_eventq,
+ node_event_new(pevents[i].portev_events, (gpointer)f));
+
+ } else {
+ FK_W ("[kernel] unknown portev_source %d\n", pevents[i].portev_source);
}
}
+
+ total += nget;
+
} else {
FK_W ("[kernel] port_getn %s\n", g_strerror (errno));
- nget = 0;
+ break;
}
} while (nget == PE_ALLOC);
+ G_UNLOCK (fen_lock);
+
+ if (total > 0 && callback) {
+ FK_W ("[kernel] get total %ld events\n", total);
+ return callback (user_data);
+ }
+ return TRUE;
+}
+
+static gboolean
+process_renamed_hash_cb(gpointer key, gpointer value, gpointer user_data)
+{
+ node_event_t *ev = value;
+
+#if 0
+ node_add_event(ev->user_data, ev);
+#else
+ user_process_events_cb(ev->user_data, ev);
+#endif
+ /* Always delete self from hash. */
+ return TRUE;
+}
+
+static gboolean
+port_events_process_cb(gpointer user_data)
+{
+ node_event_t *ev;
+
+ G_LOCK (fen_lock);
+
/* Processing g_eventq */
- port_process_kevents ();
+ while ((ev = (node_event_t*)g_queue_pop_head (g_eventq)) != NULL) {
+
+ /* FK_W ("[%s] 0x%p %s\n", __func__, ev, _event_string (ev->e)); */
+
+ {
+ gchar *log = _event_strings(ev->e);
+ FK_W ("%s %s %s\n", __func__, NODE_NAME(ev->user_data), log);
+ g_free(log);
+ }
+
+#ifdef GIO_COMPILATION
+ /* Use the parent node as a hash, because only the dir_subs in the
+ * parent node should receive MOVE event.
+ */
+ if (NODE_PARENT(ev->user_data)) {
+ if (ev->e == FILE_RENAME_TO) {
+ g_hash_table_insert(renamed_hash, NODE_PARENT(ev->user_data), ev);
+ g_time_val_add(&ev->rename_tv, RENAME_EVENTS_INTERVAL);
+ continue;
+ }
+ if (ev->e == FILE_RENAME_FROM) {
+ node_event_t *pair_ev;
+
+ pair_ev = g_hash_table_lookup(renamed_hash, NODE_PARENT(ev->user_data));
+ if (pair_ev && node_timeval_lt(&ev->ctv, &pair_ev->rename_tv)) {
+ g_hash_table_remove(renamed_hash, NODE_PARENT(ev->user_data));
+ pair_ev->pair_data = ev->user_data;
+ /* Free ev, exchange pair_ev and ev. */
+ node_event_delete(ev);
+ ev = pair_ev;
+ }
+ }
+ }
+#endif
- if (pn->ref == 0) {
- pn->port_source_id = 0;
- ret = FALSE;
+#if 0
+ node_add_event(ev->user_data, ev);
+#else
+ user_process_events_cb(ev->user_data, ev);
+#endif
}
+
+ /* Processing the events in renamed_hash. TODO we should delay it and wait
+ * for more possible pair.
+ */
+ g_hash_table_foreach_remove(renamed_hash, process_renamed_hash_cb, NULL);
+
G_UNLOCK (fen_lock);
- /* FK_W ("OUT ========> %s\n", __func__); */
- return ret;
+
+ process_port_event_id = 0;
+ return FALSE;
}
-/*
- * ref - 1 if remove a watching file succeeded.
- */
-static void
-pnode_delete (pnode_t *pn)
+static gboolean
+port_events_read_cb(gpointer user_data)
{
- 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);
+
+ if (process_port_event_id == 0) {
+ process_port_event_id = g_timeout_add(PROCESS_PORT_EVENTS_TIME,
+ port_events_process_cb,
+ NULL);
+ }
+
+ return TRUE;
}
/*
- * 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
+ * malloc PSource and port_create, start thread at pnode_ref.
+ * if psource_new succeeded, the PSource will never
+ * be freed. So PSource can be freed only in psource_new.
+ * Note pnode_monitor_remove_all can also free PSource, but currently no one
* invork it.
*/
-static pnode_t *
-pnode_new ()
+static GSource*
+psource_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);
- }
- }
+ GSource *source = NULL;
+ int fd;
+
+ if ((fd = port_create()) >= 0) {
+ source = g_source_new(&fen_source_func, sizeof(PSource));
+ PGPFD(source)->fd = fd;
+ PGPFD(source)->events = G_IO_IN | G_IO_HUP | G_IO_ERR;
+ g_source_set_callback(source, port_events_read_cb, NULL, NULL);
+ g_source_attach(source, NULL);
+ g_source_unref(source);
+ g_source_add_poll(source, PGPFD(source));
+
+ FK_W ("%s 0x%p fd %d\n", __func__, source, PGPFD(source)->fd);
+ } else {
+ FK_W ("PORT_CREATE %s\n", g_strerror(errno));
+ g_return_val_if_reached(NULL);
+ }
- return pn;
+ return source;
}
-/*
- * port_add_internal
+/**
+ * port_add:
+ * @f:
*
- * < private >
* Unsafe, need lock fen_lock.
+ * port_add will associate a GSource to @f->source
*/
-static gboolean
-port_add_internal (file_obj_t* fobj, off_t* len,
- gpointer f, gboolean need_stat)
+gint
+port_add(node_t *f)
{
- 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);
- }
+ GSource *source = f->source;
- if (fo->is_active) {
- return TRUE;
- }
+ FK_W ("%s [0x%p] %s\n", __func__, f, NODE_NAME(f));
- 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(f);
+ g_assert(NODE_HAS_FLAG(f, NODE_FLAG_STAT_UPDATED));
+
+ /* if (!NODE_HAS_FLAG(f, NODE_FLAG_STAT_DONE)) { */
+ /* if (NODE_STAT(f) != 0) { */
+ /* return errno; */
+ /* } */
+ /* } */
+
+ /* Try re-use f->pn. f->pn may be used by other request, e.g. f is deleted
+ * for a long time. So if pn is full, we try to open a new one.
+ */
+ if (!source) {
+start_over:
+ /* Try the next visible source. */
+ if (pn_visible_list) {
+ source = (GSource *)pn_visible_list->data;
+ } else {
+ if ((source = psource_new()) != NULL) {
+ g_assert (g_list_find (pn_visible_list, source) == NULL);
+ pn_visible_list = g_list_prepend (pn_visible_list, source);
+ }
}
- 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;
+
+ if (port_associate(PGPFD(source)->fd, PORT_SOURCE_FILE, (uintptr_t)FILE_OBJECT(f),
+ CONCERNED_EVENTS,
+ (void *)f) == 0) {
+ f->source = source;
+ NODE_SET_STATE(f, NODE_STATE_ASSOCIATED);
+ NODE_CLE_FLAG(f, NODE_FLAG_STAT_UPDATED);
+ FK_W ("PORT_ASSOCIATE 0x%p OK\n", f);
+ return 0;
+ } else if (errno == EAGAIN) {
+ /* Full, remove it. */
+ pn_visible_list = g_list_remove (pn_visible_list, source);
+ /* Re-add to port */
+ goto start_over;
+
+ } else if (errno == ENOENT) {
+ /* File is not exist */
} 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);
+ FK_W ("PORT_ASSOCIATE 0x%p %s\n", f, g_strerror (errno));
}
- return FALSE;
-}
-gboolean
-_port_add (file_obj_t* fobj, off_t* len, gpointer f)
-{
- return port_add_internal (fobj, len, f, TRUE);
+ /* No matter if associated successfully, stat info is out-of-date, so clean it. */
+ NODE_CLE_FLAG(f, NODE_FLAG_STAT_UPDATED);
+ return errno;
}
-gboolean
-_port_add_simple (file_obj_t* fobj, gpointer f)
-{
- return port_add_internal (fobj, NULL, f, FALSE);
-}
-
-/*
- * port_remove:
+/**
+ * port_remove
*
* < private >
* Unsafe, need lock fen_lock.
*/
void
-_port_remove (gpointer f)
+port_remove (node_t *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) {
+ /* g_assert(f->source); */
+
+ if (NODE_HAS_STATE(f, NODE_STATE_ASSOCIATED)) {
+ /* Mark unregisted. */
+ if (port_dissociate(PGPFD(f->source)->fd, PORT_SOURCE_FILE, (uintptr_t)FILE_OBJECT(f)) == 0) {
/*
* Note, we can run foode_delete if dissociating is failed,
* because there may be some pending events (mostly like
@@ -439,50 +387,29 @@ _port_remove (gpointer f)
* 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);
+ NODE_CLE_STATE(f, NODE_STATE_ASSOCIATED);
+ FK_W ("PORT_DISSOCIATE 0x%p OK\n", f);
+ } else if (errno == ENOENT) {
+ /* The file has been removed from port, after port_get or before
+ * port_get but DELETED event has been generated.
+ * Ignored. */
} else {
- FK_W ("PORT_DISSOCIATE [%-20s] %s\n", F_NAME(fo), g_strerror (errno));
+ FK_W ("PORT_DISSOCIATE 0x%p %s\n", f, g_strerror (errno));
+ g_return_if_reached();
}
}
}
-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*))
+port_class_init (void (*user_process_events_callback) (gpointer, node_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;
@@ -493,42 +420,130 @@ _port_class_init (void (*user_add_event) (gpointer, fnode_event_t*))
return FALSE;
} else {
max_port_events = rctlblk_get_value(rblk);
- FK_W ("[kernel] max_port_events = %u\n", max_port_events);
+ FK_W ("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");
+ renamed_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, NULL);
+ if (renamed_hash == NULL) {
+ FK_W ("[kernel] FEN global renamed queue initializing faild\n");
return FALSE;
}
if ((g_eventq = g_queue_new ()) == NULL) {
FK_W ("[kernel] FEN global event queue initializing faild\n");
+ return FALSE;
+ }
+ if (user_process_events_callback == NULL) {
+ FK_W ("[kernel] FEN global no user_process_events_callback\n");
+ return FALSE;
}
- if (user_add_event == NULL) {
+ user_process_events_cb = user_process_events_callback;
+ memset (&zero_wait, 0, sizeof (timespec_t));
+
+ pevents = g_malloc(PE_ALLOC * sizeof(port_event_t));
+ if (pevents == NULL) {
+ FK_W ("[kernel] FEN global alloc pevents failed\n");
return FALSE;
}
- add_event_cb = user_add_event;
+
return TRUE;
}
-fnode_event_t*
-_fnode_event_new (int event, gboolean has_twin, gpointer user_data)
+static gchar*
+printevent (const char *pname, int event, const char *tag)
{
- 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;
+ static gchar *event_string = NULL;
+ GString *str;
+
+ if (event_string) {
+ g_free(event_string);
}
- return ev;
+
+ 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");
+ }
+ event_string = str->str;
+ g_string_free (str, FALSE);
+ return event_string;
}
-void
-_fnode_event_delete (fnode_event_t* ev)
+static gchar *
+_event_strings(int event)
+{
+ GString *str = g_string_sized_new(80);
+
+ if (event & FILE_DELETE)
+ g_string_append(str, " FILE_DELETE");
+
+ if (event & FILE_RENAME_FROM)
+ g_string_append(str, " FILE_RENAME_FROM");
+
+ if (event & FILE_MODIFIED)
+ g_string_append(str, " FILE_MODIFIED");
+
+ if (event & FILE_RENAME_TO)
+ g_string_append(str, " FILE_RENAME_TO");
+
+ if (event & MOUNTEDOVER)
+ g_string_append(str, " MOUNTEDOVER");
+
+ if (event & FILE_ATTRIB)
+ g_string_append(str, " FILE_ATTRIB");
+
+ if (event & UNMOUNTED)
+ g_string_append(str, " UNMOUNTED");
+
+ if (event & FILE_ACCESS)
+ g_string_append(str, " FILE_ACCESS");
+
+ return g_string_free(str, FALSE);
+}
+
+static const gchar *
+_event_string (int event)
{
- g_free (ev);
+ 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";
+ }
}
+
diff --git a/gio/fen/fen-kernel.h b/gio/fen/fen-kernel.h
index af1ab5c..6d2c49b 100644
--- a/gio/fen/fen-kernel.h
+++ b/gio/fen/fen-kernel.h
@@ -1,8 +1,8 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim:set expandtab ts=4 shiftwidth=4: */
/*
- * Copyright (C) 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
+ * reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -22,33 +22,22 @@
* Authors: Lin Ma <lin ma sun com>
*/
-#include <port.h>
#include <sys/types.h>
-#include <sys/stat.h>
+#include <errno.h>
+
+#include "fen-node.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);
+#define CONCERNED_EVENTS (FILE_MODIFIED | FILE_ATTRIB | FILE_NOFOLLOW)
+#define EXCEPTION_EVENTS (FILE_DELETE | FILE_RENAME_FROM)
+#define HAS_EXCEPTION_EVENTS(e) ((e & EXCEPTION_EVENTS) != 0)
+#define HAS_NO_EXCEPTION_EVENTS(e) ((e & EXCEPTION_EVENTS) == 0)
-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);
+gint port_add (node_t* f);
+void port_remove (node_t *f);
-extern gboolean _port_class_init ();
+gboolean port_class_init ();
#endif /* _FEN_KERNEL_H_ */
diff --git a/gio/fen/fen-node.c b/gio/fen/fen-node.c
index a8fbf69..7238e36 100644
--- a/gio/fen/fen-node.c
+++ b/gio/fen/fen-node.c
@@ -1,8 +1,8 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim:set expandtab ts=4 shiftwidth=4: */
/*
- * Copyright (C) 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
+ * reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -23,22 +23,24 @@
*/
#include "config.h"
+#include <sys/stat.h>
#include <errno.h>
#include <strings.h>
#include <glib.h>
+#include "fen-kernel.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;
-};
+#ifdef GIO_COMPILATION
+#include "gfilemonitor.h"
+#else
+#include "gam_event.h"
+#include "gam_server.h"
+#include "gam_protocol.h"
+#endif
#ifdef GIO_COMPILATION
-#define FN_W if (fn_debug_enabled) g_warning
+#define FN_W if (fn_debug_enabled) g_debug
static gboolean fn_debug_enabled = FALSE;
#else
#include "gam_error.h"
@@ -46,50 +48,45 @@ static gboolean fn_debug_enabled = FALSE;
#endif
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;
+/* Must continue monitoring if:
+ * 1) I'm subscribed,
+ * 2) The subscribed children (one of the children has subs) are missing,
+ * 3) my parent is subscribed (monitoring directory).
+ */
+#define NODE_NEED_MONITOR(f) \
+ (NODE_IS_ACTIVE(f) || node_children_num(f) > 0 || NODE_IS_REQUIRED_BY_PARENT(f))
+
+static int concern_events[] = {
+ FILE_DELETE,
+ FILE_RENAME_FROM,
+ UNMOUNTED,
+ MOUNTEDOVER,
+#ifdef GIO_COMPILATION
+ FILE_MODIFIED,
+ FILE_ATTRIB,
+#else
+ FILE_MODIFIED | FILE_ATTRIB,
+#endif
+ FILE_RENAME_TO,
+};
+
+node_t *ROOT = NULL;
+static void node_emit_one_event(node_t *f, GList *subs, node_t *other, int event);
+static void node_emit_events(node_t *f, const node_event_t *ne);
+static int node_event_translate(int event, gboolean pair);
+static void node_add_event (node_t *f, node_event_t *ev);
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 node_t* node_get_child (node_t *f, const gchar *basename);
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 gboolean children_remove_cb (gpointer key, gpointer value, gpointer user_data);
+static guint node_children_num (node_t *f);
-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)
+gboolean
+node_timeval_lt(const GTimeVal *val1, const GTimeVal *val2)
{
if (val1->tv_sec < val2->tv_sec)
return TRUE;
@@ -104,85 +101,29 @@ g_timeval_lt (GTimeVal *val1, GTimeVal *val2)
return FALSE;
}
-static gboolean
-scan_deleting_nodes (gpointer data)
+void
+node_traverse (node_t* node, void(*traverse_cb)(node_t*, gpointer), gpointer user_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);
- }
- }
+ GHashTableIter iter;
+ gpointer value;
- 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);
+ g_assert(traverse_cb);
+ if (node == NULL) {
+ node = ROOT;
}
- 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);
- }
+ traverse_cb(node, 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);
+
+ g_hash_table_iter_init (&iter, node->children);
+ while (g_hash_table_iter_next (&iter, NULL, &value)) {
+ node_traverse((node_t *)value, traverse_cb, user_data);
}
}
-static node_t*
-find_node_internal (node_t* node, const gchar* filename, node_op_t* op)
+node_t*
+node_find(node_t* node, const gchar* filename, gboolean create_on_missing)
{
gchar* str;
gchar* token;
@@ -191,166 +132,184 @@ find_node_internal (node_t* node, const gchar* filename, node_op_t* op)
node_t* child;
g_assert (filename && filename[0] == '/');
- g_assert (node);
+
+ if (node == NULL) {
+ node = ROOT;
+ }
- parent = node;
- str = g_strdup (filename + strlen (NODE_NAME(parent)));
+ FN_W ("%s %s\n", __func__, filename);
+
+ parent = child = node;
+ str = g_strdup (filename);
- 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);
+ for (token = strtok_r (str, G_DIR_SEPARATOR_S, &lasts);
+ token != NULL && child != NULL;
+ token = strtok_r (NULL, G_DIR_SEPARATOR_S, &lasts)) {
+ FN_W ("%s %s + %s\n", __func__, NODE_NAME(parent), token);
+ child = node_get_child(parent, token);
+ if (child) {
+ parent = child;
+ } else if (create_on_missing) {
+ child = node_new (parent, token);
if (child) {
+ children_add (parent, child);
parent = child;
+ continue;
} else {
- if (op && op->add_missing) {
- child = op->add_missing (parent, op->user_data);
- goto L_hit;
- }
- break;
+ FN_W ("%s create %s failed", __func__, token);
}
- } 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);
+ } else {
+ break;
}
}
+
g_free (str);
return child;
}
node_t*
-_find_node (const gchar *filename)
+node_find_accessible_ancestor(node_t* node)
{
- 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);
+ for (node = NODE_PARENT(node); node != ROOT; node = NODE_PARENT(node)) {
+ if (NODE_HAS_STATE(node, NODE_STATE_ASSOCIATED) || node_lstat(node) == 0) {
+ return node;
+ }
+ /* else it isn't existing or not accessible */
+ }
+ g_assert(node);
+ return node;
}
-node_t*
-_add_node (node_t* parent, const gchar* filename)
+gint
+node_lstat(node_t *f)
{
- 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;
+ struct stat buf;
+
+ g_assert(!NODE_HAS_STATE(f, NODE_STATE_ASSOCIATED));
+
+ if (lstat(NODE_NAME(f), &buf) == 0) {
+ FN_W ("%s %s\n", __func__, NODE_NAME(f));
+ FILE_OBJECT(f)->fo_atime = buf.st_atim;
+ FILE_OBJECT(f)->fo_mtime = buf.st_mtim;
+ FILE_OBJECT(f)->fo_ctime = buf.st_ctim;
+ NODE_SET_FLAG(f, NODE_FLAG_STAT_UPDATED |
+ (S_ISDIR (buf.st_mode) ? NODE_FLAG_DIR : NODE_FLAG_NONE));
+ return 0;
} else {
- return NULL;
+ FN_W ("%s(lstat) %s %s\n", __func__, NODE_NAME(f), g_strerror (errno));
}
+ return errno;
}
-/*
- * delete recursively
- */
-static gboolean
-remove_children (node_t* node, node_op_t* op)
+void
+node_create_children_snapshot(node_t *f, gint created_event, gboolean emit)
{
- 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;
-}
+ GDir *dir;
+ GError *err = NULL;
+
+ FN_W ("%s %s [0x%p]\n", __func__, NODE_NAME(f), f);
+
+ dir = g_dir_open (NODE_NAME(f), 0, &err);
+ if (dir) {
+ const char *basename;
+ node_t *child = NULL;
+
+ while ((basename = g_dir_read_name (dir))) {
+ node_t* data;
+ GList *idx;
+
+ child = node_get_child (f, basename);
+ if (child == NULL) {
+ gchar *filename;
+
+ child = node_new (f, basename);
+ children_add (f, child);
+ }
-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;
+ if (f->dir_subs) {
+ /* We need monitor the new children, or the existed child which
+ * is in the DELETED mode.
+ */
+ if (!NODE_HAS_STATE(child, NODE_STATE_ASSOCIATED) &&
+ node_lstat(child) == 0 && port_add(child) == 0) {
+ if (emit) {
+ /* Emit the whatever event for the new found file. */
+ node_emit_one_event(child, child->dir_subs, NULL, created_event);
+ node_emit_one_event(child, child->subs, NULL, created_event);
+ node_emit_one_event(child, f->dir_subs, NULL, created_event);
+ node_emit_one_event(child, f->subs, NULL, created_event);
+ }
}
+ /* else ignore, because it may be deleted. */
}
- parent = node->parent;
- children_remove (parent, node);
- node_delete (node);
- if (_children_num (parent) == 0) {
- remove_node_internal (parent, op);
- }
- return TRUE;
}
- return FALSE;
+ g_dir_close (dir);
+
+ /* We have finished children snapshot. Any other new added subs should
+ * directory iterate the snapshot instead of scan directory again.
+ */
+ NODE_SET_FLAG(f, NODE_FLAG_SNAPSHOT_UPDATED);
+
+ } else {
+ FN_W (err->message);
+ g_error_free (err);
}
- return TRUE;
}
-void
-_pending_remove_node (node_t* node, node_op_t* op)
+/**
+ * If all active children nodes are ported, then cancel monitor the parent
+ * node. If we know how many children are created, then we can stop accordingly.
+ *
+ * Unsafe, need lock.
+ */
+static void
+foreach_known_children_scan(gpointer key, gpointer value, gpointer user_data)
{
- struct _dnode* d;
- GList* l;
+ node_t* f = (node_t*)value;
- for (l = deleting_nodes; l; l=l->next) {
- d = (struct _dnode*) l->data;
- if (g_ascii_strcasecmp (d->filename, NODE_NAME(node)) == 0) {
- return;
+ FN_W ("%s 0x%p %s\n", __func__, f, NODE_NAME(f));
+
+ if (!NODE_HAS_STATE(f, NODE_STATE_ASSOCIATED)) {
+ if (node_lstat(f) == 0 && port_add(f) == 0) {
+ node_emit_one_event(f, f->dir_subs, NULL, FN_EVENT_CREATED);
+ node_emit_one_event(f, f->subs, NULL, FN_EVENT_CREATED);
+ if (NODE_PARENT(f)) {
+ node_emit_one_event(f, NODE_PARENT(f)->dir_subs, NULL, FN_EVENT_CREATED);
+ node_emit_one_event(f, NODE_PARENT(f)->subs, NULL, FN_EVENT_CREATED);
+ }
}
}
-
- 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)
+gboolean
+node_try_delete(node_t* node)
{
- remove_node_internal (node, op);
+ g_assert (node);
+
+ FN_W ("%s 0x%p %s\n", __func__, node, NODE_NAME(node));
+
+ /* Try clean children */
+ if (node_children_num (node) > 0) {
+ g_hash_table_foreach_remove(node->children, children_remove_cb, NULL);
+ }
+ if (!NODE_NEED_MONITOR(node)) {
+ /* Clean some flags. */
+ /* NODE_CLE_FLAG(node, NODE_FLAG_HAS_SNAPSHOT | NODE_FLAG_STAT_DONE); */
+ node->flag = 0;
+
+ /* Now we handle the state. */
+ if (NODE_HAS_STATE(node, NODE_STATE_ASSOCIATED)) {
+ port_remove(node);
+ }
+ /* Actually ignore the ROOT node. */
+ if (node->state == 0 && NODE_PARENT(node)) {
+ children_remove(NODE_PARENT(node), node);
+ /* Do clean instead of returning TRUE. */
+ node_delete (node);
+ }
+ /* else, we have events, clean event queue? */
+ }
+ return FALSE;
}
static node_t*
@@ -359,18 +318,22 @@ 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 ((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);
+ NODE_NAME(f) = g_build_filename(NODE_NAME(parent), basename, NULL);
} else {
- f->basename = g_strdup (basename);
- f->filename = g_strdup (basename);
+ NODE_NAME(f) = g_strdup(G_DIR_SEPARATOR_S);
}
+ f->basename = g_strdup (basename);
+ /* f->children = g_hash_table_new_full (g_str_hash, g_str_equal, */
+ /* NULL, (GDestroyNotify)node_delete); */
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));
+ NULL, NULL);
+#ifdef GIO_COMPILATION
+ f->gfile = g_file_new_for_path (NODE_NAME(f));
+#endif
+ FN_W ("%s 0x%p %s\n", __func__, f, NODE_NAME(f));
}
return f;
}
@@ -378,89 +341,300 @@ node_new (node_t* parent, const gchar* basename)
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);
+ FN_W ("%s 0x%p %s\n", __func__, f, NODE_NAME(f));
+ g_assert(f->state == 0);
+ g_assert(!NODE_IS_ACTIVE(f));
+ g_assert(g_hash_table_size (f->children) == 0);
+ g_assert(NODE_PARENT(f) == NULL);
+ g_hash_table_unref(f->children);
+#ifdef GIO_COMPILATION
+ g_object_unref (f->gfile);
+#endif
+ g_free(f->basename);
+ g_free(NODE_NAME(f));
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);
+ FN_W ("%s %s %s\n", __func__, NODE_NAME(p), f->basename);
g_hash_table_insert (p->children, f->basename, f);
- f->parent = p;
+ NODE_PARENT(f) = p;
}
static void
children_remove (node_t *p, node_t *f)
{
- FN_W ("%s [p] %8s [c] %8s\n", __func__, p->basename, f->basename);
+ FN_W ("%s %s %s\n", __func__, NODE_NAME(p), f->basename);
g_hash_table_steal (p->children, f->basename);
- f->parent = NULL;
+ NODE_PARENT(f) = NULL;
}
-guint
-_children_num (node_t *f)
+static node_t *
+node_get_child (node_t *f, const gchar *basename)
{
- return g_hash_table_size (f->children);
+ if (f->children) {
+ return (node_t *) g_hash_table_lookup (f->children, (gpointer)basename);
+ }
+ return NULL;
}
-node_t *
-_children_find (node_t *f, const gchar *basename)
+static guint
+node_children_num (node_t *f)
{
- return (node_t *) g_hash_table_lookup (f->children, (gpointer)basename);
+ return g_hash_table_size (f->children);
}
-/*
+/**
* depth first delete recursively
*/
static gboolean
-children_remove_cb (gpointer key,
- gpointer value,
- gpointer user_data)
+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);
+ return node_try_delete ((node_t*)value);
+}
- 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);
+gboolean
+node_class_init()
+{
+ ROOT = node_new (NULL, G_DIR_SEPARATOR_S);
+ if (ROOT == NULL) {
+ FN_W ("[node] Create ROOT node failed.\n");
+ return FALSE;
+ }
+
+ return port_class_init (node_add_event);
+}
+
+/**
+ * Adjust self on failing to Port
+ */
+void
+node_adjust_deleted(node_t* f)
+{
+ node_t *ancestor;
+
+ FN_W ("%s %s\n", __func__, NODE_NAME(f));
+
+ for (ancestor = node_find_accessible_ancestor(f);
+ !NODE_HAS_STATE(ancestor, NODE_STATE_ASSOCIATED) && port_add(ancestor) != 0;
+ ancestor = node_find_accessible_ancestor(ancestor)) { /* Empty */ }
+}
+
+
+static void
+node_emit_events(node_t *f, const node_event_t *ne)
+{
+ gsize num = sizeof(concern_events)/sizeof(int);
+ gint i;
+ int translated_e;
+ node_t *p;
+
+ if (node_timeval_lt(&f->atv, &ne->ctv)) {
+ int event = ne->e;
+
+ /* Emit DELETED on the pair_data */
+ if (ne->pair_data) {
+ node_t *from = ne->pair_data;
+ node_emit_one_event(from, from->dir_subs, NULL, node_event_translate(FILE_DELETE, FALSE));
+ node_emit_one_event(from, from->subs, NULL, node_event_translate(FILE_DELETE, FALSE));
+ }
+
+ for (i = 0; i < num; i++) {
+ if (event & concern_events[i]) {
+ translated_e = node_event_translate(concern_events[i], FALSE);
+ /* Neither GIO or gamin cares about modified events on a
+ * directory.
+ */
+#ifdef GIO_COMPILATION
+ if ((concern_events[i] & FILE_MODIFIED) == 0) {
+ node_emit_one_event(f, f->dir_subs, NULL, translated_e);
+ }
+#else
+ /* Gamin doesn't care about attrib changed events on a directory
+ * either.
+ */
+ if ((concern_events[i] & (FILE_MODIFIED | FILE_ATTRIB)) == 0) {
+ node_emit_one_event(f, f->dir_subs, NULL, translated_e);
+ }
+#endif
+ node_emit_one_event(f, f->subs, NULL, translated_e);
+ }
+ event &= ~concern_events[i];
+ }
+ }
+
+ p = NODE_PARENT(f);
+ if (p != NULL && node_timeval_lt(&p->atv, &ne->ctv)) {
+ int event = ne->e;
+ for (i = 0; i < num; i++) {
+ if (event & concern_events[i]) {
+ translated_e = node_event_translate(concern_events[i], ne->pair_data != NULL);
+ node_emit_one_event(f, p->dir_subs, ne->pair_data, translated_e);
+ node_emit_one_event(f, p->subs, ne->pair_data, translated_e);
+ }
+ event &= ~concern_events[i];
}
- return TRUE;
}
- return FALSE;
}
-static guint
-children_foreach_remove (node_t *f, GHRFunc func, gpointer user_data)
+/**
+ * node_add_event:
+ *
+ */
+static void
+node_add_event (node_t *f, node_event_t *ev)
{
- g_assert (f);
-
- return g_hash_table_foreach_remove (f->children, func, user_data);
+ FN_W ("%s %d\n", __func__, ev->e);
+
+ /* Clean the events flag early, because all received events need be
+ * processed in this function.
+ */
+ NODE_CLE_STATE(f, NODE_STATE_HAS_EVENTS);
+
+ /*
+ * 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.
+ */
+ if (NODE_NEED_MONITOR(f)) {
+ if (HAS_NO_EXCEPTION_EVENTS(ev->e)) {
+ if (NODE_HAS_STATE(f, NODE_STATE_ASSOCIATED) || port_add(f) == 0) {
+ if ((ev->e & FILE_MODIFIED) && NODE_HAS_FLAG(f, NODE_FLAG_DIR)) {
+ if (f->dir_subs) {
+ node_create_children_snapshot(f, FN_EVENT_CREATED, TRUE);
+ } else {
+ g_hash_table_foreach(f->children, foreach_known_children_scan, NULL);
+ }
+ }
+ } else {
+ /* Emit delete event */
+ ev->e |= FILE_DELETE;
+
+ node_adjust_deleted(f);
+ }
+
+ } else {
+ node_adjust_deleted(f);
+ }
+
+ /* Send events to clients. */
+ node_emit_events (f, ev);
+
+ } else {
+ /* Send events to clients. */
+ node_emit_events (f, ev);
+
+ node_try_delete(f);
+ }
+
+ if (ev->pair_data) {
+ node_t *from = ev->pair_data;
+ g_assert(ev->e == FILE_RENAME_TO);
+
+ if (NODE_NEED_MONITOR(from)) {
+ /* Clean the events flag, since it may block free this node. */
+ NODE_CLE_STATE(from, NODE_STATE_HAS_EVENTS);
+ node_adjust_deleted(from);
+ } else {
+ node_try_delete(from);
+ }
+ }
+
+ node_event_delete (ev);
}
static void
-children_foreach (node_t *f, GHFunc func, gpointer user_data)
+node_emit_one_event(node_t *f, GList *subs, node_t *other, int event)
{
- g_assert (f);
+ GList* idx;
- g_hash_table_foreach (f->children, func, user_data);
+ FN_W ("%s %s %d\n", __func__, NODE_NAME(f), event);
+
+#ifdef GIO_COMPILATION
+ for (idx = subs; idx; idx = idx->next) {
+ g_file_monitor_emit_event(G_FILE_MONITOR(idx->data), f->gfile,
+ (other == NULL ? NULL : other->gfile), event);
+ }
+#else
+ for (idx = subs; idx; idx = idx->next) {
+ gam_server_emit_one_event(NODE_NAME(f), gam_subscription_is_dir(idx->data), event, idx->data, 1);
+ }
+#endif
}
-gboolean
-_node_class_init ()
+static int
+node_event_translate(int event, gboolean pair)
{
- FN_W ("%s\n", __func__);
- if (_head == NULL) {
- _head = node_new (NULL, G_DIR_SEPARATOR_S);
+#ifdef GIO_COMPILATION
+ switch (event) {
+ 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:
+ return G_FILE_MONITOR_EVENT_CHANGED;
+ case FILE_RENAME_TO:
+ if (pair) {
+ return G_FILE_MONITOR_EVENT_MOVED;
+ } else {
+ return G_FILE_MONITOR_EVENT_CREATED;
+ }
+ default:
+ /* case FILE_ACCESS: */
+ g_assert_not_reached ();
+ return -1;
}
- return _head != NULL;
+#else
+ switch (event) {
+ case FILE_DELETE:
+ case FILE_RENAME_FROM:
+ return GAMIN_EVENT_DELETED;
+ case MOUNTEDOVER:
+ case UNMOUNTED:
+ return GAMIN_EVENT_CHANGED;
+ case FILE_RENAME_TO:
+ if (pair) {
+ return GAMIN_EVENT_MOVED;
+ } else {
+ return GAMIN_EVENT_CREATED;
+ }
+ default:
+ if (event & (FILE_ATTRIB | FILE_MODIFIED)) {
+ return GAMIN_EVENT_CHANGED;
+ }
+ /* case FILE_ACCESS: */
+ g_assert_not_reached ();
+ return -1;
+ }
+#endif
}
+
+node_event_t*
+node_event_new (int event, gpointer user_data)
+{
+ node_event_t *ev;
+
+ if ((ev = g_new (node_event_t, 1)) != NULL) {
+ g_assert (ev);
+ ev->e = event;
+ ev->user_data = user_data;
+ ev->pair_data = NULL; /* For renamed file. */
+ /* Created timestamp */
+ g_get_current_time(&ev->ctv);
+ ev->rename_tv = ev->ctv;
+ }
+ return ev;
+}
+
+void
+node_event_delete (node_event_t* ev)
+{
+ g_free (ev);
+}
+
diff --git a/gio/fen/fen-node.h b/gio/fen/fen-node.h
index f2ef1ea..7e99032 100644
--- a/gio/fen/fen-node.h
+++ b/gio/fen/fen-node.h
@@ -1,8 +1,8 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim:set expandtab ts=4 shiftwidth=4: */
/*
- * Copyright (C) 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
+ * reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -22,52 +22,83 @@
* Authors: Lin Ma <lin ma sun com>
*/
+#include <port.h>
+#include <gio/gio.h>
+
#ifndef _FEN_NODE_H_
#define _FEN_NODE_H_
-typedef struct node node_t;
+#ifdef GIO_COMPILATION
+#define FN_EVENT_CREATED G_FILE_MONITOR_EVENT_CREATED
+#else
+#define FN_EVENT_CREATED GAMIN_EVENT_CREATED
+#endif
+
+#define NODE_STATE_NONE 0x00000000
+#define NODE_STATE_ASSOCIATED 0x00000001 /* This is a confilct to NODE_FLAG_STAT_DONE */
+#define NODE_STATE_HAS_EVENTS 0x00000002
+
+#define NODE_FLAG_NONE 0x00000000
+#define NODE_FLAG_SNAPSHOT_UPDATED 0x00000001
+#define NODE_FLAG_DIR 0x00000002
+#define NODE_FLAG_STAT_UPDATED 0x00000004
+#define NODE_CLE_STATE(f, st) (f->state &= ~(st))
+#define NODE_SET_STATE(f, st) (f->state = ((f->state & ~(st)) | (st)))
+#define NODE_HAS_STATE(f, st) (f->state & (st))
+
+#define NODE_CLE_FLAG(f, fl) (f->flag &= ~(fl))
+#define NODE_SET_FLAG(f, fl) (f->flag = ((f->flag & ~(fl)) | (fl)))
+#define NODE_HAS_FLAG(f, fl) (f->flag & (fl))
+
+typedef struct node node_t;
struct node
{
- gchar *filename;
- gchar *basename;
- gint stat;
-
+ file_obj_t fobj; /* Inherit from file_obj_t, must be the first. */
+ GSource *source;
+ gchar *basename;
+ guint32 state;
+ guint32 flag;
+ GTimeVal atv; /* Timestamp for the first added sub. */
+
/* the parent and children of node */
node_t *parent;
GHashTable *children; /* children in basename */
- gpointer user_data;
+ /* List of subscriptions monitoring this fdata/path */
+ GList *subs;
+ GList *dir_subs;
+
+#ifdef GIO_COMPILATION
+ GFile* gfile;
+#endif
};
-#define IS_TOPNODE(fp) (((node_t *)(fp))->parent == NULL)
-#define NODE_NAME(fp) (((node_t *)(fp))->filename)
+#define FILE_OBJECT(f) ((file_obj_t *)(f))
+#define NODE_NAME(f) (FILE_OBJECT(f)->fo_name)
+#define NODE_PARENT(f) (((node_t *)f)->parent)
+#define NODE_IS_ACTIVE(f) (f->dir_subs || f->subs)
+#define NODE_IS_REQUIRED_BY_PARENT(f) (NODE_PARENT(f) && NODE_PARENT(f)->dir_subs)
-typedef struct node_op
+gboolean node_timeval_lt(const GTimeVal *val1, const GTimeVal *val2);
+gboolean node_try_delete(node_t* node);
+void node_traverse(node_t* node, void(*traverse_cb)(node_t*, gpointer), gpointer user_data);
+node_t* node_find(node_t* node, const gchar* filename, gboolean create_on_missing);
+gint node_lstat(node_t *f);
+void node_create_children_snapshot(node_t *f, gint created_event, gboolean emit);
+void node_adjust_deleted(node_t *f);
+gboolean node_class_init();
+
+typedef struct node_event
{
- /* 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 */
+ int e;
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);
+ gpointer pair_data;
+ GTimeVal ctv; /* Created timestamp */
+ GTimeVal rename_tv; /* Possible rename timestamp */
+} node_event_t;
-gboolean _node_class_init ();
+node_event_t* node_event_new (int event, gpointer user_data);
+void node_event_delete (node_event_t* ev);
#endif /* _FEN_NODE_H_ */
diff --git a/gio/fen/gfendirectorymonitor.c b/gio/fen/gfendirectorymonitor.c
index ba79713..3b53a3a 100644
--- a/gio/fen/gfendirectorymonitor.c
+++ b/gio/fen/gfendirectorymonitor.c
@@ -4,8 +4,8 @@
*
* Copyright (C) 2006-2007 Red Hat, Inc.
* Copyright (C) 2007 Sebastian Dröge.
- * Copyright (C) 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
+ * reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -39,9 +39,8 @@
struct _GFenDirectoryMonitor
{
- GLocalDirectoryMonitor parent_instance;
- gboolean cancelled;
- fen_sub* sub;
+ GLocalDirectoryMonitor parent_instance;
+ gboolean enabled;
};
static gboolean g_fen_directory_monitor_cancel (GFileMonitor* monitor);
@@ -56,16 +55,15 @@ G_DEFINE_TYPE_WITH_CODE (GFenDirectoryMonitor, g_fen_directory_monitor, G_TYPE_L
static void
g_fen_directory_monitor_finalize (GObject *object)
{
- GFenDirectoryMonitor *self = G_FEN_DIRECTORY_MONITOR (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 (self->enabled) {
+ fen_remove (G_LOCAL_DIRECTORY_MONITOR (self)->dirname, self, TRUE);
+ self->enabled = FALSE;
}
- if (G_OBJECT_CLASS (g_fen_directory_monitor_parent_class)->finalize)
- (*G_OBJECT_CLASS (g_fen_directory_monitor_parent_class)->finalize) (object);
+ if (G_OBJECT_CLASS (g_fen_directory_monitor_parent_class)->finalize)
+ (*G_OBJECT_CLASS (g_fen_directory_monitor_parent_class)->finalize) (object);
}
static GObject *
@@ -73,57 +71,55 @@ 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;
+ 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,
+ 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);
+ self = G_FEN_DIRECTORY_MONITOR (obj);
- dirname = G_LOCAL_DIRECTORY_MONITOR (self)->dirname;
- g_assert (dirname != NULL);
+ 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 ())
+ /* 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);
+ /* FIXME: what to do about errors here? we can't return NULL or another
+ * kind of error and an assertion is probably too hard */
+ fen_add (dirname, self, TRUE);
+ self->enabled = TRUE;
- return obj;
+ return obj;
}
static gboolean
g_fen_directory_monitor_is_supported (void)
{
- return _fen_init ();
+ 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);
+ 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;
+ 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;
+ local_directory_monitor_class->mount_notify = TRUE;
+ local_directory_monitor_class->is_supported = g_fen_directory_monitor_is_supported;
}
static void
@@ -134,17 +130,16 @@ g_fen_directory_monitor_init (GFenDirectoryMonitor* monitor)
static gboolean
g_fen_directory_monitor_cancel (GFileMonitor* monitor)
{
- GFenDirectoryMonitor *self = G_FEN_DIRECTORY_MONITOR (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 (self->enabled) {
+ fen_remove (G_LOCAL_DIRECTORY_MONITOR (self)->dirname, self, TRUE);
+ self->enabled = FALSE;
}
- if (G_FILE_MONITOR_CLASS (g_fen_directory_monitor_parent_class)->cancel)
- (*G_FILE_MONITOR_CLASS (g_fen_directory_monitor_parent_class)->cancel) (monitor);
+ 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;
+ return TRUE;
}
diff --git a/gio/fen/gfendirectorymonitor.h b/gio/fen/gfendirectorymonitor.h
index c22998c..9359e9f 100644
--- a/gio/fen/gfendirectorymonitor.h
+++ b/gio/fen/gfendirectorymonitor.h
@@ -4,6 +4,8 @@
*
* Copyright (C) 2006-2007 Red Hat, Inc.
* Copyright (C) 2007 Sebastian Dröge.
+ * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
+ * reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -23,6 +25,7 @@
* Authors: Alexander Larsson <alexl redhat com>
* John McCutchan <john johnmccutchan com>
* Sebastian Dröge <slomo circular-chaos org>
+ * Lin Ma <lin ma sun com>
*/
#ifndef __G_FEN_DIRECTORY_MONITOR_H__
diff --git a/gio/fen/gfenfilemonitor.c b/gio/fen/gfenfilemonitor.c
index f075388..de011f0 100644
--- a/gio/fen/gfenfilemonitor.c
+++ b/gio/fen/gfenfilemonitor.c
@@ -4,8 +4,8 @@
*
* Copyright (C) 2006-2007 Red Hat, Inc.
* Copyright (C) 2007 Sebastian Dröge.
- * Copyright (C) 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
+ * reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -40,7 +40,7 @@
struct _GFenFileMonitor
{
GLocalFileMonitor parent_instance;
- fen_sub* sub;
+ gboolean enabled;
};
static gboolean g_fen_file_monitor_cancel (GFileMonitor* monitor);
@@ -55,12 +55,11 @@ G_DEFINE_TYPE_WITH_CODE (GFenFileMonitor, g_fen_file_monitor, G_TYPE_LOCAL_FILE_
static void
g_fen_file_monitor_finalize (GObject *object)
{
- GFenFileMonitor *self = G_FEN_FILE_MONITOR (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 (self->enabled) {
+ fen_remove (G_LOCAL_FILE_MONITOR (self)->filename, self, FALSE);
+ self->enabled = FALSE;
}
if (G_OBJECT_CLASS (g_fen_file_monitor_parent_class)->finalize)
@@ -92,15 +91,13 @@ g_fen_file_monitor_constructor (GType type,
/* Will never fail as is_supported() should be called before instanciating
* anyway */
- if (!_fen_init ())
+ 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);
+ fen_add (filename, self, FALSE);
+ self->enabled = TRUE;
return obj;
}
@@ -108,7 +105,7 @@ g_fen_file_monitor_constructor (GType type,
static gboolean
g_fen_file_monitor_is_supported (void)
{
- return _fen_init ();
+ return fen_init ();
}
static void
@@ -135,10 +132,9 @@ 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 (self->enabled) {
+ fen_remove (G_LOCAL_FILE_MONITOR (self)->filename, self, FALSE);
+ self->enabled = FALSE;
}
if (G_FILE_MONITOR_CLASS (g_fen_file_monitor_parent_class)->cancel)
diff --git a/gio/fen/gfenfilemonitor.h b/gio/fen/gfenfilemonitor.h
index e8b2e6a..e44fd99 100644
--- a/gio/fen/gfenfilemonitor.h
+++ b/gio/fen/gfenfilemonitor.h
@@ -4,6 +4,8 @@
*
* Copyright (C) 2006-2007 Red Hat, Inc.
* Copyright (C) 2007 Sebastian Dröge.
+ * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
+ * reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -23,6 +25,7 @@
* Authors: Alexander Larsson <alexl redhat com>
* John McCutchan <john johnmccutchan com>
* Sebastian Dröge <slomo circular-chaos org>
+ * Lin Ma <lin ma sun com>
*/
#ifndef __G_FEN_FILE_MONITOR_H__
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]