110817bf0SDaniel P. Berrange /*
210817bf0SDaniel P. Berrange * ucontext coroutine initialization code
310817bf0SDaniel P. Berrange *
410817bf0SDaniel P. Berrange * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
510817bf0SDaniel P. Berrange * Copyright (C) 2011 Kevin Wolf <kwolf@redhat.com>
610817bf0SDaniel P. Berrange *
710817bf0SDaniel P. Berrange * This library is free software; you can redistribute it and/or
810817bf0SDaniel P. Berrange * modify it under the terms of the GNU Lesser General Public
910817bf0SDaniel P. Berrange * License as published by the Free Software Foundation; either
1010817bf0SDaniel P. Berrange * version 2.0 of the License, or (at your option) any later version.
1110817bf0SDaniel P. Berrange *
1210817bf0SDaniel P. Berrange * This library is distributed in the hope that it will be useful,
1310817bf0SDaniel P. Berrange * but WITHOUT ANY WARRANTY; without even the implied warranty of
1410817bf0SDaniel P. Berrange * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1510817bf0SDaniel P. Berrange * Lesser General Public License for more details.
1610817bf0SDaniel P. Berrange *
1710817bf0SDaniel P. Berrange * You should have received a copy of the GNU Lesser General Public
1810817bf0SDaniel P. Berrange * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1910817bf0SDaniel P. Berrange */
2010817bf0SDaniel P. Berrange
2110817bf0SDaniel P. Berrange /* XXX Is there a nicer way to disable glibc's stack check for longjmp? */
2210817bf0SDaniel P. Berrange #undef _FORTIFY_SOURCE
239afa888cSDaniel P. Berrangé #define _FORTIFY_SOURCE 0
249afa888cSDaniel P. Berrangé
25aafd7584SPeter Maydell #include "qemu/osdep.h"
2610817bf0SDaniel P. Berrange #include <ucontext.h>
2710817bf0SDaniel P. Berrange #include "qemu/coroutine_int.h"
2834145a30SStefan Hajnoczi #include "qemu/coroutine-tls.h"
2910817bf0SDaniel P. Berrange
3010817bf0SDaniel P. Berrange #ifdef CONFIG_VALGRIND_H
3110817bf0SDaniel P. Berrange #include <valgrind/valgrind.h>
3210817bf0SDaniel P. Berrange #endif
3310817bf0SDaniel P. Berrange
34638466f7SMarc-André Lureau #ifdef QEMU_SANITIZE_ADDRESS
35d83414e1SMarc-André Lureau #ifdef CONFIG_ASAN_IFACE_FIBER
36d83414e1SMarc-André Lureau #define CONFIG_ASAN 1
37d83414e1SMarc-André Lureau #include <sanitizer/asan_interface.h>
38d83414e1SMarc-André Lureau #endif
39d83414e1SMarc-André Lureau #endif
40d83414e1SMarc-André Lureau
410aebab04SLingfeng Yang #ifdef CONFIG_TSAN
420aebab04SLingfeng Yang #include <sanitizer/tsan_interface.h>
430aebab04SLingfeng Yang #endif
440aebab04SLingfeng Yang
4510817bf0SDaniel P. Berrange typedef struct {
4610817bf0SDaniel P. Berrange Coroutine base;
4710817bf0SDaniel P. Berrange void *stack;
48ddba1591SPeter Lieven size_t stack_size;
4958ebc2c3SDaniele Buono #ifdef CONFIG_SAFESTACK
5058ebc2c3SDaniele Buono /* Need an unsafe stack for each coroutine */
5158ebc2c3SDaniele Buono void *unsafe_stack;
5258ebc2c3SDaniele Buono size_t unsafe_stack_size;
5358ebc2c3SDaniele Buono #endif
5410817bf0SDaniel P. Berrange sigjmp_buf env;
5510817bf0SDaniel P. Berrange
56995f5c3cSRobert Foley #ifdef CONFIG_TSAN
570aebab04SLingfeng Yang void *tsan_co_fiber;
580aebab04SLingfeng Yang void *tsan_caller_fiber;
59995f5c3cSRobert Foley #endif
600aebab04SLingfeng Yang
6110817bf0SDaniel P. Berrange #ifdef CONFIG_VALGRIND_H
6210817bf0SDaniel P. Berrange unsigned int valgrind_stack_id;
6310817bf0SDaniel P. Berrange #endif
6410817bf0SDaniel P. Berrange
6510817bf0SDaniel P. Berrange } CoroutineUContext;
6610817bf0SDaniel P. Berrange
6710817bf0SDaniel P. Berrange /**
6810817bf0SDaniel P. Berrange * Per-thread coroutine bookkeeping
6910817bf0SDaniel P. Berrange */
7034145a30SStefan Hajnoczi QEMU_DEFINE_STATIC_CO_TLS(Coroutine *, current);
7134145a30SStefan Hajnoczi QEMU_DEFINE_STATIC_CO_TLS(CoroutineUContext, leader);
7210817bf0SDaniel P. Berrange
7310817bf0SDaniel P. Berrange /*
7410817bf0SDaniel P. Berrange * va_args to makecontext() must be type 'int', so passing
7510817bf0SDaniel P. Berrange * the pointer we need may require several int args. This
7610817bf0SDaniel P. Berrange * union is a quick hack to let us do that
7710817bf0SDaniel P. Berrange */
7810817bf0SDaniel P. Berrange union cc_arg {
7910817bf0SDaniel P. Berrange void *p;
8010817bf0SDaniel P. Berrange int i[2];
8110817bf0SDaniel P. Berrange };
8210817bf0SDaniel P. Berrange
83995f5c3cSRobert Foley /*
84995f5c3cSRobert Foley * QEMU_ALWAYS_INLINE only does so if __OPTIMIZE__, so we cannot use it.
85995f5c3cSRobert Foley * always_inline is required to avoid TSan runtime fatal errors.
86995f5c3cSRobert Foley */
870aebab04SLingfeng Yang static inline __attribute__((always_inline))
on_new_fiber(CoroutineUContext * co)880aebab04SLingfeng Yang void on_new_fiber(CoroutineUContext *co)
890aebab04SLingfeng Yang {
900aebab04SLingfeng Yang #ifdef CONFIG_TSAN
910aebab04SLingfeng Yang co->tsan_co_fiber = __tsan_create_fiber(0); /* flags: sync on switch */
920aebab04SLingfeng Yang co->tsan_caller_fiber = __tsan_get_current_fiber();
930aebab04SLingfeng Yang #endif
940aebab04SLingfeng Yang }
950aebab04SLingfeng Yang
96995f5c3cSRobert Foley /* always_inline is required to avoid TSan runtime fatal errors. */
970aebab04SLingfeng Yang static inline __attribute__((always_inline))
finish_switch_fiber(void * fake_stack_save)980aebab04SLingfeng Yang void finish_switch_fiber(void *fake_stack_save)
99d83414e1SMarc-André Lureau {
100d83414e1SMarc-André Lureau #ifdef CONFIG_ASAN
10134145a30SStefan Hajnoczi CoroutineUContext *leaderp = get_ptr_leader();
102d83414e1SMarc-André Lureau const void *bottom_old;
103d83414e1SMarc-André Lureau size_t size_old;
104d83414e1SMarc-André Lureau
105d83414e1SMarc-André Lureau __sanitizer_finish_switch_fiber(fake_stack_save, &bottom_old, &size_old);
106d83414e1SMarc-André Lureau
10734145a30SStefan Hajnoczi if (!leaderp->stack) {
10834145a30SStefan Hajnoczi leaderp->stack = (void *)bottom_old;
10934145a30SStefan Hajnoczi leaderp->stack_size = size_old;
110d83414e1SMarc-André Lureau }
111d83414e1SMarc-André Lureau #endif
1120aebab04SLingfeng Yang #ifdef CONFIG_TSAN
1130aebab04SLingfeng Yang if (fake_stack_save) {
1140aebab04SLingfeng Yang __tsan_release(fake_stack_save);
1150aebab04SLingfeng Yang __tsan_switch_to_fiber(fake_stack_save, 0); /* 0=synchronize */
1160aebab04SLingfeng Yang }
1170aebab04SLingfeng Yang #endif
118d83414e1SMarc-André Lureau }
119d83414e1SMarc-André Lureau
120995f5c3cSRobert Foley /* always_inline is required to avoid TSan runtime fatal errors. */
121995f5c3cSRobert Foley static inline __attribute__((always_inline))
start_switch_fiber_asan(void ** fake_stack_save,const void * bottom,size_t size)122*f413f9fcSAkihiko Odaki void start_switch_fiber_asan(void **fake_stack_save,
123995f5c3cSRobert Foley const void *bottom, size_t size)
124d83414e1SMarc-André Lureau {
125d83414e1SMarc-André Lureau #ifdef CONFIG_ASAN
126*f413f9fcSAkihiko Odaki __sanitizer_start_switch_fiber(fake_stack_save, bottom, size);
1270aebab04SLingfeng Yang #endif
128995f5c3cSRobert Foley }
129995f5c3cSRobert Foley
130995f5c3cSRobert Foley /* always_inline is required to avoid TSan runtime fatal errors. */
131995f5c3cSRobert Foley static inline __attribute__((always_inline))
start_switch_fiber_tsan(void ** fake_stack_save,CoroutineUContext * co,bool caller)132995f5c3cSRobert Foley void start_switch_fiber_tsan(void **fake_stack_save,
133995f5c3cSRobert Foley CoroutineUContext *co,
134995f5c3cSRobert Foley bool caller)
135995f5c3cSRobert Foley {
1360aebab04SLingfeng Yang #ifdef CONFIG_TSAN
137995f5c3cSRobert Foley void *new_fiber = caller ?
138995f5c3cSRobert Foley co->tsan_caller_fiber :
139995f5c3cSRobert Foley co->tsan_co_fiber;
140995f5c3cSRobert Foley void *curr_fiber = __tsan_get_current_fiber();
1410aebab04SLingfeng Yang __tsan_acquire(curr_fiber);
1420aebab04SLingfeng Yang
1430aebab04SLingfeng Yang *fake_stack_save = curr_fiber;
1440aebab04SLingfeng Yang __tsan_switch_to_fiber(new_fiber, 0); /* 0=synchronize */
145d83414e1SMarc-André Lureau #endif
146d83414e1SMarc-André Lureau }
147d83414e1SMarc-André Lureau
coroutine_trampoline(int i0,int i1)14810817bf0SDaniel P. Berrange static void coroutine_trampoline(int i0, int i1)
14910817bf0SDaniel P. Berrange {
15010817bf0SDaniel P. Berrange union cc_arg arg;
15110817bf0SDaniel P. Berrange CoroutineUContext *self;
15210817bf0SDaniel P. Berrange Coroutine *co;
153d83414e1SMarc-André Lureau void *fake_stack_save = NULL;
154d83414e1SMarc-André Lureau
155d83414e1SMarc-André Lureau finish_switch_fiber(NULL);
15610817bf0SDaniel P. Berrange
15710817bf0SDaniel P. Berrange arg.i[0] = i0;
15810817bf0SDaniel P. Berrange arg.i[1] = i1;
15910817bf0SDaniel P. Berrange self = arg.p;
16010817bf0SDaniel P. Berrange co = &self->base;
16110817bf0SDaniel P. Berrange
16210817bf0SDaniel P. Berrange /* Initialize longjmp environment and switch back the caller */
16310817bf0SDaniel P. Berrange if (!sigsetjmp(self->env, 0)) {
16434145a30SStefan Hajnoczi CoroutineUContext *leaderp = get_ptr_leader();
16534145a30SStefan Hajnoczi
166*f413f9fcSAkihiko Odaki start_switch_fiber_asan(&fake_stack_save,
16734145a30SStefan Hajnoczi leaderp->stack, leaderp->stack_size);
168995f5c3cSRobert Foley start_switch_fiber_tsan(&fake_stack_save, self, true); /* true=caller */
16910817bf0SDaniel P. Berrange siglongjmp(*(sigjmp_buf *)co->entry_arg, 1);
17010817bf0SDaniel P. Berrange }
17110817bf0SDaniel P. Berrange
172d83414e1SMarc-André Lureau finish_switch_fiber(fake_stack_save);
173d83414e1SMarc-André Lureau
17410817bf0SDaniel P. Berrange while (true) {
17510817bf0SDaniel P. Berrange co->entry(co->entry_arg);
17610817bf0SDaniel P. Berrange qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE);
17710817bf0SDaniel P. Berrange }
17810817bf0SDaniel P. Berrange }
17910817bf0SDaniel P. Berrange
qemu_coroutine_new(void)18010817bf0SDaniel P. Berrange Coroutine *qemu_coroutine_new(void)
18110817bf0SDaniel P. Berrange {
18210817bf0SDaniel P. Berrange CoroutineUContext *co;
18310817bf0SDaniel P. Berrange ucontext_t old_uc, uc;
18410817bf0SDaniel P. Berrange sigjmp_buf old_env;
18510817bf0SDaniel P. Berrange union cc_arg arg = {0};
186d83414e1SMarc-André Lureau void *fake_stack_save = NULL;
18710817bf0SDaniel P. Berrange
18810817bf0SDaniel P. Berrange /* The ucontext functions preserve signal masks which incurs a
18910817bf0SDaniel P. Berrange * system call overhead. sigsetjmp(buf, 0)/siglongjmp() does not
19010817bf0SDaniel P. Berrange * preserve signal masks but only works on the current stack.
19110817bf0SDaniel P. Berrange * Since we need a way to create and switch to a new stack, use
19210817bf0SDaniel P. Berrange * the ucontext functions for that but sigsetjmp()/siglongjmp() for
19310817bf0SDaniel P. Berrange * everything else.
19410817bf0SDaniel P. Berrange */
19510817bf0SDaniel P. Berrange
19610817bf0SDaniel P. Berrange if (getcontext(&uc) == -1) {
19710817bf0SDaniel P. Berrange abort();
19810817bf0SDaniel P. Berrange }
19910817bf0SDaniel P. Berrange
20010817bf0SDaniel P. Berrange co = g_malloc0(sizeof(*co));
201ddba1591SPeter Lieven co->stack_size = COROUTINE_STACK_SIZE;
202ddba1591SPeter Lieven co->stack = qemu_alloc_stack(&co->stack_size);
20358ebc2c3SDaniele Buono #ifdef CONFIG_SAFESTACK
20458ebc2c3SDaniele Buono co->unsafe_stack_size = COROUTINE_STACK_SIZE;
20558ebc2c3SDaniele Buono co->unsafe_stack = qemu_alloc_stack(&co->unsafe_stack_size);
20658ebc2c3SDaniele Buono #endif
20710817bf0SDaniel P. Berrange co->base.entry_arg = &old_env; /* stash away our jmp_buf */
20810817bf0SDaniel P. Berrange
20910817bf0SDaniel P. Berrange uc.uc_link = &old_uc;
21010817bf0SDaniel P. Berrange uc.uc_stack.ss_sp = co->stack;
211ddba1591SPeter Lieven uc.uc_stack.ss_size = co->stack_size;
21210817bf0SDaniel P. Berrange uc.uc_stack.ss_flags = 0;
21310817bf0SDaniel P. Berrange
21410817bf0SDaniel P. Berrange #ifdef CONFIG_VALGRIND_H
21510817bf0SDaniel P. Berrange co->valgrind_stack_id =
216ddba1591SPeter Lieven VALGRIND_STACK_REGISTER(co->stack, co->stack + co->stack_size);
21710817bf0SDaniel P. Berrange #endif
21810817bf0SDaniel P. Berrange
21910817bf0SDaniel P. Berrange arg.p = co;
22010817bf0SDaniel P. Berrange
2210aebab04SLingfeng Yang on_new_fiber(co);
22210817bf0SDaniel P. Berrange makecontext(&uc, (void (*)(void))coroutine_trampoline,
22310817bf0SDaniel P. Berrange 2, arg.i[0], arg.i[1]);
22410817bf0SDaniel P. Berrange
22510817bf0SDaniel P. Berrange /* swapcontext() in, siglongjmp() back out */
22610817bf0SDaniel P. Berrange if (!sigsetjmp(old_env, 0)) {
227*f413f9fcSAkihiko Odaki start_switch_fiber_asan(&fake_stack_save, co->stack, co->stack_size);
228995f5c3cSRobert Foley start_switch_fiber_tsan(&fake_stack_save,
229995f5c3cSRobert Foley co, false); /* false=not caller */
23058ebc2c3SDaniele Buono
23158ebc2c3SDaniele Buono #ifdef CONFIG_SAFESTACK
23258ebc2c3SDaniele Buono /*
23358ebc2c3SDaniele Buono * Before we swap the context, set the new unsafe stack
23458ebc2c3SDaniele Buono * The unsafe stack grows just like the normal stack, so start from
23558ebc2c3SDaniele Buono * the last usable location of the memory area.
23658ebc2c3SDaniele Buono * NOTE: we don't have to re-set the usp afterwards because we are
23758ebc2c3SDaniele Buono * coming back to this context through a siglongjmp.
23858ebc2c3SDaniele Buono * The compiler already wrapped the corresponding sigsetjmp call with
23958ebc2c3SDaniele Buono * code that saves the usp on the (safe) stack before the call, and
24058ebc2c3SDaniele Buono * restores it right after (which is where we return with siglongjmp).
24158ebc2c3SDaniele Buono */
24258ebc2c3SDaniele Buono void *usp = co->unsafe_stack + co->unsafe_stack_size;
24358ebc2c3SDaniele Buono __safestack_unsafe_stack_ptr = usp;
24458ebc2c3SDaniele Buono #endif
24558ebc2c3SDaniele Buono
24610817bf0SDaniel P. Berrange swapcontext(&old_uc, &uc);
24710817bf0SDaniel P. Berrange }
248d83414e1SMarc-André Lureau
249d83414e1SMarc-André Lureau finish_switch_fiber(fake_stack_save);
250d83414e1SMarc-André Lureau
25110817bf0SDaniel P. Berrange return &co->base;
25210817bf0SDaniel P. Berrange }
25310817bf0SDaniel P. Berrange
25410817bf0SDaniel P. Berrange #ifdef CONFIG_VALGRIND_H
25510817bf0SDaniel P. Berrange /* Work around an unused variable in the valgrind.h macro... */
2567aa12aa2SThomas Huth #if !defined(__clang__)
25710817bf0SDaniel P. Berrange #pragma GCC diagnostic push
25810817bf0SDaniel P. Berrange #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
25910817bf0SDaniel P. Berrange #endif
valgrind_stack_deregister(CoroutineUContext * co)26010817bf0SDaniel P. Berrange static inline void valgrind_stack_deregister(CoroutineUContext *co)
26110817bf0SDaniel P. Berrange {
26210817bf0SDaniel P. Berrange VALGRIND_STACK_DEREGISTER(co->valgrind_stack_id);
26310817bf0SDaniel P. Berrange }
2647aa12aa2SThomas Huth #if !defined(__clang__)
26510817bf0SDaniel P. Berrange #pragma GCC diagnostic pop
26610817bf0SDaniel P. Berrange #endif
26710817bf0SDaniel P. Berrange #endif
26810817bf0SDaniel P. Berrange
269*f413f9fcSAkihiko Odaki #if defined(CONFIG_ASAN) && defined(CONFIG_COROUTINE_POOL)
terminate_asan(void * opaque)270*f413f9fcSAkihiko Odaki static void coroutine_fn terminate_asan(void *opaque)
271*f413f9fcSAkihiko Odaki {
272*f413f9fcSAkihiko Odaki CoroutineUContext *to = DO_UPCAST(CoroutineUContext, base, opaque);
273*f413f9fcSAkihiko Odaki
274*f413f9fcSAkihiko Odaki set_current(opaque);
275*f413f9fcSAkihiko Odaki start_switch_fiber_asan(NULL, to->stack, to->stack_size);
276*f413f9fcSAkihiko Odaki G_STATIC_ASSERT(!IS_ENABLED(CONFIG_TSAN));
277*f413f9fcSAkihiko Odaki siglongjmp(to->env, COROUTINE_ENTER);
278*f413f9fcSAkihiko Odaki }
279*f413f9fcSAkihiko Odaki #endif
280*f413f9fcSAkihiko Odaki
qemu_coroutine_delete(Coroutine * co_)28110817bf0SDaniel P. Berrange void qemu_coroutine_delete(Coroutine *co_)
28210817bf0SDaniel P. Berrange {
28310817bf0SDaniel P. Berrange CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_);
28410817bf0SDaniel P. Berrange
285*f413f9fcSAkihiko Odaki #if defined(CONFIG_ASAN) && defined(CONFIG_COROUTINE_POOL)
286*f413f9fcSAkihiko Odaki co_->entry_arg = qemu_coroutine_self();
287*f413f9fcSAkihiko Odaki co_->entry = terminate_asan;
288*f413f9fcSAkihiko Odaki qemu_coroutine_switch(co_->entry_arg, co_, COROUTINE_ENTER);
289*f413f9fcSAkihiko Odaki #endif
290*f413f9fcSAkihiko Odaki
29110817bf0SDaniel P. Berrange #ifdef CONFIG_VALGRIND_H
29210817bf0SDaniel P. Berrange valgrind_stack_deregister(co);
29310817bf0SDaniel P. Berrange #endif
29410817bf0SDaniel P. Berrange
295ddba1591SPeter Lieven qemu_free_stack(co->stack, co->stack_size);
29658ebc2c3SDaniele Buono #ifdef CONFIG_SAFESTACK
29758ebc2c3SDaniele Buono qemu_free_stack(co->unsafe_stack, co->unsafe_stack_size);
29858ebc2c3SDaniele Buono #endif
29910817bf0SDaniel P. Berrange g_free(co);
30010817bf0SDaniel P. Berrange }
30110817bf0SDaniel P. Berrange
30210817bf0SDaniel P. Berrange /* This function is marked noinline to prevent GCC from inlining it
30310817bf0SDaniel P. Berrange * into coroutine_trampoline(). If we allow it to do that then it
30410817bf0SDaniel P. Berrange * hoists the code to get the address of the TLS variable "current"
30510817bf0SDaniel P. Berrange * out of the while() loop. This is an invalid transformation because
30610817bf0SDaniel P. Berrange * the sigsetjmp() call may be called when running thread A but
30710817bf0SDaniel P. Berrange * return in thread B, and so we might be in a different thread
30810817bf0SDaniel P. Berrange * context each time round the loop.
30910817bf0SDaniel P. Berrange */
31010817bf0SDaniel P. Berrange CoroutineAction __attribute__((noinline))
qemu_coroutine_switch(Coroutine * from_,Coroutine * to_,CoroutineAction action)31110817bf0SDaniel P. Berrange qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
31210817bf0SDaniel P. Berrange CoroutineAction action)
31310817bf0SDaniel P. Berrange {
31410817bf0SDaniel P. Berrange CoroutineUContext *from = DO_UPCAST(CoroutineUContext, base, from_);
31510817bf0SDaniel P. Berrange CoroutineUContext *to = DO_UPCAST(CoroutineUContext, base, to_);
31610817bf0SDaniel P. Berrange int ret;
317d83414e1SMarc-André Lureau void *fake_stack_save = NULL;
31810817bf0SDaniel P. Berrange
31934145a30SStefan Hajnoczi set_current(to_);
32010817bf0SDaniel P. Berrange
32110817bf0SDaniel P. Berrange ret = sigsetjmp(from->env, 0);
32210817bf0SDaniel P. Berrange if (ret == 0) {
323*f413f9fcSAkihiko Odaki start_switch_fiber_asan(IS_ENABLED(CONFIG_COROUTINE_POOL) ||
324*f413f9fcSAkihiko Odaki action != COROUTINE_TERMINATE ?
325*f413f9fcSAkihiko Odaki &fake_stack_save : NULL,
326*f413f9fcSAkihiko Odaki to->stack, to->stack_size);
327995f5c3cSRobert Foley start_switch_fiber_tsan(&fake_stack_save,
328995f5c3cSRobert Foley to, false); /* false=not caller */
32910817bf0SDaniel P. Berrange siglongjmp(to->env, action);
33010817bf0SDaniel P. Berrange }
331d83414e1SMarc-André Lureau
332d83414e1SMarc-André Lureau finish_switch_fiber(fake_stack_save);
333d83414e1SMarc-André Lureau
33410817bf0SDaniel P. Berrange return ret;
33510817bf0SDaniel P. Berrange }
33610817bf0SDaniel P. Berrange
qemu_coroutine_self(void)33710817bf0SDaniel P. Berrange Coroutine *qemu_coroutine_self(void)
33810817bf0SDaniel P. Berrange {
33934145a30SStefan Hajnoczi Coroutine *self = get_current();
34034145a30SStefan Hajnoczi CoroutineUContext *leaderp = get_ptr_leader();
34134145a30SStefan Hajnoczi
34234145a30SStefan Hajnoczi if (!self) {
34334145a30SStefan Hajnoczi self = &leaderp->base;
34434145a30SStefan Hajnoczi set_current(self);
34510817bf0SDaniel P. Berrange }
3460aebab04SLingfeng Yang #ifdef CONFIG_TSAN
34734145a30SStefan Hajnoczi if (!leaderp->tsan_co_fiber) {
34834145a30SStefan Hajnoczi leaderp->tsan_co_fiber = __tsan_get_current_fiber();
3490aebab04SLingfeng Yang }
3500aebab04SLingfeng Yang #endif
35134145a30SStefan Hajnoczi return self;
35210817bf0SDaniel P. Berrange }
35310817bf0SDaniel P. Berrange
qemu_in_coroutine(void)35410817bf0SDaniel P. Berrange bool qemu_in_coroutine(void)
35510817bf0SDaniel P. Berrange {
35634145a30SStefan Hajnoczi Coroutine *self = get_current();
35734145a30SStefan Hajnoczi
35834145a30SStefan Hajnoczi return self && self->caller;
35910817bf0SDaniel P. Berrange }
360