Imported Upstream version 3.3.3
[debian/amanda] / ndmp-src / ndmpconnobj.c
index 41d14ed0e884515ab6c850dfb96c82c65e0a49c9..ef4de85ffeec14272c307217d8fd517999b13ab7 100644 (file)
@@ -1,9 +1,10 @@
 /*
  * Copyright (c) 2009-2012 Zmanda, Inc.  All Rights Reserved.
  *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
@@ -737,7 +738,7 @@ ndmp_connection_wait_for_notify(
     }
 }
 
-typedef struct notify_data {
+typedef struct notify_data_s {
     NDMPConnection *self;
     ndmp9_data_halt_reason *data_halt_reason;
     ndmp9_mover_halt_reason *mover_halt_reason;
@@ -746,11 +747,15 @@ typedef struct notify_data {
     GMutex *abort_mutex;
     GCond *abort_cond;
     int status;
+    int in_use;
     event_handle_t *read_event;
-} notify_data;
+} notify_data_t;
 
 static void handle_notify(void *cookie);
 
+static GStaticMutex notify_mutex = G_STATIC_MUTEX_INIT;
+static notify_data_t **notify_data = NULL;
+static int nb_notify_data = 0;
 int
 ndmp_connection_wait_for_notify_with_cond(
        NDMPConnection *self,
@@ -758,21 +763,53 @@ ndmp_connection_wait_for_notify_with_cond(
        ndmp9_mover_halt_reason *mover_halt_reason,
        ndmp9_mover_pause_reason *mover_pause_reason,
        guint64 *mover_pause_seek_position,
+       int *cancelled,
        GMutex *abort_mutex,
        GCond *abort_cond)
 {
     struct ndmp_msg_buf nmb;
-    notify_data ndata;
+    notify_data_t *ndata;
     gboolean found = FALSE;
-
-    ndata.self = self;
-    ndata.data_halt_reason= data_halt_reason;
-    ndata.mover_halt_reason= mover_halt_reason;
-    ndata.mover_pause_reason= mover_pause_reason;
-    ndata.mover_pause_seek_position = mover_pause_seek_position;
-    ndata.abort_mutex = abort_mutex;
-    ndata.abort_cond = abort_cond;
-    ndata.status = 2;
+    int status;
+    int i;
+
+    g_static_mutex_lock(&notify_mutex);
+    if (notify_data == NULL) {
+       glib_init();
+        nb_notify_data = 10;
+       notify_data = g_new0(notify_data_t *, nb_notify_data);
+       for (i=0;i<nb_notify_data;i++) {
+           notify_data[i] = g_new0(notify_data_t, 1);
+       }
+    }
+    /* find a not used notify_data */
+    ndata = *notify_data;
+    i = 0;
+    while (i< nb_notify_data && notify_data[i]->in_use > 0) {
+       i++;
+    }
+    if (i == nb_notify_data) {
+        int new_nb_notify_data = nb_notify_data * 2;
+       int j;
+       notify_data = g_realloc(notify_data,
+                               sizeof(notify_data_t *) * new_nb_notify_data);
+       for (j=nb_notify_data; j<new_nb_notify_data; j++) {
+           notify_data[j] = g_new0(notify_data_t, 1);
+       }
+       nb_notify_data = new_nb_notify_data;
+       ndata = notify_data[i];
+    }
+    ndata = notify_data[i];
+    ndata->self = self;
+    ndata->data_halt_reason= data_halt_reason;
+    ndata->mover_halt_reason= mover_halt_reason;
+    ndata->mover_pause_reason= mover_pause_reason;
+    ndata->mover_pause_seek_position = mover_pause_seek_position;
+    ndata->abort_mutex = abort_mutex;
+    ndata->abort_cond = abort_cond;
+    ndata->status = 2;
+    ndata->in_use = 1;
+    g_static_mutex_unlock(&notify_mutex);
 
     g_assert(!self->startup_err);
 
@@ -818,33 +855,43 @@ ndmp_connection_wait_for_notify_with_cond(
         * outside of the ndmlib_mutex critical section.  This will also be
         * useful to allow the wait to be aborted. */
 
-    ndata.read_event = event_register(self->conn->chan.fd,
-                                     EV_READFD, handle_notify, &ndata);
+        /* handle_notify can be executed before the register exit */
+    ndata->read_event = event_create(self->conn->chan.fd,
+                                    EV_READFD, handle_notify, ndata);
+    event_activate(ndata->read_event);
 
-    g_cond_wait(abort_cond, abort_mutex);
+    while (!*cancelled && ndata->status == 2) {
+       g_cond_wait(abort_cond, abort_mutex);
+    }
+    g_static_mutex_lock(&notify_mutex);
 
-    if (ndata.read_event) {
-       event_release(ndata.read_event);
+    if (ndata->read_event) {
+       event_release(ndata->read_event);
+       ndata->read_event = NULL;
     }
-    if (ndata.status == 2) {
+    if (ndata->status == 2) {
        ndmp_connection_mover_abort(self);
        ndmp_connection_mover_stop(self);
     }
-    return ndata.status;
+    status = ndata->status;
+    ndata->in_use++;
+    if (ndata->in_use == 3)
+       ndata->in_use = 0;
+    g_static_mutex_unlock(&notify_mutex);
+    return status;
 
 }
 
 static void
 handle_notify(void *cookie)
 {
-    notify_data *ndata = cookie;
+    notify_data_t *ndata = cookie;
     struct ndmp_msg_buf nmb;
     gboolean found = FALSE;
+    GCond  *abort_cond = ndata->abort_cond;
+    GMutex *abort_mutex = ndata->abort_mutex;
 
-    g_mutex_lock(ndata->abort_mutex);
-
-    event_release(ndata->read_event);
-    ndata->read_event = NULL;
+    g_mutex_lock(abort_mutex);
 
     g_static_mutex_lock(&ndmlib_mutex);
     NDMOS_MACRO_ZEROFILL(&nmb);
@@ -885,16 +932,31 @@ handle_notify(void *cookie)
     }
 
     if (!found) {
-       ndata->read_event = event_register(ndata->self->conn->chan.fd,
-                                          EV_READFD, handle_notify, ndata);
-       g_mutex_unlock(ndata->abort_mutex);
+        g_static_mutex_lock(&notify_mutex);
+        if (ndata->in_use == 2) {
+            goto notify_done_locked;
+       }
+        g_static_mutex_unlock(&notify_mutex);
+
+       g_mutex_unlock(abort_mutex);
        return;
     }
 
     ndata->status = 0;
 notify_done:
-    g_cond_broadcast(ndata->abort_cond);
-    g_mutex_unlock(ndata->abort_mutex);
+    g_static_mutex_lock(&notify_mutex);
+notify_done_locked:
+    if (ndata->read_event) {
+        event_release(ndata->read_event);
+        ndata->read_event = NULL;
+    }
+    ndata->in_use++;
+    if (ndata->in_use == 3)
+        ndata->in_use = 0;
+    g_static_mutex_unlock(&notify_mutex);
+
+    g_cond_broadcast(abort_cond);
+    g_mutex_unlock(abort_mutex);
 }
 /*
  * Class Mechanics