From patchwork Mon May 24 12:53:13 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gautham R Shenoy X-Patchwork-Id: 53415 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 69281B7D12 for ; Mon, 24 May 2010 22:57:41 +1000 (EST) Received: from localhost ([127.0.0.1]:58675 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OGXDu-0006WW-2z for incoming@patchwork.ozlabs.org; Mon, 24 May 2010 08:57:38 -0400 Received: from [140.186.70.92] (port=44442 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OGX9j-0004aP-8n for qemu-devel@nongnu.org; Mon, 24 May 2010 08:53:20 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1OGX9h-00071Z-41 for qemu-devel@nongnu.org; Mon, 24 May 2010 08:53:19 -0400 Received: from e23smtp07.au.ibm.com ([202.81.31.140]:58521) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1OGX9g-00071N-Av for qemu-devel@nongnu.org; Mon, 24 May 2010 08:53:17 -0400 Received: from d23relay05.au.ibm.com (d23relay05.au.ibm.com [202.81.31.247]) by e23smtp07.au.ibm.com (8.14.3/8.13.1) with ESMTP id o4OCrF0U029898 for ; Mon, 24 May 2010 22:53:15 +1000 Received: from d23av04.au.ibm.com (d23av04.au.ibm.com [9.190.235.139]) by d23relay05.au.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id o4OCrEKu1634304 for ; Mon, 24 May 2010 22:53:14 +1000 Received: from d23av04.au.ibm.com (loopback [127.0.0.1]) by d23av04.au.ibm.com (8.14.3/8.13.1/NCO v10.0 AVout) with ESMTP id o4OCrEhX028184 for ; Mon, 24 May 2010 22:53:14 +1000 Received: from sofia.in.ibm.com ([9.124.35.40]) by d23av04.au.ibm.com (8.14.3/8.13.1/NCO v10.0 AVin) with ESMTP id o4OCrDLe028179; Mon, 24 May 2010 22:53:13 +1000 Received: from localhost.localdomain (localhost [IPv6:::1]) by sofia.in.ibm.com (Postfix) with ESMTP id 50882E4B35; Mon, 24 May 2010 18:23:13 +0530 (IST) To: Qemu-development List From: Gautham R Shenoy Date: Mon, 24 May 2010 18:23:13 +0530 Message-ID: <20100524125313.29646.18863.stgit@localhost.localdomain> In-Reply-To: <20100524125220.29646.62160.stgit@localhost.localdomain> References: <20100524125220.29646.62160.stgit@localhost.localdomain> User-Agent: StGit/0.15-51-gc750 MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) Cc: Anthony Liguori , Avi Kivity Subject: [Qemu-devel] [RFC/ PATCH 3/4] virtio-9p: Add async helper functions X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add helper functions to enable virtio-9p make use of the generic asynchronous threading framework for offloading blocking tasks such as making posix calls on to the asynchronous threads and handle the post_posix_operations() from the context of the iothread. This frees the vcpu thread to process any other guest operations while the processing of v9fs_io is in progress. Signed-off-by: Gautham R Shenoy --- hw/virtio-9p.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 167 insertions(+), 0 deletions(-) diff --git a/hw/virtio-9p.c b/hw/virtio-9p.c index 82bb663..f8f60d3 100644 --- a/hw/virtio-9p.c +++ b/hw/virtio-9p.c @@ -17,10 +17,147 @@ #include "virtio-9p.h" #include "fsdev/qemu-fsdev.h" #include "virtio-9p-debug.h" +#include "async-work.h" int dotu = 1; int debug_9p_pdu; +struct v9fs_post_op { + QTAILQ_ENTRY(v9fs_post_op) node; + void (*func)(void *arg); + void *arg; +}; + +static struct { + struct async_queue virtio_9p_aqueue; + int rfd; + int wfd; + pthread_mutex_t lock; + QTAILQ_HEAD(, v9fs_post_op) post_op_list; +} v9fs_async_struct; + +static void die2(int err, const char *what) +{ + fprintf(stderr, "%s failed: %s\n", what, strerror(err)); + abort(); +} + +static void die(const char *what) +{ + die2(errno, what); +} + +/** + * v9fs_signal_handler: Handle the SIGUSR1 signal. + * @signum: Is SIGUSR1 in this case. + * + * This function is used to inform the iothread that a particular + * async-operation pertaining to v9fs has been completed and that the io thread + * can handle the v9fs_post_posix_operation. + * + * This is based on the aio_signal_handler + */ +static void v9fs_signal_handler(int signum) +{ + char byte = 0; + ssize_t ret; + + printf("Writing to file descriptor %d\n", v9fs_async_struct.wfd); + ret = write(v9fs_async_struct.wfd, &byte, sizeof(byte)); + + if (ret < 0 && errno != EAGAIN) + die("write() in v9fs"); + + qemu_service_io(); +} + +#define ASYNC_MAX_PROCESS 5 + +/** + * v9fs_process_post_ops: Process any pending v9fs_post_posix_operation + * @arg: Not used. + * + * This function serves as a callback to the iothread to be called into whenever + * the v9fs_async_struct.wfd is written into. This thread goes through the list + * of v9fs_post_posix_operations() and executes them. In the process, it might + * queue more job on the asynchronous thread pool. + */ +static void v9fs_process_post_ops(void *arg) +{ + int count = 0; + struct v9fs_post_op *post_op; + + pthread_mutex_lock(&v9fs_async_struct.lock); + for (count = 0; count < ASYNC_MAX_PROCESS; count++) { + if (QTAILQ_EMPTY(&(v9fs_async_struct.post_op_list))) { + break; + } + post_op = QTAILQ_FIRST(&(v9fs_async_struct.post_op_list)); + QTAILQ_REMOVE(&(v9fs_async_struct.post_op_list), post_op, node); + + pthread_mutex_unlock(&v9fs_async_struct.lock); + post_op->func(post_op->arg); + qemu_free(post_op); + pthread_mutex_lock(&v9fs_async_struct.lock); + } + pthread_mutex_unlock(&v9fs_async_struct.lock); +} + +/** + * v9fs_async_signal: Send a signal to the iothread. + * @func: v9fs_post_posix_func() to be called by the iothread. + * @arg: Argument to func. + * + * This function is called from the context of one of the asynchronous threads + * in the thread pool. This is called when the asynchronous thread has finished + * executing a v9fs_posix_operation. It's purpose is to initiate the process of + * informing the iothread that the v9fs_posix_operation has completed. + * + * This code follows the suit of the aio_thread() and uses SIGUSR1 to notify the + * iothread. + */ +static void v9fs_async_signal(void (*func)(void *arg), void *arg) +{ + struct v9fs_post_op *post_op; + pid_t pid = getpid(); + + post_op = qemu_mallocz(sizeof(*post_op)); + post_op->func = func; + post_op->arg = arg; + + pthread_mutex_lock(&v9fs_async_struct.lock); + QTAILQ_INSERT_TAIL(&(v9fs_async_struct.post_op_list), post_op, node); + pthread_mutex_unlock(&v9fs_async_struct.lock); + + if(kill(pid, SIGUSR1)) die("v9fs kill failed"); +} + +/** + * v9fs_do_async_posix: Offload v9fs_posix_operation onto async thread. + * @vs: V9fsOPState variable for the OP operation. + * @posix_fn: The posix function which has to be offloaded onto async thread. + * @post_fn_ptr: Address of the location to hold the post_fn corresponding to + * the posix_fn + * @post_fn: The post_fn corresponding to the posix_fn. + * + * This function is a helper to offload posix_operation on to the asynchronous + * thread pool. It sets up the associations with the post_function that needs to + * be invoked by from the context of the iothread once the posix_fn has been + * executed. + */ +static void v9fs_do_async_posix(void *vs , + void (*posix_fn)(struct work_item *work), + void (**post_fn_ptr)(void *arg), + void (*post_fn)(void *arg)) +{ + struct work_item *work; + + *post_fn_ptr = post_fn; + work = async_work_init(&v9fs_async_struct.virtio_9p_aqueue, + posix_fn, vs); + qemu_async_submit(&v9fs_async_struct.virtio_9p_aqueue, work); +} + enum { Oread = 0x00, Owrite = 0x01, @@ -2321,6 +2458,8 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf) int i, len; struct stat stat; FsTypeEntry *fse; + int fds[2]; + struct sigaction act; s = (V9fsState *)virtio_common_init("virtio-9p", @@ -2395,5 +2534,33 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf) s->tag_len; s->vdev.get_config = virtio_9p_get_config; + sigfillset(&act.sa_mask); + act.sa_flags = 0; + act.sa_handler = v9fs_signal_handler; + sigaction(SIGUSR1, &act, NULL); + + if (qemu_pipe(fds) == -1) { + fprintf(stderr, "failed to create fd's for virtio-9p\n"); + exit(1); + } + + v9fs_async_struct.rfd = fds[0]; + v9fs_async_struct.wfd = fds[1]; + + printf("v9fs: rfd: %d\n", v9fs_async_struct.rfd); + printf("v9fs: wfd: %d\n", v9fs_async_struct.wfd); + + fcntl(fds[0], F_SETFL, O_NONBLOCK); + fcntl(fds[1], F_SETFL, O_NONBLOCK); + + qemu_set_fd_handler(fds[0], v9fs_process_post_ops, NULL, NULL); + QTAILQ_INIT(&v9fs_async_struct.post_op_list); + pthread_mutex_init(&(v9fs_async_struct.lock), NULL); + /* Create async queue. */ + async_queue_init(&v9fs_async_struct.virtio_9p_aqueue, 10, 3); + + (void)v9fs_do_async_posix; + (void)v9fs_async_signal; + return &s->vdev; }