[virt-tools-list] [libosinfo 2/2] Async variant of osinfo_media_create_from_location()

Zeeshan Ali (Khattak) zeeshanak at gnome.org
Tue Aug 23 20:47:43 UTC 2011


From: "Zeeshan Ali (Khattak)" <zeeshanak at gnome.org>

---
 docs/reference/Libosinfo-sections.txt |    2 +
 osinfo/libosinfo.syms                 |    2 +
 osinfo/osinfo_media.c                 |  351 +++++++++++++++++++++++++-------
 osinfo/osinfo_media.h                 |    7 +
 4 files changed, 285 insertions(+), 77 deletions(-)

diff --git a/docs/reference/Libosinfo-sections.txt b/docs/reference/Libosinfo-sections.txt
index e2454da..68464e3 100644
--- a/docs/reference/Libosinfo-sections.txt
+++ b/docs/reference/Libosinfo-sections.txt
@@ -404,6 +404,8 @@ OsinfMediaoClass
 OsinfMediaoPrivate
 osinfo_media_new
 osinfo_media_create_from_location
+osinfo_media_create_from_location_async
+osinfo_media_create_from_location_finish
 osinfo_media_get_architecture
 osinfo_media_get_url
 osinfo_media_get_volume_id
diff --git a/osinfo/libosinfo.syms b/osinfo/libosinfo.syms
index 6541a90..2be90ee 100644
--- a/osinfo/libosinfo.syms
+++ b/osinfo/libosinfo.syms
@@ -144,6 +144,8 @@ LIBOSINFO_0.0.1 {
 	osinfo_media_error_quark;
 	osinfo_media_new;
 	osinfo_media_create_from_location;
+	osinfo_media_create_from_location_async;
+	osinfo_media_create_from_location_finish;
 	osinfo_media_get_architecture;
 	osinfo_media_get_url;
 	osinfo_media_get_volume_id;
diff --git a/osinfo/osinfo_media.c b/osinfo/osinfo_media.c
index 431ae72..6adf623 100644
--- a/osinfo/osinfo_media.c
+++ b/osinfo/osinfo_media.c
@@ -53,6 +53,44 @@ struct _SupplementaryVolumeDescriptor {
     gchar  system[MAX_SYSTEM]; /* System ID */
 };
 
+typedef struct _CreateFromLocationAsyncData CreateFromLocationAsyncData;
+struct _CreateFromLocationAsyncData {
+    GFile *file;
+
+    gint priority;
+    GCancellable *cancellable;
+
+    GSimpleAsyncResult *res;
+
+    PrimaryVolumeDescriptor pvd;
+    SupplementaryVolumeDescriptor svd;
+};
+
+static void create_from_location_async_data_free
+                                (CreateFromLocationAsyncData *data)
+{
+   g_object_unref(data->file);
+   g_clear_object(&data->cancellable);
+   g_object_unref(data->res);
+
+   g_slice_free(CreateFromLocationAsyncData, data);
+}
+
+typedef struct _CreateFromLocationData CreateFromLocationData;
+struct _CreateFromLocationData {
+    GMainLoop *main_loop;
+
+    GAsyncResult *res;
+};
+
+static void create_from_location_data_free(CreateFromLocationData *data)
+{
+   g_object_unref(data->res);
+   g_main_loop_unref(data->main_loop);
+
+   g_slice_free(CreateFromLocationData, data);
+}
+
 GQuark
 osinfo_media_error_quark (void)
 {
@@ -114,7 +152,7 @@ OsinfoMedia *osinfo_media_new(const gchar *id,
                               const gchar *architecture)
 {
     OsinfoMedia *media;
-  
+
     media = g_object_new(OSINFO_TYPE_MEDIA,
                          "id", id,
                          NULL);
@@ -126,6 +164,17 @@ OsinfoMedia *osinfo_media_new(const gchar *id,
     return media;
 }
 
+static void on_media_create_from_location_ready (GObject *source_object,
+                                                 GAsyncResult *res,
+                                                 gpointer user_data)
+{
+    CreateFromLocationData *data = (CreateFromLocationData *)user_data;
+
+    data->res = g_object_ref(res);
+
+    g_main_loop_quit(data->main_loop);
+}
+
 /**
  * osinfo_media_create_from_location:
  * @location: the location of an installation media
@@ -143,91 +192,61 @@ OsinfoMedia *osinfo_media_create_from_location(const gchar *location,
                                                GCancellable *cancellable,
                                                GError **error)
 {
-    OsinfoMedia *ret = NULL;
-    PrimaryVolumeDescriptor pvd;
-    SupplementaryVolumeDescriptor svd;
-    GFile *file;
-    GFileInputStream *stream;
-    gchar *uri;
+    CreateFromLocationData *data;
+    OsinfoMedia *ret;
 
-    g_return_val_if_fail(location != NULL, NULL);
-    g_return_val_if_fail(error == NULL || *error == NULL, NULL);
-
-    file = g_file_new_for_commandline_arg(location);
-    stream = g_file_read(file, cancellable, error);
-    if (error != NULL && *error != NULL) {
-        g_prefix_error(error, "Failed to open file");
+    data = g_slice_new0(CreateFromLocationData);
+    data->main_loop = g_main_loop_new (g_main_context_get_thread_default (),
+                                       TRUE);
 
-        goto EXIT;
-    }
+    osinfo_media_create_from_location_async(location,
+                                            G_PRIORITY_DEFAULT,
+                                            cancellable,
+                                            on_media_create_from_location_ready,
+                                            data);
 
-    memset(&pvd, 0, sizeof(pvd));
-    if (g_input_stream_skip(G_INPUT_STREAM(stream),
-                            PVD_OFFSET,
-                            cancellable,
-                            error) < sizeof(pvd)) {
-        if (*error)
-            g_prefix_error(error, "Failed to skip %d bytes", PVD_OFFSET);
-        else
-            g_set_error(error,
-                         OSINFO_MEDIA_ERROR,
-                         OSINFO_MEDIA_ERROR_NO_DESCRIPTORS,
-                         "No volume descriptors");
-
-        goto EXIT;
-    }
-
-    if (g_input_stream_read(G_INPUT_STREAM(stream),
-                            &pvd,
-                            sizeof(pvd),
-                            cancellable,
-                            error) < sizeof(pvd)) {
-        if (*error)
-            g_prefix_error(error, "Failed to read primary volume descriptor");
-        else
-            g_set_error(error,
-                        OSINFO_MEDIA_ERROR,
-                        OSINFO_MEDIA_ERROR_NO_PVD,
-                        "Primary volume descriptor unavailable");
+    /* Loop till we get a reply (or time out) */
+    if (g_main_loop_is_running (data->main_loop))
+        g_main_loop_run (data->main_loop);
 
-        goto EXIT;
-    }
+    ret = osinfo_media_create_from_location_finish(data->res, error);
+    create_from_location_data_free(data);
 
-    pvd.volume[MAX_VOLUME - 1] = 0;
-    pvd.system[MAX_SYSTEM - 1] = 0;
-    pvd.publisher[MAX_PUBLISHER - 1] = 0;
+    return ret;
+}
 
-    if (pvd.volume[0] && (pvd.system[0] == 0 && pvd.publisher[0] == 0)) {
-        g_set_error(error,
-                    OSINFO_MEDIA_ERROR,
-                    OSINFO_MEDIA_ERROR_INSUFFIENT_METADATA,
-                    "Insufficient metadata on installation media");
+static void on_svd_read (GObject *source,
+                         GAsyncResult *res,
+                         gpointer user_data)
+{
+    OsinfoMedia *ret = NULL;
+    GInputStream *stream = G_INPUT_STREAM(source);
+    gchar *uri;
+    GError *error = NULL;
+    CreateFromLocationAsyncData *data;
 
-        goto EXIT;
-    }
+    data = (CreateFromLocationAsyncData *)user_data;
 
-    memset(&svd, 0, sizeof(svd));
-    if (g_input_stream_read(G_INPUT_STREAM(stream),
-                            &svd,
-                            sizeof(svd),
-                            cancellable,
-                            error) < sizeof(svd)) {
-        if (*error)
-            g_prefix_error(error,
+    if (g_input_stream_read_finish(stream,
+                                   res,
+                                   &error) < sizeof(data->svd)) {
+        if (error)
+            g_prefix_error(&error,
                            "Failed to read supplementary volume descriptor");
         else
-            g_set_error(error,
+            g_set_error(&error,
                         OSINFO_MEDIA_ERROR,
                         OSINFO_MEDIA_ERROR_NO_SVD,
                         "Supplementary volume descriptor unavailable");
 
+
         goto EXIT;
     }
 
-    svd.system[MAX_SYSTEM - 1] = 0;
+    data->svd.system[MAX_SYSTEM - 1] = 0;
 
-    if (strncmp(BOOTABLE_TAG, svd.system, sizeof(BOOTABLE_TAG) != 0)) {
-        g_set_error(error,
+    if (strncmp(BOOTABLE_TAG, data->svd.system, sizeof(BOOTABLE_TAG) != 0)) {
+        g_set_error(&error,
                     OSINFO_MEDIA_ERROR,
                     OSINFO_MEDIA_ERROR_NOT_BOOTABLE,
                     "Install media is not bootable");
@@ -235,7 +254,7 @@ OsinfoMedia *osinfo_media_create_from_location(const gchar *location,
         goto EXIT;
     }
 
-    uri = g_file_get_uri(file);
+    uri = g_file_get_uri(data->file);
     ret = g_object_new(OSINFO_TYPE_MEDIA,
                        "id", uri,
                        NULL);
@@ -243,24 +262,202 @@ OsinfoMedia *osinfo_media_create_from_location(const gchar *location,
                             OSINFO_MEDIA_PROP_URL,
                             uri);
     g_free(uri);
-    if (pvd.volume[0] != 0)
+    if (data->pvd.volume[0] != 0)
         osinfo_entity_set_param(OSINFO_ENTITY(ret),
                                 OSINFO_MEDIA_PROP_VOLUME_ID,
-                                pvd.volume);
-    if (pvd.system[0] != 0)
+                                data->pvd.volume);
+    if (data->pvd.system[0] != 0)
         osinfo_entity_set_param(OSINFO_ENTITY(ret),
                                 OSINFO_MEDIA_PROP_SYSTEM_ID,
-                                pvd.system);
-    if (pvd.publisher[0] != 0)
+                                data->pvd.system);
+    if (data->pvd.publisher[0] != 0)
         osinfo_entity_set_param(OSINFO_ENTITY(ret),
                                 OSINFO_MEDIA_PROP_PUBLISHER_ID,
-                                pvd.publisher);
+                                data->pvd.publisher);
 
 EXIT:
+    if (error != NULL)
+        g_simple_async_result_take_error(data->res, error);
+    else
+        g_simple_async_result_set_op_res_gpointer(data->res, ret, NULL);
+    g_simple_async_result_complete (data->res);
+
     g_object_unref(stream);
-    g_object_unref(file);
+    create_from_location_async_data_free(data);
+}
 
-    return ret;
+static void on_pvd_read (GObject *source,
+                         GAsyncResult *res,
+                         gpointer user_data)
+{
+    GInputStream *stream = G_INPUT_STREAM(source);
+    CreateFromLocationAsyncData *data;
+    GError *error = NULL;
+
+    data = (CreateFromLocationAsyncData *)user_data;
+
+    if (g_input_stream_read_finish(stream,
+                                   res,
+                                   &error) < sizeof(data->pvd)) {
+        if (error)
+            g_prefix_error(&error, "Failed to read primary volume descriptor");
+        else
+            g_set_error(&error,
+                        OSINFO_MEDIA_ERROR,
+                        OSINFO_MEDIA_ERROR_NO_PVD,
+                        "Primary volume descriptor unavailable");
+
+        goto ON_ERROR;
+    }
+
+    data->pvd.volume[MAX_VOLUME - 1] = 0;
+    data->pvd.system[MAX_SYSTEM - 1] = 0;
+    data->pvd.publisher[MAX_PUBLISHER - 1] = 0;
+
+    if (data->pvd.volume[0] &&
+        (data->pvd.system[0] == 0 && data->pvd.publisher[0] == 0)) {
+        g_set_error(&error,
+                    OSINFO_MEDIA_ERROR,
+                    OSINFO_MEDIA_ERROR_INSUFFIENT_METADATA,
+                    "Insufficient metadata on installation media");
+
+        goto ON_ERROR;
+    }
+
+    g_input_stream_read_async(stream,
+                              &data->svd,
+                              sizeof(data->svd),
+                              data->priority,
+                              data->cancellable,
+                              on_svd_read,
+                              data);
+    return;
+
+ON_ERROR:
+    g_simple_async_result_take_error(data->res, error);
+    g_simple_async_result_complete (data->res);
+    create_from_location_async_data_free(data);
+}
+
+static void on_location_skipped(GObject *source,
+                                GAsyncResult *res,
+                                gpointer user_data)
+{
+    GInputStream *stream = G_INPUT_STREAM(source);
+    CreateFromLocationAsyncData *data;
+    GError *error = NULL;
+
+    data = (CreateFromLocationAsyncData *)user_data;
+
+    if (g_input_stream_skip_finish(stream, res, &error) < PVD_OFFSET) {
+        if (error)
+            g_prefix_error(&error, "Failed to skip %d bytes", PVD_OFFSET);
+        else
+            g_set_error(&error,
+                         OSINFO_MEDIA_ERROR,
+                         OSINFO_MEDIA_ERROR_NO_DESCRIPTORS,
+                         "No volume descriptors");
+        g_simple_async_result_take_error(data->res, error);
+        g_simple_async_result_complete (data->res);
+        create_from_location_async_data_free(data);
+
+        return;
+    }
+
+    g_input_stream_read_async(stream,
+                              &data->pvd,
+                              sizeof(data->pvd),
+                              data->priority,
+                              data->cancellable,
+                              on_pvd_read,
+                              data);
+}
+
+static void on_location_read(GObject *source,
+                             GAsyncResult *res,
+                             gpointer user_data)
+{
+    GFileInputStream *stream;
+    CreateFromLocationAsyncData *data;
+    GError *error = NULL;
+
+    data = (CreateFromLocationAsyncData *)user_data;
+
+    stream = g_file_read_finish(G_FILE(source), res, &error);
+    if (error != NULL) {
+        g_prefix_error(&error, "Failed to open file");
+        g_simple_async_result_take_error(data->res, error);
+        g_simple_async_result_complete (data->res);
+        create_from_location_async_data_free(data);
+
+        return;
+    }
+
+    g_input_stream_skip_async(G_INPUT_STREAM(stream),
+                              PVD_OFFSET,
+                              data->priority,
+                              data->cancellable,
+                              on_location_skipped,
+                              data);
+}
+
+/**
+ * osinfo_media_create_from_location_async:
+ * @location: the location of an installation media
+ * @priority: the I/O priority of the request
+ * @cancellable (allow-none): a #GCancellable, or %NULL
+ * @callback: Function to call when result of this call is ready
+ * @user_data: The user data to pass to @callback, or %NULL
+ *
+ * Asynchronous variant of #osinfo_media_create_from_location.
+ */
+void osinfo_media_create_from_location_async(const gchar *location,
+                                             gint priority,
+                                             GCancellable *cancellable,
+                                             GAsyncReadyCallback callback,
+                                             gpointer user_data)
+{
+    CreateFromLocationAsyncData *data;
+
+    g_return_if_fail(location != NULL);
+
+    data = g_slice_new0(CreateFromLocationAsyncData);
+    data->res = g_simple_async_result_new
+                                (NULL,
+                                 callback,
+                                 user_data,
+                                 osinfo_media_create_from_location_async);
+    data->file = g_file_new_for_commandline_arg(location);
+    data->priority = priority;
+    data->cancellable = cancellable;
+    g_file_read_async(data->file,
+                      priority,
+                      cancellable,
+                      on_location_read,
+                      data);
+}
+
+/**
+ * osinfo_media_create_from_location_finish:
+ * @res: a #GAsyncResult
+ * @error: The location where to store any error, or %NULL
+ *
+ * Finishes an asynchronous media object creation process started with
+ * #osinfo_media_create_from_location_async.
+ *
+ * Returns: (transfer full): a new #OsinfoMedia , or NULL on error
+ */
+OsinfoMedia *osinfo_media_create_from_location_finish(GAsyncResult *res,
+                                                      GError **error)
+{
+    GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT(res);
+
+    g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+
+    if (g_simple_async_result_propagate_error(simple, error))
+        return NULL;
+
+    return g_simple_async_result_get_op_res_gpointer(simple);
 }
 
 /**
diff --git a/osinfo/osinfo_media.h b/osinfo/osinfo_media.h
index 89eb1f6..9ecf0b1 100644
--- a/osinfo/osinfo_media.h
+++ b/osinfo/osinfo_media.h
@@ -101,6 +101,13 @@ OsinfoMedia *osinfo_media_new(const gchar *id, const gchar *architecture);
 OsinfoMedia *osinfo_media_create_from_location(const gchar *location,
                                                GCancellable *cancellable,
                                                GError **error);
+void osinfo_media_create_from_location_async(const gchar *location,
+                                             gint priority,
+                                             GCancellable *cancellable,
+                                             GAsyncReadyCallback callback,
+                                             gpointer user_data);
+OsinfoMedia *osinfo_media_create_from_location_finish(GAsyncResult *res,
+                                                      GError **error);
 
 const gchar *osinfo_media_get_architecture(OsinfoMedia *media);
 const gchar *osinfo_media_get_url(OsinfoMedia *media);
-- 
1.7.6




More information about the virt-tools-list mailing list