[libvirt] [libvirt-glib] API to save and suspend

From: "Zeeshan Ali (Khattak)" <zeeshanak@gnome.org> Its just a set of synchronous and asynchronous wrappers around virDomainManagedSave. --- libvirt-gobject/libvirt-gobject-domain.c | 119 ++++++++++++++++++++++++++++++ libvirt-gobject/libvirt-gobject-domain.h | 11 +++ libvirt-gobject/libvirt-gobject.sym | 3 + 3 files changed, 133 insertions(+), 0 deletions(-) diff --git a/libvirt-gobject/libvirt-gobject-domain.c b/libvirt-gobject/libvirt-gobject-domain.c index e4963ed..616273b 100644 --- a/libvirt-gobject/libvirt-gobject-domain.c +++ b/libvirt-gobject/libvirt-gobject-domain.c @@ -708,3 +708,122 @@ gboolean gvir_domain_suspend (GVirDomain *dom, cleanup: return ret; } + +/** + * gvir_domain_saved_suspend: + * @dom: the domain to save and suspend + * @flags: extra flags, currently unused + * @err: Place-holder for possible errors + * + * Just like #gvir_domain_suspend but also saves the state of the domain on disk + * and therefore makes it possible to restore the domain to its previous state + * even after shutdown/reboot of host machine. + * + * Returns: TRUE if domain was saved and suspended successfully, FALSE otherwise. + */ +gboolean gvir_domain_saved_suspend (GVirDomain *dom, + unsigned int flags, + GError **err) +{ + gboolean ret = FALSE; + + g_return_val_if_fail(GVIR_IS_DOMAIN(dom), FALSE); + + if (virDomainManagedSave(dom->priv->handle, flags) < 0) { + gvir_set_error_literal(err, GVIR_DOMAIN_ERROR, + 0, + "Unable to saved and suspend domain"); + goto cleanup; + } + + ret = TRUE; +cleanup: + return ret; +} + +typedef struct { + guint flags; +} DomainSavedSuspendData; + +static void +gvir_domain_saved_suspend_helper(GSimpleAsyncResult *res, + GObject *object, + GCancellable *cancellable G_GNUC_UNUSED) +{ + GVirDomain *dom = GVIR_DOMAIN(object); + DomainSavedSuspendData *data; + GError *err = NULL; + + data = g_simple_async_result_get_op_res_gpointer (res); + + if (!gvir_domain_saved_suspend(dom, data->flags, &err)) { + g_simple_async_result_set_from_error(res, err); + g_error_free(err); + } + + g_slice_free (DomainSavedSuspendData, data); +} + +/** + * gir_domain_saved_suspend_async: + * @dom: the domain to save and suspend + * @flags: extra flags, currently unused + * @cancellable: (allow-none)(transfer none): cancellation object + * @callback: (scope async): completion callback + * @user_data: (closure): opaque data for callback + * + * Asynchronous variant of #gvir_domain_saved_suspend. + */ +void gvir_domain_saved_suspend_async (GVirDomain *dom, + unsigned int flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + DomainSavedSuspendData *data; + + g_return_if_fail(GVIR_IS_DOMAIN(dom)); + + data = g_slice_new0(DomainSavedSuspendData); + data->flags = flags; + + res = g_simple_async_result_new(G_OBJECT(dom), + callback, + user_data, + gvir_domain_saved_suspend); + g_simple_async_result_set_op_res_gpointer (res, data, NULL); + g_simple_async_result_run_in_thread(res, + gvir_domain_saved_suspend_helper, + G_PRIORITY_DEFAULT, + cancellable); + g_object_unref(res); +} + +/** + * gir_domain_saved_suspend_finish: + * @dom: the domain to save and suspend + * @result: (transfer none): async method result + * @err: Place-holder for possible errors + * + * Finishes the operation started by #gvir_domain_saved_suspend_async. + * + * Returns: TRUE if domain was saved and suspended successfully, FALSE otherwise. + */ +gboolean gvir_domain_saved_suspend_finish (GVirDomain *dom, + GAsyncResult *result, + GError **err) +{ + g_return_val_if_fail(GVIR_IS_DOMAIN(dom), FALSE); + g_return_val_if_fail(G_IS_ASYNC_RESULT(result), FALSE); + + if (G_IS_SIMPLE_ASYNC_RESULT(result)) { + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT(result); + g_warn_if_fail (g_simple_async_result_get_source_tag(simple) == + gvir_domain_saved_suspend); + if (g_simple_async_result_propagate_error(simple, err)) + return FALSE; + } + + return TRUE; +} diff --git a/libvirt-gobject/libvirt-gobject-domain.h b/libvirt-gobject/libvirt-gobject-domain.h index a5923f4..96a1560 100644 --- a/libvirt-gobject/libvirt-gobject-domain.h +++ b/libvirt-gobject/libvirt-gobject-domain.h @@ -155,6 +155,17 @@ gboolean gvir_domain_open_graphics(GVirDomain *dom, gboolean gvir_domain_suspend (GVirDomain *dom, GError **err); +gboolean gvir_domain_saved_suspend (GVirDomain *dom, + unsigned int flags, + GError **err); +void gvir_domain_saved_suspend_async (GVirDomain *dom, + unsigned int flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean gvir_domain_saved_suspend_finish (GVirDomain *dom, + GAsyncResult *result, + GError **err); G_END_DECLS diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym index 526098d..c04d67a 100644 --- a/libvirt-gobject/libvirt-gobject.sym +++ b/libvirt-gobject/libvirt-gobject.sym @@ -52,6 +52,9 @@ LIBVIRT_GOBJECT_0.0.3 { gvir_domain_resume; gvir_domain_stop; gvir_domain_suspend; + gvir_domain_saved_suspend; + gvir_domain_saved_suspend_async; + gvir_domain_saved_suspend_finish; gvir_domain_delete; gvir_domain_open_console; gvir_domain_open_graphics; -- 1.7.7.5

On Tue, Jan 3, 2012 at 5:08 PM, Zeeshan Ali (Khattak) <zeeshanak@gnome.org> wrote:
From: "Zeeshan Ali (Khattak)" <zeeshanak@gnome.org> + res = g_simple_async_result_new(G_OBJECT(dom), + callback, + user_data, + gvir_domain_saved_suspend); + g_simple_async_result_set_op_res_gpointer (res, data, NULL);
The reason I'm not using destroy notify argument here is that I can't: g_slice_free*() takes 2 arguments and thats not what DestroyNotify expects. I could write a wrapper function but I don't see the point. -- Regards, Zeeshan Ali (Khattak) FSF member#5124

On Tue, Jan 3, 2012 at 4:22 PM, Zeeshan Ali (Khattak) <zeeshanak@gnome.org>wrote:
On Tue, Jan 3, 2012 at 5:08 PM, Zeeshan Ali (Khattak) <zeeshanak@gnome.org> wrote:
From: "Zeeshan Ali (Khattak)" <zeeshanak@gnome.org> + res = g_simple_async_result_new(G_OBJECT(dom), + callback, + user_data, + gvir_domain_saved_suspend); + g_simple_async_result_set_op_res_gpointer (res, data, NULL);
The reason I'm not using destroy notify argument here is that I can't: g_slice_free*() takes 2 arguments and thats not what DestroyNotify expects. I could write a wrapper function but I don't see the point.
Oh, I see. Perhaps we don't need gslice then. fyi, none of the gio data structs used in this case are allocated with gslice . Tbh, I think it's better having the small wrapper if we keep gslice. -- Marc-André Lureau

On Tue, Jan 3, 2012 at 5:35 PM, Marc-André Lureau <marcandre.lureau@gmail.com> wrote:
On Tue, Jan 3, 2012 at 4:22 PM, Zeeshan Ali (Khattak) <zeeshanak@gnome.org> wrote:
On Tue, Jan 3, 2012 at 5:08 PM, Zeeshan Ali (Khattak) <zeeshanak@gnome.org> wrote:
From: "Zeeshan Ali (Khattak)" <zeeshanak@gnome.org> + res = g_simple_async_result_new(G_OBJECT(dom), + callback, + user_data, + gvir_domain_saved_suspend); + g_simple_async_result_set_op_res_gpointer (res, data, NULL);
The reason I'm not using destroy notify argument here is that I can't: g_slice_free*() takes 2 arguments and thats not what DestroyNotify expects. I could write a wrapper function but I don't see the point.
Oh, I see. Perhaps we don't need gslice then.
Why? gslice is *the* glib way to allocate/free fixed-sized structures.
fyi, none of the gio data structs used in this case are allocated with gslice .
Weird! Perhaps there is a reason for them to not use gslice there?
Tbh, I think it's better having the small wrapper if we keep gslice.
Why? I don't see any possible leaks here. -- Regards, Zeeshan Ali (Khattak) FSF member#5124

On Tue, Jan 3, 2012 at 4:40 PM, Zeeshan Ali (Khattak) <zeeshanak@gnome.org>wrote:
Tbh, I think it's better having the small wrapper if we keep gslice.
Why? I don't see any possible leaks here.
I am thinking of calling cancel before the thread func runs. I suppose it is cancellable this way too (or by other means), but I haven't checked gio code. -- Marc-André Lureau

On Tue, Jan 3, 2012 at 6:07 PM, Marc-André Lureau <marcandre.lureau@gmail.com> wrote:
On Tue, Jan 3, 2012 at 4:40 PM, Zeeshan Ali (Khattak) <zeeshanak@gnome.org> wrote:
Tbh, I think it's better having the small wrapper if we keep gslice.
Why? I don't see any possible leaks here.
I am thinking of calling cancel before the thread func runs. I suppose it is cancellable this way too (or by other means), but I haven't checked gio code.
The callback is supposed to be called anyway. In case of cancellation, you get G_IO_ERROR_CANCELLED. i-e no leaks possible. Anyway, I'll provide a wrapper func and use destroy notify, not a lot of work after all. :) -- Regards, Zeeshan Ali (Khattak) FSF member#5124
participants (2)
-
Marc-André Lureau
-
Zeeshan Ali (Khattak)