ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro/State.xs
(Generate patch)

Comparing Coro/Coro/State.xs (file contents):
Revision 1.92 by root, Sun Nov 26 02:16:19 2006 UTC vs.
Revision 1.105 by root, Mon Nov 27 02:01:33 2006 UTC

1#define PERL_NO_GET_CONTEXT
2
3#include "libcoro/coro.c" 1#include "libcoro/coro.c"
4 2
5#include "EXTERN.h" 3#include "EXTERN.h"
6#include "perl.h" 4#include "perl.h"
7#include "XSUB.h" 5#include "XSUB.h"
8 6
9#include "patchlevel.h" 7#include "patchlevel.h"
10 8
11#if PERL_VERSION < 6 9#if USE_VALGRIND
10# include <valgrind/valgrind.h>
11#endif
12
13#define PERL_VERSION_ATLEAST(a,b,c) \
14 (PERL_REVISION > (a) \
15 || (PERL_REVISION == (a) \
16 && (PERL_VERSION > (b) \
17 || (PERL_VERSION == (b) && PERLSUBVERSION >= (c)))))
18
19#if !PERL_VERSION_ATLEAST (5,6,0)
12# ifndef PL_ppaddr 20# ifndef PL_ppaddr
13# define PL_ppaddr ppaddr 21# define PL_ppaddr ppaddr
14# endif 22# endif
15# ifndef call_sv 23# ifndef call_sv
16# define call_sv perl_call_sv 24# define call_sv perl_call_sv
66#define dSTACKLEVEL int stacklevel 74#define dSTACKLEVEL int stacklevel
67#define STACKLEVEL ((void *)&stacklevel) 75#define STACKLEVEL ((void *)&stacklevel)
68 76
69#define IN_DESTRUCT (PL_main_cv == Nullcv) 77#define IN_DESTRUCT (PL_main_cv == Nullcv)
70 78
71#define labs(l) ((l) >= 0 ? (l) : -(l)) 79#if __GNUC__ >= 3
80# define attribute(x) __attribute__(x)
81#else
82# define attribute(x)
83#endif
84
85#define NOINLINE attribute ((noinline))
72 86
73#include "CoroAPI.h" 87#include "CoroAPI.h"
74 88
75#define TRANSFER_SET_STACKLEVEL 0x8bfbfbfb /* magic cookie */ 89#define TRANSFER_SET_STACKLEVEL 0x8bfbfbfb /* magic cookie */
76 90
90 104
91/* this is a structure representing a c-level coroutine */ 105/* this is a structure representing a c-level coroutine */
92typedef struct coro_stack { 106typedef struct coro_stack {
93 struct coro_stack *next; 107 struct coro_stack *next;
94 108
95 void *idle_sp; /* original stacklevel when coroutine was created */ 109 /* the stack */
96 void *sptr; 110 void *sptr;
97 long ssize; /* positive == mmap, otherwise malloc */ 111 long ssize; /* positive == mmap, otherwise malloc */
98 112
99 /* cpu state */ 113 /* cpu state */
114 void *idle_sp; /* sp of top-level transfer/schedule/cede call */
115 JMPENV *top_env;
100 coro_context cctx; 116 coro_context cctx;
101 JMPENV *top_env; 117
118#if USE_VALGRIND
119 int valgrind_id;
120#endif
102} coro_stack; 121} coro_stack;
103
104/* the (fake) coro_stack representing the main program */
105static coro_stack *main_stack;
106 122
107/* this is a structure representing a perl-level coroutine */ 123/* this is a structure representing a perl-level coroutine */
108struct coro { 124struct coro {
109 /* the c coroutine allocated to this perl coroutine, if any */ 125 /* the c coroutine allocated to this perl coroutine, if any */
110 coro_stack *stack; 126 coro_stack *stack;
158 174
159typedef struct coro *Coro__State; 175typedef struct coro *Coro__State;
160typedef struct coro *Coro__State_or_hashref; 176typedef struct coro *Coro__State_or_hashref;
161 177
162static AV * 178static AV *
163coro_clone_padlist (pTHX_ CV *cv) 179coro_clone_padlist (CV *cv)
164{ 180{
165 AV *padlist = CvPADLIST (cv); 181 AV *padlist = CvPADLIST (cv);
166 AV *newpadlist, *newpad; 182 AV *newpadlist, *newpad;
167 183
168 newpadlist = newAV (); 184 newpadlist = newAV ();
169 AvREAL_off (newpadlist); 185 AvREAL_off (newpadlist);
170#if PERL_VERSION < 9 186#if PERL_VERSION_ATLEAST (5,9,0)
187 Perl_pad_push (aTHX_ padlist, AvFILLp (padlist) + 1);
188#else
171 Perl_pad_push (aTHX_ padlist, AvFILLp (padlist) + 1, 1); 189 Perl_pad_push (aTHX_ padlist, AvFILLp (padlist) + 1, 1);
172#else
173 Perl_pad_push (aTHX_ padlist, AvFILLp (padlist) + 1);
174#endif 190#endif
175 newpad = (AV *)AvARRAY (padlist)[AvFILLp (padlist)]; 191 newpad = (AV *)AvARRAY (padlist)[AvFILLp (padlist)];
176 --AvFILLp (padlist); 192 --AvFILLp (padlist);
177 193
178 av_store (newpadlist, 0, SvREFCNT_inc (*av_fetch (padlist, 0, FALSE))); 194 av_store (newpadlist, 0, SvREFCNT_inc (*av_fetch (padlist, 0, FALSE)));
180 196
181 return newpadlist; 197 return newpadlist;
182} 198}
183 199
184static void 200static void
185free_padlist (pTHX_ AV *padlist) 201free_padlist (AV *padlist)
186{ 202{
187 /* may be during global destruction */ 203 /* may be during global destruction */
188 if (SvREFCNT (padlist)) 204 if (SvREFCNT (padlist))
189 { 205 {
190 I32 i = AvFILLp (padlist); 206 I32 i = AvFILLp (padlist);
211 AV *padlist; 227 AV *padlist;
212 AV *av = (AV *)mg->mg_obj; 228 AV *av = (AV *)mg->mg_obj;
213 229
214 /* casting is fun. */ 230 /* casting is fun. */
215 while (&PL_sv_undef != (SV *)(padlist = (AV *)av_pop (av))) 231 while (&PL_sv_undef != (SV *)(padlist = (AV *)av_pop (av)))
216 free_padlist (aTHX_ padlist); 232 free_padlist (padlist);
217 233
218 SvREFCNT_dec (av); 234 SvREFCNT_dec (av);
219 235
220 return 0; 236 return 0;
221} 237}
224 240
225static MGVTBL vtbl_coro = {0, 0, 0, 0, coro_cv_free}; 241static MGVTBL vtbl_coro = {0, 0, 0, 0, coro_cv_free};
226 242
227/* the next two functions merely cache the padlists */ 243/* the next two functions merely cache the padlists */
228static void 244static void
229get_padlist (pTHX_ CV *cv) 245get_padlist (CV *cv)
230{ 246{
231 MAGIC *mg = mg_find ((SV *)cv, PERL_MAGIC_coro); 247 MAGIC *mg = mg_find ((SV *)cv, PERL_MAGIC_coro);
232 248
233 if (mg && AvFILLp ((AV *)mg->mg_obj) >= 0) 249 if (mg && AvFILLp ((AV *)mg->mg_obj) >= 0)
234 CvPADLIST (cv) = (AV *)av_pop ((AV *)mg->mg_obj); 250 CvPADLIST (cv) = (AV *)av_pop ((AV *)mg->mg_obj);
235 else 251 else
236 { 252 {
237#if 0 253#if 0
238 /* this should work - but it doesn't :( */ 254 /* this is probably cleaner, but also slower? */
239 CV *cp = Perl_cv_clone (aTHX_ cv); 255 CV *cp = Perl_cv_clone (cv);
240 CvPADLIST (cv) = CvPADLIST (cp); 256 CvPADLIST (cv) = CvPADLIST (cp);
241 CvPADLIST (cp) = 0; 257 CvPADLIST (cp) = 0;
242 SvREFCNT_dec (cp); 258 SvREFCNT_dec (cp);
243#else 259#else
244 CvPADLIST (cv) = coro_clone_padlist (aTHX_ cv); 260 CvPADLIST (cv) = coro_clone_padlist (cv);
245#endif 261#endif
246 } 262 }
247} 263}
248 264
249static void 265static void
250put_padlist (pTHX_ CV *cv) 266put_padlist (CV *cv)
251{ 267{
252 MAGIC *mg = mg_find ((SV *)cv, PERL_MAGIC_coro); 268 MAGIC *mg = mg_find ((SV *)cv, PERL_MAGIC_coro);
253 269
254 if (!mg) 270 if (!mg)
255 { 271 {
263} 279}
264 280
265#define SB do { 281#define SB do {
266#define SE } while (0) 282#define SE } while (0)
267 283
268#define LOAD(state) load_state(aTHX_ (state)); 284#define LOAD(state) load_state((state));
269#define SAVE(state,flags) save_state(aTHX_ (state),(flags)); 285#define SAVE(state,flags) save_state((state),(flags));
270 286
271#define REPLACE_SV(sv,val) SB SvREFCNT_dec(sv); (sv) = (val); (val) = 0; SE 287#define REPLACE_SV(sv,val) SB SvREFCNT_dec(sv); (sv) = (val); (val) = 0; SE
272 288
273static void 289static void
274load_state(pTHX_ Coro__State c) 290load_state(Coro__State c)
275{ 291{
276 PL_dowarn = c->dowarn; 292 PL_dowarn = c->dowarn;
277 PL_in_eval = c->in_eval; 293 PL_in_eval = c->in_eval;
278 294
279 PL_curstackinfo = c->curstackinfo; 295 PL_curstackinfo = c->curstackinfo;
297 PL_scopestack_ix = c->scopestack_ix; 313 PL_scopestack_ix = c->scopestack_ix;
298 PL_scopestack_max = c->scopestack_max; 314 PL_scopestack_max = c->scopestack_max;
299 PL_savestack = c->savestack; 315 PL_savestack = c->savestack;
300 PL_savestack_ix = c->savestack_ix; 316 PL_savestack_ix = c->savestack_ix;
301 PL_savestack_max = c->savestack_max; 317 PL_savestack_max = c->savestack_max;
302#if PERL_VERSION < 9 318#if !PERL_VERSION_ATLEAST (5,9,0)
303 PL_retstack = c->retstack; 319 PL_retstack = c->retstack;
304 PL_retstack_ix = c->retstack_ix; 320 PL_retstack_ix = c->retstack_ix;
305 PL_retstack_max = c->retstack_max; 321 PL_retstack_max = c->retstack_max;
306#endif 322#endif
307 PL_curpm = c->curpm; 323 PL_curpm = c->curpm;
320 { 336 {
321 AV *padlist = (AV *)POPs; 337 AV *padlist = (AV *)POPs;
322 338
323 if (padlist) 339 if (padlist)
324 { 340 {
325 put_padlist (aTHX_ cv); /* mark this padlist as available */ 341 put_padlist (cv); /* mark this padlist as available */
326 CvPADLIST(cv) = padlist; 342 CvPADLIST(cv) = padlist;
327 } 343 }
328 344
329 ++CvDEPTH(cv); 345 ++CvDEPTH(cv);
330 } 346 }
332 PUTBACK; 348 PUTBACK;
333 } 349 }
334} 350}
335 351
336static void 352static void
337save_state(pTHX_ Coro__State c, int flags) 353save_state(Coro__State c, int flags)
338{ 354{
339 { 355 {
340 dSP; 356 dSP;
341 I32 cxix = cxstack_ix; 357 I32 cxix = cxstack_ix;
342 PERL_CONTEXT *ccstk = cxstack; 358 PERL_CONTEXT *ccstk = cxstack;
370 } 386 }
371 387
372 PUSHs ((SV *)CvPADLIST(cv)); 388 PUSHs ((SV *)CvPADLIST(cv));
373 PUSHs ((SV *)cv); 389 PUSHs ((SV *)cv);
374 390
375 get_padlist (aTHX_ cv); 391 get_padlist (cv);
376 } 392 }
377 } 393 }
378#ifdef CXt_FORMAT 394#ifdef CXt_FORMAT
379 else if (CxTYPE(cx) == CXt_FORMAT) 395 else if (CxTYPE(cx) == CXt_FORMAT)
380 { 396 {
424 c->scopestack_ix = PL_scopestack_ix; 440 c->scopestack_ix = PL_scopestack_ix;
425 c->scopestack_max = PL_scopestack_max; 441 c->scopestack_max = PL_scopestack_max;
426 c->savestack = PL_savestack; 442 c->savestack = PL_savestack;
427 c->savestack_ix = PL_savestack_ix; 443 c->savestack_ix = PL_savestack_ix;
428 c->savestack_max = PL_savestack_max; 444 c->savestack_max = PL_savestack_max;
429#if PERL_VERSION < 9 445#if !PERL_VERSION_ATLEAST (5,9,0)
430 c->retstack = PL_retstack; 446 c->retstack = PL_retstack;
431 c->retstack_ix = PL_retstack_ix; 447 c->retstack_ix = PL_retstack_ix;
432 c->retstack_max = PL_retstack_max; 448 c->retstack_max = PL_retstack_max;
433#endif 449#endif
434 c->curpm = PL_curpm; 450 c->curpm = PL_curpm;
440 * of perl.c:init_stacks, except that it uses less memory 456 * of perl.c:init_stacks, except that it uses less memory
441 * on the (sometimes correct) assumption that coroutines do 457 * on the (sometimes correct) assumption that coroutines do
442 * not usually need a lot of stackspace. 458 * not usually need a lot of stackspace.
443 */ 459 */
444static void 460static void
445coro_init_stacks (pTHX) 461coro_init_stacks ()
446{ 462{
447 LOCK;
448
449 PL_curstackinfo = new_stackinfo(96, 1024/sizeof(PERL_CONTEXT) - 1); 463 PL_curstackinfo = new_stackinfo(96, 1024/sizeof(PERL_CONTEXT) - 1);
450 PL_curstackinfo->si_type = PERLSI_MAIN; 464 PL_curstackinfo->si_type = PERLSI_MAIN;
451 PL_curstack = PL_curstackinfo->si_stack; 465 PL_curstack = PL_curstackinfo->si_stack;
452 PL_mainstack = PL_curstack; /* remember in case we switch stacks */ 466 PL_mainstack = PL_curstack; /* remember in case we switch stacks */
453 467
474 488
475 New(54,PL_savestack,96,ANY); 489 New(54,PL_savestack,96,ANY);
476 PL_savestack_ix = 0; 490 PL_savestack_ix = 0;
477 PL_savestack_max = 96; 491 PL_savestack_max = 96;
478 492
479#if PERL_VERSION < 9 493#if !PERL_VERSION_ATLEAST (5,9,0)
480 New(54,PL_retstack,8,OP*); 494 New(54,PL_retstack,8,OP*);
481 PL_retstack_ix = 0; 495 PL_retstack_ix = 0;
482 PL_retstack_max = 8; 496 PL_retstack_max = 8;
483#endif 497#endif
484
485 UNLOCK;
486} 498}
487 499
488/* 500/*
489 * destroy the stacks, the callchain etc... 501 * destroy the stacks, the callchain etc...
490 */ 502 */
491static void 503static void
492destroy_stacks(pTHX) 504coro_destroy_stacks()
493{ 505{
494 if (!IN_DESTRUCT) 506 if (!IN_DESTRUCT)
495 { 507 {
496 /* is this ugly, I ask? */ 508 /* is this ugly, I ask? */
497 LEAVE_SCOPE (0); 509 LEAVE_SCOPE (0);
528 540
529 Safefree (PL_tmps_stack); 541 Safefree (PL_tmps_stack);
530 Safefree (PL_markstack); 542 Safefree (PL_markstack);
531 Safefree (PL_scopestack); 543 Safefree (PL_scopestack);
532 Safefree (PL_savestack); 544 Safefree (PL_savestack);
533#if PERL_VERSION < 9 545#if !PERL_VERSION_ATLEAST (5,9,0)
534 Safefree (PL_retstack); 546 Safefree (PL_retstack);
535#endif 547#endif
536} 548}
537 549
538static void 550static void
539setup_coro (struct coro *coro) 551setup_coro (struct coro *coro)
540{ 552{
541 /* 553 /*
542 * emulate part of the perl startup here. 554 * emulate part of the perl startup here.
543 */ 555 */
544 dTHX;
545 dSP;
546 UNOP myop;
547 SV *sub_init = (SV *)get_cv ("Coro::State::coro_init", FALSE);
548 556
549 coro_init_stacks (aTHX); 557 coro_init_stacks ();
558
550 /*PL_curcop = 0;*/ 559 PL_curcop = 0;
551 /*PL_in_eval = PL_in_eval;*/ /* inherit */ 560 PL_in_eval = 0;
561 PL_curpm = 0;
562
563 {
564 dSP;
565 LOGOP myop;
566
567 /* I have no idea why this is needed, but it is */
568 PUSHMARK (SP);
569
552 SvREFCNT_dec (GvAV (PL_defgv)); 570 SvREFCNT_dec (GvAV (PL_defgv));
553 GvAV (PL_defgv) = coro->args; coro->args = 0; 571 GvAV (PL_defgv) = coro->args; coro->args = 0;
554 572
555 SPAGAIN;
556
557 Zero (&myop, 1, UNOP); 573 Zero (&myop, 1, LOGOP);
558 myop.op_next = Nullop; 574 myop.op_next = Nullop;
559 myop.op_flags = OPf_WANT_VOID; 575 myop.op_flags = OPf_WANT_VOID;
560 576
561 PL_op = (OP *)&myop; 577 PL_op = (OP *)&myop;
562 578
563 PUSHMARK(SP); 579 PUSHMARK (SP);
564 XPUSHs (sub_init); 580 XPUSHs ((SV *)get_cv ("Coro::State::coro_init", FALSE));
565 PUTBACK; 581 PUTBACK;
566 PL_op = PL_ppaddr[OP_ENTERSUB](aTHX); 582 PL_op = PL_ppaddr[OP_ENTERSUB](aTHX);
567 SPAGAIN; 583 SPAGAIN;
568 584
569 ENTER; /* necessary e.g. for dounwind */ 585 ENTER; /* necessary e.g. for dounwind */
586 }
570} 587}
571 588
572static void 589static void
573free_coro_mortal () 590free_coro_mortal ()
574{ 591{
577 SvREFCNT_dec (coro_mortal); 594 SvREFCNT_dec (coro_mortal);
578 coro_mortal = 0; 595 coro_mortal = 0;
579 } 596 }
580} 597}
581 598
599static void NOINLINE
600prepare_cctx (coro_stack *cctx)
601{
602 dSP;
603 LOGOP myop;
604
605 Zero (&myop, 1, LOGOP);
606 myop.op_next = PL_op;
607 myop.op_flags = OPf_WANT_VOID;
608
609 sv_setiv (get_sv ("Coro::State::cctx_stack", FALSE), PTR2IV (cctx));
610
611 PUSHMARK (SP);
612 XPUSHs ((SV *)get_cv ("Coro::State::cctx_init", FALSE));
613 PUTBACK;
614 PL_restartop = PL_ppaddr[OP_ENTERSUB](aTHX);
615 SPAGAIN;
616}
617
582static void 618static void
583coro_run (void *arg) 619coro_run (void *arg)
584{ 620{
621 /* coro_run is the alternative epilogue of transfer() */
622 UNLOCK;
623
585 /* 624 /*
586 * this is a _very_ stripped down perl interpreter ;) 625 * this is a _very_ stripped down perl interpreter ;)
587 */ 626 */
588 dTHX;
589 PL_top_env = &PL_start_env; 627 PL_top_env = &PL_start_env;
628 /* inject call to cctx_init */
629 prepare_cctx ((coro_stack *)arg);
590 630
591 UNLOCK;
592
593 sv_setiv (get_sv ("Coro::State::cctx_stack", FALSE), PTR2IV ((coro_stack *)arg));
594 sv_setiv (get_sv ("Coro::State::cctx_restartop", FALSE), PTR2IV (PL_op));
595 PL_restartop = CvSTART (get_cv ("Coro::State::cctx_init", FALSE));
596
597 /* somebody will hit me for both perl_run and PL_restart_op */ 631 /* somebody will hit me for both perl_run and PL_restartop */
598 perl_run (aTHX_ PERL_GET_CONTEXT); 632 perl_run (PL_curinterp);
599 633
634 fputs ("FATAL: C coroutine fell over the edge of the world, aborting. Did you call exit in a coroutine?\n", stderr);
600 abort (); 635 abort ();
601} 636}
602 637
603static coro_stack * 638static coro_stack *
604stack_new () 639stack_new ()
607 642
608 New (0, stack, 1, coro_stack); 643 New (0, stack, 1, coro_stack);
609 644
610#if HAVE_MMAP 645#if HAVE_MMAP
611 646
612 stack->ssize = ((STACKSIZE * sizeof (long) + PAGESIZE - 1) / PAGESIZE + STACKGUARD) * PAGESIZE; /* mmap should do allocate-on-write for us */ 647 stack->ssize = ((STACKSIZE * sizeof (long) + PAGESIZE - 1) / PAGESIZE + STACKGUARD) * PAGESIZE;
648 /* mmap suppsedly does allocate-on-write for us */
613 stack->sptr = mmap (0, stack->ssize, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); 649 stack->sptr = mmap (0, stack->ssize, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
614 650
615 if (stack->sptr == (void *)-1) 651 if (stack->sptr == (void *)-1)
616 { 652 {
617 perror ("FATAL: unable to mmap stack for coroutine"); 653 perror ("FATAL: unable to mmap stack for coroutine");
618 _exit (EXIT_FAILURE); 654 _exit (EXIT_FAILURE);
619 } 655 }
620 656
657# if STACKGUARD
621 mprotect (stack->sptr, STACKGUARD * PAGESIZE, PROT_NONE); 658 mprotect (stack->sptr, STACKGUARD * PAGESIZE, PROT_NONE);
659# endif
622 660
623#else 661#else
624 662
625 stack->ssize = STACKSIZE * (long)sizeof (long); 663 stack->ssize = STACKSIZE * (long)sizeof (long);
626 New (0, stack->sptr, STACKSIZE, long); 664 New (0, stack->sptr, STACKSIZE, long);
631 _exit (EXIT_FAILURE); 669 _exit (EXIT_FAILURE);
632 } 670 }
633 671
634#endif 672#endif
635 673
674#if USE_VALGRIND
675 stack->valgrind_id = VALGRIND_STACK_REGISTER (
676 STACKGUARD * PAGESIZE + (char *)stack->sptr,
677 stack->ssize + (char *)stack->sptr
678 );
679#endif
680
636 coro_create (&stack->cctx, coro_run, (void *)stack, stack->sptr, stack->ssize); 681 coro_create (&stack->cctx, coro_run, (void *)stack, stack->sptr, stack->ssize);
637 682
638 return stack; 683 return stack;
639} 684}
640 685
641static void 686static void
642stack_free (coro_stack *stack) 687stack_free (coro_stack *stack)
643{ 688{
644 if (!stack || stack == main_stack) 689 if (!stack)
645 return; 690 return;
691
692#if USE_VALGRIND
693 VALGRIND_STACK_DEREGISTER (stack->valgrind_id);
694#endif
646 695
647#if HAVE_MMAP 696#if HAVE_MMAP
648 munmap (stack->sptr, stack->ssize); 697 munmap (stack->sptr, stack->ssize);
649#else 698#else
650 Safefree (stack->sptr); 699 Safefree (stack->sptr);
652 701
653 Safefree (stack); 702 Safefree (stack);
654} 703}
655 704
656static coro_stack *stack_first; 705static coro_stack *stack_first;
706static int cctx_count, cctx_idle;
657 707
658static coro_stack * 708static coro_stack *
659stack_get () 709stack_get ()
660{ 710{
661 coro_stack *stack; 711 coro_stack *stack;
662 712
663 if (stack_first) 713 if (stack_first)
664 { 714 {
715 --cctx_idle;
665 stack = stack_first; 716 stack = stack_first;
666 stack_first = stack->next; 717 stack_first = stack->next;
667 } 718 }
668 else 719 else
669 { 720 {
721 ++cctx_count;
670 stack = stack_new (); 722 stack = stack_new ();
671 PL_op = PL_op->op_next; 723 PL_op = PL_op->op_next;
672 } 724 }
673 725
674 return stack; 726 return stack;
675} 727}
676 728
677static void 729static void
678stack_put (coro_stack *stack) 730stack_put (coro_stack *stack)
679{ 731{
732 ++cctx_idle;
680 stack->next = stack_first; 733 stack->next = stack_first;
681 stack_first = stack; 734 stack_first = stack;
682} 735}
683 736
684/* never call directly, always through the coro_state_transfer global variable */ 737/* never call directly, always through the coro_state_transfer global variable */
685static void 738static void NOINLINE
686transfer_impl (pTHX_ struct coro *prev, struct coro *next, int flags) 739transfer (struct coro *prev, struct coro *next, int flags)
687{ 740{
688 dSTACKLEVEL; 741 dSTACKLEVEL;
689 742
690 /* sometimes transfer is only called to set idle_sp */ 743 /* sometimes transfer is only called to set idle_sp */
691 if (flags == TRANSFER_SET_STACKLEVEL) 744 if (flags == TRANSFER_SET_STACKLEVEL)
711 setup_coro (next); 764 setup_coro (next);
712 /* need a stack */ 765 /* need a stack */
713 next->stack = 0; 766 next->stack = 0;
714 } 767 }
715 768
769 if (!prev->stack)
770 /* create a new empty context */
771 Newz (0, prev->stack, 1, coro_stack);
772
716 prev__stack = prev->stack; 773 prev__stack = prev->stack;
717 774
718 /* possibly "free" the stack */ 775 /* possibly "free" the stack */
719 if (prev__stack->idle_sp == STACKLEVEL) 776 if (prev__stack->idle_sp == STACKLEVEL)
720 { 777 {
736 793
737 UNLOCK; 794 UNLOCK;
738 } 795 }
739} 796}
740 797
741/* use this function pointer to call the above function */
742/* this is done to increase chances of the compiler not inlining the call */
743/* not static to make it even harder for the compiler (and theoretically impossible in most cases */
744void (*coro_state_transfer)(pTHX_ struct coro *prev, struct coro *next, int flags) = transfer_impl;
745
746struct transfer_args 798struct transfer_args
747{ 799{
748 struct coro *prev, *next; 800 struct coro *prev, *next;
749 int flags; 801 int flags;
750}; 802};
751 803
752#define TRANSFER(ta) coro_state_transfer ((ta).prev, (ta).next, (ta).flags) 804#define TRANSFER(ta) transfer ((ta).prev, (ta).next, (ta).flags)
753 805
754static void 806static void
755coro_state_destroy (struct coro *coro) 807coro_state_destroy (struct coro *coro)
756{ 808{
757 if (coro->refcnt--) 809 if (coro->refcnt--)
759 811
760 if (coro->mainstack && coro->mainstack != main_mainstack) 812 if (coro->mainstack && coro->mainstack != main_mainstack)
761 { 813 {
762 struct coro temp; 814 struct coro temp;
763 815
764 SAVE (aTHX_ (&temp), TRANSFER_SAVE_ALL); 816 SAVE ((&temp), TRANSFER_SAVE_ALL);
765 LOAD (aTHX_ coro); 817 LOAD (coro);
766 818
767 destroy_stacks (aTHX); 819 coro_destroy_stacks ();
768 820
769 LOAD ((&temp)); /* this will get rid of defsv etc.. */ 821 LOAD ((&temp)); /* this will get rid of defsv etc.. */
770 822
771 coro->mainstack = 0; 823 coro->mainstack = 0;
772 } 824 }
775 SvREFCNT_dec (coro->args); 827 SvREFCNT_dec (coro->args);
776 Safefree (coro); 828 Safefree (coro);
777} 829}
778 830
779static int 831static int
780coro_state_clear (SV *sv, MAGIC *mg) 832coro_state_clear (pTHX_ SV *sv, MAGIC *mg)
781{ 833{
782 struct coro *coro = (struct coro *)mg->mg_ptr; 834 struct coro *coro = (struct coro *)mg->mg_ptr;
783 mg->mg_ptr = 0; 835 mg->mg_ptr = 0;
784 836
785 coro_state_destroy (coro); 837 coro_state_destroy (coro);
786 838
787 return 0; 839 return 0;
788} 840}
789 841
790static int 842static int
791coro_state_dup (MAGIC *mg, CLONE_PARAMS *params) 843coro_state_dup (pTHX_ MAGIC *mg, CLONE_PARAMS *params)
792{ 844{
793 struct coro *coro = (struct coro *)mg->mg_ptr; 845 struct coro *coro = (struct coro *)mg->mg_ptr;
794 846
795 ++coro->refcnt; 847 ++coro->refcnt;
796 848
797 return 0; 849 return 0;
798} 850}
799 851
800static MGVTBL coro_state_vtbl = { 0, 0, 0, 0, coro_state_clear, 0, coro_state_dup, 0 }; 852static MGVTBL coro_state_vtbl = {
853 0, 0, 0, 0,
854 coro_state_clear,
855 0,
856#ifdef MGf_DUP
857 coro_state_dup,
858#else
859# define MGf_DUP 0
860#endif
861};
801 862
802static struct coro * 863static struct coro *
803SvSTATE (SV *coro) 864SvSTATE (SV *coro)
804{ 865{
805 HV *stash; 866 HV *stash;
820 assert (mg->mg_type == PERL_MAGIC_ext); 881 assert (mg->mg_type == PERL_MAGIC_ext);
821 return (struct coro *)mg->mg_ptr; 882 return (struct coro *)mg->mg_ptr;
822} 883}
823 884
824static void 885static void
825prepare_transfer (pTHX_ struct transfer_args *ta, SV *prev, SV *next, int flags) 886prepare_transfer (struct transfer_args *ta, SV *prev, SV *next, int flags)
826{ 887{
827 ta->prev = SvSTATE (prev); 888 ta->prev = SvSTATE (prev);
828 ta->next = SvSTATE (next); 889 ta->next = SvSTATE (next);
829 ta->flags = flags; 890 ta->flags = flags;
830} 891}
833api_transfer (SV *prev, SV *next, int flags) 894api_transfer (SV *prev, SV *next, int flags)
834{ 895{
835 dTHX; 896 dTHX;
836 struct transfer_args ta; 897 struct transfer_args ta;
837 898
838 prepare_transfer (aTHX_ &ta, prev, next, flags); 899 prepare_transfer (&ta, prev, next, flags);
839 TRANSFER (ta); 900 TRANSFER (ta);
840} 901}
841 902
842/** Coro ********************************************************************/ 903/** Coro ********************************************************************/
843 904
852static GV *coro_current, *coro_idle; 913static GV *coro_current, *coro_idle;
853static AV *coro_ready [PRIO_MAX-PRIO_MIN+1]; 914static AV *coro_ready [PRIO_MAX-PRIO_MIN+1];
854static int coro_nready; 915static int coro_nready;
855 916
856static void 917static void
857coro_enq (pTHX_ SV *sv) 918coro_enq (SV *sv)
858{ 919{
859 int prio; 920 int prio;
860 921
861 if (SvTYPE (sv) != SVt_PVHV) 922 if (SvTYPE (sv) != SVt_PVHV)
862 croak ("Coro::ready tried to enqueue something that is not a coroutine"); 923 croak ("Coro::ready tried to enqueue something that is not a coroutine");
866 av_push (coro_ready [prio - PRIO_MIN], sv); 927 av_push (coro_ready [prio - PRIO_MIN], sv);
867 coro_nready++; 928 coro_nready++;
868} 929}
869 930
870static SV * 931static SV *
871coro_deq (pTHX_ int min_prio) 932coro_deq (int min_prio)
872{ 933{
873 int prio = PRIO_MAX - PRIO_MIN; 934 int prio = PRIO_MAX - PRIO_MIN;
874 935
875 min_prio -= PRIO_MIN; 936 min_prio -= PRIO_MIN;
876 if (min_prio < 0) 937 if (min_prio < 0)
893 954
894 if (SvROK (coro)) 955 if (SvROK (coro))
895 coro = SvRV (coro); 956 coro = SvRV (coro);
896 957
897 LOCK; 958 LOCK;
898 coro_enq (aTHX_ SvREFCNT_inc (coro)); 959 coro_enq (SvREFCNT_inc (coro));
899 UNLOCK; 960 UNLOCK;
900} 961}
901 962
902static void 963static void
903prepare_schedule (aTHX_ struct transfer_args *ta) 964prepare_schedule (struct transfer_args *ta)
904{ 965{
905 SV *current, *prev, *next; 966 SV *current, *prev, *next;
906
907 LOCK;
908 967
909 current = GvSV (coro_current); 968 current = GvSV (coro_current);
910 969
911 for (;;) 970 for (;;)
912 { 971 {
913 LOCK; 972 LOCK;
914
915 next = coro_deq (aTHX_ PRIO_MIN); 973 next = coro_deq (PRIO_MIN);
974 UNLOCK;
916 975
917 if (next) 976 if (next)
918 break; 977 break;
919
920 UNLOCK;
921 978
922 { 979 {
923 dSP; 980 dSP;
924 981
925 ENTER; 982 ENTER;
936 993
937 prev = SvRV (current); 994 prev = SvRV (current);
938 SvRV (current) = next; 995 SvRV (current) = next;
939 996
940 /* free this only after the transfer */ 997 /* free this only after the transfer */
998 LOCK;
941 free_coro_mortal (); 999 free_coro_mortal ();
1000 UNLOCK;
942 coro_mortal = prev; 1001 coro_mortal = prev;
943 1002
944 ta->prev = SvSTATE (prev); 1003 ta->prev = SvSTATE (prev);
945 ta->next = SvSTATE (next); 1004 ta->next = SvSTATE (next);
946 ta->flags = TRANSFER_SAVE_ALL; 1005 ta->flags = TRANSFER_SAVE_ALL;
947
948 UNLOCK;
949} 1006}
950 1007
951static void 1008static void
952prepare_cede (aTHX_ struct transfer_args *ta) 1009prepare_cede (struct transfer_args *ta)
953{ 1010{
954 LOCK; 1011 LOCK;
955 coro_enq (aTHX_ SvREFCNT_inc (SvRV (GvSV (coro_current)))); 1012 coro_enq (SvREFCNT_inc (SvRV (GvSV (coro_current))));
956 UNLOCK; 1013 UNLOCK;
957 1014
958 prepare_schedule (ta); 1015 prepare_schedule (ta);
959} 1016}
960 1017
998 main_mainstack = PL_mainstack; 1055 main_mainstack = PL_mainstack;
999 1056
1000 coroapi.ver = CORO_API_VERSION; 1057 coroapi.ver = CORO_API_VERSION;
1001 coroapi.transfer = api_transfer; 1058 coroapi.transfer = api_transfer;
1002 1059
1003 Newz (0, main_stack, 1, coro_stack);
1004 main_stack->idle_sp = (void *)-1;
1005
1006 assert (("PRIO_NORMAL must be 0", !PRIO_NORMAL)); 1060 assert (("PRIO_NORMAL must be 0", !PRIO_NORMAL));
1007} 1061}
1008 1062
1009SV * 1063SV *
1010new (char *klass, ...) 1064new (char *klass, ...)
1022 RETVAL = sv_bless (newRV_noinc ((SV *)hv), gv_stashpv (klass, 1)); 1076 RETVAL = sv_bless (newRV_noinc ((SV *)hv), gv_stashpv (klass, 1));
1023 1077
1024 for (i = 1; i < items; i++) 1078 for (i = 1; i < items; i++)
1025 av_push (coro->args, newSVsv (ST (i))); 1079 av_push (coro->args, newSVsv (ST (i)));
1026 1080
1027 coro->stack = main_stack;
1028 /*coro->mainstack = 0; *//*actual work is done inside transfer */ 1081 /*coro->mainstack = 0; *//*actual work is done inside transfer */
1029 /*coro->stack = 0;*/ 1082 /*coro->stack = 0;*/
1030} 1083}
1031 OUTPUT: 1084 OUTPUT:
1032 RETVAL 1085 RETVAL
1033 1086
1034void 1087void
1035transfer (...) 1088_set_stacklevel (...)
1036 ALIAS: 1089 ALIAS:
1037 Coro::schedule = 1 1090 Coro::State::transfer = 1
1038 Coro::cede = 2 1091 Coro::schedule = 2
1039 _set_stacklevel = 3 1092 Coro::cede = 3
1093 Coro::Cont::yield = 4
1040 CODE: 1094 CODE:
1041{ 1095{
1042 struct transfer_args ta; 1096 struct transfer_args ta;
1043 1097
1044 switch (ix) 1098 switch (ix)
1045 { 1099 {
1046 case 0: 1100 case 0:
1047 if (items != 3)
1048 croak ("Coro::State::transfer(prev,next,flags) expects three arguments, not %d", items);
1049
1050 prepare_transfer (&ta, ST (0), ST (1), SvIV (ST (2)));
1051 break;
1052
1053 case 1:
1054 prepare_schedule (&ta);
1055 break;
1056
1057 case 2:
1058 prepare_cede (&ta);
1059 break;
1060
1061 case 3:
1062 ta.prev = (struct coro *)INT2PTR (coro_stack *, SvIV (ST (0))); 1101 ta.prev = (struct coro *)INT2PTR (coro_stack *, SvIV (ST (0)));
1063 ta.next = 0; 1102 ta.next = 0;
1064 ta.flags = TRANSFER_SET_STACKLEVEL; 1103 ta.flags = TRANSFER_SET_STACKLEVEL;
1065 break; 1104 break;
1105
1106 case 1:
1107 if (items != 3)
1108 croak ("Coro::State::transfer(prev,next,flags) expects three arguments, not %d", items);
1109
1110 prepare_transfer (&ta, ST (0), ST (1), SvIV (ST (2)));
1111 break;
1112
1113 case 2:
1114 prepare_schedule (&ta);
1115 break;
1116
1117 case 3:
1118 prepare_cede (&ta);
1119 break;
1120
1121 case 4:
1122 {
1123 SV *yieldstack;
1124 SV *sv;
1125 AV *defav = GvAV (PL_defgv);
1126
1127 yieldstack = *hv_fetch (
1128 (HV *)SvRV (GvSV (coro_current)),
1129 "yieldstack", sizeof ("yieldstack") - 1,
1130 0
1131 );
1132
1133 /* set up @_ -- ugly */
1134 av_clear (defav);
1135 av_fill (defav, items - 1);
1136 while (items--)
1137 av_store (defav, items, SvREFCNT_inc (ST(items)));
1138
1139 sv = av_pop ((AV *)SvRV (yieldstack));
1140 ta.prev = SvSTATE (*av_fetch ((AV *)SvRV (sv), 0, 0));
1141 ta.next = SvSTATE (*av_fetch ((AV *)SvRV (sv), 1, 0));
1142 ta.flags = 0;
1143 SvREFCNT_dec (sv);
1144 }
1145 break;
1146
1066 } 1147 }
1067 1148
1068 TRANSFER (ta); 1149 TRANSFER (ta);
1069} 1150}
1070 1151
1077 sv_unmagic (SvRV (dst), PERL_MAGIC_ext); 1158 sv_unmagic (SvRV (dst), PERL_MAGIC_ext);
1078 1159
1079 ++coro_src->refcnt; 1160 ++coro_src->refcnt;
1080 sv_magicext (SvRV (dst), 0, PERL_MAGIC_ext, &coro_state_vtbl, (char *)coro_src, 0)->mg_flags |= MGf_DUP; 1161 sv_magicext (SvRV (dst), 0, PERL_MAGIC_ext, &coro_state_vtbl, (char *)coro_src, 0)->mg_flags |= MGf_DUP;
1081} 1162}
1082
1083void
1084_nonlocal_goto (IV nextop)
1085 CODE:
1086 /* uuh, somebody will kill me again for this */
1087 PL_op->op_next = INT2PTR (OP *, nextop);
1088 1163
1089void 1164void
1090_exit (code) 1165_exit (code)
1091 int code 1166 int code
1092 PROTOTYPE: $ 1167 PROTOTYPE: $
1093 CODE: 1168 CODE:
1094 _exit (code); 1169 _exit (code);
1095
1096MODULE = Coro::State PACKAGE = Coro::Cont
1097
1098void
1099yield (...)
1100 PROTOTYPE: @
1101 CODE:
1102{
1103 SV *yieldstack;
1104 SV *sv;
1105 AV *defav = GvAV (PL_defgv);
1106 struct coro *prev, *next;
1107
1108 yieldstack = *hv_fetch (
1109 (HV *)SvRV (GvSV (coro_current)),
1110 "yieldstack", sizeof ("yieldstack") - 1,
1111 0
1112 );
1113
1114 /* set up @_ -- ugly */
1115 av_clear (defav);
1116 av_fill (defav, items - 1);
1117 while (items--)
1118 av_store (defav, items, SvREFCNT_inc (ST(items)));
1119
1120 sv = av_pop ((AV *)SvRV (yieldstack));
1121 prev = SvSTATE (*av_fetch ((AV *)SvRV (sv), 0, 0));
1122 next = SvSTATE (*av_fetch ((AV *)SvRV (sv), 1, 0));
1123 SvREFCNT_dec (sv);
1124
1125 coro_state_transfer (aTHX_ prev, next, 0);
1126}
1127 1170
1128MODULE = Coro::State PACKAGE = Coro 1171MODULE = Coro::State PACKAGE = Coro
1129 1172
1130BOOT: 1173BOOT:
1131{ 1174{

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines