xref: /openbmc/qemu/util/coroutine-ucontext.c (revision f413f9fc)
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