From: Gautham R Shenoy <ego@in.ibm.com>
To: Qemu-development List <qemu-devel@nongnu.org>
Subject: [Qemu-devel] [RFC/ PATCH 1/2] qemu: Create a generic asynchronous threading framework to offload tasks
Date: Mon, 10 May 2010 11:45:50 +0530 [thread overview]
Message-ID: <20100510061550.6600.18897.stgit@localhost.localdomain> (raw)
In-Reply-To: <20100510061439.6600.3818.stgit@localhost.localdomain>
From: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
This patch creates a generic asynchronous-task-offloading infrastructure. It's
based on the threading framework that was being used by paio.
The reason why the generic infrastructure has been extracted out of the
posix-aio-compat.c is so that other subsystems, such as virtio-9p could make use
of it for offloading tasks that could block.
[ego@in.ibm.com: work_item_pool, async_work_init, async_work_release,
async_cancel_work]
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Gautham R Shenoy <ego@in.ibm.com>
---
Makefile.objs | 2 +
async-work.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
async-work.h | 85 +++++++++++++++++++++++++++++++++
3 files changed, 236 insertions(+), 0 deletions(-)
create mode 100644 async-work.c
create mode 100644 async-work.h
diff --git a/Makefile.objs b/Makefile.objs
index 32fc37f..7a94fff 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -9,6 +9,7 @@ qobject-obj-y += qerror.o
block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o
block-obj-y += nbd.o block.o aio.o aes.o osdep.o qemu-config.o
+block-obj-y += async-work.o
block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
@@ -44,6 +45,7 @@ fsdev-obj-$(CONFIG_LINUX_VIRTFS) += $(addprefix fsdev/, $(fsdev-nested-y))
# system emulation, i.e. a single QEMU executable should support all
# CPUs and machines.
+#common-obj-y = $(asyncwork-obj-y)
common-obj-y = $(block-obj-y)
common-obj-y += $(net-obj-y)
common-obj-y += $(qobject-obj-y)
diff --git a/async-work.c b/async-work.c
new file mode 100644
index 0000000..3f28475
--- /dev/null
+++ b/async-work.c
@@ -0,0 +1,149 @@
+/*
+ * Async work support
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include "async-work.h"
+#include "osdep.h"
+
+static void async_abort(int err, const char *what)
+{
+ fprintf(stderr, "%s failed: %s\n", what, strerror(err));
+ abort();
+}
+
+static void *async_worker_thread(void *data)
+{
+ struct async_queue *queue = data;
+
+ while (1) {
+ struct work_item *work;
+ int ret = 0;
+ qemu_timeval tv;
+ struct timespec ts;
+
+ qemu_gettimeofday(&tv);
+ ts.tv_sec = tv.tv_sec + 10;
+ ts.tv_nsec = 0;
+
+ pthread_mutex_lock(&(queue->lock));
+
+ while (QTAILQ_EMPTY(&(queue->request_list)) &&
+ (ret != ETIMEDOUT)) {
+ ret = pthread_cond_timedwait(&(queue->cond),
+ &(queue->lock), &ts);
+ }
+
+ if (QTAILQ_EMPTY(&(queue->request_list)))
+ break;
+
+ work = QTAILQ_FIRST(&(queue->request_list));
+ QTAILQ_REMOVE(&(queue->request_list), work, node);
+ queue->idle_threads--;
+ pthread_mutex_unlock(&(queue->lock));
+
+ /* execute the work function */
+ work->func(work);
+
+ pthread_mutex_lock(&(queue->lock));
+ queue->idle_threads++;
+ if ((queue->idle_threads > 0) &&
+ (queue->cur_threads > queue->min_threads)) {
+ /* we retain minimum number of threads */
+ break;
+ }
+ pthread_mutex_unlock(&(queue->lock));
+ }
+
+ queue->idle_threads--;
+ queue->cur_threads--;
+ pthread_mutex_unlock(&(queue->lock));
+
+ return NULL;
+}
+
+static void spawn_async_thread(struct async_queue *queue)
+{
+ int ret;
+ pthread_attr_t attr;
+ pthread_t thread_id;
+ sigset_t set, oldset;
+
+ queue->cur_threads++;
+ queue->idle_threads++;
+ ret = pthread_attr_init(&attr);
+ if (ret) {
+ async_abort(ret, "pthread_attr_init");
+ }
+
+ /* create a detached thread so that we don't need to wait on it */
+ ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ if (ret) {
+ async_abort(ret, "pthread_attr_setdetachstate");
+ }
+
+ /* block all signals */
+ if (sigfillset(&set)) {
+ async_abort(errno, "sigfillset");
+ }
+
+ if (sigprocmask(SIG_SETMASK, &set, &oldset)) {
+ async_abort(errno, "sigprocmask");
+ }
+
+ ret = pthread_create(&thread_id, &attr, async_worker_thread, queue);
+ if (ret) {
+ async_abort(ret, "pthread_create");
+ }
+
+ if (sigprocmask(SIG_SETMASK, &oldset, NULL)) {
+ async_abort(errno, "sigprocmask restore");
+ }
+}
+
+void qemu_async_submit(struct async_queue *queue, struct work_item *work)
+{
+ pthread_mutex_lock(&(queue->lock));
+ if (queue->idle_threads == 0 && queue->cur_threads < queue->max_threads) {
+ spawn_async_thread(queue);
+ }
+ QTAILQ_INSERT_TAIL(&(queue->request_list), work, node);
+ pthread_mutex_unlock(&(queue->lock));
+ pthread_cond_signal(&(queue->cond));
+}
+
+int qemu_async_cancel_work(struct async_queue *queue, struct work_item *work)
+{
+ struct work_item *ret_work;
+ int found = 0;
+
+ pthread_mutex_lock(&(queue->lock));
+ QTAILQ_FOREACH(ret_work, &(queue->request_list), node) {
+ if (ret_work == work) {
+ QTAILQ_REMOVE(&(queue->request_list), ret_work, node);
+ found = 1;
+ break;
+ }
+ }
+ pthread_mutex_unlock(&(queue->lock));
+
+ if (found) {
+ async_work_release(queue, work);
+ return 0;
+ }
+
+ return 1;
+}
+
diff --git a/async-work.h b/async-work.h
new file mode 100644
index 0000000..eef60f7
--- /dev/null
+++ b/async-work.h
@@ -0,0 +1,85 @@
+/*
+ * Async work support
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#ifndef QEMU_ASYNC_WORK_H
+#define QEMU_ASYNC_WORK_H
+
+#include <pthread.h>
+#include "qemu-queue.h"
+#include "qemu-common.h"
+
+struct async_queue
+{
+ pthread_mutex_t lock;
+ pthread_cond_t cond;
+ int max_threads;
+ int min_threads;
+ int cur_threads;
+ int idle_threads;
+ QTAILQ_HEAD(, work_item) request_list;
+ QTAILQ_HEAD(, work_item) work_item_pool;
+};
+
+struct work_item
+{
+ QTAILQ_ENTRY(work_item) node;
+ void (*func)(struct work_item *work);
+ void *private;
+};
+
+static inline void async_queue_init(struct async_queue *queue,
+ int max_threads, int min_threads)
+{
+ queue->cur_threads = 0;
+ queue->idle_threads = 0;
+ queue->max_threads = max_threads;
+ queue->min_threads = min_threads;
+ QTAILQ_INIT(&(queue->request_list));
+ QTAILQ_INIT(&(queue->work_item_pool));
+ pthread_mutex_init(&(queue->lock), NULL);
+ pthread_cond_init(&(queue->cond), NULL);
+}
+
+static inline struct work_item *async_work_init(struct async_queue *queue,
+ void (*func)(struct work_item *),
+ void *data)
+{
+ struct work_item *work;
+ pthread_mutex_lock(&(queue->lock));
+ if (QTAILQ_EMPTY(&(queue->work_item_pool))) {
+ work = qemu_mallocz(sizeof(*work));
+ } else {
+ work = QTAILQ_FIRST(&(queue->work_item_pool));
+ QTAILQ_REMOVE(&(queue->work_item_pool), work, node);
+ }
+
+ work->func = func;
+ work->private = data;
+ pthread_mutex_unlock(&(queue->lock));
+
+ return work;
+}
+
+static inline void async_work_release(struct async_queue *queue,
+ struct work_item *work)
+{
+ pthread_mutex_lock(&(queue->lock));
+ QTAILQ_INSERT_TAIL(&(queue->work_item_pool), work, node);
+ pthread_mutex_unlock(&(queue->lock));
+}
+
+extern void qemu_async_submit(struct async_queue *queue,
+ struct work_item *work);
+
+extern int qemu_async_cancel_work(struct async_queue *queue,
+ struct work_item *work);
+#endif
next prev parent reply other threads:[~2010-05-10 6:16 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-05-10 6:15 [Qemu-devel] [RFC/ PATCH 0/2] qemu: Asynchronous task offloading framework Gautham R Shenoy
2010-05-10 6:15 ` Gautham R Shenoy [this message]
2010-05-10 6:15 ` [Qemu-devel] [RFC/ PATCH 2/2] qemu: Convert paio code to use the generic threading infrastructure Gautham R Shenoy
2010-05-13 5:52 ` Venkateswararao Jujjuri (JV)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20100510061550.6600.18897.stgit@localhost.localdomain \
--to=ego@in.ibm.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.