Imported Upstream version 3.3.3
[debian/amanda] / common-src / event.c
index 218d63872fbd0386d9fdf23e65af9f35aa40a3bc..436c85bd249e2ba4af58d538b584aeabb3aa2688 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * 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
@@ -73,7 +74,16 @@ struct event_handle {
 
 /* 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
@@ -118,7 +128,22 @@ event_register(
     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)) {
@@ -143,21 +168,34 @@ event_register(
     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);
@@ -175,7 +213,7 @@ event_register(
        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.. */
@@ -189,12 +227,14 @@ event_register(
            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
@@ -206,6 +246,7 @@ event_release(
 {
     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));
@@ -213,6 +254,7 @@ event_release(
 
     /* Mark it as dead and leave it for the event_loop to remove */
     handle->is_dead = TRUE;
+    g_static_mutex_unlock(&event_mutex);
 }
 
 /*
@@ -226,6 +268,7 @@ event_wakeup(
     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
@@ -243,7 +286,10 @@ event_wakeup(
        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++;
        }
     }
@@ -251,6 +297,7 @@ event_wakeup(
     /* and free the temporary list */
     g_slist_free(tofire);
 
+    g_static_mutex_unlock(&event_mutex);
     return (nwaken);
 }
 
@@ -308,15 +355,16 @@ static gboolean
 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
@@ -324,6 +372,7 @@ event_loop_wait(
     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 */
@@ -342,8 +391,11 @@ event_loop_wait(
        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
@@ -361,6 +413,7 @@ event_loop_wait(
      * has been released. */
     flush_dead_events(NULL);
 
+    g_static_mutex_unlock(&event_mutex);
 }
 
 GMainLoop *