summaryrefslogtreecommitdiffstats
path: root/xlators/features/qemu-block/src/coroutine-synctask.c
diff options
context:
space:
mode:
Diffstat (limited to 'xlators/features/qemu-block/src/coroutine-synctask.c')
-rw-r--r--xlators/features/qemu-block/src/coroutine-synctask.c213
1 files changed, 213 insertions, 0 deletions
diff --git a/xlators/features/qemu-block/src/coroutine-synctask.c b/xlators/features/qemu-block/src/coroutine-synctask.c
new file mode 100644
index 000000000..c3538f60e
--- /dev/null
+++ b/xlators/features/qemu-block/src/coroutine-synctask.c
@@ -0,0 +1,213 @@
+/*
+ Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif
+
+#include "glusterfs.h"
+#include "logging.h"
+#include "dict.h"
+#include "xlator.h"
+#include "syncop.h"
+#include "qemu-block-memory-types.h"
+
+#include "qemu-block.h"
+#include "coroutine-synctask.h"
+
+void
+qemu_coroutine_delete (Coroutine *co_)
+{
+ struct synctask *synctask = NULL;
+ CoroutineSynctask *cs = NULL;
+
+ cs = DO_UPCAST(CoroutineSynctask, base, co_);
+ synctask = cs->synctask;
+
+ cs->die = 1;
+ synctask_wake (synctask);
+
+ /* Do not free either @cs or @synctask here.
+ @synctask is naturally destroyed when
+ cs_proc() returns (after "break"ing out of
+ the loop because of setting cs->die=1 above.
+
+ We free @cs too just before returning from
+ cs_proc()
+ */
+ return;
+}
+
+
+CoroutineAction
+qemu_coroutine_switch (Coroutine *from_, Coroutine *to_, CoroutineAction action)
+{
+ struct synctask *to = NULL;
+ struct synctask *from = NULL;
+ CoroutineSynctask *csto = NULL;
+ CoroutineSynctask *csfrom = NULL;
+
+ csto = DO_UPCAST(CoroutineSynctask, base, to_);
+ csfrom = DO_UPCAST(CoroutineSynctask, base, from_);
+ to = csto->synctask;
+ from = csfrom->synctask;
+
+ /* TODO: need mutex/cond guarding when making syncenv
+ multithreaded
+ */
+ csfrom->run = false;
+ csto->run = true;
+
+ /* the next three lines must be in this specific order only */
+ csfrom->action = action;
+
+ synctask_wake (to);
+
+ synctask_yield (from);
+
+ /* the yielder set @action value in @csfrom, but for the
+ resumer it is @csto
+ */
+ return csto->action;
+}
+
+
+int
+cs_fin (int ret, call_frame_t *frame, void *opaque)
+{
+ /* nop */
+ return 0;
+}
+
+
+static int
+cs_proc (void *opaque)
+{
+ CoroutineSynctask *cs = opaque;
+ struct synctask *synctask = NULL;
+
+ synctask = synctask_get (); /* == cs->synctask */
+
+ for (;;) {
+ while (!cs->run && !cs->die)
+ /* entry function (i.e cs->base.entry) will
+ not be set just yet first time. Wait for
+ caller to set it and call switch()
+ */
+ synctask_yield (synctask);
+
+ if (cs->die)
+ break;
+
+ cs->base.entry (cs->base.entry_arg);
+ qemu_coroutine_switch (&cs->base, cs->base.caller,
+ COROUTINE_TERMINATE);
+ }
+
+ GF_FREE (cs);
+
+ return 0;
+}
+
+
+Coroutine *
+qemu_coroutine_new()
+{
+ qb_conf_t *conf = NULL;
+ CoroutineSynctask *cs = NULL;
+ struct synctask *task = NULL;
+
+ conf = THIS->private;
+
+ cs = GF_CALLOC (1, sizeof (*cs), gf_qb_mt_coroutinesynctask_t);
+ if (!cs)
+ return NULL;
+
+ task = synctask_get ();
+ /* Inherit the frame from the parent synctask, as this will
+ carry forward things like uid, gid, pid, lkowner etc. of the
+ caller properly.
+ */
+ cs->synctask = synctask_create (conf->env, cs_proc, cs_fin,
+ task ? task->frame : NULL, cs);
+ if (!cs->synctask)
+ return NULL;
+
+ return &cs->base;
+}
+
+
+Coroutine *
+qemu_coroutine_self()
+{
+ struct synctask *synctask = NULL;
+ CoroutineSynctask *cs = NULL;
+
+ synctask = synctask_get();
+
+ cs = synctask->opaque;
+
+ return &cs->base;
+}
+
+
+bool
+qemu_in_coroutine ()
+{
+ Coroutine *co = NULL;
+
+ co = qemu_coroutine_self ();
+
+ return co && co->caller;
+}
+
+
+/* These are calls for the "top" xlator to invoke/submit
+ coroutines
+*/
+
+static int
+synctask_nop_cbk (int ret, call_frame_t *frame, void *opaque)
+{
+ return 0;
+}
+
+
+int
+qb_synctask_wrap (void *opaque)
+{
+ struct synctask *task = NULL;
+ CoroutineSynctask *cs = NULL;
+ qb_local_t *qb_local = NULL;
+
+ task = synctask_get ();
+ cs = opaque;
+ cs->synctask = task;
+ qb_local = DO_UPCAST (qb_local_t, cs, cs);
+
+ return qb_local->synctask_fn (opaque);
+}
+
+
+int
+qb_coroutine (call_frame_t *frame, synctask_fn_t fn)
+{
+ qb_local_t *qb_local = NULL;
+ qb_conf_t *qb_conf = NULL;
+
+ qb_local = frame->local;
+ qb_local->synctask_fn = fn;
+ qb_conf = frame->this->private;
+
+ return synctask_new (qb_conf->env, qb_synctask_wrap, synctask_nop_cbk,
+ frame, &qb_local->cs);
+}