1 /* 2 * ucontext coroutine initialization code 3 * 4 * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws> 5 * Copyright (C) 2011 Kevin Wolf <kwolf@redhat.com> 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.0 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 /* XXX Is there a nicer way to disable glibc's stack check for longjmp? */ 22 #ifdef _FORTIFY_SOURCE 23 #undef _FORTIFY_SOURCE 24 #endif 25 #include "qemu/osdep.h" 26 #include <ucontext.h> 27 #include "qemu-common.h" 28 #include "qemu/coroutine_int.h" 29 30 #ifdef CONFIG_VALGRIND_H 31 #include <valgrind/valgrind.h> 32 #endif 33 34 typedef struct { 35 Coroutine base; 36 void *stack; 37 sigjmp_buf env; 38 39 #ifdef CONFIG_VALGRIND_H 40 unsigned int valgrind_stack_id; 41 #endif 42 43 } CoroutineUContext; 44 45 /** 46 * Per-thread coroutine bookkeeping 47 */ 48 static __thread CoroutineUContext leader; 49 static __thread Coroutine *current; 50 51 /* 52 * va_args to makecontext() must be type 'int', so passing 53 * the pointer we need may require several int args. This 54 * union is a quick hack to let us do that 55 */ 56 union cc_arg { 57 void *p; 58 int i[2]; 59 }; 60 61 static void coroutine_trampoline(int i0, int i1) 62 { 63 union cc_arg arg; 64 CoroutineUContext *self; 65 Coroutine *co; 66 67 arg.i[0] = i0; 68 arg.i[1] = i1; 69 self = arg.p; 70 co = &self->base; 71 72 /* Initialize longjmp environment and switch back the caller */ 73 if (!sigsetjmp(self->env, 0)) { 74 siglongjmp(*(sigjmp_buf *)co->entry_arg, 1); 75 } 76 77 while (true) { 78 co->entry(co->entry_arg); 79 qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE); 80 } 81 } 82 83 Coroutine *qemu_coroutine_new(void) 84 { 85 const size_t stack_size = 1 << 20; 86 CoroutineUContext *co; 87 ucontext_t old_uc, uc; 88 sigjmp_buf old_env; 89 union cc_arg arg = {0}; 90 91 /* The ucontext functions preserve signal masks which incurs a 92 * system call overhead. sigsetjmp(buf, 0)/siglongjmp() does not 93 * preserve signal masks but only works on the current stack. 94 * Since we need a way to create and switch to a new stack, use 95 * the ucontext functions for that but sigsetjmp()/siglongjmp() for 96 * everything else. 97 */ 98 99 if (getcontext(&uc) == -1) { 100 abort(); 101 } 102 103 co = g_malloc0(sizeof(*co)); 104 co->stack = g_malloc(stack_size); 105 co->base.entry_arg = &old_env; /* stash away our jmp_buf */ 106 107 uc.uc_link = &old_uc; 108 uc.uc_stack.ss_sp = co->stack; 109 uc.uc_stack.ss_size = stack_size; 110 uc.uc_stack.ss_flags = 0; 111 112 #ifdef CONFIG_VALGRIND_H 113 co->valgrind_stack_id = 114 VALGRIND_STACK_REGISTER(co->stack, co->stack + stack_size); 115 #endif 116 117 arg.p = co; 118 119 makecontext(&uc, (void (*)(void))coroutine_trampoline, 120 2, arg.i[0], arg.i[1]); 121 122 /* swapcontext() in, siglongjmp() back out */ 123 if (!sigsetjmp(old_env, 0)) { 124 swapcontext(&old_uc, &uc); 125 } 126 return &co->base; 127 } 128 129 #ifdef CONFIG_VALGRIND_H 130 #ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE 131 /* Work around an unused variable in the valgrind.h macro... */ 132 #pragma GCC diagnostic push 133 #pragma GCC diagnostic ignored "-Wunused-but-set-variable" 134 #endif 135 static inline void valgrind_stack_deregister(CoroutineUContext *co) 136 { 137 VALGRIND_STACK_DEREGISTER(co->valgrind_stack_id); 138 } 139 #ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE 140 #pragma GCC diagnostic pop 141 #endif 142 #endif 143 144 void qemu_coroutine_delete(Coroutine *co_) 145 { 146 CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_); 147 148 #ifdef CONFIG_VALGRIND_H 149 valgrind_stack_deregister(co); 150 #endif 151 152 g_free(co->stack); 153 g_free(co); 154 } 155 156 /* This function is marked noinline to prevent GCC from inlining it 157 * into coroutine_trampoline(). If we allow it to do that then it 158 * hoists the code to get the address of the TLS variable "current" 159 * out of the while() loop. This is an invalid transformation because 160 * the sigsetjmp() call may be called when running thread A but 161 * return in thread B, and so we might be in a different thread 162 * context each time round the loop. 163 */ 164 CoroutineAction __attribute__((noinline)) 165 qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, 166 CoroutineAction action) 167 { 168 CoroutineUContext *from = DO_UPCAST(CoroutineUContext, base, from_); 169 CoroutineUContext *to = DO_UPCAST(CoroutineUContext, base, to_); 170 int ret; 171 172 current = to_; 173 174 ret = sigsetjmp(from->env, 0); 175 if (ret == 0) { 176 siglongjmp(to->env, action); 177 } 178 return ret; 179 } 180 181 Coroutine *qemu_coroutine_self(void) 182 { 183 if (!current) { 184 current = &leader.base; 185 } 186 return current; 187 } 188 189 bool qemu_in_coroutine(void) 190 { 191 return current && current->caller; 192 } 193