[Spice-devel] [spice-gtk v4 05/24] file-xfer: introduce functions to init task async

Victor Toso lists at victortoso.com
Fri Jun 24 12:00:43 UTC 2016


Hi,

On Thu, Jun 23, 2016 at 03:39:58PM -0500, Jonathon Jongsma wrote:
> On Thu, 2016-06-23 at 19:37 +0200, Victor Toso wrote:
> > Introduced functions (private):
> > * void       spice_file_transfer_task_init_task_async()
> > * GFileInfo *spice_file_transfer_task_init_task_finish()
> > 
> > The init process of SpiceFileTransferTask does initialize its
> > GFileInputStream (for reading the file) and also its GFileInfo
> > (necessary to protocol in order to start the file-transfer with agent)
> > 
> > Due the logic changed involved, some functions were renamed to better
> > match its place and purpose:
> > 
> > * file_xfer_info_async_cb -> file_xfer_init_task_async_cb
> >   It is channel-main's callback for each _init_task_async()
> > 
> > * file_xfer_read_async_cb -> spice_file_transfer_task_read_file_cb
> > * file_xfer_info_async_cb -> spice_file_transfer_task_query_info_cb
> >   Both should be private to SpiceFileTransferTask now.
> > 
> > As the _init_task_async() uses GTask, some error handling was moved to
> > channel-main's after _init_task_finish() is called.
> > 
> > This change is related to split SpiceFileTransferTask from
> > channel-main.
> > ---
> >  src/channel-main.c | 181 +++++++++++++++++++++++++++++++++++++---------------
> > -
> >  1 file changed, 126 insertions(+), 55 deletions(-)
> > 
> > diff --git a/src/channel-main.c b/src/channel-main.c
> > index 1411fb3..ceca7e3 100644
> > --- a/src/channel-main.c
> > +++ b/src/channel-main.c
> > @@ -65,6 +65,12 @@ static GHashTable
> > *spice_file_transfer_task_create_tasks(GFile **files,
> >                                                           gpointer
> > progress_callback_data,
> >                                                           GAsyncReadyCallback
> > callback,
> >                                                           gpointer user_data);
> > +static void spice_file_transfer_task_init_task_async(SpiceFileTransferTask
> > *self,
> > +                                                     GAsyncReadyCallback
> > callback,
> > +                                                     gpointer userdata);
> > +static GFileInfo
> > *spice_file_transfer_task_init_task_finish(SpiceFileTransferTask *xfer_task,
> > +                                                            GAsyncResult
> > *result,
> > +                                                            GError **error);
> >  
> >  /**
> >   * SECTION:file-transfer-task
> > @@ -3025,35 +3031,32 @@ signal:
> >  }
> >  
> >  
> > -static void file_xfer_info_async_cb(GObject *obj, GAsyncResult *res, gpointer
> > data)
> > +static void file_xfer_init_task_async_cb(GObject *obj, GAsyncResult *res,
> > gpointer data)
> >  {
> >      GFileInfo *info;
> > -    GFile *file = G_FILE(obj);
> > -    GError *error = NULL;
> > -    GKeyFile *keyfile = NULL;
> > -    gchar *basename = NULL;
> > +    SpiceFileTransferTask *xfer_task;
> > +    SpiceMainChannel *channel;
> > +    gchar *string, *basename;
> > +    GKeyFile *keyfile;
> >      VDAgentFileXferStartMessage msg;
> > -    gsize /*msg_size*/ data_len;
> > -    gchar *string;
> > -    SpiceFileTransferTask *self = SPICE_FILE_TRANSFER_TASK(data);
> > +    guint64 file_size;
> > +    gsize data_len;
> > +    GError *error = NULL;
> >  
> > -    self->pending = FALSE;
> > -    info = g_file_query_info_finish(file, res, &error);
> > -    if (error || self->error)
> > +    xfer_task = SPICE_FILE_TRANSFER_TASK(obj);
> > +
> > +    info = spice_file_transfer_task_init_task_finish(xfer_task, res, &error);
> > +    if (info == NULL)
> >          goto failed;
> >  
> > -    self->file_info = info;
> > -    self->file_size =
> > -        g_file_info_get_attribute_uint64(info,
> > G_FILE_ATTRIBUTE_STANDARD_SIZE);
> > -    g_object_notify(G_OBJECT(self), "progress");
> > -    keyfile = g_key_file_new();
> > +    channel = spice_file_transfer_task_get_channel(xfer_task);
> > +    basename = g_file_info_get_attribute_as_string(info,
> > G_FILE_ATTRIBUTE_STANDARD_NAME);
> > +    file_size = g_file_info_get_attribute_uint64(info,
> > G_FILE_ATTRIBUTE_STANDARD_SIZE);
> >  
> > -    /* File name */
> > -    basename = g_file_get_basename(file);
> > +    keyfile = g_key_file_new();
> >      g_key_file_set_string(keyfile, "vdagent-file-xfer", "name", basename);
> > +    g_key_file_set_uint64(keyfile, "vdagent-file-xfer", "size", file_size);
> >      g_free(basename);
> > -    /* File size */
> > -    g_key_file_set_uint64(keyfile, "vdagent-file-xfer", "size", self-
> > >file_size);
> >  
> >      /* Save keyfile content to memory. TODO: more file attributions
> >         need to be sent to guest */
> > @@ -3063,39 +3066,16 @@ static void file_xfer_info_async_cb(GObject *obj,
> > GAsyncResult *res, gpointer da
> >          goto failed;
> >  
> >      /* Create file-xfer start message */
> > -    msg.id = self->id;
> > -    agent_msg_queue_many(self->channel, VD_AGENT_FILE_XFER_START,
> > +    msg.id = spice_file_transfer_task_get_id(xfer_task);
> > +    agent_msg_queue_many(channel, VD_AGENT_FILE_XFER_START,
> >                           &msg, sizeof(msg),
> >                           string, data_len + 1, NULL);
> >      g_free(string);
> > -    spice_channel_wakeup(SPICE_CHANNEL(self->channel), FALSE);
> > +    spice_channel_wakeup(SPICE_CHANNEL(channel), FALSE);
> 
> [NOTE: read comments below first]
> 
> If you follow my suggestions below, you'll need to unref 'info' here.
> 
> >      return;
> >  
> >  failed:
> > -    spice_file_transfer_task_completed(self, error);
> > -}
> > -
> > -static void file_xfer_read_async_cb(GObject *obj, GAsyncResult *res, gpointer
> > data)
> > -{
> > -    GFile *file = G_FILE(obj);
> > -    SpiceFileTransferTask *self = SPICE_FILE_TRANSFER_TASK(data);
> > -    GError *error = NULL;
> > -
> > -    self->pending = FALSE;
> > -    self->file_stream = g_file_read_finish(file, res, &error);
> > -    if (error || self->error) {
> > -        spice_file_transfer_task_completed(self, error);
> > -        return;
> > -    }
> > -
> > -    g_file_query_info_async(self->file,
> > -                            G_FILE_ATTRIBUTE_STANDARD_SIZE,
> > -                            G_FILE_QUERY_INFO_NONE,
> > -                            G_PRIORITY_DEFAULT,
> > -                            self->cancellable,
> > -                            file_xfer_info_async_cb,
> > -                            self);
> > -    self->pending = TRUE;
> > +    spice_file_transfer_task_completed(xfer_task, error);
> >  }
> >  
> >  static SpiceFileTransferTask *spice_file_transfer_task_new(SpiceMainChannel
> > *channel,
> > @@ -3184,12 +3164,10 @@ void spice_main_file_copy_async(SpiceMainChannel
> > *channel,
> >      g_hash_table_iter_init(&iter, xfer_ht);
> >      while (g_hash_table_iter_next(&iter, &key, &value)) {
> >          guint32 task_id;
> > -        GFile *file;
> >          SpiceFileTransferTask *xfer_task;
> >  
> >          xfer_task = value;
> >          task_id = spice_file_transfer_task_get_id(xfer_task);
> > -        g_object_get(xfer_task, "file", &file, NULL);
> >  
> >          SPICE_DEBUG("Insert a xfer task:%u to task list", task_id);
> >  
> > @@ -3197,12 +3175,9 @@ void spice_main_file_copy_async(SpiceMainChannel
> > *channel,
> >          g_signal_connect(xfer_task, "finished", G_CALLBACK(task_finished),
> > channel);
> >          g_signal_emit(channel, signals[SPICE_MAIN_NEW_FILE_TRANSFER], 0,
> > xfer_task);
> >  
> > -        g_file_read_async(file,
> > -                          G_PRIORITY_DEFAULT,
> > -                          cancellable,
> > -                          file_xfer_read_async_cb,
> > -                          xfer_task);
> > -        xfer_task->pending = TRUE;
> > +        spice_file_transfer_task_init_task_async(xfer_task,
> > +                                                 file_xfer_init_task_async_cb
> > ,
> > +                                                 NULL);
> >      }
> >      g_hash_table_unref(xfer_ht);
> >  }
> > @@ -3296,6 +3271,102 @@ static GHashTable
> > *spice_file_transfer_task_create_tasks(GFile **files,
> >      return xfer_ht;
> >  }
> >  
> > +static void spice_file_transfer_task_query_info_cb(GObject *obj,
> > +                                                   GAsyncResult *res,
> > +                                                   gpointer user_data)
> > +{
> > +    SpiceFileTransferTask *self;
> > +    GFileInfo *info;
> > +    GTask *task;
> > +    GError *error = NULL;
> > +
> > +    task = G_TASK(user_data);
> > +    self = g_task_get_source_object(task);
> > +
> > +    g_return_if_fail(self->pending == TRUE);
> > +    self->pending = FALSE;
> > +
> > +    info = g_file_query_info_finish(G_FILE(obj), res, &error);
> > +    if (error || self->error) {
> > +        error = (error == NULL) ? self->error : error;
> > +        g_task_return_error(task, error);
> > +        return;
> > +    }
> > +
> > +    self->file_info = info;
> 
> don't need to save this: see below.
> 
> > +    self->file_size =
> > +        g_file_info_get_attribute_uint64(info,
> > G_FILE_ATTRIBUTE_STANDARD_SIZE);
> > +
> > +    /* SpiceFileTransferTask's init is done, handshake for file-trasfer will
> > +     * start soon. First "progress" can be emitted ~ 0% */
> > +    g_object_notify(G_OBJECT(self), "progress");
> > +
> > +    g_task_return_boolean(task, TRUE);
>
> Instead of returning a boolean here, I think it would be better to do:
>
> g_task_return_pointer(task, info);
>
> Then see suggested changes below to _init_task_finish()

Right!

>
> > +}
> > +
> > +static void spice_file_transfer_task_read_file_cb(GObject *obj,
> > +                                                  GAsyncResult *res,
> > +                                                  gpointer user_data)
> > +{
> > +    SpiceFileTransferTask *self;
> > +    GTask *task;
> > +    GError *error = NULL;
> > +
> > +    task = G_TASK(user_data);
> > +    self = g_task_get_source_object(task);
> > +
> > +    g_return_if_fail(self->pending == TRUE);
> > +
> > +    self->file_stream = g_file_read_finish(G_FILE(obj), res, &error);
> > +    if (error || self->error) {
> > +        self->pending = FALSE;
> > +        error = (error == NULL) ? self->error : error;
> > +        g_task_return_error(task, error);
> > +        return;
> > +    }
> > +
> > +    g_file_query_info_async(self->file,
> > +                            "standard::*",
> > +                            G_FILE_QUERY_INFO_NONE,
> > +                            G_PRIORITY_DEFAULT,
> > +                            self->cancellable,
> > +                            spice_file_transfer_task_query_info_cb,
> > +                            task);
> > +}
> > +
> > +static void spice_file_transfer_task_init_task_async(SpiceFileTransferTask
> > *self,
> > +                                                     GAsyncReadyCallback
> > callback,
> > +                                                     gpointer userdata)
> > +{
> > +    GTask *task;
> > +
> > +    g_return_if_fail(self != NULL);
> > +    g_return_if_fail(self->pending == FALSE);
> > +
> > +    task = g_task_new(self, self->cancellable, callback, userdata);
> > +
> > +    self->pending = TRUE;
> > +    g_file_read_async(self->file,
> > +                      G_PRIORITY_DEFAULT,
> > +                      self->cancellable,
> > +                      spice_file_transfer_task_read_file_cb,
> > +                      task);
> > +}
> > +
> > +static GFileInfo
> > *spice_file_transfer_task_init_task_finish(SpiceFileTransferTask *self,
> > +                                                            GAsyncResult
> > *result,
> > +                                                            GError **error)
> > +{
> > +    GTask *task = G_TASK(result);
> > +
> > +    g_return_val_if_fail(self != NULL, NULL);
> > +
> > +    if (g_task_propagate_boolean(task, error))
> > +        return self->file_info;
> > +
> > +    return NULL;
>
> This function can basically just be:
>
> return g_task_propagate_pointer(task, error);

Indeed :-)

I'll send the changed patch in-reply-too here and I'll keep the rebased
version in the gitlab [0] repo for now.

Many thanks,
  toso

[0] (move-xfer-last) https://gitlab.com/victortoso/spice-gtk

>
> > +}
> > +
> >  static void
> >  spice_file_transfer_task_get_property(GObject *object,
> >                                        guint property_id,
> 
> 
> Reviewed-by: Jonathon Jongsma <jjongsma at redhat.com>
> 
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/spice-devel


More information about the Spice-devel mailing list