/*
* Amanda, The Advanced Maryland Automatic Network Disk Archiver
* Copyright (c) 1999 University of Maryland at College Park
+ * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved.
* All Rights Reserved.
*
* Permission to use, copy, modify, distribute, and sell this software and its
/* A list of all extant event_handle objects, used for searching for particular
* events and for deleting dead events */
-GSList *all_events;
+GSList *all_events = NULL;
+
+#if (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 31))
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#endif
+GStaticMutex event_mutex = G_STATIC_MUTEX_INIT;
+#if (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 31))
+# pragma GCC diagnostic pop
+#endif
/*
* Utility functions
void *arg)
{
event_handle_t *handle;
- GIOCondition cond;
+
+ handle = event_create(data, type, fn, arg);
+ event_activate(handle);
+ return handle;
+}
+
+event_handle_t *
+event_create(
+ event_id_t data,
+ event_type_t type,
+ event_fn_t fn,
+ void *arg)
+{
+ event_handle_t *handle;
+
+ g_static_mutex_lock(&event_mutex);
/* sanity-checking */
if ((type == EV_READFD) || (type == EV_WRITEFD)) {
event_debug(1, _("event: register: %p->data=%jd, type=%s\n"),
handle, handle->data, event_type2str(handle->type));
+ g_static_mutex_unlock(&event_mutex);
+ return handle;
+}
+
+void
+event_activate(
+ event_handle_t *handle)
+{
+ GIOCondition cond;
+ assert(handle != NULL);
+
+ g_static_mutex_lock(&event_mutex);
+
/* add to the list of events */
all_events = g_slist_prepend(all_events, (gpointer)handle);
/* and set up the GSource for this event */
- switch (type) {
+ switch (handle->type) {
case EV_READFD:
case EV_WRITEFD:
/* create a new source */
- if (type == EV_READFD) {
+ if (handle->type == EV_READFD) {
cond = G_IO_IN | G_IO_HUP | G_IO_ERR;
} else {
cond = G_IO_OUT | G_IO_ERR;
}
- handle->source = new_fdsource(data, cond);
+ handle->source = new_fdsource(handle->data, cond);
/* attach it to the default GMainLoop */
g_source_attach(handle->source, NULL);
case EV_TIME:
/* Glib provides a nice shortcut for timeouts. The *1000 converts
* seconds to milliseconds. */
- handle->source_id = g_timeout_add(data * 1000, event_handle_callback,
+ handle->source_id = g_timeout_add(handle->data * 1000, event_handle_callback,
(gpointer)handle);
/* But it doesn't give us the source directly.. */
handle->source = g_main_context_find_source_by_id(NULL, handle->source_id);
+ /* EV_TIME must always be handled after EV_READ */
+ g_source_set_priority(handle->source, 10);
break;
case EV_WAIT:
break;
default:
- error(_("Unknown event type %s"), event_type2str(type));
+ error(_("Unknown event type %s"), event_type2str(handle->type));
}
- return handle;
+ g_static_mutex_unlock(&event_mutex);
+ return;
}
+
/*
* Mark an event to be released. Because we may be traversing the queue
* when this is called, we must wait until later to actually remove
{
assert(handle != NULL);
+ g_static_mutex_lock(&event_mutex);
event_debug(1, _("event: release (mark): %p data=%jd, type=%s\n"),
handle, handle->data,
event_type2str(handle->type));
/* Mark it as dead and leave it for the event_loop to remove */
handle->is_dead = TRUE;
+ g_static_mutex_unlock(&event_mutex);
}
/*
GSList *tofire = NULL;
int nwaken = 0;
+ g_static_mutex_lock(&event_mutex);
event_debug(1, _("event: wakeup: enter (%jd)\n"), id);
/* search for any and all matching events, and record them. This way
event_handle_t *eh = (event_handle_t *)iter->data;
if (eh->type == EV_WAIT && eh->data == id && !eh->is_dead) {
event_debug(1, _("A: event: wakeup triggering: %p id=%jd\n"), eh, id);
+ /* The lcok must be release before running the event */
+ g_static_mutex_unlock(&event_mutex);
fire(eh);
+ g_static_mutex_lock(&event_mutex);
nwaken++;
}
}
/* and free the temporary list */
g_slist_free(tofire);
+ g_static_mutex_unlock(&event_mutex);
return (nwaken);
}
any_mainloop_events(void)
{
GSList *iter;
+ gboolean ret = FALSE;
for (iter = all_events; iter != NULL; iter = g_slist_next(iter)) {
event_handle_t *hdl = (event_handle_t *)iter->data;
+ event_debug(2, _("list %p: %s/%jd\n"), hdl, event_type2str((hdl)->type), (hdl)->data);
if (hdl->type != EV_WAIT)
- return TRUE;
+ ret = TRUE;
}
- return FALSE;
+ return ret;
}
static void
event_handle_t *wait_eh,
int nonblock)
{
+ g_static_mutex_lock(&event_mutex);
event_debug(1, _("event: loop: enter: nonblockg=%d, eh=%p\n"), nonblock, wait_eh);
/* If we're waiting for a specific event, then reset its has_fired flag */
if (!any_mainloop_events())
break;
- /* Do an interation */
+ /* Do an iteration */
+ /* Relese the lock before running an iteration */
+ g_static_mutex_unlock(&event_mutex);
g_main_context_iteration(NULL, !nonblock);
+ g_static_mutex_lock(&event_mutex);
/* If the event we've been waiting for has fired or been released, as
* appropriate, we're done. See the comments for event_wait in event.h
* has been released. */
flush_dead_events(NULL);
+ g_static_mutex_unlock(&event_mutex);
}
GMainLoop *
* exponentially increasing interals. Writing a smarter implementation runs into
* some tricky race conditions and extra machinery. Since there are few, if any,
* users of a glib version this old, such machinery wouldn't get much testing.
+ *
+ * FreeBSD users have also reported problems with the glib child watch source,
+ * so we use the dumb version on FreeBSD, too.
*/
-#if (GLIB_MAJOR_VERSION < 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 6))
+
+#if (defined(__FreeBSD__) || GLIB_MAJOR_VERSION < 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 6))
typedef struct ChildWatchSource {
GSource source; /* must be the first element in the struct */