ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/libcoro/coro.c
Revision: 1.73
Committed: Tue Aug 14 15:46:03 2018 UTC (5 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-6_52, rel-6_53, rel-6_54, rel-6_55, rel-6_56, rel-6_57, HEAD
Changes since 1.72: +26 -34 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 /*
2 root 1.56 * Copyright (c) 2001-2011 Marc Alexander Lehmann <schmorp@schmorp.de>
3 root 1.63 *
4 root 1.1 * Redistribution and use in source and binary forms, with or without modifica-
5     * tion, are permitted provided that the following conditions are met:
6 root 1.63 *
7 root 1.1 * 1. Redistributions of source code must retain the above copyright notice,
8     * this list of conditions and the following disclaimer.
9 root 1.63 *
10 root 1.1 * 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 root 1.63 *
14 root 1.1 * 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 root 1.29 * 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 root 1.1 * This library is modelled strictly after Ralf S. Engelschalls article at
37 root 1.29 * http://www.gnu.org/software/pth/rse-pmt.ps. So most of the credit must
38 root 1.1 * go to Ralf S. Engelschall <rse@engelschall.com>.
39     */
40    
41     #include "coro.h"
42    
43 root 1.66 #include <stddef.h>
44 root 1.38 #include <string.h>
45    
46 root 1.39 /*****************************************************************************/
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 <stddef.h>
53     # endif
54    
55     # if !defined(STACK_ADJUST_PTR)
56     # if __sgi
57 root 1.5 /* IRIX is decidedly NON-unix */
58 root 1.39 # 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 root 1.8 # endif
71 root 1.1
72 root 1.38 # include <stdlib.h>
73 root 1.17
74 root 1.38 # if CORO_SJLJ
75     # include <stdio.h>
76     # include <signal.h>
77     # include <unistd.h>
78     # endif
79 root 1.1
80 root 1.40 static coro_func coro_init_func;
81     static void *coro_init_arg;
82     static coro_context *new_coro, *create_coro;
83 root 1.1
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 root 1.40 coro_transfer (new_coro, create_coro);
91 root 1.1
92 root 1.61 #if __GCC_HAVE_DWARF2_CFI_ASM && __amd64
93 root 1.71 /*asm (".cfi_startproc");*/
94     /*asm (".cfi_undefined rip");*/
95 root 1.56 #endif
96    
97 root 1.3 func ((void *)arg);
98 root 1.1
99 root 1.70 #if __GCC_HAVE_DWARF2_CFI_ASM && __amd64
100 root 1.71 /*asm (".cfi_endproc");*/
101 root 1.70 #endif
102    
103 root 1.1 /* the new coro returned. bad. just abort() for now */
104     abort ();
105     }
106    
107     # if CORO_SJLJ
108    
109 root 1.39 static volatile int trampoline_done;
110 root 1.1
111     /* trampoline signal handler */
112     static void
113 root 1.14 trampoline (int sig)
114 root 1.1 {
115 root 1.44 if (coro_setjmp (new_coro->env))
116     coro_init (); /* start it */
117 root 1.1 else
118 root 1.39 trampoline_done = 1;
119 root 1.1 }
120    
121     # endif
122    
123 root 1.39 # if CORO_ASM
124 root 1.38
125 root 1.68 #if __arm__ && \
126     (defined __ARM_ARCH_7__ || defined __ARM_ARCH_7A__ \
127     || defined __ARM_ARCH_7R__ || defined __ARM_ARCH_7M__ \
128 root 1.69 || __ARM_ARCH == 7)
129 root 1.68 #define CORO_ARM 1
130     #endif
131    
132 root 1.63 #if _WIN32 || __CYGWIN__
133 root 1.60 #define CORO_WIN_TIB 1
134     #endif
135    
136 root 1.38 asm (
137 root 1.60 "\t.text\n"
138 root 1.63 #if _WIN32 || __CYGWIN__
139     "\t.globl _coro_transfer\n"
140     "_coro_transfer:\n"
141     #else
142 root 1.60 "\t.globl coro_transfer\n"
143 root 1.38 "coro_transfer:\n"
144 root 1.63 #endif
145 root 1.52 /* windows, of course, gives a shit on the amd64 ABI and uses different registers */
146     /* http://blogs.msdn.com/freik/archive/2005/03/17/398200.aspx */
147 root 1.39 #if __amd64
148 root 1.63
149     #if _WIN32 || __CYGWIN__
150     #define NUM_SAVED 29
151     "\tsubq $168, %rsp\t" /* one dummy qword to improve alignment */
152     "\tmovaps %xmm6, (%rsp)\n"
153     "\tmovaps %xmm7, 16(%rsp)\n"
154     "\tmovaps %xmm8, 32(%rsp)\n"
155     "\tmovaps %xmm9, 48(%rsp)\n"
156     "\tmovaps %xmm10, 64(%rsp)\n"
157     "\tmovaps %xmm11, 80(%rsp)\n"
158     "\tmovaps %xmm12, 96(%rsp)\n"
159     "\tmovaps %xmm13, 112(%rsp)\n"
160     "\tmovaps %xmm14, 128(%rsp)\n"
161     "\tmovaps %xmm15, 144(%rsp)\n"
162 root 1.59 "\tpushq %rsi\n"
163     "\tpushq %rdi\n"
164     "\tpushq %rbp\n"
165     "\tpushq %rbx\n"
166     "\tpushq %r12\n"
167     "\tpushq %r13\n"
168     "\tpushq %r14\n"
169     "\tpushq %r15\n"
170 root 1.60 #if CORO_WIN_TIB
171     "\tpushq %fs:0x0\n"
172     "\tpushq %fs:0x8\n"
173     "\tpushq %fs:0xc\n"
174     #endif
175 root 1.59 "\tmovq %rsp, (%rcx)\n"
176     "\tmovq (%rdx), %rsp\n"
177 root 1.60 #if CORO_WIN_TIB
178     "\tpopq %fs:0xc\n"
179     "\tpopq %fs:0x8\n"
180     "\tpopq %fs:0x0\n"
181     #endif
182 root 1.59 "\tpopq %r15\n"
183     "\tpopq %r14\n"
184     "\tpopq %r13\n"
185     "\tpopq %r12\n"
186     "\tpopq %rbx\n"
187     "\tpopq %rbp\n"
188     "\tpopq %rdi\n"
189     "\tpopq %rsi\n"
190 root 1.63 "\tmovaps (%rsp), %xmm6\n"
191     "\tmovaps 16(%rsp), %xmm7\n"
192     "\tmovaps 32(%rsp), %xmm8\n"
193     "\tmovaps 48(%rsp), %xmm9\n"
194     "\tmovaps 64(%rsp), %xmm10\n"
195     "\tmovaps 80(%rsp), %xmm11\n"
196     "\tmovaps 96(%rsp), %xmm12\n"
197     "\tmovaps 112(%rsp), %xmm13\n"
198     "\tmovaps 128(%rsp), %xmm14\n"
199     "\tmovaps 144(%rsp), %xmm15\n"
200     "\taddq $168, %rsp\n"
201 root 1.58 #else
202     #define NUM_SAVED 6
203 root 1.59 "\tpushq %rbp\n"
204     "\tpushq %rbx\n"
205     "\tpushq %r12\n"
206     "\tpushq %r13\n"
207     "\tpushq %r14\n"
208     "\tpushq %r15\n"
209     "\tmovq %rsp, (%rdi)\n"
210     "\tmovq (%rsi), %rsp\n"
211     "\tpopq %r15\n"
212     "\tpopq %r14\n"
213     "\tpopq %r13\n"
214     "\tpopq %r12\n"
215     "\tpopq %rbx\n"
216     "\tpopq %rbp\n"
217 root 1.50 #endif
218 root 1.63 "\tpopq %rcx\n"
219     "\tjmpq *%rcx\n"
220    
221 root 1.68 #elif __i386__
222 root 1.63
223 root 1.50 #define NUM_SAVED 4
224 root 1.59 "\tpushl %ebp\n"
225     "\tpushl %ebx\n"
226     "\tpushl %esi\n"
227     "\tpushl %edi\n"
228 root 1.50 #if CORO_WIN_TIB
229 root 1.63 #undef NUM_SAVED
230     #define NUM_SAVED 7
231 root 1.59 "\tpushl %fs:0\n"
232     "\tpushl %fs:4\n"
233     "\tpushl %fs:8\n"
234 root 1.50 #endif
235 root 1.59 "\tmovl %esp, (%eax)\n"
236     "\tmovl (%edx), %esp\n"
237 root 1.50 #if CORO_WIN_TIB
238 root 1.59 "\tpopl %fs:8\n"
239     "\tpopl %fs:4\n"
240     "\tpopl %fs:0\n"
241 root 1.50 #endif
242 root 1.59 "\tpopl %edi\n"
243     "\tpopl %esi\n"
244     "\tpopl %ebx\n"
245     "\tpopl %ebp\n"
246 root 1.63 "\tpopl %ecx\n"
247     "\tjmpl *%ecx\n"
248    
249 root 1.68 #elif CORO_ARM /* untested, what about thumb, neon, iwmmxt? */
250    
251     #if __ARM_PCS_VFP
252     "\tvpush {d8-d15}\n"
253     #define NUM_SAVED (9 + 8 * 2)
254     #else
255     #define NUM_SAVED 9
256     #endif
257     "\tpush {r4-r11,lr}\n"
258     "\tstr sp, [r0]\n"
259     "\tldr sp, [r1]\n"
260     "\tpop {r4-r11,lr}\n"
261     #if __ARM_PCS_VFP
262     "\tvpop {d8-d15}\n"
263     #endif
264     "\tmov r15, lr\n"
265    
266     #elif __mips__ && 0 /* untested, 32 bit only */
267    
268     #define NUM_SAVED (12 + 8 * 2)
269     /* TODO: n64/o64, lw=>ld */
270    
271     "\t.set nomips16\n"
272     "\t.frame $sp,112,$31\n"
273     #if __mips_soft_float
274     "\taddiu $sp,$sp,-44\n"
275     #else
276     "\taddiu $sp,$sp,-112\n"
277     "\ts.d $f30,88($sp)\n"
278     "\ts.d $f28,80($sp)\n"
279     "\ts.d $f26,72($sp)\n"
280     "\ts.d $f24,64($sp)\n"
281     "\ts.d $f22,56($sp)\n"
282     "\ts.d $f20,48($sp)\n"
283     #endif
284     "\tsw $28,40($sp)\n"
285     "\tsw $31,36($sp)\n"
286     "\tsw $fp,32($sp)\n"
287     "\tsw $23,28($sp)\n"
288     "\tsw $22,24($sp)\n"
289     "\tsw $21,20($sp)\n"
290     "\tsw $20,16($sp)\n"
291     "\tsw $19,12($sp)\n"
292     "\tsw $18,8($sp)\n"
293     "\tsw $17,4($sp)\n"
294     "\tsw $16,0($sp)\n"
295     "\tsw $sp,0($4)\n"
296     "\tlw $sp,0($5)\n"
297     #if !__mips_soft_float
298     "\tl.d $f30,88($sp)\n"
299     "\tl.d $f28,80($sp)\n"
300     "\tl.d $f26,72($sp)\n"
301     "\tl.d $f24,64($sp)\n"
302     "\tl.d $f22,56($sp)\n"
303     "\tl.d $f20,48($sp)\n"
304     #endif
305     "\tlw $28,40($sp)\n"
306     "\tlw $31,36($sp)\n"
307     "\tlw $fp,32($sp)\n"
308     "\tlw $23,28($sp)\n"
309     "\tlw $22,24($sp)\n"
310     "\tlw $21,20($sp)\n"
311     "\tlw $20,16($sp)\n"
312     "\tlw $19,12($sp)\n"
313     "\tlw $18,8($sp)\n"
314     "\tlw $17,4($sp)\n"
315     "\tlw $16,0($sp)\n"
316     "\tj $31\n"
317     #if __mips_soft_float
318     "\taddiu $sp,$sp,44\n"
319     #else
320     "\taddiu $sp,$sp,112\n"
321     #endif
322    
323 root 1.39 #else
324     #error unsupported architecture
325     #endif
326 root 1.38 );
327    
328 root 1.39 # endif
329 root 1.38
330     void
331 root 1.66 coro_create (coro_context *ctx, coro_func coro, void *arg, void *sptr, size_t ssize)
332 root 1.1 {
333 root 1.39 coro_context nctx;
334 root 1.1 # if CORO_SJLJ
335     stack_t ostk, nstk;
336     struct sigaction osa, nsa;
337     sigset_t nsig, osig;
338     # endif
339    
340 root 1.38 if (!coro)
341     return;
342    
343 root 1.1 coro_init_func = coro;
344     coro_init_arg = arg;
345    
346     new_coro = ctx;
347     create_coro = &nctx;
348    
349     # if CORO_SJLJ
350     /* we use SIGUSR2. first block it, then fiddle with it. */
351    
352     sigemptyset (&nsig);
353     sigaddset (&nsig, SIGUSR2);
354     sigprocmask (SIG_BLOCK, &nsig, &osig);
355    
356     nsa.sa_handler = trampoline;
357     sigemptyset (&nsa.sa_mask);
358     nsa.sa_flags = SA_ONSTACK;
359    
360     if (sigaction (SIGUSR2, &nsa, &osa))
361 root 1.23 {
362     perror ("sigaction");
363     abort ();
364     }
365 root 1.1
366     /* set the new stack */
367 root 1.54 nstk.ss_sp = STACK_ADJUST_PTR (sptr, ssize); /* yes, some platforms (IRIX) get this wrong. */
368     nstk.ss_size = STACK_ADJUST_SIZE (sptr, ssize);
369 root 1.1 nstk.ss_flags = 0;
370    
371     if (sigaltstack (&nstk, &ostk) < 0)
372 root 1.23 {
373     perror ("sigaltstack");
374     abort ();
375     }
376 root 1.1
377 root 1.39 trampoline_done = 0;
378 root 1.1 kill (getpid (), SIGUSR2);
379     sigfillset (&nsig); sigdelset (&nsig, SIGUSR2);
380    
381 root 1.39 while (!trampoline_done)
382 root 1.1 sigsuspend (&nsig);
383    
384     sigaltstack (0, &nstk);
385     nstk.ss_flags = SS_DISABLE;
386     if (sigaltstack (&nstk, 0) < 0)
387     perror ("sigaltstack");
388    
389     sigaltstack (0, &nstk);
390     if (~nstk.ss_flags & SS_DISABLE)
391     abort ();
392    
393     if (~ostk.ss_flags & SS_DISABLE)
394     sigaltstack (&ostk, 0);
395    
396 root 1.19 sigaction (SIGUSR2, &osa, 0);
397 root 1.1 sigprocmask (SIG_SETMASK, &osig, 0);
398    
399 root 1.16 # elif CORO_LOSER
400 root 1.1
401 root 1.44 coro_setjmp (ctx->env);
402 root 1.68 #if __CYGWIN__ && __i386__
403 root 1.47 ctx->env[8] = (long) coro_init;
404     ctx->env[7] = (long) ((char *)sptr + ssize) - sizeof (long);
405 root 1.68 #elif __CYGWIN__ && __x86_64__
406 root 1.48 ctx->env[7] = (long) coro_init;
407     ctx->env[6] = (long) ((char *)sptr + ssize) - sizeof (long);
408 root 1.63 #elif defined __MINGW32__
409 root 1.47 ctx->env[5] = (long) coro_init;
410     ctx->env[4] = (long) ((char *)sptr + ssize) - sizeof (long);
411 root 1.63 #elif defined _M_IX86
412 root 1.47 ((_JUMP_BUFFER *)&ctx->env)->Eip = (long) coro_init;
413     ((_JUMP_BUFFER *)&ctx->env)->Esp = (long) STACK_ADJUST_PTR (sptr, ssize) - sizeof (long);
414 root 1.63 #elif defined _M_AMD64
415 root 1.47 ((_JUMP_BUFFER *)&ctx->env)->Rip = (__int64) coro_init;
416 root 1.48 ((_JUMP_BUFFER *)&ctx->env)->Rsp = (__int64) STACK_ADJUST_PTR (sptr, ssize) - sizeof (__int64);
417 root 1.63 #elif defined _M_IA64
418 root 1.47 ((_JUMP_BUFFER *)&ctx->env)->StIIP = (__int64) coro_init;
419 root 1.48 ((_JUMP_BUFFER *)&ctx->env)->IntSp = (__int64) STACK_ADJUST_PTR (sptr, ssize) - sizeof (__int64);
420 root 1.39 #else
421     #error "microsoft libc or architecture not supported"
422     #endif
423 root 1.4
424     # elif CORO_LINUX
425    
426 root 1.44 coro_setjmp (ctx->env);
427 root 1.39 #if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && defined (JB_PC) && defined (JB_SP)
428 root 1.47 ctx->env[0].__jmpbuf[JB_PC] = (long) coro_init;
429     ctx->env[0].__jmpbuf[JB_SP] = (long) STACK_ADJUST_PTR (sptr, ssize) - sizeof (long);
430 root 1.39 #elif __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && defined (__mc68000__)
431     ctx->env[0].__jmpbuf[0].__aregs[0] = (long int)coro_init;
432 root 1.47 ctx->env[0].__jmpbuf[0].__sp = (int *) ((char *)sptr + ssize) - sizeof (long);
433 root 1.39 #elif defined (__GNU_LIBRARY__) && defined (__i386__)
434 root 1.47 ctx->env[0].__jmpbuf[0].__pc = (char *) coro_init;
435     ctx->env[0].__jmpbuf[0].__sp = (void *) ((char *)sptr + ssize) - sizeof (long);
436 root 1.68 #elif defined (__GNU_LIBRARY__) && defined (__x86_64__)
437 root 1.47 ctx->env[0].__jmpbuf[JB_PC] = (long) coro_init;
438     ctx->env[0].__jmpbuf[0].__sp = (void *) ((char *)sptr + ssize) - sizeof (long);
439 root 1.39 #else
440     #error "linux libc or architecture not supported"
441     #endif
442 root 1.5
443     # elif CORO_IRIX
444    
445 root 1.44 coro_setjmp (ctx->env, 0);
446 root 1.47 ctx->env[JB_PC] = (__uint64_t)coro_init;
447     ctx->env[JB_SP] = (__uint64_t)STACK_ADJUST_PTR (sptr, ssize) - sizeof (long);
448 root 1.1
449 root 1.27 # elif CORO_ASM
450    
451 root 1.68 #if __i386__ || __x86_64__
452     ctx->sp = (void **)(ssize + (char *)sptr);
453     *--ctx->sp = (void *)abort; /* needed for alignment only */
454     *--ctx->sp = (void *)coro_init;
455     #if CORO_WIN_TIB
456     *--ctx->sp = 0; /* ExceptionList */
457     *--ctx->sp = (char *)sptr + ssize; /* StackBase */
458     *--ctx->sp = sptr; /* StackLimit */
459     #endif
460     #elif CORO_ARM
461     /* return address stored in lr register, don't push anything */
462     #else
463     #error unsupported architecture
464 root 1.50 #endif
465    
466 root 1.51 ctx->sp -= NUM_SAVED;
467 root 1.55 memset (ctx->sp, 0, sizeof (*ctx->sp) * NUM_SAVED);
468 root 1.51
469 root 1.68 #if __i386__ || __x86_64__
470     /* done already */
471     #elif CORO_ARM
472     ctx->sp[0] = coro; /* r4 */
473     ctx->sp[1] = arg; /* r5 */
474     ctx->sp[8] = (char *)coro_init; /* lr */
475     #else
476     #error unsupported architecture
477     #endif
478    
479 root 1.39 # elif CORO_UCONTEXT
480    
481     getcontext (&(ctx->uc));
482    
483     ctx->uc.uc_link = 0;
484     ctx->uc.uc_stack.ss_sp = sptr;
485     ctx->uc.uc_stack.ss_size = (size_t)ssize;
486     ctx->uc.uc_stack.ss_flags = 0;
487    
488     makecontext (&(ctx->uc), (void (*)())coro_init, 0);
489    
490 root 1.1 # endif
491    
492 root 1.39 coro_transfer (create_coro, new_coro);
493     }
494    
495     /*****************************************************************************/
496     /* pthread backend */
497     /*****************************************************************************/
498 root 1.40 #elif CORO_PTHREAD
499 root 1.1
500 root 1.39 /* this mutex will be locked by the running coroutine */
501     pthread_mutex_t coro_mutex = PTHREAD_MUTEX_INITIALIZER;
502 root 1.30
503 root 1.39 struct coro_init_args
504     {
505     coro_func func;
506     void *arg;
507     coro_context *self, *main;
508     };
509    
510     static void *
511     coro_init (void *args_)
512     {
513     struct coro_init_args *args = (struct coro_init_args *)args_;
514     coro_func func = args->func;
515     void *arg = args->arg;
516    
517 root 1.73 coro_transfer (args->self, args->main);
518     func (arg);
519 root 1.39
520     return 0;
521     }
522    
523     void
524     coro_transfer (coro_context *prev, coro_context *next)
525     {
526 root 1.73 pthread_mutex_lock (&coro_mutex);
527    
528     next->flags = 1;
529 root 1.39 pthread_cond_signal (&next->cv);
530 root 1.73
531     prev->flags = 0;
532    
533     while (!prev->flags)
534     pthread_cond_wait (&prev->cv, &coro_mutex);
535    
536     if (prev->flags == 2)
537     {
538     pthread_mutex_unlock (&coro_mutex);
539     pthread_cond_destroy (&prev->cv);
540     pthread_detach (pthread_self ());
541     pthread_exit (0);
542     }
543    
544     pthread_mutex_unlock (&coro_mutex);
545 root 1.39 }
546    
547     void
548 root 1.66 coro_create (coro_context *ctx, coro_func coro, void *arg, void *sptr, size_t ssize)
549 root 1.39 {
550 root 1.38 static coro_context nctx;
551 root 1.30 static int once;
552    
553     if (!once)
554     {
555 root 1.38 once = 1;
556    
557     pthread_cond_init (&nctx.cv, 0);
558 root 1.30 }
559    
560 root 1.38 pthread_cond_init (&ctx->cv, 0);
561 root 1.30
562 root 1.38 if (coro)
563     {
564     pthread_attr_t attr;
565     struct coro_init_args args;
566 root 1.73 pthread_t id;
567 root 1.38
568     args.func = coro;
569     args.arg = arg;
570     args.self = ctx;
571     args.main = &nctx;
572    
573     pthread_attr_init (&attr);
574 root 1.53 #if __UCLIBC__
575 root 1.54 /* exists, but is borked */
576     /*pthread_attr_setstacksize (&attr, (size_t)ssize);*/
577 root 1.62 #elif __CYGWIN__
578     /* POSIX, not here */
579     pthread_attr_setstacksize (&attr, (size_t)ssize);
580 root 1.53 #else
581 root 1.38 pthread_attr_setstack (&attr, sptr, (size_t)ssize);
582 root 1.53 #endif
583 root 1.38 pthread_attr_setscope (&attr, PTHREAD_SCOPE_PROCESS);
584 root 1.73 pthread_create (&id, &attr, coro_init, &args);
585 root 1.38
586     coro_transfer (args.main, args.self);
587     }
588 root 1.39 }
589    
590     void
591     coro_destroy (coro_context *ctx)
592     {
593 root 1.73 pthread_mutex_lock (&coro_mutex);
594     ctx->flags = 2;
595     pthread_cond_signal (&ctx->cv);
596     pthread_mutex_unlock (&coro_mutex);
597 root 1.39 }
598 root 1.30
599 root 1.63 /*****************************************************************************/
600     /* fiber backend */
601     /*****************************************************************************/
602     #elif CORO_FIBER
603    
604     #define WIN32_LEAN_AND_MEAN
605 root 1.66 #if _WIN32_WINNT < 0x0400
606     #undef _WIN32_WINNT
607     #define _WIN32_WINNT 0x0400
608     #endif
609 root 1.63 #include <windows.h>
610    
611     VOID CALLBACK
612     coro_init (PVOID arg)
613     {
614     coro_context *ctx = (coro_context *)arg;
615    
616     ctx->coro (ctx->arg);
617     }
618    
619     void
620     coro_transfer (coro_context *prev, coro_context *next)
621     {
622     if (!prev->fiber)
623     {
624     prev->fiber = GetCurrentFiber ();
625    
626     if (prev->fiber == 0 || prev->fiber == (void *)0x1e00)
627     prev->fiber = ConvertThreadToFiber (0);
628     }
629    
630     SwitchToFiber (next->fiber);
631     }
632    
633     void
634 root 1.66 coro_create (coro_context *ctx, coro_func coro, void *arg, void *sptr, size_t ssize)
635 root 1.63 {
636     ctx->fiber = 0;
637     ctx->coro = coro;
638     ctx->arg = arg;
639    
640     if (!coro)
641     return;
642    
643     ctx->fiber = CreateFiber (ssize, coro_init, ctx);
644     }
645    
646     void
647     coro_destroy (coro_context *ctx)
648     {
649     DeleteFiber (ctx->fiber);
650     }
651    
652 root 1.40 #else
653 root 1.66 #error unsupported backend
654     #endif
655    
656     /*****************************************************************************/
657     /* stack management */
658     /*****************************************************************************/
659     #if CORO_STACKALLOC
660    
661     #include <stdlib.h>
662    
663     #ifndef _WIN32
664     # include <unistd.h>
665     #endif
666    
667     #if CORO_USE_VALGRIND
668     # include <valgrind/valgrind.h>
669     #endif
670    
671     #if _POSIX_MAPPED_FILES
672     # include <sys/mman.h>
673     # define CORO_MMAP 1
674     # ifndef MAP_ANONYMOUS
675     # ifdef MAP_ANON
676     # define MAP_ANONYMOUS MAP_ANON
677     # else
678     # undef CORO_MMAP
679     # endif
680     # endif
681     # include <limits.h>
682     #else
683     # undef CORO_MMAP
684     #endif
685    
686     #if _POSIX_MEMORY_PROTECTION
687     # ifndef CORO_GUARDPAGES
688     # define CORO_GUARDPAGES 4
689     # endif
690     #else
691     # undef CORO_GUARDPAGES
692     #endif
693    
694     #if !CORO_MMAP
695     # undef CORO_GUARDPAGES
696     #endif
697    
698 root 1.68 #if !__i386__ && !__x86_64__ && !__powerpc__ && !__arm__ && !__aarch64__ && !__m68k__ && !__alpha__ && !__mips__ && !__sparc64__
699 root 1.66 # undef CORO_GUARDPAGES
700     #endif
701    
702     #ifndef CORO_GUARDPAGES
703     # define CORO_GUARDPAGES 0
704     #endif
705    
706     #if !PAGESIZE
707     #if !CORO_MMAP
708     #define PAGESIZE 4096
709     #else
710     static size_t
711     coro_pagesize (void)
712     {
713     static size_t pagesize;
714    
715     if (!pagesize)
716     pagesize = sysconf (_SC_PAGESIZE);
717    
718     return pagesize;
719     }
720    
721     #define PAGESIZE coro_pagesize ()
722     #endif
723     #endif
724    
725     int
726     coro_stack_alloc (struct coro_stack *stack, unsigned int size)
727     {
728     if (!size)
729     size = 256 * 1024;
730    
731     stack->sptr = 0;
732     stack->ssze = ((size_t)size * sizeof (void *) + PAGESIZE - 1) / PAGESIZE * PAGESIZE;
733    
734     #if CORO_FIBER
735    
736     stack->sptr = (void *)stack;
737     return 1;
738    
739     #else
740    
741     size_t ssze = stack->ssze + CORO_GUARDPAGES * PAGESIZE;
742     void *base;
743    
744     #if CORO_MMAP
745     /* mmap supposedly does allocate-on-write for us */
746     base = mmap (0, ssze, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
747    
748     if (base == (void *)-1)
749     {
750     /* some systems don't let us have executable heap */
751     /* we assume they won't need executable stack in that case */
752     base = mmap (0, ssze, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
753    
754     if (base == (void *)-1)
755     return 0;
756     }
757    
758     #if CORO_GUARDPAGES
759     mprotect (base, CORO_GUARDPAGES * PAGESIZE, PROT_NONE);
760     #endif
761    
762     base = (void*)((char *)base + CORO_GUARDPAGES * PAGESIZE);
763     #else
764     base = malloc (ssze);
765     if (!base)
766     return 0;
767     #endif
768    
769     #if CORO_USE_VALGRIND
770 root 1.67 stack->valgrind_id = VALGRIND_STACK_REGISTER ((char *)base, ((char *)base) + ssze - CORO_GUARDPAGES * PAGESIZE);
771 root 1.66 #endif
772    
773     stack->sptr = base;
774     return 1;
775    
776     #endif
777     }
778    
779     void
780     coro_stack_free (struct coro_stack *stack)
781     {
782     #if CORO_FIBER
783     /* nop */
784     #else
785     #if CORO_USE_VALGRIND
786     VALGRIND_STACK_DEREGISTER (stack->valgrind_id);
787     #endif
788    
789     #if CORO_MMAP
790     if (stack->sptr)
791     munmap ((void*)((char *)stack->sptr - CORO_GUARDPAGES * PAGESIZE),
792     stack->ssze + CORO_GUARDPAGES * PAGESIZE);
793     #else
794     free (stack->sptr);
795     #endif
796     #endif
797     }
798    
799 root 1.1 #endif
800