Skip to content

Commit

Permalink
Streamline exit / END phaser handling
Browse files Browse the repository at this point in the history
- falling off the end of a program / exit now share END phaser handling
- the first value given to exit() is what will be returned to the OS
  - END blocks can also execute exit(), so we could nest
- only *one* thread will execute the END phasers on first come/served basis
  - before, multiple threads could be doing this
  • Loading branch information
lizmat committed Sep 7, 2017
1 parent 9785356 commit 1adacc7
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 21 deletions.
2 changes: 1 addition & 1 deletion src/core/Exception.pm
Expand Up @@ -388,7 +388,7 @@ do {
$err.say("===SORRY!===");
$err.say($e.Str);
}
Rakudo::Internals.THE_END();
nqp::getcurhllsym('&THE_END')();
CONTROL { when CX::Warn { .resume } }
}
if $! {
Expand Down
40 changes: 27 additions & 13 deletions src/core/Rakudo/Internals.pm
Expand Up @@ -128,12 +128,6 @@ my class Rakudo::Internals {
0;
}

method THE_END {
my @END := nqp::p6bindattrinvres(nqp::create(List), List, '$!reified',
nqp::getcurhllsym("@END_PHASERS"));
for @END -> $end { $end() };
}

method createENV(int $bind) {
nqp::stmts(
(my $hash := nqp::hash),
Expand Down Expand Up @@ -1530,17 +1524,37 @@ my class Rakudo::Internals {
# expose the number of bits a native int has
my constant $?BITS = nqp::isgt_i(nqp::add_i(2147483648, 1), 0) ?? 64 !! 32;

{ # setting up END phaser handling
my int $the-end-is-done;
my $the-end-locker = Lock.new;
# END handling, returns trueish if END handling already done/in progress
nqp::bindcurhllsym('&THE_END', {
unless $the-end-is-done {
$the-end-locker.protect: {
unless $the-end-is-done {
my $comp := nqp::getcomp('perl6');
my $end := nqp::getcurhllsym('@END_PHASERS');
while nqp::elems($end) {
my $result := nqp::shift($end)();
$result.sink if nqp::can($result,'sink');
CATCH { $comp.handle-exception($_) }
CONTROL { $comp.handle-control($_) }
}
nqp::not_i(($the-end-is-done = 1));
}
}
}
} );
}

# we need this to run *after* the mainline of Rakudo::Internals has run
Rakudo::Internals.REGISTER-DYNAMIC: '&*EXIT', {
PROCESS::<&EXIT> := sub exit($status) {
state $exit;
$exit = $status;
state $exit = $status; # first call to exit sets value

once {
Rakudo::Internals.THE_END();
nqp::exit(nqp::unbox_i($exit.Int));
}
$exit;
nqp::getcurhllsym('&THE_END')()
?? $exit
!! nqp::exit(nqp::unbox_i($exit.Int))
}
}

Expand Down
10 changes: 3 additions & 7 deletions src/main.nqp
Expand Up @@ -43,12 +43,8 @@ sub MAIN(@ARGS) {
# Enter the compiler.
$comp.command_line(@ARGS, :encoding('utf8'), :transcode('ascii iso-8859-1'));

# Run any END blocks before exiting.
my @END := nqp::gethllsym('perl6', '@END_PHASERS');
while +@END {
my $result := (@END.shift)();
nqp::can($result, 'sink') && $result.sink();
CATCH { $comp.handle-exception($_); }
CONTROL { $comp.handle-control($_); }
# do all the necessary actions at the end, if any
if nqp::gethllsym('perl6', '&THE_END') -> $THE_END {
$THE_END()
}
}

0 comments on commit 1adacc7

Please sign in to comment.