/* -*- 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
* 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.
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Authors: Lin Ma <lin.ma@sun.com>
*/
#include "config.h"
#include <rctl.h>
#include <strings.h>
-#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "fen-dump.h"
#ifdef GIO_COMPILATION
-#define FK_W if (fk_debug_enabled) g_warning
-static gboolean fk_debug_enabled = FALSE;
+#define FK_W if (FALSE) g_debug
#else
#include "gam_error.h"
#define FK_W(...) GAM_DEBUG(DEBUG_INFO, __VA_ARGS__)
#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 */
+G_LOCK_DEFINE (fen_lock);
-static GHashTable *_obj_fen_hash = NULL; /* <user_data, port> */
static ulong max_port_events = 512;
-static GList *pn_vq; /* the queue of ports which don't have the max objs */
-static GList *pn_fq; /* the queue of ports which have the max objs */
+static GList *pn_visible_list; /* the queue of ports which don't have the max objs */
static GQueue *g_eventq = NULL;
-static void (*add_event_cb) (gpointer, fnode_event_t*);
+static timespec_t zero_wait;
+static void (*user_process_events_cb) (gpointer, node_event_t*);
+static port_event_t *pevents = NULL;
+static gint PE_ALLOC = 2048;
+static GHashTable *renamed_hash = NULL; /* <parent node, ev> */
+
+typedef struct _PSource {
+ GSource source; /* Inherit from GSource, must be the first. */
+ GPollFD gfd;
+ gboolean pending;
+ uint_t event_growing_factor;
+ uint_t pending_events;
+} PSource;
+
+#define PGPFD(s) (&((PSource *)(s))->gfd)
+#define SLEEP_BASE_TIME 10 /* in milliseconds */
+#define EXPECT_INC_EVENTS(pn) (1 << (pn->event_growing_factor))
+
+#define RENAME_EVENTS_INTERVAL 500 /* in milliseconds */
+#define PROCESS_PORT_EVENTS_TIME 1000 /* in milliseconds */
+guint process_port_event_id = 0;
+
+static gchar* _event_strings(int event);
+static const gchar* _event_string (int event);
+static GSource *psource_new();
+
+static gboolean port_prepare(GSource *source, gint *timeout_);
+static gboolean port_check(GSource *source);
+static gboolean port_dispatch(GSource *source, GSourceFunc callback, gpointer user_data);
+static GSourceFuncs fen_source_func = {
+ port_prepare,
+ port_check,
+ port_dispatch,
+ NULL
+};
-typedef struct pnode
-{
- long ref; /* how many fds are associated to this port */
- int port;
- guint port_source_id;
-} pnode_t;
-
-typedef struct {
- pnode_t* port;
- file_obj_t* fobj;
-
- gboolean is_active;
- gpointer user_data;
-} _f;
-
-static gboolean port_fetch_event_cb (void *arg);
-static pnode_t *pnode_new ();
-static void pnode_delete (pnode_t *pn);
-
-gboolean
-_is_ported (gpointer f)
+static gboolean
+port_prepare(GSource *source, gint *timeout_)
{
- _f* fo = g_hash_table_lookup (_obj_fen_hash, f);
-
- if (fo) {
- return fo->is_active;
- }
return FALSE;
}
-static gchar*
-printevent (const char *pname, int event, const char *tag)
-{
- static gchar *event_string = NULL;
- GString *str;
-
- if (event_string) {
- g_free(event_string);
- }
-
- str = g_string_new ("");
- g_string_printf (str, "[%s] [%-20s]", tag, pname);
- if (event & FILE_ACCESS) {
- str = g_string_append (str, " ACCESS");
- }
- if (event & FILE_MODIFIED) {
- str = g_string_append (str, " MODIFIED");
- }
- if (event & FILE_ATTRIB) {
- str = g_string_append (str, " ATTRIB");
- }
- if (event & FILE_DELETE) {
- str = g_string_append (str, " DELETE");
- }
- if (event & FILE_RENAME_TO) {
- str = g_string_append (str, " RENAME_TO");
- }
- if (event & FILE_RENAME_FROM) {
- str = g_string_append (str, " RENAME_FROM");
- }
- if (event & UNMOUNTED) {
- str = g_string_append (str, " UNMOUNTED");
- }
- if (event & MOUNTEDOVER) {
- str = g_string_append (str, " MOUNTEDOVER");
- }
- event_string = str->str;
- g_string_free (str, FALSE);
- return event_string;
-}
-
-static void
-port_add_kevent (int e, gpointer f)
+static gboolean
+port_check(GSource *source)
{
- fnode_event_t *ev, *tail;
- GTimeVal t;
- gboolean has_twin = FALSE;
-
- /*
- * Child FILE_DELETE | FILE_RENAME_FROM will trigger parent FILE_MODIFIED.
- * FILE_MODIFIED will trigger FILE_ATTRIB.
- */
-
- if ((e & FILE_ATTRIB) && e != FILE_ATTRIB) {
- e ^= FILE_ATTRIB;
- has_twin = TRUE;
- }
- if (e == FILE_RENAME_FROM) {
- e = FILE_DELETE;
- }
- if (e == FILE_RENAME_TO) {
- e = FILE_MODIFIED;
- }
+ PSource *pn = (PSource *)source;
+ uint_t nget;
- switch (e) {
- case FILE_DELETE:
- case FILE_RENAME_FROM:
- case FILE_MODIFIED:
- case FILE_ATTRIB:
- case UNMOUNTED:
- case MOUNTEDOVER:
- break;
- case FILE_RENAME_TO:
- case FILE_ACCESS:
- default:
- g_assert_not_reached ();
- return;
+ if (pn->pending) {
+ pn->pending = FALSE;
+ g_source_add_poll(source, PGPFD(source));
+ g_source_unref(source);
+ return FALSE;
}
- tail = (fnode_event_t*) g_queue_peek_tail (g_eventq);
- if (tail) {
- if (tail->user_data == f) {
- if (tail->e == e) {
- tail->has_twin = (has_twin | (tail->has_twin ^ has_twin));
- /* skip the current */
- return;
- } else if (e == FILE_MODIFIED && !has_twin
- && tail->e == FILE_ATTRIB) {
- tail->e = FILE_MODIFIED;
- tail->has_twin = TRUE;
- return;
- } else if (e == FILE_ATTRIB
- && tail->e == FILE_MODIFIED && !tail->has_twin) {
- tail->has_twin = TRUE;
- return;
- }
+ if (!(PGPFD(pn)->revents & G_IO_IN))
+ return FALSE;
+
+ if (port_getn(PGPFD(source)->fd, NULL, 0, &nget, 0) == 0) {
+ if (nget - pn->pending_events > EXPECT_INC_EVENTS(pn)) {
+ /* Sleep for a while. */
+ pn->pending_events = nget;
+ pn->event_growing_factor ++;
+
+ pn->pending = TRUE;
+ g_source_ref(source);
+ g_source_remove_poll(source, PGPFD(source));
+ g_timeout_add(SLEEP_BASE_TIME,
+ (GSourceFunc)port_check,
+ (gpointer)pn);
+ return FALSE;
}
}
-
- if ((ev = _fnode_event_new (e, has_twin, f)) != NULL) {
- g_queue_push_tail (g_eventq, ev);
- }
-}
-static void
-port_process_kevents ()
-{
- fnode_event_t *ev;
-
- while ((ev = (fnode_event_t*)g_queue_pop_head (g_eventq)) != NULL) {
- FK_W ("[%s] 0x%p %s\n", __func__, ev, _event_string (ev->e));
- add_event_cb (ev->user_data, ev);
- }
+ pn->pending_events = 0;
+ pn->event_growing_factor = 0;
+
+ return TRUE;
}
static gboolean
-port_fetch_event_cb (void *arg)
+port_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
{
- pnode_t *pn = (pnode_t *)arg;
- _f* fo;
+ node_t *f;
uint_t nget = 0;
- port_event_t pe[PE_ALLOC];
- timespec_t timeout;
- gpointer f;
- gboolean ret = TRUE;
-
- /* FK_W ("IN <======== %s\n", __func__); */
+ uint_t total = 0;
+
+ FK_W ("%s 0x%p fd %d\n", __func__, source, PGPFD(source)->fd);
+
G_LOCK (fen_lock);
-
- memset (&timeout, 0, sizeof (timespec_t));
do {
nget = 1;
- if (port_getn (pn->port, pe, PE_ALLOC, &nget, &timeout) == 0) {
+ if (port_getn(PGPFD(source)->fd, pevents, PE_ALLOC, &nget, &zero_wait) == 0) {
int i;
for (i = 0; i < nget; i++) {
- fo = (_f*)pe[i].portev_user;
- /* handle event */
- switch (pe[i].portev_source) {
- case PORT_SOURCE_FILE:
- /* If got FILE_EXCEPTION or add to port failed,
- delete the pnode */
- fo->is_active = FALSE;
- if (fo->user_data) {
- FK_W("%s\n",
- printevent(F_NAME(fo), pe[i].portev_events, "RAW"));
- port_add_kevent (pe[i].portev_events, fo->user_data);
- } else {
- /* fnode is deleted */
- goto L_delete;
- }
- if (pe[i].portev_events & FILE_EXCEPTION) {
- g_hash_table_remove (_obj_fen_hash, fo->user_data);
- L_delete:
- FK_W ("[ FREE_FO ] [0x%p]\n", fo);
- pnode_delete (fo->port);
- g_free (fo);
+ f = (node_t *)pevents[i].portev_user;
+
+ if (pevents[i].portev_source == PORT_SOURCE_FILE) {
+
+ NODE_CLE_STATE(f, NODE_STATE_ASSOCIATED);
+ NODE_SET_STATE(f, NODE_STATE_HAS_EVENTS);
+
+ if (HAS_NO_EXCEPTION_EVENTS(pevents[i].portev_events)) {
+ /* If the events do not show it's deleted, update
+ * file timestamp to avoid missing events next time.
+ */
+ if (node_lstat(f) != 0 /* || port_add(f) != 0 */) {
+ /* Included deleted event. */
+ pevents[i].portev_events |= FILE_DELETE;
+ }
}
- break;
- default:
- /* case PORT_SOURCE_TIMER: */
- FK_W ("[kernel] unknown portev_source %d\n", pe[i].portev_source);
+
+ /* Queue it and waiting for processing. */
+ g_queue_push_tail(g_eventq,
+ node_event_new(pevents[i].portev_events, (gpointer)f));
+
+ } else {
+ FK_W ("[kernel] unknown portev_source %d\n", pevents[i].portev_source);
}
}
+
+ total += nget;
+
} else {
FK_W ("[kernel] port_getn %s\n", g_strerror (errno));
- nget = 0;
+ break;
}
} while (nget == PE_ALLOC);
+ G_UNLOCK (fen_lock);
+
+ if (total > 0 && callback) {
+ FK_W ("[kernel] get total %ld events\n", total);
+ return callback (user_data);
+ }
+ return TRUE;
+}
+
+static gboolean
+process_renamed_hash_cb(gpointer key, gpointer value, gpointer user_data)
+{
+ node_event_t *ev = value;
+
+#if 0
+ node_add_event(ev->user_data, ev);
+#else
+ user_process_events_cb(ev->user_data, ev);
+#endif
+ /* Always delete self from hash. */
+ return TRUE;
+}
+
+static gboolean
+port_events_process_cb(gpointer user_data)
+{
+ node_event_t *ev;
+
+ G_LOCK (fen_lock);
+
/* Processing g_eventq */
- port_process_kevents ();
+ while ((ev = (node_event_t*)g_queue_pop_head (g_eventq)) != NULL) {
+
+ /* FK_W ("[%s] 0x%p %s\n", __func__, ev, _event_string (ev->e)); */
+
+ {
+ gchar *log = _event_strings(ev->e);
+ FK_W ("%s %s %s\n", __func__, NODE_NAME(ev->user_data), log);
+ g_free(log);
+ }
+
+#ifdef GIO_COMPILATION
+ /* Use the parent node as a hash, because only the dir_subs in the
+ * parent node should receive MOVE event.
+ */
+ if (NODE_PARENT(ev->user_data)) {
+ if (ev->e == FILE_RENAME_TO) {
+ g_hash_table_insert(renamed_hash, NODE_PARENT(ev->user_data), ev);
+ g_time_val_add(&ev->rename_tv, RENAME_EVENTS_INTERVAL);
+ continue;
+ }
+ if (ev->e == FILE_RENAME_FROM) {
+ node_event_t *pair_ev;
+
+ pair_ev = g_hash_table_lookup(renamed_hash, NODE_PARENT(ev->user_data));
+ if (pair_ev && node_timeval_lt(&ev->ctv, &pair_ev->rename_tv)) {
+ g_hash_table_remove(renamed_hash, NODE_PARENT(ev->user_data));
+ pair_ev->pair_data = ev->user_data;
+ /* Free ev, exchange pair_ev and ev. */
+ node_event_delete(ev);
+ ev = pair_ev;
+ }
+ }
+ }
+#endif
- if (pn->ref == 0) {
- pn->port_source_id = 0;
- ret = FALSE;
+#if 0
+ node_add_event(ev->user_data, ev);
+#else
+ user_process_events_cb(ev->user_data, ev);
+#endif
}
+
+ /* Processing the events in renamed_hash. TODO we should delay it and wait
+ * for more possible pair.
+ */
+ g_hash_table_foreach_remove(renamed_hash, process_renamed_hash_cb, NULL);
+
G_UNLOCK (fen_lock);
- /* FK_W ("OUT ========> %s\n", __func__); */
- return ret;
+
+ process_port_event_id = 0;
+ return FALSE;
}
-/*
- * ref - 1 if remove a watching file succeeded.
- */
-static void
-pnode_delete (pnode_t *pn)
+static gboolean
+port_events_read_cb(gpointer user_data)
{
- g_assert (pn->ref <= max_port_events);
-
- if (pn->ref == max_port_events) {
- FK_W ("PORT : move to visible queue - [pn] 0x%p [ref] %d\n", pn, pn->ref);
- pn_fq = g_list_remove (pn_fq, pn);
- pn_vq = g_list_prepend (pn_vq, pn);
- }
- if ((-- pn->ref) == 0) {
- /* Should dispatch the source */
- }
- FK_W ("%s [pn] 0x%p [ref] %d\n", __func__, pn, pn->ref);
+
+ if (process_port_event_id == 0) {
+ process_port_event_id = g_timeout_add(PROCESS_PORT_EVENTS_TIME,
+ port_events_process_cb,
+ NULL);
+ }
+
+ return TRUE;
}
/*
- * malloc pnode_t and port_create, start thread at pnode_ref.
- * if pnode_new succeeded, the pnode_t will never
- * be freed. So pnode_t can be freed only in pnode_new.
- * Note pnode_monitor_remove_all can also free pnode_t, but currently no one
+ * malloc PSource and port_create, start thread at pnode_ref.
+ * if psource_new succeeded, the PSource will never
+ * be freed. So PSource can be freed only in psource_new.
+ * Note pnode_monitor_remove_all can also free PSource, but currently no one
* invork it.
*/
-static pnode_t *
-pnode_new ()
+static GSource*
+psource_new()
{
- pnode_t *pn = NULL;
-
- if (pn_vq) {
- pn = (pnode_t*)pn_vq->data;
- g_assert (pn->ref < max_port_events);
- } else {
- pn = g_new0 (pnode_t, 1);
- if (pn != NULL) {
- if ((pn->port = port_create ()) >= 0) {
- g_assert (g_list_find (pn_vq, pn) == NULL);
- pn_vq = g_list_prepend (pn_vq, pn);
- } else {
- FK_W ("PORT_CREATE %s\n", g_strerror (errno));
- g_free (pn);
- pn = NULL;
- }
- }
- }
- if (pn) {
- FK_W ("%s [pn] 0x%p [ref] %d\n", __func__, pn, pn->ref);
- pn->ref++;
- if (pn->ref == max_port_events) {
- FK_W ("PORT : move to full queue - [pn] 0x%p [ref] %d\n", pn, pn->ref);
- pn_vq = g_list_remove (pn_vq, pn);
- pn_fq = g_list_prepend (pn_fq, pn);
- g_assert (g_list_find (pn_vq, pn) == NULL);
- }
- /* attach the source */
- if (pn->port_source_id == 0) {
- pn->port_source_id = g_timeout_add (PROCESS_PORT_EVENTS_TIME,
- port_fetch_event_cb,
- (void *)pn);
- g_assert (pn->port_source_id > 0);
- }
- }
+ GSource *source = NULL;
+ int fd;
+
+ if ((fd = port_create()) >= 0) {
+ source = g_source_new(&fen_source_func, sizeof(PSource));
+ PGPFD(source)->fd = fd;
+ PGPFD(source)->events = G_IO_IN | G_IO_HUP | G_IO_ERR;
+ g_source_set_callback(source, port_events_read_cb, NULL, NULL);
+ g_source_attach(source, NULL);
+ g_source_unref(source);
+ g_source_add_poll(source, PGPFD(source));
+
+ FK_W ("%s 0x%p fd %d\n", __func__, source, PGPFD(source)->fd);
+ } else {
+ FK_W ("PORT_CREATE %s\n", g_strerror(errno));
+ g_return_val_if_reached(NULL);
+ }
- return pn;
+ return source;
}
-/*
- * port_add_internal
+/**
+ * port_add:
+ * @f:
*
- * < private >
* Unsafe, need lock fen_lock.
+ * port_add will associate a GSource to @f->source
*/
-static gboolean
-port_add_internal (file_obj_t* fobj, off_t* len,
- gpointer f, gboolean need_stat)
+gint
+port_add(node_t *f)
{
- int ret;
- struct stat buf;
- _f* fo = NULL;
-
- g_assert (f && fobj);
- FK_W ("%s [0x%p] %s\n", __func__, f, fobj->fo_name);
-
- if ((fo = g_hash_table_lookup (_obj_fen_hash, f)) == NULL) {
- fo = g_new0 (_f, 1);
- fo->fobj = fobj;
- fo->user_data = f;
- g_assert (fo);
- FK_W ("[ NEW_FO ] [0x%p] %s\n", fo, F_NAME(fo));
- g_hash_table_insert (_obj_fen_hash, f, fo);
- }
+ GSource *source = f->source;
- if (fo->is_active) {
- return TRUE;
- }
+ FK_W ("%s [0x%p] %s\n", __func__, f, NODE_NAME(f));
- if (fo->port == NULL) {
- fo->port = pnode_new ();
- }
-
- if (need_stat) {
- if (FN_STAT (F_NAME(fo), &buf) != 0) {
- FK_W ("LSTAT [%-20s] %s\n", F_NAME(fo), g_strerror (errno));
- goto L_exit;
+ g_assert(f);
+ g_assert(NODE_HAS_FLAG(f, NODE_FLAG_STAT_UPDATED));
+
+ /* if (!NODE_HAS_FLAG(f, NODE_FLAG_STAT_DONE)) { */
+ /* if (NODE_STAT(f) != 0) { */
+ /* return errno; */
+ /* } */
+ /* } */
+
+ /* Try re-use f->pn. f->pn may be used by other request, e.g. f is deleted
+ * for a long time. So if pn is full, we try to open a new one.
+ */
+ if (!source) {
+start_over:
+ /* Try the next visible source. */
+ if (pn_visible_list) {
+ source = (GSource *)pn_visible_list->data;
+ } else {
+ if ((source = psource_new()) != NULL) {
+ g_assert (g_list_find (pn_visible_list, source) == NULL);
+ pn_visible_list = g_list_prepend (pn_visible_list, source);
+ }
}
- g_assert (len);
- fo->fobj->fo_atime = buf.st_atim;
- fo->fobj->fo_mtime = buf.st_mtim;
- fo->fobj->fo_ctime = buf.st_ctim;
- *len = buf.st_size;
}
-
- if (port_associate (F_PORT(fo),
- PORT_SOURCE_FILE,
- (uintptr_t)fo->fobj,
- FEN_ALL_EVENTS,
- (void *)fo) == 0) {
- fo->is_active = TRUE;
- FK_W ("%s %s\n", "PORT_ASSOCIATE", F_NAME(fo));
- return TRUE;
+
+ if (port_associate(PGPFD(source)->fd, PORT_SOURCE_FILE, (uintptr_t)FILE_OBJECT(f),
+ CONCERNED_EVENTS,
+ (void *)f) == 0) {
+ f->source = source;
+ NODE_SET_STATE(f, NODE_STATE_ASSOCIATED);
+ NODE_CLE_FLAG(f, NODE_FLAG_STAT_UPDATED);
+ FK_W ("PORT_ASSOCIATE 0x%p OK\n", f);
+ return 0;
+ } else if (errno == EAGAIN) {
+ /* Full, remove it. */
+ pn_visible_list = g_list_remove (pn_visible_list, source);
+ /* Re-add to port */
+ goto start_over;
+
+ } else if (errno == ENOENT) {
+ /* File is not exist */
+ } else if (errno == ENOTSUP) {
+ /* FS is not supported. Currently we think it no longer make sense to
+ * monitor it, so clean the stat info and return 0 to ignore this
+ * node. If there are requirement, we can consider to add polling
+ * method.
+ */
+ NODE_CLE_FLAG(f, NODE_FLAG_STAT_UPDATED);
+ return 0;
} else {
- FK_W ("PORT_ASSOCIATE [%-20s] %s\n", F_NAME(fo), g_strerror (errno));
- L_exit:
- FK_W ("[ FREE_FO ] [0x%p]\n", fo);
- g_hash_table_remove (_obj_fen_hash, f);
- pnode_delete (fo->port);
- g_free (fo);
+ FK_W ("PORT_ASSOCIATE 0x%p %s\n", f, g_strerror (errno));
}
- return FALSE;
-}
-
-gboolean
-_port_add (file_obj_t* fobj, off_t* len, gpointer f)
-{
- return port_add_internal (fobj, len, f, TRUE);
-}
-gboolean
-_port_add_simple (file_obj_t* fobj, gpointer f)
-{
- return port_add_internal (fobj, NULL, f, FALSE);
+ /* 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 (gpointer f)
+port_remove (node_t *f)
{
- _f* fo = NULL;
-
- FK_W ("%s\n", __func__);
- if ((fo = g_hash_table_lookup (_obj_fen_hash, f)) != NULL) {
- /* Marked */
- fo->user_data = NULL;
- g_hash_table_remove (_obj_fen_hash, f);
-
- if (port_dissociate (F_PORT(fo),
- PORT_SOURCE_FILE,
- (uintptr_t)fo->fobj) == 0) {
+ /* g_assert(f->source); */
+
+ if (NODE_HAS_STATE(f, NODE_STATE_ASSOCIATED)) {
+ /* Mark unregisted. */
+ if (port_dissociate(PGPFD(f->source)->fd, PORT_SOURCE_FILE, (uintptr_t)FILE_OBJECT(f)) == 0) {
/*
* Note, we can run foode_delete if dissociating is failed,
* because there may be some pending events (mostly like
* the fnode may be deleted, then port_get will run on an invalid
* address.
*/
- FK_W ("[ FREE_FO ] [0x%p]\n", fo);
- pnode_delete (fo->port);
- g_free (fo);
+ NODE_CLE_STATE(f, NODE_STATE_ASSOCIATED);
+ FK_W ("PORT_DISSOCIATE 0x%p OK\n", f);
+ } else if (errno == ENOENT) {
+ /* The file has been removed from port, after port_get or before
+ * port_get but DELETED event has been generated.
+ * Ignored. */
} else {
- FK_W ("PORT_DISSOCIATE [%-20s] %s\n", F_NAME(fo), g_strerror (errno));
+ FK_W ("PORT_DISSOCIATE 0x%p %s\n", f, g_strerror (errno));
+ g_return_if_reached();
}
}
}
-const gchar *
-_event_string (int event)
-{
- switch (event) {
- case FILE_DELETE:
- return "FILE_DELETE";
- case FILE_RENAME_FROM:
- return "FILE_RENAME_FROM";
- case FILE_MODIFIED:
- return "FILE_MODIFIED";
- case FILE_RENAME_TO:
- return "FILE_RENAME_TO";
- case MOUNTEDOVER:
- return "MOUNTEDOVER";
- case FILE_ATTRIB:
- return "FILE_ATTRIB";
- case UNMOUNTED:
- return "UNMOUNTED";
- case FILE_ACCESS:
- return "FILE_ACCESS";
- default:
- return "EVENT_UNKNOWN";
- }
-}
-
/*
* Get Solaris resouce values.
*
*/
extern gboolean
-_port_class_init (void (*user_add_event) (gpointer, fnode_event_t*))
+port_class_init (void (*user_process_events_callback) (gpointer, node_event_t*))
{
rctlblk_t *rblk;
- FK_W ("%s\n", __func__);
+
if ((rblk = malloc (rctlblk_size ())) == NULL) {
FK_W ("[kernel] rblk malloc %s\n", g_strerror (errno));
return FALSE;
return FALSE;
} else {
max_port_events = rctlblk_get_value(rblk);
- FK_W ("[kernel] max_port_events = %u\n", max_port_events);
+ FK_W ("max_port_events = %u\n", max_port_events);
free (rblk);
}
- if ((_obj_fen_hash = g_hash_table_new(g_direct_hash,
- g_direct_equal)) == NULL) {
- FK_W ("[kernel] fobj hash initializing faild\n");
+ renamed_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, NULL);
+ if (renamed_hash == NULL) {
+ FK_W ("[kernel] FEN global renamed queue initializing faild\n");
return FALSE;
}
if ((g_eventq = g_queue_new ()) == NULL) {
FK_W ("[kernel] FEN global event queue initializing faild\n");
+ return FALSE;
+ }
+ if (user_process_events_callback == NULL) {
+ FK_W ("[kernel] FEN global no user_process_events_callback\n");
+ return FALSE;
}
- if (user_add_event == NULL) {
+ user_process_events_cb = user_process_events_callback;
+ memset (&zero_wait, 0, sizeof (timespec_t));
+
+ pevents = g_malloc(PE_ALLOC * sizeof(port_event_t));
+ if (pevents == NULL) {
+ FK_W ("[kernel] FEN global alloc pevents failed\n");
return FALSE;
}
- add_event_cb = user_add_event;
+
return TRUE;
}
-fnode_event_t*
-_fnode_event_new (int event, gboolean has_twin, gpointer user_data)
+static gchar*
+printevent (const char *pname, int event, const char *tag)
{
- fnode_event_t *ev;
-
- if ((ev = g_new (fnode_event_t, 1)) != NULL) {
- g_assert (ev);
- ev->e = event;
- ev->user_data = user_data;
- ev->has_twin = has_twin;
- /* Default isn't a pending event. */
- ev->is_pending = FALSE;
+ static gchar *event_string = NULL;
+ GString *str;
+
+ g_free(event_string);
+
+ str = g_string_new ("");
+ g_string_printf (str, "[%s] [%-20s]", tag, pname);
+ if (event & FILE_ACCESS) {
+ str = g_string_append (str, " ACCESS");
+ }
+ if (event & FILE_MODIFIED) {
+ str = g_string_append (str, " MODIFIED");
+ }
+ if (event & FILE_ATTRIB) {
+ str = g_string_append (str, " ATTRIB");
+ }
+ if (event & FILE_DELETE) {
+ str = g_string_append (str, " DELETE");
+ }
+ if (event & FILE_RENAME_TO) {
+ str = g_string_append (str, " RENAME_TO");
+ }
+ if (event & FILE_RENAME_FROM) {
+ str = g_string_append (str, " RENAME_FROM");
+ }
+ if (event & UNMOUNTED) {
+ str = g_string_append (str, " UNMOUNTED");
}
- return ev;
+ if (event & MOUNTEDOVER) {
+ str = g_string_append (str, " MOUNTEDOVER");
+ }
+ event_string = str->str;
+ g_string_free (str, FALSE);
+ return event_string;
}
-void
-_fnode_event_delete (fnode_event_t* ev)
+static gchar *
+_event_strings(int event)
+{
+ GString *str = g_string_sized_new(80);
+
+ if (event & FILE_DELETE)
+ g_string_append(str, " FILE_DELETE");
+
+ if (event & FILE_RENAME_FROM)
+ g_string_append(str, " FILE_RENAME_FROM");
+
+ if (event & FILE_MODIFIED)
+ g_string_append(str, " FILE_MODIFIED");
+
+ if (event & FILE_RENAME_TO)
+ g_string_append(str, " FILE_RENAME_TO");
+
+ if (event & MOUNTEDOVER)
+ g_string_append(str, " MOUNTEDOVER");
+
+ if (event & FILE_ATTRIB)
+ g_string_append(str, " FILE_ATTRIB");
+
+ if (event & UNMOUNTED)
+ g_string_append(str, " UNMOUNTED");
+
+ if (event & FILE_ACCESS)
+ g_string_append(str, " FILE_ACCESS");
+
+ return g_string_free(str, FALSE);
+}
+
+static const gchar *
+_event_string (int event)
{
- g_free (ev);
+ switch (event) {
+ case FILE_DELETE:
+ return "FILE_DELETE";
+ case FILE_RENAME_FROM:
+ return "FILE_RENAME_FROM";
+ case FILE_MODIFIED:
+ return "FILE_MODIFIED";
+ case FILE_RENAME_TO:
+ return "FILE_RENAME_TO";
+ case MOUNTEDOVER:
+ return "MOUNTEDOVER";
+ case FILE_ATTRIB:
+ return "FILE_ATTRIB";
+ case UNMOUNTED:
+ return "UNMOUNTED";
+ case FILE_ACCESS:
+ return "FILE_ACCESS";
+ default:
+ return "EVENT_UNKNOWN";
+ }
}