| 14 | | Maintainer: Elizabeth Mattijsen <liz@dijkmat.nl> |
| 15 | | Date: 13 Jun 2005 |
| 16 | | Last Modified: 08 Feb 2008 |
| 17 | | Number: 0 |
| 18 | | Version: 2 |
| 19 | | |
| 20 | | =head1 SKETCH |
| 21 | | |
| 22 | | This is a rough sketch of how concurrency works in Perl 6. |
| 23 | | |
| 24 | | (actually these are just random notes, put here under the release-early |
| 25 | | release-often principle, slowly being integrated in a more textual format. |
| 26 | | Patches welcome!) |
| 27 | | |
| 28 | | =head1 OVERVIEW |
| | 14 | Maintainer: Elizabeth Mattijsen <liz@dijkmat.nl> |
| | 15 | Contributions: Christoph Buchetmann |
| | 16 | Date: 13 Jun 2005 |
| | 17 | Last Modified: 4 Mar 2008 |
| | 18 | Number 0 |
| | 19 | Version: 3 |
| | 20 | |
| | 21 | This is a draft document. After being some time under the surface of Perl 6 |
| | 22 | development this is a attempt to document working concurrency issues, list the |
| | 23 | remaining todos and mark the probably obsolete and redundant points. |
| | 24 | |
| | 25 | =head1 Overview |
| 357 | | |
| 358 | | =head2 Still more or less unorganized stuff |
| 359 | | |
| 360 | | |
| 361 | | ### INTERFACE BARRIER ### |
| 362 | | module Blah; |
| 363 | | { |
| 364 | | |
| 365 | | is atomic; # contend/maybe/whatever other rollback stuff |
| 366 | | # limitation: no external IO (without lethal warnings anyway) |
| 367 | | # can't do anything irreversible |
| 368 | | |
| 369 | | is critical; # free to do anything irreversible |
| 370 | | # means "don't interrupt me" |
| 371 | | # in system with critical section, no interrupts from |
| 372 | | # other threads will happen during execution |
| 373 | | # you can't suspend me |
| 374 | | |
| 375 | | my $boo is export; |
| 376 | | $boo = 1; |
| 377 | | |
| 378 | | # We decree that this part forms the static interface |
| 379 | | # it's run once during initial compilation under the |
| 380 | | # Separate Compilation doctrine and the syms sealed off |
| 381 | | # to form part of bytecode syms headers |
| 382 | | %CALLER::<&blah> = { 1 }; # work - adds to export set |
| 383 | | die "Eureka!" if %CALLER::<$sym>; # never dies |
| 384 | | |
| 385 | | # BEGIN { $boo = time }; |
| 386 | | |
| 387 | | sub IMPORT { |
| 388 | | # VERY DYNAMIC! |
| 389 | | |
| 390 | | our $i = time; |
| 391 | | %CALLER::<&blah> = { 1 }; # work - adds to export set |
| 392 | | die "Eureka!" if %CALLER::<$sym>; # probes interactively |
| 393 | | } |
| 394 | | } |
| 395 | | ### INTERFACE BARRIER ### |
| 396 | | |
| 397 | | my $sym; |
| 398 | | threads.new({ |
| 399 | | use Blah; |
| 400 | | BEGIN { require(Blah).import } |
| 401 | | |
| 402 | | my $boo; BEGIN { eval slurp<Blah.pm>; $boo := $Blah::boo }; |
| 403 | | |
| 404 | | ... |
| 405 | | }); |
| 486 | | =head3 Coroutines |
| 487 | | |
| 488 | | ## braindump of coro meeting by Liz and Autri, more to follow |
| | 422 | =head2 Junctive Autothreading and Hyper Operations |
| | 423 | |
| | 424 | Live in userland for the time being. |
| | 425 | |
| | 426 | =head2 Interprocess Communication |
| | 427 | |
| | 428 | =head2 I/O Considerations |
| | 429 | |
| | 430 | =head3 File Descriptors |
| | 431 | |
| | 432 | =head3 Sockets |
| | 433 | |
| | 434 | |
| | 435 | =head2 Still more or less unorganized stuff |
| | 436 | |
| | 437 | |
| | 438 | ### INTERFACE BARRIER ### |
| | 439 | module Blah; |
| | 440 | { |
| | 441 | |
| | 442 | is atomic; # contend/maybe/whatever other rollback stuff |
| | 443 | # limitation: no external IO (without lethal warnings anyway) |
| | 444 | # can't do anything irreversible |
| | 445 | |
| | 446 | is critical; # free to do anything irreversible |
| | 447 | # means "don't interrupt me" |
| | 448 | # in system with critical section, no interrupts from |
| | 449 | # other threads will happen during execution |
| | 450 | # you can't suspend me |
| | 451 | |
| | 452 | my $boo is export; |
| | 453 | $boo = 1; |
| | 454 | |
| | 455 | # We decree that this part forms the static interface |
| | 456 | # it's run once during initial compilation under the |
| | 457 | # Separate Compilation doctrine and the syms sealed off |
| | 458 | # to form part of bytecode syms headers |
| | 459 | %CALLER::<&blah> = { 1 }; # work - adds to export set |
| | 460 | die "Eureka!" if %CALLER::<$sym>; # never dies |
| | 461 | |
| | 462 | # BEGIN { $boo = time }; |
| | 463 | |
| | 464 | sub IMPORT { |
| | 465 | # VERY DYNAMIC! |
| | 466 | |
| | 467 | our $i = time; |
| | 468 | %CALLER::<&blah> = { 1 }; # work - adds to export set |
| | 469 | die "Eureka!" if %CALLER::<$sym>; # probes interactively |
| | 470 | } |
| | 471 | } |
| | 472 | ### INTERFACE BARRIER ### |
| | 473 | |
| | 474 | =head3 braindump of coro meeting by Liz and Autri, more to follow |
| 492 | | coro dbl { yield $_ * 2; yield $_; return }; |
| 493 | | my @x = 1..10; |
| 494 | | my %y = map &dbl, @x; |
| 495 | | # 2 => 2, 6 => 4, 10 => 6, ... |
| 496 | | |
| 497 | | coro perm (@x) { |
| 498 | | @x.splice(rand(@x),1).yield while @x; |
| 499 | | } |
| 500 | | |
| 501 | | my &p1 := &perm.start(1..10); |
| 502 | | my &p2 := &perm.start(1..20); |
| 503 | | |
| 504 | | p1(); p1(); |
| 505 | | p2(); p2(); |
| 506 | | |
| 507 | | coro foo { yield 42 }; |
| 508 | | |
| 509 | | (1..10).pick; |
| 510 | | |
| 511 | | coro foo ($x) { |
| | 478 | coro perm (@x) { |
| | 479 | @x.splice(rand(@x),1).yield while @x; |
| | 480 | } |
| | 481 | my &p1 := &perm.start(1..10); |
| | 482 | my &p2 := &perm.start(1..20); |
| | 483 | p1(); p1(); |
| | 484 | p2(); p2(); |
| | 485 | |
| | 486 | coro foo { yield 42 }; |
| | 487 | |
| | 488 | coro foo ($x) { |
| 520 | | } # implicit falloff return + return() means start over without yielding |
| 521 | | # return() means yielding and restart + no implicit falloff (I LIKE THIS) |
| 522 | | |
| 523 | | &foo.finished; # true on return() and false on midway yield() |
| 524 | | |
| 525 | | foo(4); # and that's all she wrote |
| 526 | | |
| 527 | | coro foo ($x) { |
| | 497 | } # implicit falloff return + return() means start over without yielding |
| | 498 | # return() means yielding and restart + no implicit falloff (I LIKE THIS) |
| | 499 | |
| | 500 | &foo.finished; # true on return() and false on midway yield() |
| | 501 | |
| | 502 | foo(4); # and that's all she wrote |
| | 503 | |
| | 504 | coro foo ($x) { |
| 569 | | } |
| 570 | | |
| 571 | | %*ENV(123); |
| 572 | | |
| 573 | | &foo_continued := &foo.start(10); |
| 574 | | &foo.start(20); |
| 575 | | |
| 576 | | foo(10); # returns 10 |
| 577 | | |
| 578 | | foo(); # be "insufficient param" error or just return 11? |
| 579 | | foo(20); # returns 21 |
| 580 | | |
| 581 | | # continuation coros |
| 582 | | multi foo () { ...no rebinding... } |
| 583 | | multi foo ($x) { ...rebinding... } |
| 584 | | |
| 585 | | &foo.kill; |
| 586 | | |
| 587 | | |
| 588 | | my $first_ret = zoro( type => <even> ); |
| 589 | | &zoro.variant(:type<even>).kill; |
| 590 | | &zoro.variant(type => 'even').kill; |
| 591 | | |
| 592 | | zoro( type => <odd> ); |
| 593 | | |
| 594 | | zoro( even => 1 ); |
| 595 | | zoro( odd => 1 ); |
| 596 | | |
| 597 | | multi coro zoro ($type where 'even') {} |
| 598 | | multi coro zoro ($type where 'odd') {} |
| 599 | | |
| 600 | | multi coro zoro ($even is named) {} |
| 601 | | multi coro zoro ($odd is named) {} |
| 602 | | |
| 603 | | |
| 604 | | # iblech's thoughts: |
| 605 | | # Coroutine parameters should never be rebound. Instead, yield(...)s return |
| 606 | | # value is an Arglist object containing the new arguments: |
| 607 | | coro bar ($a, $b) { |
| | 546 | } |
| | 547 | |
| | 548 | %*ENV(123); |
| | 549 | |
| | 550 | &foo_continued := &foo.start(10); |
| | 551 | &foo.start(20); |
| | 552 | |
| | 553 | foo(10); # returns 10 |
| | 554 | |
| | 555 | foo(); # be "insufficient param" error or just return 11? |
| | 556 | foo(20); # returns 21 |
| | 557 | |
| | 558 | # continuation coros |
| | 559 | multi foo () { ...no rebinding... } |
| | 560 | multi foo ($x) { ...rebinding... } |
| | 561 | |
| | 562 | &foo.kill; |
| | 563 | |
| | 564 | |
| | 565 | my $first_ret = zoro( type => <even> ); |
| | 566 | &zoro.variant(:type<even>).kill; |
| | 567 | &zoro.variant(type => 'even').kill; |
| | 568 | |
| | 569 | zoro( type => <odd> ); |
| | 570 | |
| | 571 | zoro( even => 1 ); |
| | 572 | zoro( odd => 1 ); |
| | 573 | |
| | 574 | multi coro zoro ($type where 'even') {} |
| | 575 | multi coro zoro ($type where 'odd') {} |
| | 576 | |
| | 577 | multi coro zoro ($even is named) {} |
| | 578 | multi coro zoro ($odd is named) {} |
| | 579 | |
| | 580 | |
| | 581 | # iblech's thoughts: |
| | 582 | # Coroutine parameters should never be rebound. Instead, yield(...)s return |
| | 583 | # value is an Arglist object containing the new arguments: |
| | 584 | coro bar ($a, $b) { |
| 612 | | } |
| 613 | | bar(42, 23); # $a is 42, $b is 23 |
| 614 | | bar(17, 19); # $a still 42, $b still 19, |
| 615 | | # $new_set_of_args is \(a => 17, b => 19) |
| 616 | | |
| 617 | | =head2 Junctive Autothreading and Hyper Operations |
| 618 | | |
| 619 | | Live in userland for the time being. |
| 620 | | |
| 621 | | =head2 Interprocess Communication |
| 622 | | |
| 623 | | =head2 I/O Considerations |
| 624 | | |
| 625 | | =head3 File Descriptors |
| 626 | | |
| 627 | | =head3 Sockets |
| | 589 | } |
| | 590 | bar(42, 23); # $a is 42, $b is 23 |
| | 591 | bar(17, 19); # $a still 42, $b still 19, |