[Spice-devel] [PATCH spice-gtk V3 1/3] file-xfer: handling various transfer messages in main channel

Dunrong Huang riegamaths at gmail.com
Tue Dec 18 02:38:44 PST 2012


Hi

On Fri, Dec 7, 2012 at 7:45 PM, Marc-André Lureau
<marcandre.lureau at gmail.com> wrote:
> Hi
>
> On Wed, Dec 5, 2012 at 5:22 AM, Dunrong Huang <riegamaths at gmail.com> wrote:
>>
>> This patch is aimed to handle various file xfer messages.
>>
>> How it works:
>> 0) our main channel introduces a API spice_main_file_xfer().
>
>
> In general we prefer more human name in API, such as spice_main_file_copy()
>
> Imho, it should follow gio async model, so a client can track progress of
> each calls. (look at g_file_copy_async)
>
> I think a client API such as this one would fit better:
>
> spice_main_file_copy_async (GFile**, SpiceFileCopyFlags .., GCancellable,
> GFileProgressCallback, gpointer, GAsyncReadyCallback, gpointer)
>
Ok.
>
>>
>> 1) When user drags a file and drop to spice client, spice client will
>>    catch a signal "drag-data-received", then it should call
>>    spice_main_file_xfer() for transfering file to guest.
>>
>> 2) In main channel: when spice_main_file_xfer() get called with file
>>    list passed, the API will send a start message which includes file
>>    and other needed information for each file. Then it will create a
>>    new xfer task and insert task list for each file, and return to caller.
>
>
> We shouldn't create several tasks simultaneously for a single call, it
> should be serialized to minimize completion time of each file.
>>
It makes sense.
>>
>> 3) According to the response message sent from guest, our main channel
>>    decides whether send more data, or cancel this xfer task.
>>
>> 4) When file transfer has finished, file xfer task will be removed from
>>    task list.
>>
>> Signed-off-by: Dunrong Huang <riegamaths at gmail.com>
>> ---
>>  gtk/channel-main.c      | 202
>> ++++++++++++++++++++++++++++++++++++++++++++++++
>>  gtk/channel-main.h      |   1 +
>>  gtk/map-file            |   1 +
>>  gtk/spice-glib-sym-file |   1 +
>>  4 files changed, 205 insertions(+)
>>
>> diff --git a/gtk/channel-main.c b/gtk/channel-main.c
>> index 6b9ba8d..b2253a6 100644
>> --- a/gtk/channel-main.c
>> +++ b/gtk/channel-main.c
>> @@ -18,6 +18,7 @@
>>  #include <math.h>
>>  #include <spice/vd_agent.h>
>>  #include <common/rect.h>
>> +#include <glib/gstdio.h>
>>
>>  #include "glib-compat.h"
>>  #include "spice-client.h"
>> @@ -51,6 +52,12 @@
>>
>>  typedef struct spice_migrate spice_migrate;
>>
>> +typedef struct SpiceFileXferTask {
>> +    uint32_t                       id;
>> +    SpiceChannel                   *channel;
>> +    GFileInputStream               *file_stream;
>> +} SpiceFileXferTask;
>> +
>>  struct _SpiceMainChannelPrivate  {
>>      enum SpiceMouseMode         mouse_mode;
>>      bool                        agent_connected;
>> @@ -79,6 +86,7 @@ struct _SpiceMainChannelPrivate  {
>>      } display[MAX_DISPLAY];
>>      gint                        timer_id;
>>      GQueue                      *agent_msg_queue;
>> +    GList                       *file_xfer_task_list;
>>
>>      guint                       switch_host_delayed_id;
>>      guint                       migrate_delayed_id;
>> @@ -1384,6 +1392,100 @@ static void
>> main_handle_agent_disconnected(SpiceChannel *channel, SpiceMsgIn *in
>>      agent_stopped(SPICE_MAIN_CHANNEL(channel));
>>  }
>>
>> +static gboolean send_data(gpointer opaque)
>> +{
>> +#define FILE_XFER_CHUNK_SIZE (VD_AGENT_MAX_DATA_SIZE -
>> sizeof(VDAgentMessage))
>> +    SpiceFileXferTask *task = (SpiceFileXferTask *)opaque;
>> +
>> +    SpiceMainChannel *channel = SPICE_MAIN_CHANNEL(task->channel);
>> +    SpiceMainChannelPrivate *c = channel->priv;
>> +    gssize len;
>> +    GError *error = NULL;
>> +    VDAgentFileXferDataMessage *msg;
>> +    uint32_t msg_size;
>> +
>> +    if (!g_queue_is_empty(c->agent_msg_queue)) {
>> +        spice_channel_wakeup(SPICE_CHANNEL(channel), FALSE);
>> +        return TRUE;
>
>
> You can't use Idle functions this way, you are going to busy-loop. You need
> to handle filling the queue differently.
>
I  knew this way is not good, but I cant find a better way to handle
it. What about using g_io_scheduler_push_job() to fill data into msg
queue.
e.g.:

// gio thread context
static gboolean send_data()
{
    // code

    for (;;) {
        if (agent msg queue is not empty) {
            // wait for 1ms until msg queue become empty, so that other messages
            // can still get through.
            usleep(1000);
            continue;
        }

        // read some data from file
        // ====== code ======

        // fill data to queue in main loop.
        g_idle_add(fill_data, userdata);
    }

    // code
}

void file_xfer_send_data_msg
{
    // code

    g_io_scheduler_push_job(send_data);

    // code
}

-- 
Best Regards,

Dunrong Huang


More information about the Spice-devel mailing list