├── LICENSE ├── README.rst ├── conftest.c ├── coro.c ├── coro.h └── package.json /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2000-2009 Marc Alexander Lehmann 2 | 3 | Redistribution and use in source and binary forms, with or without modifica- 4 | tion, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 14 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- 15 | CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 16 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- 17 | CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 18 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 19 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 20 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- 21 | ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 22 | OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | Alternatively, the following files carry an additional notice that 25 | explicitly allows relicensing under the GPLv2: coro.c, coro.h. 26 | 27 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | http://software.schmorp.de/pkg/libcoro.html 2 | 3 | Configuration, documentation etc. is provided in the coro.h file. Please 4 | note that the file conftest.c in this distribution is under the GPL. It is 5 | not needed for proper operation of this library though, for that, coro.h 6 | and coro.c suffice. 7 | 8 | Marc Lehmann 9 | -------------------------------------------------------------------------------- /conftest.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was taken from pth-1.40/aclocal.m4 3 | * The original copyright is below. 4 | * 5 | * GNU Pth - The GNU Portable Threads 6 | * Copyright (c) 1999-2001 Ralf S. Engelschall 7 | * 8 | * This file is part of GNU Pth, a non-preemptive thread scheduling 9 | * library which can be found at http://www.gnu.org/software/pth/. 10 | * 11 | * This file is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This file is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this file; if not, write to the Free Software 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 24 | * USA, or contact Marc Lehmann . 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | #if defined(TEST_sigstack) || defined(TEST_sigaltstack) 31 | #include 32 | #include 33 | #include 34 | #endif 35 | #if defined(TEST_makecontext) 36 | #include 37 | #endif 38 | union alltypes { 39 | long l; 40 | double d; 41 | void *vp; 42 | void (*fp)(void); 43 | char *cp; 44 | }; 45 | static volatile char *handler_addr = (char *)0xDEAD; 46 | #if defined(TEST_sigstack) || defined(TEST_sigaltstack) 47 | static volatile int handler_done = 0; 48 | void handler(int sig) 49 | { 50 | char garbage[1024]; 51 | int i; 52 | auto int dummy; 53 | for (i = 0; i < 1024; i++) 54 | garbage[i] = 'X'; 55 | handler_addr = (char *)&dummy; 56 | handler_done = 1; 57 | return; 58 | } 59 | #endif 60 | #if defined(TEST_makecontext) 61 | static ucontext_t uc_handler; 62 | static ucontext_t uc_main; 63 | void handler(void) 64 | { 65 | char garbage[1024]; 66 | int i; 67 | auto int dummy; 68 | for (i = 0; i < 1024; i++) 69 | garbage[i] = 'X'; 70 | handler_addr = (char *)&dummy; 71 | swapcontext(&uc_handler, &uc_main); 72 | return; 73 | } 74 | #endif 75 | int main(int argc, char *argv[]) 76 | { 77 | FILE *f; 78 | char *skaddr; 79 | char *skbuf; 80 | int sksize; 81 | char result[1024]; 82 | int i; 83 | sksize = 32768; 84 | skbuf = (char *)malloc(sksize*2+2*sizeof(union alltypes)); 85 | if (skbuf == NULL) 86 | exit(1); 87 | for (i = 0; i < sksize*2+2*sizeof(union alltypes); i++) 88 | skbuf[i] = 'A'; 89 | skaddr = skbuf+sizeof(union alltypes); 90 | #if defined(TEST_sigstack) || defined(TEST_sigaltstack) 91 | { 92 | struct sigaction sa; 93 | #if defined(TEST_sigstack) 94 | struct sigstack ss; 95 | #elif defined(TEST_sigaltstack) && defined(HAVE_STACK_T) 96 | stack_t ss; 97 | #else 98 | struct sigaltstack ss; 99 | #endif 100 | #if defined(TEST_sigstack) 101 | ss.ss_sp = (void *)(skaddr + sksize); 102 | ss.ss_onstack = 0; 103 | if (sigstack(&ss, NULL) < 0) 104 | exit(1); 105 | #elif defined(TEST_sigaltstack) 106 | ss.ss_sp = (void *)(skaddr + sksize); 107 | ss.ss_size = sksize; 108 | ss.ss_flags = 0; 109 | if (sigaltstack(&ss, NULL) < 0) 110 | exit(1); 111 | #endif 112 | memset((void *)&sa, 0, sizeof(struct sigaction)); 113 | sa.sa_handler = handler; 114 | sa.sa_flags = SA_ONSTACK; 115 | sigemptyset(&sa.sa_mask); 116 | sigaction(SIGUSR1, &sa, NULL); 117 | kill(getpid(), SIGUSR1); 118 | while (!handler_done) 119 | /*nop*/; 120 | } 121 | #endif 122 | #if defined(TEST_makecontext) 123 | { 124 | if (getcontext(&uc_handler) != 0) 125 | exit(1); 126 | uc_handler.uc_link = NULL; 127 | uc_handler.uc_stack.ss_sp = (void *)(skaddr + sksize); 128 | uc_handler.uc_stack.ss_size = sksize; 129 | uc_handler.uc_stack.ss_flags = 0; 130 | makecontext(&uc_handler, handler, 1); 131 | swapcontext(&uc_main, &uc_handler); 132 | } 133 | #endif 134 | if (handler_addr == (char *)0xDEAD) 135 | exit(1); 136 | if (handler_addr < skaddr+sksize) { 137 | /* stack was placed into lower area */ 138 | if (*(skaddr+sksize) != 'A') 139 | sprintf(result, "(skaddr)+(sksize)-%d,(sksize)-%d", 140 | sizeof(union alltypes), sizeof(union alltypes)); 141 | else 142 | strcpy(result, "(skaddr)+(sksize),(sksize)"); 143 | } 144 | else { 145 | /* stack was placed into higher area */ 146 | if (*(skaddr+sksize*2) != 'A') 147 | sprintf(result, "(skaddr),(sksize)-%d", sizeof(union alltypes)); 148 | else 149 | strcpy(result, "(skaddr),(sksize)"); 150 | } 151 | printf("%s\n", result); 152 | exit(0); 153 | } 154 | 155 | -------------------------------------------------------------------------------- /coro.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2001-2011 Marc Alexander Lehmann 3 | * 4 | * Redistribution and use in source and binary forms, with or without modifica- 5 | * tion, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, 8 | * this list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 15 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- 16 | * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 17 | * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- 18 | * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- 22 | * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 23 | * OF THE POSSIBILITY OF SUCH DAMAGE. 24 | * 25 | * Alternatively, the contents of this file may be used under the terms of 26 | * the GNU General Public License ("GPL") version 2 or any later version, 27 | * in which case the provisions of the GPL are applicable instead of 28 | * the above. If you wish to allow the use of your version of this file 29 | * only under the terms of the GPL and not to allow others to use your 30 | * version of this file under the BSD license, indicate your decision 31 | * by deleting the provisions above and replace them with the notice 32 | * and other provisions required by the GPL. If you do not delete the 33 | * provisions above, a recipient may use your version of this file under 34 | * either the BSD or the GPL. 35 | * 36 | * This library is modelled strictly after Ralf S. Engelschalls article at 37 | * http://www.gnu.org/software/pth/rse-pmt.ps. So most of the credit must 38 | * go to Ralf S. Engelschall . 39 | */ 40 | 41 | #include "coro.h" 42 | 43 | #include 44 | #include 45 | 46 | /*****************************************************************************/ 47 | /* ucontext/setjmp/asm backends */ 48 | /*****************************************************************************/ 49 | #if CORO_UCONTEXT || CORO_SJLJ || CORO_LOSER || CORO_LINUX || CORO_IRIX || CORO_ASM 50 | 51 | # if CORO_UCONTEXT 52 | # include 53 | # endif 54 | 55 | # if !defined(STACK_ADJUST_PTR) 56 | # if __sgi 57 | /* IRIX is decidedly NON-unix */ 58 | # define STACK_ADJUST_PTR(sp,ss) ((char *)(sp) + (ss) - 8) 59 | # define STACK_ADJUST_SIZE(sp,ss) ((ss) - 8) 60 | # elif (__i386__ && CORO_LINUX) || (_M_IX86 && CORO_LOSER) 61 | # define STACK_ADJUST_PTR(sp,ss) ((char *)(sp) + (ss)) 62 | # define STACK_ADJUST_SIZE(sp,ss) (ss) 63 | # elif (__amd64__ && CORO_LINUX) || ((_M_AMD64 || _M_IA64) && CORO_LOSER) 64 | # define STACK_ADJUST_PTR(sp,ss) ((char *)(sp) + (ss) - 8) 65 | # define STACK_ADJUST_SIZE(sp,ss) (ss) 66 | # else 67 | # define STACK_ADJUST_PTR(sp,ss) (sp) 68 | # define STACK_ADJUST_SIZE(sp,ss) (ss) 69 | # endif 70 | # endif 71 | 72 | # include 73 | 74 | # if CORO_SJLJ 75 | # include 76 | # include 77 | # include 78 | # endif 79 | 80 | static coro_func coro_init_func; 81 | static void *coro_init_arg; 82 | static coro_context *new_coro, *create_coro; 83 | 84 | static void 85 | coro_init (void) 86 | { 87 | volatile coro_func func = coro_init_func; 88 | volatile void *arg = coro_init_arg; 89 | 90 | coro_transfer (new_coro, create_coro); 91 | 92 | #if __GCC_HAVE_DWARF2_CFI_ASM && __amd64 93 | asm (".cfi_undefined rip"); 94 | #endif 95 | 96 | func ((void *)arg); 97 | 98 | /* the new coro returned. bad. just abort() for now */ 99 | abort (); 100 | } 101 | 102 | # if CORO_SJLJ 103 | 104 | static volatile int trampoline_done; 105 | 106 | /* trampoline signal handler */ 107 | static void 108 | trampoline (int sig) 109 | { 110 | if (coro_setjmp (new_coro->env)) 111 | coro_init (); /* start it */ 112 | else 113 | trampoline_done = 1; 114 | } 115 | 116 | # endif 117 | 118 | # if CORO_ASM 119 | 120 | #if _WIN32 || __CYGWIN__ 121 | #define CORO_WIN_TIB 1 122 | #endif 123 | 124 | asm ( 125 | "\t.text\n" 126 | #if _WIN32 || __CYGWIN__ 127 | "\t.globl _coro_transfer\n" 128 | "_coro_transfer:\n" 129 | #else 130 | "\t.globl coro_transfer\n" 131 | "coro_transfer:\n" 132 | #endif 133 | /* windows, of course, gives a shit on the amd64 ABI and uses different registers */ 134 | /* http://blogs.msdn.com/freik/archive/2005/03/17/398200.aspx */ 135 | #if __amd64 136 | 137 | #if _WIN32 || __CYGWIN__ 138 | #define NUM_SAVED 29 139 | "\tsubq $168, %rsp\t" /* one dummy qword to improve alignment */ 140 | "\tmovaps %xmm6, (%rsp)\n" 141 | "\tmovaps %xmm7, 16(%rsp)\n" 142 | "\tmovaps %xmm8, 32(%rsp)\n" 143 | "\tmovaps %xmm9, 48(%rsp)\n" 144 | "\tmovaps %xmm10, 64(%rsp)\n" 145 | "\tmovaps %xmm11, 80(%rsp)\n" 146 | "\tmovaps %xmm12, 96(%rsp)\n" 147 | "\tmovaps %xmm13, 112(%rsp)\n" 148 | "\tmovaps %xmm14, 128(%rsp)\n" 149 | "\tmovaps %xmm15, 144(%rsp)\n" 150 | "\tpushq %rsi\n" 151 | "\tpushq %rdi\n" 152 | "\tpushq %rbp\n" 153 | "\tpushq %rbx\n" 154 | "\tpushq %r12\n" 155 | "\tpushq %r13\n" 156 | "\tpushq %r14\n" 157 | "\tpushq %r15\n" 158 | #if CORO_WIN_TIB 159 | "\tpushq %fs:0x0\n" 160 | "\tpushq %fs:0x8\n" 161 | "\tpushq %fs:0xc\n" 162 | #endif 163 | "\tmovq %rsp, (%rcx)\n" 164 | "\tmovq (%rdx), %rsp\n" 165 | #if CORO_WIN_TIB 166 | "\tpopq %fs:0xc\n" 167 | "\tpopq %fs:0x8\n" 168 | "\tpopq %fs:0x0\n" 169 | #endif 170 | "\tpopq %r15\n" 171 | "\tpopq %r14\n" 172 | "\tpopq %r13\n" 173 | "\tpopq %r12\n" 174 | "\tpopq %rbx\n" 175 | "\tpopq %rbp\n" 176 | "\tpopq %rdi\n" 177 | "\tpopq %rsi\n" 178 | "\tmovaps (%rsp), %xmm6\n" 179 | "\tmovaps 16(%rsp), %xmm7\n" 180 | "\tmovaps 32(%rsp), %xmm8\n" 181 | "\tmovaps 48(%rsp), %xmm9\n" 182 | "\tmovaps 64(%rsp), %xmm10\n" 183 | "\tmovaps 80(%rsp), %xmm11\n" 184 | "\tmovaps 96(%rsp), %xmm12\n" 185 | "\tmovaps 112(%rsp), %xmm13\n" 186 | "\tmovaps 128(%rsp), %xmm14\n" 187 | "\tmovaps 144(%rsp), %xmm15\n" 188 | "\taddq $168, %rsp\n" 189 | #else 190 | #define NUM_SAVED 6 191 | "\tpushq %rbp\n" 192 | "\tpushq %rbx\n" 193 | "\tpushq %r12\n" 194 | "\tpushq %r13\n" 195 | "\tpushq %r14\n" 196 | "\tpushq %r15\n" 197 | "\tmovq %rsp, (%rdi)\n" 198 | "\tmovq (%rsi), %rsp\n" 199 | "\tpopq %r15\n" 200 | "\tpopq %r14\n" 201 | "\tpopq %r13\n" 202 | "\tpopq %r12\n" 203 | "\tpopq %rbx\n" 204 | "\tpopq %rbp\n" 205 | #endif 206 | "\tpopq %rcx\n" 207 | "\tjmpq *%rcx\n" 208 | 209 | #elif __i386 210 | 211 | #define NUM_SAVED 4 212 | "\tpushl %ebp\n" 213 | "\tpushl %ebx\n" 214 | "\tpushl %esi\n" 215 | "\tpushl %edi\n" 216 | #if CORO_WIN_TIB 217 | #undef NUM_SAVED 218 | #define NUM_SAVED 7 219 | "\tpushl %fs:0\n" 220 | "\tpushl %fs:4\n" 221 | "\tpushl %fs:8\n" 222 | #endif 223 | "\tmovl %esp, (%eax)\n" 224 | "\tmovl (%edx), %esp\n" 225 | #if CORO_WIN_TIB 226 | "\tpopl %fs:8\n" 227 | "\tpopl %fs:4\n" 228 | "\tpopl %fs:0\n" 229 | #endif 230 | "\tpopl %edi\n" 231 | "\tpopl %esi\n" 232 | "\tpopl %ebx\n" 233 | "\tpopl %ebp\n" 234 | "\tpopl %ecx\n" 235 | "\tjmpl *%ecx\n" 236 | 237 | #else 238 | #error unsupported architecture 239 | #endif 240 | ); 241 | 242 | # endif 243 | 244 | void 245 | coro_create (coro_context *ctx, coro_func coro, void *arg, void *sptr, size_t ssize) 246 | { 247 | coro_context nctx; 248 | # if CORO_SJLJ 249 | stack_t ostk, nstk; 250 | struct sigaction osa, nsa; 251 | sigset_t nsig, osig; 252 | # endif 253 | 254 | if (!coro) 255 | return; 256 | 257 | coro_init_func = coro; 258 | coro_init_arg = arg; 259 | 260 | new_coro = ctx; 261 | create_coro = &nctx; 262 | 263 | # if CORO_SJLJ 264 | /* we use SIGUSR2. first block it, then fiddle with it. */ 265 | 266 | sigemptyset (&nsig); 267 | sigaddset (&nsig, SIGUSR2); 268 | sigprocmask (SIG_BLOCK, &nsig, &osig); 269 | 270 | nsa.sa_handler = trampoline; 271 | sigemptyset (&nsa.sa_mask); 272 | nsa.sa_flags = SA_ONSTACK; 273 | 274 | if (sigaction (SIGUSR2, &nsa, &osa)) 275 | { 276 | perror ("sigaction"); 277 | abort (); 278 | } 279 | 280 | /* set the new stack */ 281 | nstk.ss_sp = STACK_ADJUST_PTR (sptr, ssize); /* yes, some platforms (IRIX) get this wrong. */ 282 | nstk.ss_size = STACK_ADJUST_SIZE (sptr, ssize); 283 | nstk.ss_flags = 0; 284 | 285 | if (sigaltstack (&nstk, &ostk) < 0) 286 | { 287 | perror ("sigaltstack"); 288 | abort (); 289 | } 290 | 291 | trampoline_done = 0; 292 | kill (getpid (), SIGUSR2); 293 | sigfillset (&nsig); sigdelset (&nsig, SIGUSR2); 294 | 295 | while (!trampoline_done) 296 | sigsuspend (&nsig); 297 | 298 | sigaltstack (0, &nstk); 299 | nstk.ss_flags = SS_DISABLE; 300 | if (sigaltstack (&nstk, 0) < 0) 301 | perror ("sigaltstack"); 302 | 303 | sigaltstack (0, &nstk); 304 | if (~nstk.ss_flags & SS_DISABLE) 305 | abort (); 306 | 307 | if (~ostk.ss_flags & SS_DISABLE) 308 | sigaltstack (&ostk, 0); 309 | 310 | sigaction (SIGUSR2, &osa, 0); 311 | sigprocmask (SIG_SETMASK, &osig, 0); 312 | 313 | # elif CORO_LOSER 314 | 315 | coro_setjmp (ctx->env); 316 | #if __CYGWIN__ && __i386 317 | ctx->env[8] = (long) coro_init; 318 | ctx->env[7] = (long) ((char *)sptr + ssize) - sizeof (long); 319 | #elif __CYGWIN__ && __x86_64 320 | ctx->env[7] = (long) coro_init; 321 | ctx->env[6] = (long) ((char *)sptr + ssize) - sizeof (long); 322 | #elif defined __MINGW32__ 323 | ctx->env[5] = (long) coro_init; 324 | ctx->env[4] = (long) ((char *)sptr + ssize) - sizeof (long); 325 | #elif defined _M_IX86 326 | ((_JUMP_BUFFER *)&ctx->env)->Eip = (long) coro_init; 327 | ((_JUMP_BUFFER *)&ctx->env)->Esp = (long) STACK_ADJUST_PTR (sptr, ssize) - sizeof (long); 328 | #elif defined _M_AMD64 329 | ((_JUMP_BUFFER *)&ctx->env)->Rip = (__int64) coro_init; 330 | ((_JUMP_BUFFER *)&ctx->env)->Rsp = (__int64) STACK_ADJUST_PTR (sptr, ssize) - sizeof (__int64); 331 | #elif defined _M_IA64 332 | ((_JUMP_BUFFER *)&ctx->env)->StIIP = (__int64) coro_init; 333 | ((_JUMP_BUFFER *)&ctx->env)->IntSp = (__int64) STACK_ADJUST_PTR (sptr, ssize) - sizeof (__int64); 334 | #else 335 | #error "microsoft libc or architecture not supported" 336 | #endif 337 | 338 | # elif CORO_LINUX 339 | 340 | coro_setjmp (ctx->env); 341 | #if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && defined (JB_PC) && defined (JB_SP) 342 | ctx->env[0].__jmpbuf[JB_PC] = (long) coro_init; 343 | ctx->env[0].__jmpbuf[JB_SP] = (long) STACK_ADJUST_PTR (sptr, ssize) - sizeof (long); 344 | #elif __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && defined (__mc68000__) 345 | ctx->env[0].__jmpbuf[0].__aregs[0] = (long int)coro_init; 346 | ctx->env[0].__jmpbuf[0].__sp = (int *) ((char *)sptr + ssize) - sizeof (long); 347 | #elif defined (__GNU_LIBRARY__) && defined (__i386__) 348 | ctx->env[0].__jmpbuf[0].__pc = (char *) coro_init; 349 | ctx->env[0].__jmpbuf[0].__sp = (void *) ((char *)sptr + ssize) - sizeof (long); 350 | #elif defined (__GNU_LIBRARY__) && defined (__amd64__) 351 | ctx->env[0].__jmpbuf[JB_PC] = (long) coro_init; 352 | ctx->env[0].__jmpbuf[0].__sp = (void *) ((char *)sptr + ssize) - sizeof (long); 353 | #else 354 | #error "linux libc or architecture not supported" 355 | #endif 356 | 357 | # elif CORO_IRIX 358 | 359 | coro_setjmp (ctx->env, 0); 360 | ctx->env[JB_PC] = (__uint64_t)coro_init; 361 | ctx->env[JB_SP] = (__uint64_t)STACK_ADJUST_PTR (sptr, ssize) - sizeof (long); 362 | 363 | # elif CORO_ASM 364 | 365 | ctx->sp = (void **)(ssize + (char *)sptr); 366 | *--ctx->sp = (void *)abort; /* needed for alignment only */ 367 | *--ctx->sp = (void *)coro_init; 368 | 369 | #if CORO_WIN_TIB 370 | *--ctx->sp = 0; /* ExceptionList */ 371 | *--ctx->sp = (char *)sptr + ssize; /* StackBase */ 372 | *--ctx->sp = sptr; /* StackLimit */ 373 | #endif 374 | 375 | ctx->sp -= NUM_SAVED; 376 | memset (ctx->sp, 0, sizeof (*ctx->sp) * NUM_SAVED); 377 | 378 | # elif CORO_UCONTEXT 379 | 380 | getcontext (&(ctx->uc)); 381 | 382 | ctx->uc.uc_link = 0; 383 | ctx->uc.uc_stack.ss_sp = sptr; 384 | ctx->uc.uc_stack.ss_size = (size_t)ssize; 385 | ctx->uc.uc_stack.ss_flags = 0; 386 | 387 | makecontext (&(ctx->uc), (void (*)())coro_init, 0); 388 | 389 | # endif 390 | 391 | coro_transfer (create_coro, new_coro); 392 | } 393 | 394 | /*****************************************************************************/ 395 | /* pthread backend */ 396 | /*****************************************************************************/ 397 | #elif CORO_PTHREAD 398 | 399 | /* this mutex will be locked by the running coroutine */ 400 | pthread_mutex_t coro_mutex = PTHREAD_MUTEX_INITIALIZER; 401 | 402 | struct coro_init_args 403 | { 404 | coro_func func; 405 | void *arg; 406 | coro_context *self, *main; 407 | }; 408 | 409 | static pthread_t null_tid; 410 | 411 | /* I'd so love to cast pthread_mutex_unlock to void (*)(void *)... */ 412 | static void 413 | mutex_unlock_wrapper (void *arg) 414 | { 415 | pthread_mutex_unlock ((pthread_mutex_t *)arg); 416 | } 417 | 418 | static void * 419 | coro_init (void *args_) 420 | { 421 | struct coro_init_args *args = (struct coro_init_args *)args_; 422 | coro_func func = args->func; 423 | void *arg = args->arg; 424 | 425 | pthread_mutex_lock (&coro_mutex); 426 | 427 | /* we try to be good citizens and use deferred cancellation and cleanup handlers */ 428 | pthread_cleanup_push (mutex_unlock_wrapper, &coro_mutex); 429 | coro_transfer (args->self, args->main); 430 | func (arg); 431 | pthread_cleanup_pop (1); 432 | 433 | return 0; 434 | } 435 | 436 | void 437 | coro_transfer (coro_context *prev, coro_context *next) 438 | { 439 | pthread_cond_signal (&next->cv); 440 | pthread_cond_wait (&prev->cv, &coro_mutex); 441 | #if __FreeBSD__ /* freebsd is of course broken and needs manual testcancel calls... yay... */ 442 | pthread_testcancel (); 443 | #endif 444 | } 445 | 446 | void 447 | coro_create (coro_context *ctx, coro_func coro, void *arg, void *sptr, size_t ssize) 448 | { 449 | static coro_context nctx; 450 | static int once; 451 | 452 | if (!once) 453 | { 454 | once = 1; 455 | 456 | pthread_mutex_lock (&coro_mutex); 457 | pthread_cond_init (&nctx.cv, 0); 458 | null_tid = pthread_self (); 459 | } 460 | 461 | pthread_cond_init (&ctx->cv, 0); 462 | 463 | if (coro) 464 | { 465 | pthread_attr_t attr; 466 | struct coro_init_args args; 467 | 468 | args.func = coro; 469 | args.arg = arg; 470 | args.self = ctx; 471 | args.main = &nctx; 472 | 473 | pthread_attr_init (&attr); 474 | #if __UCLIBC__ 475 | /* exists, but is borked */ 476 | /*pthread_attr_setstacksize (&attr, (size_t)ssize);*/ 477 | #elif __CYGWIN__ 478 | /* POSIX, not here */ 479 | pthread_attr_setstacksize (&attr, (size_t)ssize); 480 | #else 481 | pthread_attr_setstack (&attr, sptr, (size_t)ssize); 482 | #endif 483 | pthread_attr_setscope (&attr, PTHREAD_SCOPE_PROCESS); 484 | pthread_create (&ctx->id, &attr, coro_init, &args); 485 | 486 | coro_transfer (args.main, args.self); 487 | } 488 | else 489 | ctx->id = null_tid; 490 | } 491 | 492 | void 493 | coro_destroy (coro_context *ctx) 494 | { 495 | if (!pthread_equal (ctx->id, null_tid)) 496 | { 497 | pthread_cancel (ctx->id); 498 | pthread_mutex_unlock (&coro_mutex); 499 | pthread_join (ctx->id, 0); 500 | pthread_mutex_lock (&coro_mutex); 501 | } 502 | 503 | pthread_cond_destroy (&ctx->cv); 504 | } 505 | 506 | /*****************************************************************************/ 507 | /* fiber backend */ 508 | /*****************************************************************************/ 509 | #elif CORO_FIBER 510 | 511 | #define WIN32_LEAN_AND_MEAN 512 | #if _WIN32_WINNT < 0x0400 513 | #undef _WIN32_WINNT 514 | #define _WIN32_WINNT 0x0400 515 | #endif 516 | #include 517 | 518 | VOID CALLBACK 519 | coro_init (PVOID arg) 520 | { 521 | coro_context *ctx = (coro_context *)arg; 522 | 523 | ctx->coro (ctx->arg); 524 | } 525 | 526 | void 527 | coro_transfer (coro_context *prev, coro_context *next) 528 | { 529 | if (!prev->fiber) 530 | { 531 | prev->fiber = GetCurrentFiber (); 532 | 533 | if (prev->fiber == 0 || prev->fiber == (void *)0x1e00) 534 | prev->fiber = ConvertThreadToFiber (0); 535 | } 536 | 537 | SwitchToFiber (next->fiber); 538 | } 539 | 540 | void 541 | coro_create (coro_context *ctx, coro_func coro, void *arg, void *sptr, size_t ssize) 542 | { 543 | ctx->fiber = 0; 544 | ctx->coro = coro; 545 | ctx->arg = arg; 546 | 547 | if (!coro) 548 | return; 549 | 550 | ctx->fiber = CreateFiber (ssize, coro_init, ctx); 551 | } 552 | 553 | void 554 | coro_destroy (coro_context *ctx) 555 | { 556 | DeleteFiber (ctx->fiber); 557 | } 558 | 559 | #else 560 | #error unsupported backend 561 | #endif 562 | 563 | /*****************************************************************************/ 564 | /* stack management */ 565 | /*****************************************************************************/ 566 | #if CORO_STACKALLOC 567 | 568 | #include 569 | 570 | #ifndef _WIN32 571 | # include 572 | #endif 573 | 574 | #if CORO_USE_VALGRIND 575 | # include 576 | #endif 577 | 578 | #if _POSIX_MAPPED_FILES 579 | # include 580 | # define CORO_MMAP 1 581 | # ifndef MAP_ANONYMOUS 582 | # ifdef MAP_ANON 583 | # define MAP_ANONYMOUS MAP_ANON 584 | # else 585 | # undef CORO_MMAP 586 | # endif 587 | # endif 588 | # include 589 | #else 590 | # undef CORO_MMAP 591 | #endif 592 | 593 | #if _POSIX_MEMORY_PROTECTION 594 | # ifndef CORO_GUARDPAGES 595 | # define CORO_GUARDPAGES 4 596 | # endif 597 | #else 598 | # undef CORO_GUARDPAGES 599 | #endif 600 | 601 | #if !CORO_MMAP 602 | # undef CORO_GUARDPAGES 603 | #endif 604 | 605 | #if !__i386 && !__x86_64 && !__powerpc && !__m68k && !__alpha && !__mips && !__sparc64 606 | # undef CORO_GUARDPAGES 607 | #endif 608 | 609 | #ifndef CORO_GUARDPAGES 610 | # define CORO_GUARDPAGES 0 611 | #endif 612 | 613 | #if !PAGESIZE 614 | #if !CORO_MMAP 615 | #define PAGESIZE 4096 616 | #else 617 | static size_t 618 | coro_pagesize (void) 619 | { 620 | static size_t pagesize; 621 | 622 | if (!pagesize) 623 | pagesize = sysconf (_SC_PAGESIZE); 624 | 625 | return pagesize; 626 | } 627 | 628 | #define PAGESIZE coro_pagesize () 629 | #endif 630 | #endif 631 | 632 | int 633 | coro_stack_alloc (struct coro_stack *stack, unsigned int size) 634 | { 635 | if (!size) 636 | size = 256 * 1024; 637 | 638 | stack->sptr = 0; 639 | stack->ssze = ((size_t)size * sizeof (void *) + PAGESIZE - 1) / PAGESIZE * PAGESIZE; 640 | 641 | #if CORO_FIBER 642 | 643 | stack->sptr = (void *)stack; 644 | return 1; 645 | 646 | #else 647 | 648 | size_t ssze = stack->ssze + CORO_GUARDPAGES * PAGESIZE; 649 | void *base; 650 | 651 | #if CORO_MMAP 652 | /* mmap supposedly does allocate-on-write for us */ 653 | base = mmap (0, ssze, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 654 | 655 | if (base == (void *)-1) 656 | { 657 | /* some systems don't let us have executable heap */ 658 | /* we assume they won't need executable stack in that case */ 659 | base = mmap (0, ssze, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 660 | 661 | if (base == (void *)-1) 662 | return 0; 663 | } 664 | 665 | #if CORO_GUARDPAGES 666 | mprotect (base, CORO_GUARDPAGES * PAGESIZE, PROT_NONE); 667 | #endif 668 | 669 | base = (void*)((char *)base + CORO_GUARDPAGES * PAGESIZE); 670 | #else 671 | base = malloc (ssze); 672 | if (!base) 673 | return 0; 674 | #endif 675 | 676 | #if CORO_USE_VALGRIND 677 | stack->valgrind_id = VALGRIND_STACK_REGISTER ((char *)base, ((char *)base) + ssze - CORO_GUARDPAGES * PAGESIZE); 678 | #endif 679 | 680 | stack->sptr = base; 681 | return 1; 682 | 683 | #endif 684 | } 685 | 686 | void 687 | coro_stack_free (struct coro_stack *stack) 688 | { 689 | #if CORO_FIBER 690 | /* nop */ 691 | #else 692 | #if CORO_USE_VALGRIND 693 | VALGRIND_STACK_DEREGISTER (stack->valgrind_id); 694 | #endif 695 | 696 | #if CORO_MMAP 697 | if (stack->sptr) 698 | munmap ((void*)((char *)stack->sptr - CORO_GUARDPAGES * PAGESIZE), 699 | stack->ssze + CORO_GUARDPAGES * PAGESIZE); 700 | #else 701 | free (stack->sptr); 702 | #endif 703 | #endif 704 | } 705 | 706 | #endif 707 | 708 | -------------------------------------------------------------------------------- /coro.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2001-2012 Marc Alexander Lehmann 3 | * 4 | * Redistribution and use in source and binary forms, with or without modifica- 5 | * tion, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, 8 | * this list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 15 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- 16 | * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 17 | * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- 18 | * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- 22 | * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 23 | * OF THE POSSIBILITY OF SUCH DAMAGE. 24 | * 25 | * Alternatively, the contents of this file may be used under the terms of 26 | * the GNU General Public License ("GPL") version 2 or any later version, 27 | * in which case the provisions of the GPL are applicable instead of 28 | * the above. If you wish to allow the use of your version of this file 29 | * only under the terms of the GPL and not to allow others to use your 30 | * version of this file under the BSD license, indicate your decision 31 | * by deleting the provisions above and replace them with the notice 32 | * and other provisions required by the GPL. If you do not delete the 33 | * provisions above, a recipient may use your version of this file under 34 | * either the BSD or the GPL. 35 | * 36 | * This library is modelled strictly after Ralf S. Engelschalls article at 37 | * http://www.gnu.org/software/pth/rse-pmt.ps. So most of the credit must 38 | * go to Ralf S. Engelschall . 39 | * 40 | * This coroutine library is very much stripped down. You should either 41 | * build your own process abstraction using it or - better - just use GNU 42 | * Portable Threads, http://www.gnu.org/software/pth/. 43 | * 44 | */ 45 | 46 | /* 47 | * 2006-10-26 Include stddef.h on OS X to work around one of its bugs. 48 | * Reported by Michael_G_Schwern. 49 | * 2006-11-26 Use _setjmp instead of setjmp on GNU/Linux. 50 | * 2007-04-27 Set unwind frame info if gcc 3+ and ELF is detected. 51 | * Use _setjmp instead of setjmp on _XOPEN_SOURCE >= 600. 52 | * 2007-05-02 Add assembly versions for x86 and amd64 (to avoid reliance 53 | * on SIGUSR2 and sigaltstack in Crossfire). 54 | * 2008-01-21 Disable CFI usage on anything but GNU/Linux. 55 | * 2008-03-02 Switched to 2-clause BSD license with GPL exception. 56 | * 2008-04-04 New (but highly unrecommended) pthreads backend. 57 | * 2008-04-24 Reinstate CORO_LOSER (had wrong stack adjustments). 58 | * 2008-10-30 Support assembly method on x86 with and without frame pointer. 59 | * 2008-11-03 Use a global asm statement for CORO_ASM, idea by pippijn. 60 | * 2008-11-05 Hopefully fix misaligned stacks with CORO_ASM/SETJMP. 61 | * 2008-11-07 rbp wasn't saved in CORO_ASM on x86_64. 62 | * introduce coro_destroy, which is a nop except for pthreads. 63 | * speed up CORO_PTHREAD. Do no longer leak threads either. 64 | * coro_create now allows one to create source coro_contexts. 65 | * do not rely on makecontext passing a void * correctly. 66 | * try harder to get _setjmp/_longjmp. 67 | * major code cleanup/restructuring. 68 | * 2008-11-10 the .cfi hacks are no longer needed. 69 | * 2008-11-16 work around a freebsd pthread bug. 70 | * 2008-11-19 define coro_*jmp symbols for easier porting. 71 | * 2009-06-23 tentative win32-backend support for mingw32 (Yasuhiro Matsumoto). 72 | * 2010-12-03 tentative support for uclibc (which lacks all sorts of things). 73 | * 2011-05-30 set initial callee-saved-registers to zero with CORO_ASM. 74 | * use .cfi_undefined rip on linux-amd64 for better backtraces. 75 | * 2011-06-08 maybe properly implement weird windows amd64 calling conventions. 76 | * 2011-07-03 rely on __GCC_HAVE_DWARF2_CFI_ASM for cfi detection. 77 | * 2011-08-08 cygwin trashes stacks, use pthreads with double stack on cygwin. 78 | * 2012-12-04 reduce misprediction penalty for x86/amd64 assembly switcher. 79 | * 2012-12-05 experimental fiber backend (allocates stack twice). 80 | * 2012-12-07 API version 3 - add coro_stack_alloc/coro_stack_free. 81 | * 2012-12-21 valgrind stack registering was broken. 82 | */ 83 | 84 | #ifndef CORO_H 85 | #define CORO_H 86 | 87 | #if __cplusplus 88 | extern "C" { 89 | #endif 90 | 91 | /* 92 | * This library consists of only three files 93 | * coro.h, coro.c and LICENSE (and optionally README) 94 | * 95 | * It implements what is known as coroutines, in a hopefully 96 | * portable way. 97 | * 98 | * All compiletime symbols must be defined both when including coro.h 99 | * (using libcoro) as well as when compiling coro.c (the implementation). 100 | * 101 | * You can manually specify which flavour you want. If you don't define 102 | * any of these, libcoro tries to choose a safe and fast default: 103 | * 104 | * -DCORO_UCONTEXT 105 | * 106 | * This flavour uses SUSv2's get/set/swap/makecontext functions that 107 | * unfortunately only some unices support, and is quite slow. 108 | * 109 | * -DCORO_SJLJ 110 | * 111 | * This flavour uses SUSv2's setjmp/longjmp and sigaltstack functions to 112 | * do it's job. Coroutine creation is much slower than UCONTEXT, but 113 | * context switching is a bit cheaper. It should work on almost all unices. 114 | * 115 | * -DCORO_LINUX 116 | * 117 | * CORO_SJLJ variant. 118 | * Old GNU/Linux systems (<= glibc-2.1) only work with this implementation 119 | * (it is very fast and therefore recommended over other methods, but 120 | * doesn't work with anything newer). 121 | * 122 | * -DCORO_LOSER 123 | * 124 | * CORO_SJLJ variant. 125 | * Microsoft's highly proprietary platform doesn't support sigaltstack, and 126 | * this selects a suitable workaround for this platform. It might not work 127 | * with your compiler though - it has only been tested with MSVC 6. 128 | * 129 | * -DCORO_FIBER 130 | * 131 | * Slower, but probably more portable variant for the Microsoft operating 132 | * system, using fibers. Ignores the passed stack and allocates it internally. 133 | * Also, due to bugs in cygwin, this does not work with cygwin. 134 | * 135 | * -DCORO_IRIX 136 | * 137 | * CORO_SJLJ variant. 138 | * For SGI's version of Microsoft's NT ;) 139 | * 140 | * -DCORO_ASM 141 | * 142 | * Hand coded assembly, known to work only on a few architectures/ABI: 143 | * GCC + x86/IA32 and amd64/x86_64 + GNU/Linux and a few BSDs. Fastest choice, 144 | * if it works. 145 | * 146 | * -DCORO_PTHREAD 147 | * 148 | * Use the pthread API. You have to provide and -lpthread. 149 | * This is likely the slowest backend, and it also does not support fork(), 150 | * so avoid it at all costs. 151 | * 152 | * If you define neither of these symbols, coro.h will try to autodetect 153 | * the best/safest model. To help with the autodetection, you should check 154 | * (e.g. using autoconf) and define the following symbols: HAVE_UCONTEXT_H 155 | * / HAVE_SETJMP_H / HAVE_SIGALTSTACK. 156 | */ 157 | 158 | /* 159 | * Changes when the API changes incompatibly. 160 | * This is ONLY the API version - there is no ABI compatibility between releases. 161 | * 162 | * Changes in API version 2: 163 | * replaced bogus -DCORO_LOOSE with grammatically more correct -DCORO_LOSER 164 | * Changes in API version 3: 165 | * introduced stack management (CORO_STACKALLOC) 166 | */ 167 | #define CORO_VERSION 3 168 | 169 | #include 170 | 171 | /* 172 | * This is the type for the initialization function of a new coroutine. 173 | */ 174 | typedef void (*coro_func)(void *); 175 | 176 | /* 177 | * A coroutine state is saved in the following structure. Treat it as an 178 | * opaque type. errno and sigmask might be saved, but don't rely on it, 179 | * implement your own switching primitive if you need that. 180 | */ 181 | typedef struct coro_context coro_context; 182 | 183 | /* 184 | * This function creates a new coroutine. Apart from a pointer to an 185 | * uninitialised coro_context, it expects a pointer to the entry function 186 | * and the single pointer value that is given to it as argument. 187 | * 188 | * Allocating/deallocating the stack is your own responsibility. 189 | * 190 | * As a special case, if coro, arg, sptr and ssze are all zero, 191 | * then an "empty" coro_context will be created that is suitable 192 | * as an initial source for coro_transfer. 193 | * 194 | * This function is not reentrant, but putting a mutex around it 195 | * will work. 196 | */ 197 | void coro_create (coro_context *ctx, /* an uninitialised coro_context */ 198 | coro_func coro, /* the coroutine code to be executed */ 199 | void *arg, /* a single pointer passed to the coro */ 200 | void *sptr, /* start of stack area */ 201 | size_t ssze); /* size of stack area in bytes */ 202 | 203 | /* 204 | * The following prototype defines the coroutine switching function. It is 205 | * sometimes implemented as a macro, so watch out. 206 | * 207 | * This function is thread-safe and reentrant. 208 | */ 209 | #if 0 210 | void coro_transfer (coro_context *prev, coro_context *next); 211 | #endif 212 | 213 | /* 214 | * The following prototype defines the coroutine destroy function. It 215 | * is sometimes implemented as a macro, so watch out. It also serves no 216 | * purpose unless you want to use the CORO_PTHREAD backend, where it is 217 | * used to clean up the thread. You are responsible for freeing the stack 218 | * and the context itself. 219 | * 220 | * This function is thread-safe and reentrant. 221 | */ 222 | #if 0 223 | void coro_destroy (coro_context *ctx); 224 | #endif 225 | 226 | /*****************************************************************************/ 227 | /* optional stack management */ 228 | /*****************************************************************************/ 229 | /* 230 | * You can disable all of the stack management functions by 231 | * defining CORO_STACKALLOC to 0. Otherwise, they are enabled by default. 232 | * 233 | * If stack management is enabled, you can influence the implementation via these 234 | * symbols: 235 | * 236 | * -DCORO_USE_VALGRIND 237 | * 238 | * If defined, then libcoro will include valgrind/valgrind.h and register 239 | * and unregister stacks with valgrind. 240 | * 241 | * -DCORO_GUARDPAGES=n 242 | * 243 | * libcoro will try to use the specified number of guard pages to protect against 244 | * stack overflow. If n is 0, then the feature will be disabled. If it isn't 245 | * defined, then libcoro will choose a suitable default. If guardpages are not 246 | * supported on the platform, then the feature will be silently disabled. 247 | */ 248 | #ifndef CORO_STACKALLOC 249 | # define CORO_STACKALLOC 1 250 | #endif 251 | 252 | #if CORO_STACKALLOC 253 | 254 | /* 255 | * The only allowed operations on these struct members is to read the 256 | * "sptr" and "ssze" members to pass it to coro_create, to read the "sptr" 257 | * member to see if it is false, in which case the stack isn't allocated, 258 | * and to set the "sptr" member to 0, to indicate to coro_stack_free to 259 | * not actually do anything. 260 | */ 261 | 262 | struct coro_stack 263 | { 264 | void *sptr; 265 | size_t ssze; 266 | #if CORO_USE_VALGRIND 267 | int valgrind_id; 268 | #endif 269 | }; 270 | 271 | /* 272 | * Try to allocate a stack of at least the given size and return true if 273 | * successful, or false otherwise. 274 | * 275 | * The size is *NOT* specified in bytes, but in units of sizeof (void *), 276 | * i.e. the stack is typically 4(8) times larger on 32 bit(64 bit) platforms 277 | * then the size passed in. 278 | * 279 | * If size is 0, then a "suitable" stack size is chosen (usually 1-2MB). 280 | */ 281 | int coro_stack_alloc (struct coro_stack *stack, unsigned int size); 282 | 283 | /* 284 | * Free the stack allocated by coro_stack_alloc again. It is safe to 285 | * call this function on the coro_stack structure even if coro_stack_alloc 286 | * failed. 287 | */ 288 | void coro_stack_free (struct coro_stack *stack); 289 | 290 | #endif 291 | 292 | /* 293 | * That was it. No other user-serviceable parts below here. 294 | */ 295 | 296 | /*****************************************************************************/ 297 | 298 | #if !defined CORO_LOSER && !defined CORO_UCONTEXT \ 299 | && !defined CORO_SJLJ && !defined CORO_LINUX \ 300 | && !defined CORO_IRIX && !defined CORO_ASM \ 301 | && !defined CORO_PTHREAD && !defined CORO_FIBER 302 | # if defined WINDOWS && (defined __i386 || (__x86_64 || defined _M_IX86 || defined _M_AMD64) 303 | # define CORO_ASM 1 304 | # elif defined WINDOWS || defined _WIN32 305 | # define CORO_LOSER 1 /* you don't win with windoze */ 306 | # elif __linux && (__i386 || (__x86_64 && !__ILP32)) 307 | # define CORO_ASM 1 308 | # elif defined HAVE_UCONTEXT_H 309 | # define CORO_UCONTEXT 1 310 | # elif defined HAVE_SETJMP_H && defined HAVE_SIGALTSTACK 311 | # define CORO_SJLJ 1 312 | # else 313 | error unknown or unsupported architecture 314 | # endif 315 | #endif 316 | 317 | /*****************************************************************************/ 318 | 319 | #if CORO_UCONTEXT 320 | 321 | # include 322 | 323 | struct coro_context 324 | { 325 | ucontext_t uc; 326 | }; 327 | 328 | # define coro_transfer(p,n) swapcontext (&((p)->uc), &((n)->uc)) 329 | # define coro_destroy(ctx) (void *)(ctx) 330 | 331 | #elif CORO_SJLJ || CORO_LOSER || CORO_LINUX || CORO_IRIX 332 | 333 | # if defined(CORO_LINUX) && !defined(_GNU_SOURCE) 334 | # define _GNU_SOURCE /* for glibc */ 335 | # endif 336 | 337 | # if !CORO_LOSER 338 | # include 339 | # endif 340 | 341 | /* solaris is hopelessly borked, it expands _XOPEN_UNIX to nothing */ 342 | # if __sun 343 | # undef _XOPEN_UNIX 344 | # define _XOPEN_UNIX 1 345 | # endif 346 | 347 | # include 348 | 349 | # if _XOPEN_UNIX > 0 || defined (_setjmp) 350 | # define coro_jmp_buf jmp_buf 351 | # define coro_setjmp(env) _setjmp (env) 352 | # define coro_longjmp(env) _longjmp ((env), 1) 353 | # elif CORO_LOSER 354 | # define coro_jmp_buf jmp_buf 355 | # define coro_setjmp(env) setjmp (env) 356 | # define coro_longjmp(env) longjmp ((env), 1) 357 | # else 358 | # define coro_jmp_buf sigjmp_buf 359 | # define coro_setjmp(env) sigsetjmp (env, 0) 360 | # define coro_longjmp(env) siglongjmp ((env), 1) 361 | # endif 362 | 363 | struct coro_context 364 | { 365 | coro_jmp_buf env; 366 | }; 367 | 368 | # define coro_transfer(p,n) do { if (!coro_setjmp ((p)->env)) coro_longjmp ((n)->env); } while (0) 369 | # define coro_destroy(ctx) (void *)(ctx) 370 | 371 | #elif CORO_ASM 372 | 373 | struct coro_context 374 | { 375 | void **sp; /* must be at offset 0 */ 376 | }; 377 | 378 | void __attribute__ ((__noinline__, __regparm__(2))) 379 | coro_transfer (coro_context *prev, coro_context *next); 380 | 381 | # define coro_destroy(ctx) (void *)(ctx) 382 | 383 | #elif CORO_PTHREAD 384 | 385 | # include 386 | 387 | extern pthread_mutex_t coro_mutex; 388 | 389 | struct coro_context 390 | { 391 | pthread_cond_t cv; 392 | pthread_t id; 393 | }; 394 | 395 | void coro_transfer (coro_context *prev, coro_context *next); 396 | void coro_destroy (coro_context *ctx); 397 | 398 | #elif CORO_FIBER 399 | 400 | struct coro_context 401 | { 402 | void *fiber; 403 | /* only used for initialisation */ 404 | coro_func coro; 405 | void *arg; 406 | }; 407 | 408 | void coro_transfer (coro_context *prev, coro_context *next); 409 | void coro_destroy (coro_context *ctx); 410 | 411 | #endif 412 | 413 | #if __cplusplus 414 | } 415 | #endif 416 | 417 | #endif 418 | 419 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "coro", 3 | "version": "2012-12-21", 4 | "repo": "clibs/coro", 5 | "description": "C coroutines", 6 | "keywords": ["coroutine"], 7 | "license": "BSD", 8 | "src": ["coro.c", "coro.h"] 9 | } 10 | --------------------------------------------------------------------------------