qemu/io/task.c
<<
>>
Prefs
   1/*
   2 * QEMU I/O task
   3 *
   4 * Copyright (c) 2015 Red Hat, Inc.
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2 of the License, or (at your option) any later version.
  10 *
  11 * This library is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18 *
  19 */
  20
  21#include "qemu/osdep.h"
  22#include "io/task.h"
  23#include "qapi/error.h"
  24#include "qemu/thread.h"
  25#include "trace.h"
  26
  27struct QIOTask {
  28    Object *source;
  29    QIOTaskFunc func;
  30    gpointer opaque;
  31    GDestroyNotify destroy;
  32    Error *err;
  33    gpointer result;
  34    GDestroyNotify destroyResult;
  35};
  36
  37
  38QIOTask *qio_task_new(Object *source,
  39                      QIOTaskFunc func,
  40                      gpointer opaque,
  41                      GDestroyNotify destroy)
  42{
  43    QIOTask *task;
  44
  45    task = g_new0(QIOTask, 1);
  46
  47    task->source = source;
  48    object_ref(source);
  49    task->func = func;
  50    task->opaque = opaque;
  51    task->destroy = destroy;
  52
  53    trace_qio_task_new(task, source, func, opaque);
  54
  55    return task;
  56}
  57
  58static void qio_task_free(QIOTask *task)
  59{
  60    if (task->destroy) {
  61        task->destroy(task->opaque);
  62    }
  63    if (task->destroyResult) {
  64        task->destroyResult(task->result);
  65    }
  66    if (task->err) {
  67        error_free(task->err);
  68    }
  69    object_unref(task->source);
  70
  71    g_free(task);
  72}
  73
  74
  75struct QIOTaskThreadData {
  76    QIOTask *task;
  77    QIOTaskWorker worker;
  78    gpointer opaque;
  79    GDestroyNotify destroy;
  80};
  81
  82
  83static gboolean gio_task_thread_result(gpointer opaque)
  84{
  85    struct QIOTaskThreadData *data = opaque;
  86
  87    trace_qio_task_thread_result(data->task);
  88    qio_task_complete(data->task);
  89
  90    if (data->destroy) {
  91        data->destroy(data->opaque);
  92    }
  93
  94    g_free(data);
  95
  96    return FALSE;
  97}
  98
  99
 100static gpointer qio_task_thread_worker(gpointer opaque)
 101{
 102    struct QIOTaskThreadData *data = opaque;
 103
 104    trace_qio_task_thread_run(data->task);
 105    data->worker(data->task, data->opaque);
 106
 107    /* We're running in the background thread, and must only
 108     * ever report the task results in the main event loop
 109     * thread. So we schedule an idle callback to report
 110     * the worker results
 111     */
 112    trace_qio_task_thread_exit(data->task);
 113    g_idle_add(gio_task_thread_result, data);
 114    return NULL;
 115}
 116
 117
 118void qio_task_run_in_thread(QIOTask *task,
 119                            QIOTaskWorker worker,
 120                            gpointer opaque,
 121                            GDestroyNotify destroy)
 122{
 123    struct QIOTaskThreadData *data = g_new0(struct QIOTaskThreadData, 1);
 124    QemuThread thread;
 125
 126    data->task = task;
 127    data->worker = worker;
 128    data->opaque = opaque;
 129    data->destroy = destroy;
 130
 131    trace_qio_task_thread_start(task, worker, opaque);
 132    qemu_thread_create(&thread,
 133                       "io-task-worker",
 134                       qio_task_thread_worker,
 135                       data,
 136                       QEMU_THREAD_DETACHED);
 137}
 138
 139
 140void qio_task_complete(QIOTask *task)
 141{
 142    task->func(task, task->opaque);
 143    trace_qio_task_complete(task);
 144    qio_task_free(task);
 145}
 146
 147
 148void qio_task_set_error(QIOTask *task,
 149                        Error *err)
 150{
 151    error_propagate(&task->err, err);
 152}
 153
 154
 155bool qio_task_propagate_error(QIOTask *task,
 156                              Error **errp)
 157{
 158    if (task->err) {
 159        error_propagate(errp, task->err);
 160        task->err = NULL;
 161        return true;
 162    }
 163
 164    return false;
 165}
 166
 167
 168void qio_task_set_result_pointer(QIOTask *task,
 169                                 gpointer result,
 170                                 GDestroyNotify destroy)
 171{
 172    task->result = result;
 173    task->destroyResult = destroy;
 174}
 175
 176
 177gpointer qio_task_get_result_pointer(QIOTask *task)
 178{
 179    return task->result;
 180}
 181
 182
 183Object *qio_task_get_source(QIOTask *task)
 184{
 185    return task->source;
 186}
 187