/* * QEMU I/O task * * Copyright (c) 2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . * */ #ifndef QIO_TASK_H__ #define QIO_TASK_H__ #include "qemu-common.h" #include "qom/object.h" typedef struct QIOTask QIOTask; typedef void (*QIOTaskFunc)(Object *source, Error *err, gpointer opaque); typedef int (*QIOTaskWorker)(QIOTask *task, Error **errp, gpointer opaque); /** * QIOTask: * * The QIOTask object provides a simple mechanism for reporting * success / failure of long running background operations. * * A object on which the operation is to be performed could have * a public API which accepts a task callback: * * * Task callback function signature * * void myobject_operation(QMyObject *obj, * QIOTaskFunc *func, * gpointer opaque, * GDestroyNotify *notify); * * * * The 'func' parameter is the callback to be invoked, and 'opaque' * is data to pass to it. The optional 'notify' function is used * to free 'opaque' when no longer needed. * * Now, lets say the implementation of this method wants to set * a timer to run once a second checking for completion of some * activity. It would do something like * * * Task callback function implementation * * void myobject_operation(QMyObject *obj, * QIOTaskFunc *func, * gpointer opaque, * GDestroyNotify *notify) * { * QIOTask *task; * * task = qio_task_new(OBJECT(obj), func, opaque, notify); * * g_timeout_add_full(G_PRIORITY_DEFAULT, * 1000, * myobject_operation_timer, * task, * NULL); * } * * * * It could equally have setup a watch on a file descriptor or * created a background thread, or something else entirely. * Notice that the source object is passed to the task, and * QIOTask will hold a reference on that. This ensure that * the QMyObject instance cannot be garbage collected while * the async task is still in progress. * * In this case, myobject_operation_timer will fire after * 3 secs and do * * * Task timer function * * gboolean myobject_operation_timer(gpointer opaque) * { * QIOTask *task = QIO_TASK(opaque); * Error *err;* * * ...check something important... * if (err) { * qio_task_abort(task, err); * error_free(task); * return FALSE; * } else if (...work is completed ...) { * qio_task_complete(task); * return FALSE; * } * ...carry on polling ... * return TRUE; * } * * * * Once this function returns false, object_unref will be called * automatically on the task causing it to be released and the * ref on QMyObject dropped too. * * The QIOTask module can also be used to perform operations * in a background thread context, while still reporting the * results in the main event thread. This allows code which * cannot easily be rewritten to be asychronous (such as DNS * lookups) to be easily run non-blocking. Reporting the * results in the main thread context means that the caller * typically does not need to be concerned about thread * safety wrt the QEMU global mutex. * * For example, the socket_listen() method will block the caller * while DNS lookups take place if given a name, instead of IP * address. The C library often do not provide a practical async * DNS API, so the to get non-blocking DNS lookups in a portable * manner requires use of a thread. So achieve a non-blocking * socket listen using QIOTask would require: * * * static int myobject_listen_worker(QIOTask *task, * Error **errp, * gpointer opaque) * { * QMyObject obj = QMY_OBJECT(qio_task_get_source(task)); * SocketAddress *addr = opaque; * * obj->fd = socket_listen(addr, errp); * if (obj->fd < 0) { * return -1; * } * return 0; * } * * void myobject_listen_async(QMyObject *obj, * SocketAddress *addr, * QIOTaskFunc *func, * gpointer opaque, * GDestroyNotify *notify) * { * QIOTask *task; * SocketAddress *addrCopy; * * qapi_copy_SocketAddress(&addrCopy, addr); * task = qio_task_new(OBJECT(obj), func, opaque, notify); * * qio_task_run_in_thread(task, myobject_listen_worker, * addrCopy, * qapi_free_SocketAddress); * } * * * NB, The 'func' callback passed into myobject_listen_async * will be invoked from the main event thread, despite the * actual operation being performed in a different thread. */ /** * qio_task_new: * @source: the object on which the operation is invoked * @func: the callback to invoke when the task completes * @opaque: opaque data to pass to @func when invoked * @destroy: optional callback to free @opaque * * Creates a new task struct to track completion of a * background operation running on the object @source. * When the operation completes or fails, the callback * @func will be invoked. The callback can access the * 'err' attribute in the task object to determine if * the operation was successful or not. * * The returned task will be released when one of * qio_task_abort() or qio_task_complete() are invoked. * * Returns: the task struct */ QIOTask *qio_task_new(Object *source, QIOTaskFunc func, gpointer opaque, GDestroyNotify destroy); /** * qio_task_run_in_thread: * @task: the task struct * @worker: the function to invoke in a thread * @opaque: opaque data to pass to @worker * @destroy: function to free @opaque * * Run a task in a background thread. If @worker * returns 0 it will call qio_task_complete() in * the main event thread context. If @worker * returns -1 it will call qio_task_abort() in * the main event thread context. */ void qio_task_run_in_thread(QIOTask *task, QIOTaskWorker worker, gpointer opaque, GDestroyNotify destroy); /** * qio_task_complete: * @task: the task struct * * Mark the operation as succesfully completed * and free the memory for @task. */ void qio_task_complete(QIOTask *task); /** * qio_task_abort: * @task: the task struct * @err: the error to record for the operation * * Mark the operation as failed, with @err providing * details about the failure. The @err may be freed * afer the function returns, as the notification * callback is invoked synchronously. The @task will * be freed when this call completes. */ void qio_task_abort(QIOTask *task, Error *err); /** * qio_task_get_source: * @task: the task struct * * Get the source object associated with the background * task. This returns a new reference to the object, * which the caller must released with object_unref() * when no longer required. * * Returns: the source object */ Object *qio_task_get_source(QIOTask *task); #endif /* QIO_TASK_H__ */