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.14 by root, Mon Jul 23 23:48:05 2001 UTC vs.
Revision 1.15 by root, Wed Jul 25 04:14:38 2001 UTC

9# include <sys/mman.h> 9# include <sys/mman.h>
10#endif 10#endif
11 11
12#define MAY_FLUSH /* increases codesize */ 12#define MAY_FLUSH /* increases codesize */
13 13
14/* perl-related */
14#define TRANSFER_SAVE_DEFAV 0x00000001 15#define TRANSFER_SAVE_DEFAV 0x00000001
15#define TRANSFER_SAVE_DEFSV 0x00000002 16#define TRANSFER_SAVE_DEFSV 0x00000002
16#define TRANSFER_SAVE_ERRSV 0x00000004 17#define TRANSFER_SAVE_ERRSV 0x00000004
18/* c-related */
17#define TRANSFER_SAVE_CCTXT 0x00000008 19#define TRANSFER_SAVE_CCTXT 0x00000008
20#ifdef CORO_LAZY_STACK
21# define TRANSFER_LAZY_STACK 0x00000010
22#else
23# define TRANSFER_LAZY_STACK 0x00000000
24#endif
18 25
19#define TRANSFER_SAVE_ALL -1 26#define TRANSFER_SAVE_ALL (TRANSFER_SAVE_DEFAV|TRANSFER_SAVE_DEFSV \
27 |TRANSFER_SAVE_ERRSV|TRANSFER_SAVE_CCTXT)
20 28
21#define SUB_INIT "Coro::State::initialize" 29#define SUB_INIT "Coro::State::initialize"
22#define UCORO_STATE "_coro_state" 30#define UCORO_STATE "_coro_state"
23 31
32/* The next macro should delcare a variable stacklevel that contains and approximation
33 * to the current C stack pointer. It's property is that it changes with each call
34 * and should be unique. */
35#define dSTACKLEVEL void *stacklevel = &stacklevel
36
37#define labs(l) ((l) >= 0 ? (l) : -(l))
38
39/* this is actually not only the c stack but also c registers etc... */
40typedef struct {
41 int refcnt; /* pointer reference counter */
42 int usecnt; /* shared by how many coroutines */
43 int gencnt; /* generation counter */
44
45 coro_context cctx;
46
47 void *sptr;
48 long ssize; /* positive == mmap, otherwise malloc */
49} coro_stack;
50
51static coro_stack main_stack = { 1, 0, 0 };
52
24struct coro { 53struct coro {
25 /* the optional C context */ 54 /* the optional C context */
26 coro_context cctx; 55 coro_stack *stack;
27 void *sptr; 56 void *cursp;
28 long ssize; 57 int gencnt;
29 58
30 /* optionally saved, might be zero */ 59 /* optionally saved, might be zero */
31 AV *defav; 60 AV *defav;
32 SV *defsv; 61 SV *defsv;
33 SV *errsv; 62 SV *errsv;
437 466
438 PL_stack_base = AvARRAY(PL_curstack); 467 PL_stack_base = AvARRAY(PL_curstack);
439 PL_stack_sp = PL_stack_base; 468 PL_stack_sp = PL_stack_base;
440 PL_stack_max = PL_stack_base + AvMAX(PL_curstack); 469 PL_stack_max = PL_stack_base + AvMAX(PL_curstack);
441 470
442 New(50,PL_tmps_stack,64,SV*); 471 New(50,PL_tmps_stack,96,SV*);
443 PL_tmps_floor = -1; 472 PL_tmps_floor = -1;
444 PL_tmps_ix = -1; 473 PL_tmps_ix = -1;
445 PL_tmps_max = 64; 474 PL_tmps_max = 96;
446 475
447 New(54,PL_markstack,12,I32); 476 New(54,PL_markstack,16,I32);
448 PL_markstack_ptr = PL_markstack; 477 PL_markstack_ptr = PL_markstack;
449 PL_markstack_max = PL_markstack + 12; 478 PL_markstack_max = PL_markstack + 16;
450 479
451 SET_MARK_OFFSET; 480 SET_MARK_OFFSET;
452 481
453 New(54,PL_scopestack,12,I32); 482 New(54,PL_scopestack,16,I32);
454 PL_scopestack_ix = 0; 483 PL_scopestack_ix = 0;
455 PL_scopestack_max = 12; 484 PL_scopestack_max = 16;
456 485
457 New(54,PL_savestack,64,ANY); 486 New(54,PL_savestack,96,ANY);
458 PL_savestack_ix = 0; 487 PL_savestack_ix = 0;
459 PL_savestack_max = 64; 488 PL_savestack_max = 96;
460 489
461 New(54,PL_retstack,8,OP*); 490 New(54,PL_retstack,8,OP*);
462 PL_retstack_ix = 0; 491 PL_retstack_ix = 0;
463 PL_retstack_max = 8; 492 PL_retstack_max = 8;
464} 493}
505 Safefree(PL_savestack); 534 Safefree(PL_savestack);
506 Safefree(PL_retstack); 535 Safefree(PL_retstack);
507} 536}
508 537
509static void 538static void
510allocate_stack (Coro__State ctx) 539allocate_stack (Coro__State ctx, int alloc)
511{ 540{
541 coro_stack *stack;
542
543 New (0, stack, 1, coro_stack);
544
545 stack->refcnt = 1;
546 stack->usecnt = 1;
547 stack->gencnt = ctx->gencnt = 0;
548 if (alloc)
549 {
512#ifdef HAVE_MMAP 550#ifdef HAVE_MMAP
513 ctx->ssize = 128 * 1024 * sizeof (long); /* mmap should do allocate-on-use */ 551 stack->ssize = 128 * 1024 * sizeof (long); /* mmap should do allocate-on-use */
514 ctx->sptr = mmap (0, ctx->ssize, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, 0, 0); 552 stack->sptr = mmap (0, stack->ssize, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, 0, 0);
515 if (ctx->sptr == (void *)-1) 553 if (stack->sptr == (void *)-1)
516#endif 554#endif
517 { 555 {
518 /*FIXME*//*D*//* reasonable stack size! */ 556 /*FIXME*//*D*//* reasonable stack size! */
519 ctx->ssize = 4096 * sizeof (long); 557 stack->ssize = -4096 * sizeof (long);
520 New (0, ctx->sptr, 4096, long); 558 New (0, stack->sptr, 4096, long);
559 }
521 } 560 }
561 else
562 stack->sptr = 0;
563
564 ctx->stack = stack;
522} 565}
523 566
524static void 567static void
525deallocate_stack (Coro__State ctx) 568deallocate_stack (Coro__State ctx)
526{ 569{
570 coro_stack *stack = ctx->stack;
571
572 ctx->stack = 0;
573
574 if (stack)
575 {
576 if (!--stack->refcnt)
577 {
527#ifdef HAVE_MMAP 578#ifdef HAVE_MMAP
528 munmap (ctx->sptr, ctx->ssize); 579 if (stack->ssize > 0 && stack->sptr)
580 munmap (stack->sptr, stack->ssize);
581 else
529#else 582#else
530 Safefree (ctx->sptr); 583 Safefree (stack->sptr);
531#endif 584#endif
585 Safefree (stack);
586 }
587 else if (ctx->gencnt == stack->gencnt)
588 --stack->usecnt;
589 }
532} 590}
533 591
534/* might go away together with optional SAVE_CCTXT */
535static void 592static void
536setup_coro (void *arg) 593setup_coro (void *arg)
537{ 594{
538 /* 595 /*
539 * emulate part of the perl startup here. 596 * emulate part of the perl startup here.
548 605
549 /*PL_curcop = 0;*/ 606 /*PL_curcop = 0;*/
550 SvREFCNT_dec (GvAV (PL_defgv)); 607 SvREFCNT_dec (GvAV (PL_defgv));
551 GvAV (PL_defgv) = ctx->args; 608 GvAV (PL_defgv) = ctx->args;
552 609
553 if (ctx->sptr) 610 if (ctx->stack)
554 { 611 {
612 ctx->cursp = 0;
613
555 PUSHMARK(SP); 614 PUSHMARK(SP);
556 PUTBACK; 615 PUTBACK;
557 (void) call_sv (sub_init, G_VOID|G_NOARGS); 616 (void) call_sv (sub_init, G_VOID|G_NOARGS);
558 croak ("FATAL: CCTXT coroutine returned!"); 617 croak ("FATAL: CCTXT coroutine returned!");
559 } 618 }
582 641
583 ENTER; /* necessary e.g. for dounwind */ 642 ENTER; /* necessary e.g. for dounwind */
584 } 643 }
585} 644}
586 645
646static void
647continue_coro (void *arg)
648{
649 /*
650 * this is a _very_ stripped down perl interpreter ;)
651 */
652 Coro__State ctx = (Coro__State)arg;
653
654 ctx->cursp = 0;
655 PL_op = PL_op->op_next;
656 CALLRUNOPS(aTHX);
657 /*NORETURN*/
658 abort ();
659}
660
587STATIC void 661STATIC void
588transfer(pTHX_ struct coro *prev, struct coro *next, int flags) 662transfer(pTHX_ struct coro *prev, struct coro *next, int flags)
589{ 663{
590 dSP; 664 dSP;
665 dSTACKLEVEL;
591 666
592 if (prev != next) 667 if (prev != next)
593 { 668 {
594 /*
595 * this could be done in newprocess which would lead to
596 * extremely elegant and fast (basically just SAVE/LOAD)
597 * code here, but lazy allocation of stacks has also
598 * some virtues and the overhead of the if() is nil.
599 */
600 if (next->mainstack) 669 if (next->mainstack)
601 { 670 {
602 SAVE (prev, flags); 671 SAVE (prev, flags);
603 LOAD (next); 672 LOAD (next);
604 673
605 /* mark this state as in-use */ 674 /* mark this state as in-use */
606 next->mainstack = 0; 675 next->mainstack = 0;
607 next->tmps_ix = -2; 676 next->tmps_ix = -2;
608 677
678 /* stacklevel changed? if yes, grab the stack for us! */
609 if (flags & TRANSFER_SAVE_CCTXT) 679 if (flags & TRANSFER_SAVE_CCTXT)
610 { 680 {
611 if (!next->ssize)
612 croak ("destination coroutine has no CCTXT (%p, %d)", next->sptr, next->ssize);
613
614 if (!prev->ssize) 681 if (!prev->stack)
615 prev->ssize = 1; /* mark cctx as valid ;) */ 682 allocate_stack (prev, 0);
683 else if (prev->cursp != stacklevel
684 && prev->stack->usecnt > 1)
685 {
686 prev->gencnt = ++prev->stack->gencnt;
687 prev->stack->usecnt = 1;
688 }
616 689
690 /* has our stack been invalidated? */
691 if (next->stack && next->stack->gencnt != next->gencnt)
692 {
693 deallocate_stack (next);
694 allocate_stack (next, 1);
695 coro_create (&(next->stack->cctx),
696 continue_coro, (void *)next,
697 next->stack->sptr, labs (next->stack->ssize));
698 }
699
617 coro_transfer (&(prev->cctx), &(next->cctx)); 700 coro_transfer (&(prev->stack->cctx), &(next->stack->cctx));
618 } 701 }
619 702
620 } 703 }
621 else if (next->tmps_ix == -2) 704 else if (next->tmps_ix == -2)
622 croak ("tried to transfer to running coroutine"); 705 croak ("tried to transfer to running coroutine");
624 { 707 {
625 SAVE (prev, -1); /* first get rid of the old state */ 708 SAVE (prev, -1); /* first get rid of the old state */
626 709
627 if (flags & TRANSFER_SAVE_CCTXT) 710 if (flags & TRANSFER_SAVE_CCTXT)
628 { 711 {
629 if (!next->ssize) 712 if (!prev->stack)
713 allocate_stack (prev, 0);
714
715 if (prev->stack->sptr && flags & TRANSFER_LAZY_STACK)
630 { 716 {
717 setup_coro (next);
718
719 prev->stack->refcnt++;
720 prev->stack->usecnt++;
721 next->stack = prev->stack;
722 next->gencnt = prev->gencnt;
723 }
724 else
725 {
631 allocate_stack (next); 726 allocate_stack (next, 1);
632 coro_create (&(next->cctx), 727 coro_create (&(next->stack->cctx),
633 setup_coro, (void *)next, 728 setup_coro, (void *)next,
634 next->sptr, next->ssize); 729 next->stack->sptr, labs (next->stack->ssize));
730 coro_transfer (&(prev->stack->cctx), &(next->stack->cctx));
635 } 731 }
636
637 if (!prev->ssize)
638 prev->ssize = 1; /* mark cctx as valid ;) */
639
640 coro_transfer (&(prev->cctx), &(next->cctx));
641 } 732 }
642 else 733 else
643 setup_coro (next); 734 setup_coro (next);
644 } 735 }
645 } 736 }
737
738 next->cursp = stacklevel;
646} 739}
647 740
648MODULE = Coro::State PACKAGE = Coro::State 741MODULE = Coro::State PACKAGE = Coro::State
649 742
650PROTOTYPES: ENABLE 743PROTOTYPES: ENABLE
678 771
679 New (0, coro, 1, struct coro); 772 New (0, coro, 1, struct coro);
680 773
681 coro->args = (AV *)SvREFCNT_inc (SvRV (args)); 774 coro->args = (AV *)SvREFCNT_inc (SvRV (args));
682 coro->mainstack = 0; /* actual work is done inside transfer */ 775 coro->mainstack = 0; /* actual work is done inside transfer */
683 coro->sptr = 0; 776 coro->stack = 0;
684 coro->ssize = 0;
685 777
686 RETVAL = coro; 778 RETVAL = coro;
687 OUTPUT: 779 OUTPUT:
688 RETVAL 780 RETVAL
689 781
690void 782void
691transfer(prev, next, flags = TRANSFER_SAVE_ALL) 783transfer(prev, next, flags = TRANSFER_SAVE_ALL | TRANSFER_LAZY_STACK)
692 Coro::State_or_hashref prev 784 Coro::State_or_hashref prev
693 Coro::State_or_hashref next 785 Coro::State_or_hashref next
694 int flags 786 int flags
695 PROTOTYPE: @ 787 PROTOTYPE: @
696 CODE: 788 CODE:
713 LOAD((&temp)); /* this will get rid of defsv etc.. */ 805 LOAD((&temp)); /* this will get rid of defsv etc.. */
714 806
715 coro->mainstack = 0; 807 coro->mainstack = 0;
716 } 808 }
717 809
718 if (coro->sptr)
719 {
720 deallocate_stack (coro); 810 deallocate_stack (coro);
721 coro->sptr = 0;
722 }
723 811
724 Safefree (coro); 812 Safefree (coro);
725 813
726void 814void
727flush() 815flush()

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines