Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add failing test for purescript-contrib/purescript-aff#174 #175

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 25 additions & 7 deletions src/Effect/Aff.js
Original file line number Diff line number Diff line change
@@ -238,6 +238,7 @@ var Aff = function () {
var step = aff; // Successful step
var fail = null; // Failure step
var interrupt = null; // Asynchronous interrupt
var pendingInterrupt = null; // Pending, asynchronous interrupt

// Stack of continuations for the current fiber.
var bhead = null;
@@ -455,10 +456,10 @@ var Aff = function () {
result = util.fromRight(step);
// We need to enqueue the Release with the same interrupt
// status as the Bracket that is initiating it.
attempts = new Aff(CONS, new Aff(RELEASE, attempt._2, result), attempts, tmp);
attempts = new Aff(CONS, new Aff(RELEASE, attempt._2, result, pendingInterrupt), attempts, tmp);
// We should only coninue as long as the interrupt status has not changed or
// we are currently within a non-interruptable finalizer.
if (interrupt === tmp || bracketCount > 0) {
if ((!pendingInterrupt && interrupt === tmp) || bracketCount > 0) {
status = CONTINUE;
step = attempt._3(result);
}
@@ -470,12 +471,13 @@ var Aff = function () {
case RELEASE:
attempts = new Aff(CONS, new Aff(FINALIZED, step, fail), attempts, interrupt);
status = CONTINUE;

// It has only been killed if the interrupt status has changed
// since we enqueued the item, and the bracket count is 0. If the
// bracket count is non-zero then we are in a masked state so it's
// impossible to be killed.
if (interrupt && interrupt !== tmp && bracketCount === 0) {
step = attempt._1.killed(util.fromLeft(interrupt))(attempt._2);
if (((interrupt && interrupt !== tmp) || attempt._3) && bracketCount === 0) {
step = attempt._1.killed(util.fromLeft(interrupt || pendingInterrupt))(attempt._2);
} else if (fail) {
step = attempt._1.failed(util.fromLeft(fail))(attempt._2);
} else {
@@ -494,6 +496,18 @@ var Aff = function () {

case FINALIZED:
bracketCount--;

// If we've got a pending interrupt and are no longer masked,
// check the stack if we are about to run the release handler of a
// containing bracket. If that is the case, postpone setting the
// interrupt until after the release handler ran.
if (pendingInterrupt != null && bracketCount === 0) {
if (attempts == null || attempts._1.tag !== RELEASE) {
interrupt = pendingInterrupt;
pendingInterrupt = null;
}
}

status = RETURN;
step = attempt._1;
fail = attempt._2;
@@ -578,17 +592,21 @@ var Aff = function () {
run(runTick);
break;
case PENDING:
if (interrupt === null) {
interrupt = util.left(error);
}
if (bracketCount === 0) {
if (interrupt === null) {
interrupt = util.left(error);
}
if (status === PENDING) {
attempts = new Aff(CONS, new Aff(FINALIZER, step(error)), attempts, interrupt);
}
status = RETURN;
step = null;
fail = null;
run(++runTick);
} else {
if (pendingInterrupt === null) {
pendingInterrupt = util.left(error);
}
}
break;
default:
21 changes: 21 additions & 0 deletions test/Test/Main.purs
Original file line number Diff line number Diff line change
@@ -730,6 +730,26 @@ test_regression_kill_empty_supervisor = assert "regression/kill-empty-supervisor
b = parallel $ delay (Milliseconds 20.0) $> false
sequential (a <|> b)

test_invincible_completes ∷ Aff Unit
test_invincible_completes = assert "test/invincible-completes" do
ref ← newRef Nothing
f1 ← forkAff $
generalBracket
(pure unit)
{ killed: \_ _ -> writeRef ref (Just "killed")
, failed: \_ _ -> writeRef ref (Just "failed")
, completed: \_ _ -> writeRef ref (Just "completed")
}
(\_ ->
bracket
(delay (Milliseconds 20.0))
(const (pure unit))
pure
)
delay (Milliseconds 10.0)
killFiber (error "kaboom.") f1
readRef ref <#> (_ == Just "completed")

main ∷ Effect Unit
main = do
test_pure
@@ -781,3 +801,4 @@ main = do
test_regression_kill_sync_async
test_regression_bracket_kill_mask
test_regression_kill_empty_supervisor
test_invincible_completes