From e5440f865d79795061cf5e64d8ed7300222c4a79 Mon Sep 17 00:00:00 2001 From: Lin Ma Date: Mon, 17 May 2010 14:42:52 +0800 Subject: [PATCH] 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 | 334 ++++--------- gio/fen/fen-helper.h | 13 +- gio/fen/fen-kernel.c | 847 +++++++++++++++++---------------- gio/fen/fen-kernel.h | 35 +- gio/fen/fen-missing.c | 121 ----- gio/fen/fen-missing.h | 38 -- gio/fen/fen-node.c | 812 ++++++++++++++++++------------- 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, 1179 insertions(+), 2192 deletions(-) delete mode 100644 gio/fen/fen-data.c delete mode 100644 gio/fen/fen-data.h delete mode 100644 gio/fen/fen-missing.c delete mode 100644 gio/fen/fen-missing.h delete mode 100644 gio/fen/fen-sub.c delete mode 100644 gio/fen/fen-sub.h diff --git a/gio/fen/Makefile.am b/gio/fen/Makefile.am index 1acaa442e..d96da4517 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-data.c b/gio/fen/fen-data.c deleted file mode 100644 index fed317ffa..000000000 --- a/gio/fen/fen-data.c +++ /dev/null @@ -1,718 +0,0 @@ -/* -*- 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. - * - * 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 - */ - -#include "config.h" -#include -#include -#include -#include -#include -#include -#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 - -#ifdef GIO_COMPILATION -#define FD_W if (fd_debug_enabled) g_warning -static gboolean fd_debug_enabled = FALSE; -#else -#include "gam_error.h" -#define FD_W(...) GAM_DEBUG(DEBUG_INFO, __VA_ARGS__) -#endif - -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: - g_assert (f->change_update_id == 0); - if (!_port_add (&f->fobj, &f->len, f)) { - ev = _fnode_event_new (FILE_DELETE, FALSE, f); - if (ev != NULL) { - _fdata_add_event (f, ev); - } - } - break; - case FILE_DELETE: /* Ignored */ - 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; -} - -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 (ev->e == FILE_MODIFIED && tail->e == FILE_ATTRIB) { - ev->has_twin = TRUE; - _fnode_event_delete (tail); - } else if (ev->e == FILE_ATTRIB && f->change_update_id > 0) { - 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; -} diff --git a/gio/fen/fen-data.h b/gio/fen/fen-data.h deleted file mode 100644 index 67419a249..000000000 --- a/gio/fen/fen-data.h +++ /dev/null @@ -1,89 +0,0 @@ -/* -*- 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. - * - * 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 - */ - -#include -#include -#include -#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_ */ diff --git a/gio/fen/fen-dump.c b/gio/fen/fen-dump.c index d9ac36382..98d20ebbe 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 #include #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) +dump_event (node_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); - } + 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 0e866fa07..ffac822c6 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 c05cb412c..e68e7c32c 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 -#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; - - 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); */ + emit = FALSE; + event = G_FILE_MONITOR_EVENT_CREATED; #else - gam_server_emit_one_event (NODE_NAME(childf), - gam_subscription_is_dir (sub), GAMIN_EVENT_EXISTS, sub, 1); + 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; + +#ifdef GIO_COMPILATION + /* 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(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 ++; + f->dir_subs = g_list_prepend(f->dir_subs, sub); + } else { + f->subs = g_list_prepend(f->subs, sub); } - /* 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), + 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 + if (f) { + if (is_mondir) { + f->dir_subs = g_list_remove(f->dir_subs, sub); + } else { + f->subs = g_list_remove(f->subs, sub); + } + + if (!NODE_IS_ACTIVE(f)) { + node_try_delete (f); + } } 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; -} - +/** + * fen_init: + * + * FEN subsystem initializing. + */ gboolean -_fen_init () +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 gboolean initialized = FALSE; + static gboolean result = FALSE; + + G_LOCK (fen_lock); + if (initialized) { + G_UNLOCK (fen_lock); + return result; + } + + result = node_class_init(); + + if (!result) { + G_UNLOCK (fen_lock); + return result; + } + + initialized = TRUE; + + G_UNLOCK (fen_lock); + return result; } -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 -} diff --git a/gio/fen/fen-helper.h b/gio/fen/fen-helper.h index 330d007f3..25df38fa7 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 */ -#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 1747d8fb6..64ec910db 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 #include -#include #include #include #include @@ -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,50 +41,414 @@ 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; /* */ 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*); +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; /* */ -typedef struct pnode +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_prepare(GSource *source, gint *timeout_) { - 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 gboolean +port_check(GSource *source) +{ + PSource *pn = (PSource *)source; + uint_t nget; + + if (pn->pending) { + pn->pending = FALSE; + g_source_add_poll(source, PGPFD(source)); + g_source_unref(source); + return FALSE; + } + + 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; + } + } + + pn->pending_events = 0; + pn->event_growing_factor = 0; + + return TRUE; +} + +static gboolean +port_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) +{ + node_t *f; + uint_t nget = 0; + uint_t total = 0; + + FK_W ("%s 0x%p fd %d\n", __func__, source, PGPFD(source)->fd); + + G_LOCK (fen_lock); + do { + nget = 1; + if (port_getn(PGPFD(source)->fd, pevents, PE_ALLOC, &nget, &zero_wait) == 0) { + int i; + for (i = 0; i < nget; i++) { + 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; + } + } + + /* 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)); + 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 */ + 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 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); + + process_port_event_id = 0; + return FALSE; +} + +static gboolean +port_events_read_cb(gpointer user_data) +{ + + 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 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 GSource* +psource_new() +{ + 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 source; +} + +/** + * port_add: + * @f: + * + * Unsafe, need lock fen_lock. + * port_add will associate a GSource to @f->source + */ +gint +port_add(node_t *f) +{ + GSource *source = f->source; + + FK_W ("%s [0x%p] %s\n", __func__, f, NODE_NAME(f)); + + 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); + } + } + } + + 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 0x%p %s\n", f, g_strerror (errno)); + } + + /* No matter if associated successfully, stat info is out-of-date, so clean it. */ + NODE_CLE_FLAG(f, NODE_FLAG_STAT_UPDATED); + return errno; +} + +/** + * port_remove + * + * < private > + * Unsafe, need lock fen_lock. + */ +void +port_remove (node_t *f) +{ + /* 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 + * 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. + */ + 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 0x%p %s\n", f, g_strerror (errno)); + g_return_if_reached(); + } + } +} + +/** + * Get Solaris resouce values. + * + */ + +extern gboolean +port_class_init (void (*user_process_events_callback) (gpointer, node_event_t*)) +{ + rctlblk_t *rblk; + + 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 ("max_port_events = %u\n", max_port_events); + free (rblk); + } + 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; + } + 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; + } + + return TRUE; +} + static gchar* printevent (const char *pname, int event, const char *tag) { @@ -127,328 +490,39 @@ printevent (const char *pname, int event, const char *tag) return event_string; } -static void -port_add_kevent (int e, gpointer f) +static gchar * +_event_strings(int event) { - fnode_event_t *ev, *tail; - GTimeVal t; - gboolean has_twin = FALSE; - - /* - * Child FILE_DELETE | FILE_RENAME_FROM will trigger parent FILE_MODIFIED. - * FILE_MODIFIED will trigger FILE_ATTRIB. - */ + GString *str = g_string_sized_new(80); - 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 (event & FILE_DELETE) + g_string_append(str, " FILE_DELETE"); - 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); - } + 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 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) { - 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); - } - 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 * +static const gchar * _event_string (int event) { switch (event) { @@ -473,62 +547,3 @@ _event_string (int event) } } -/* - * 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); -} diff --git a/gio/fen/fen-kernel.h b/gio/fen/fen-kernel.h index af1ab5cb6..6d2c49bce 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 */ -#include #include -#include +#include + +#include "fen-node.h" #ifndef _FEN_KERNEL_H_ #define _FEN_KERNEL_H_ -#define FN_STAT lstat +#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) -typedef struct fnode_event -{ - int e; - gboolean has_twin; - gboolean is_pending; - gpointer user_data; - GTimeVal t; -} fnode_event_t; +gint port_add (node_t* f); +void port_remove (node_t *f); -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 (); +gboolean port_class_init (); #endif /* _FEN_KERNEL_H_ */ diff --git a/gio/fen/fen-missing.c b/gio/fen/fen-missing.c deleted file mode 100644 index 90915873b..000000000 --- a/gio/fen/fen-missing.c +++ /dev/null @@ -1,121 +0,0 @@ -/* -*- 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. - * - * 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 - */ - -#include "config.h" -#include -#include "fen-data.h" -#include "fen-missing.h" - -G_LOCK_EXTERN (fen_lock); -#define SCAN_MISSING_INTERVAL 4000 /* in milliseconds */ - -#ifdef GIO_COMPILATION -#define FM_W if (fm_debug_enabled) g_warning -gboolean fm_debug_enabled = FALSE; -#else -#include "gam_error.h" -#define FM_W(...) GAM_DEBUG(DEBUG_INFO, __VA_ARGS__) -#endif - -/* global data structure for scan missing files */ -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); -} diff --git a/gio/fen/fen-missing.h b/gio/fen/fen-missing.h deleted file mode 100644 index d431a007d..000000000 --- a/gio/fen/fen-missing.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- 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. - * - * 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 - */ - -#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__ */ - diff --git a/gio/fen/fen-node.c b/gio/fen/fen-node.c index a8fbf69b2..7238e36bc 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 #include #include #include +#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 gboolean children_remove_cb (gpointer key, gpointer value, gpointer user_data); +static guint node_children_num (node_t *f); -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) +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) -{ - 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) +node_traverse (node_t* node, void(*traverse_cb)(node_t*, gpointer), gpointer user_data) { - GList* children; - GList* i; + GHashTableIter iter; + gpointer value; + + g_assert(traverse_cb); + if (node == NULL) { + node = ROOT; + } 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,186 +132,208 @@ find_node_internal (node_t* node, const gchar* filename, node_op_t* op) 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 (node == NULL) { + node = ROOT; } - if (token == NULL && child) { - L_hit: - if (op && op->hit) { - op->hit (child, op->user_data); + FN_W ("%s %s\n", __func__, filename); + + parent = child = node; + str = g_strdup (filename); + + 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 { + FN_W ("%s create %s failed", __func__, token); + } + } 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); + 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* -_find_node_full (const gchar* filename, node_op_t* op) +gint +node_lstat(node_t *f) { - return find_node_internal (_head, filename, op); -} + struct stat buf; -node_t* -_add_node (node_t* parent, const gchar* filename) -{ - gchar* str; - gchar* token; - gchar* lasts; - node_t* child = NULL; + g_assert(!NODE_HAS_STATE(f, NODE_STATE_ASSOCIATED)); - 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; + 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; +} + +void +node_create_children_snapshot(node_t *f, gint created_event, gboolean emit) +{ + 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); + } + + 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. */ + } + } + 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); } } -/* - * delete recursively +/** + * 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 gboolean -remove_children (node_t* node, node_op_t* op) +static void +foreach_known_children_scan(gpointer key, gpointer value, gpointer user_data) { - 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); + node_t* f = (node_t*)value; + + 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); + } + } } - if (_children_num (node) == 0) { - return TRUE; +} + +gboolean +node_try_delete(node_t* node) +{ + 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 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 ((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) +{ + if (f->children) { + return (node_t *) g_hash_table_lookup (f->children, (gpointer)basename); + } + return NULL; +} + +static guint +node_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) +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); + return node_try_delete ((node_t*)value); } gboolean -_node_class_init () +node_class_init() { - FN_W ("%s\n", __func__); - if (_head == NULL) { - _head = node_new (NULL, G_DIR_SEPARATOR_S); + ROOT = node_new (NULL, G_DIR_SEPARATOR_S); + if (ROOT == NULL) { + FN_W ("[node] Create ROOT node failed.\n"); + return FALSE; } - return _head != NULL; + + 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]; + } + } +} + +/** + * node_add_event: + * + */ +static void +node_add_event (node_t *f, node_event_t *ev) +{ + 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 +node_emit_one_event(node_t *f, GList *subs, node_t *other, int event) +{ + GList* idx; + + 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 +} + +static int +node_event_translate(int event, gboolean pair) +{ +#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; + } +#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 f2ef1ea70..7e9903269 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 */ +#include +#include + #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; + gpointer pair_data; + GTimeVal ctv; /* Created timestamp */ + GTimeVal rename_tv; /* Possible rename timestamp */ +} node_event_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 (); +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/fen-sub.c b/gio/fen/fen-sub.c deleted file mode 100644 index 780a825ce..000000000 --- a/gio/fen/fen-sub.c +++ /dev/null @@ -1,42 +0,0 @@ -/* -*- 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. - * - * 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 - */ - -#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); -} diff --git a/gio/fen/fen-sub.h b/gio/fen/fen-sub.h deleted file mode 100644 index ad232bc2c..000000000 --- a/gio/fen/fen-sub.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- 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. - * - * 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 - */ - -#include - -#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_ diff --git a/gio/fen/gfendirectorymonitor.c b/gio/fen/gfendirectorymonitor.c index ba79713c5..3b53a3aaa 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 c22998c02..9359e9fd4 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 * John McCutchan * Sebastian Dröge + * Lin Ma */ #ifndef __G_FEN_DIRECTORY_MONITOR_H__ diff --git a/gio/fen/gfenfilemonitor.c b/gio/fen/gfenfilemonitor.c index f075388ec..de011f0cd 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 e8b2e6a40..e44fd99b3 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 * John McCutchan * Sebastian Dröge + * Lin Ma */ #ifndef __G_FEN_FILE_MONITOR_H__