Skip to content

Commit ae7a9f7

Browse files
committed
Implement supervise with generalBracket
1 parent 116b499 commit ae7a9f7

File tree

2 files changed

+82
-99
lines changed

2 files changed

+82
-99
lines changed

src/Control/Monad/Aff.js

Lines changed: 46 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -168,45 +168,47 @@ var Aff = function () {
168168
return count === 0;
169169
},
170170
killAll: function (killError, cb) {
171-
var killCount = 0;
172-
var kills = {};
171+
return function () {
172+
var killCount = 0;
173+
var kills = {};
173174

174-
function kill(fid) {
175-
kills[fid] = fibers[fid].kill(killError, function (result) {
176-
return function () {
177-
delete kills[fid];
178-
killCount--;
179-
if (util.isLeft(result) && util.fromLeft(result)) {
180-
setTimeout(function () {
181-
throw util.fromLeft(result);
182-
}, 0);
183-
}
184-
if (killCount === 0) {
185-
cb();
186-
}
187-
};
188-
})();
189-
}
175+
function kill(fid) {
176+
kills[fid] = fibers[fid].kill(killError, function (result) {
177+
return function () {
178+
delete kills[fid];
179+
killCount--;
180+
if (util.isLeft(result) && util.fromLeft(result)) {
181+
setTimeout(function () {
182+
throw util.fromLeft(result);
183+
}, 0);
184+
}
185+
if (killCount === 0) {
186+
cb();
187+
}
188+
};
189+
})();
190+
}
190191

191-
for (var k in fibers) {
192-
if (fibers.hasOwnProperty(k)) {
193-
killCount++;
194-
kill(k);
192+
for (var k in fibers) {
193+
if (fibers.hasOwnProperty(k)) {
194+
killCount++;
195+
kill(k);
196+
}
195197
}
196-
}
197198

198-
fibers = {};
199-
fiberId = 0;
200-
count = 0;
199+
fibers = {};
200+
fiberId = 0;
201+
count = 0;
201202

202-
return function (error) {
203-
return new Aff(SYNC, function () {
204-
for (var k in kills) {
205-
if (kills.hasOwnProperty(k)) {
206-
kills[k]();
203+
return function (error) {
204+
return new Aff(SYNC, function () {
205+
for (var k in kills) {
206+
if (kills.hasOwnProperty(k)) {
207+
kills[k]();
208+
}
207209
}
208-
}
209-
});
210+
});
211+
};
210212
};
211213
}
212214
};
@@ -1046,64 +1048,18 @@ exports._makeFiber = function (util, aff) {
10461048
};
10471049
};
10481050

1049-
exports._supervise = function (util, aff) {
1050-
return Aff.Async(function (cb) {
1051-
return function () {
1052-
var supervisor = Aff.Supervisor(util);
1053-
var fiber = Aff.Fiber(util, supervisor, aff);
1054-
var killing = false;
1055-
var cancelCb = fiber.onComplete({
1056-
rethrow: false,
1057-
handler: function (result) {
1058-
return function () {
1059-
killing = true;
1060-
supervisor.killAll(new Error("[Aff] Child fiber outlived parent"), cb(result));
1061-
};
1062-
}
1063-
})();
1064-
1065-
fiber.run();
1066-
1067-
return function (killError) {
1068-
return Aff.Async(function (killCb) {
1069-
return function () {
1070-
if (killing) {
1071-
return Aff.nonCanceler;
1072-
}
1073-
cancelCb();
1074-
1075-
var killResult = null;
1076-
var killedAll = false;
1077-
1078-
var canceler1 = fiber.kill(killError, function (result) {
1079-
return function () {
1080-
if (killedAll) {
1081-
killCb(result)();
1082-
} else {
1083-
killResult = result;
1084-
}
1085-
};
1086-
})();
1087-
1088-
var canceler2 = supervisor.killAll(killError, function () {
1089-
if (killResult) {
1090-
killCb(killResult)();
1091-
} else {
1092-
killedAll = true;
1093-
}
1094-
});
1095-
1096-
return function (/* unused */) {
1097-
return Aff.Sync(function () {
1098-
canceler1();
1099-
canceler2();
1100-
});
1101-
};
1102-
};
1103-
});
1104-
};
1051+
exports._makeSupervisedFiber = function (util, aff) {
1052+
return function () {
1053+
var supervisor = Aff.Supervisor(util);
1054+
return {
1055+
fiber: Aff.Fiber(util, supervisor, aff),
1056+
supervisor: supervisor
11051057
};
1106-
});
1058+
};
1059+
};
1060+
1061+
exports._killAll = function (error, supervisor, cb) {
1062+
return supervisor.killAll(error, cb);
11071063
};
11081064

11091065
exports._delay = function () {

src/Control/Monad/Aff.purs

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,8 @@ nonCanceler = Canceler (const (pure unit))
193193
-- | Forks an `Aff` from an `Eff` context, returning the `Fiber`.
194194
launchAff eff a. Aff eff a Eff eff (Fiber eff a)
195195
launchAff aff = do
196-
fiber@(Fiber { run }) ← makeFiber aff
197-
run
196+
fiber ← makeFiber aff
197+
case fiber of Fiber f → f.run
198198
pure fiber
199199

200200
-- | Suspends an `Aff` from an `Eff` context, returning the `Fiber`.
@@ -221,12 +221,6 @@ forkAff = _fork true
221221
suspendAff eff a. Aff eff a Aff eff (Fiber eff a)
222222
suspendAff = _fork false
223223

224-
-- | Creates a new supervision context for some `Aff`, guaranteeing fiber
225-
-- | cleanup when the parent completes. Any pending fibers forked within
226-
-- | the context will be killed and have their cancelers run.
227-
supervise eff a. Aff eff a Aff eff a
228-
supervise aff = Fn.runFn2 _supervise ffiUtil aff
229-
230224
-- | Pauses the running fiber.
231225
delay eff. Milliseconds Aff eff Unit
232226
delay (Milliseconds n) = Fn.runFn2 _delay Right n
@@ -282,6 +276,38 @@ bracket acquire completed =
282276
, completed: const completed
283277
}
284278

279+
type Supervised eff a =
280+
{ fiber Fiber eff a
281+
, supervisor Supervisor eff
282+
}
283+
284+
-- | Creates a new supervision context for some `Aff`, guaranteeing fiber
285+
-- | cleanup when the parent completes. Any pending fibers forked within
286+
-- | the context will be killed and have their cancelers run.
287+
supervise eff a. Aff eff a Aff eff a
288+
supervise aff =
289+
generalBracket (liftEff acquire)
290+
{ killed: \err sup → parSequence_ [ killFiber err sup.fiber, killAll err sup ]
291+
, failed: const (killAll killError)
292+
, completed: const (killAll killError)
293+
}
294+
(joinFiber <<< _.fiber)
295+
where
296+
killError Error
297+
killError =
298+
error "[Aff] Child fiber outlived parent"
299+
300+
killAll Error Supervised eff a Aff eff Unit
301+
killAll err sup = makeAff \k →
302+
Fn.runFn3 _killAll err sup.supervisor (k (pure unit))
303+
304+
acquire Eff eff (Supervised eff a)
305+
acquire = do
306+
sup ← Fn.runFn2 _makeSupervisedFiber ffiUtil aff
307+
case sup.fiber of Fiber f → f.run
308+
pure sup
309+
310+
foreign import data Supervisor ∷ # Effect Type
285311
foreign import _pure eff a. a Aff eff a
286312
foreign import _throwError eff a. Error Aff eff a
287313
foreign import _catchError eff a. Aff eff a (Error Aff eff a) Aff eff a
@@ -294,7 +320,8 @@ foreign import _parAffMap ∷ ∀ eff a b. (a → b) → ParAff eff a → ParAff
294320
foreign import _parAffApply eff a b. ParAff eff (a b) ParAff eff a ParAff eff b
295321
foreign import _parAffAlt eff a. ParAff eff a ParAff eff a ParAff eff a
296322
foreign import _makeFiber eff a. Fn.Fn2 FFIUtil (Aff eff a) (Eff eff (Fiber eff a))
297-
foreign import _supervise eff a. Fn.Fn2 FFIUtil (Aff eff a) (Aff eff a)
323+
foreign import _makeSupervisedFiber eff a. Fn.Fn2 FFIUtil (Aff eff a) (Eff eff (Supervised eff a))
324+
foreign import _killAll eff. Fn.Fn3 Error (Supervisor eff) (Eff eff Unit) (Eff eff (Canceler eff))
298325
foreign import _sequential eff a. ParAff eff a Aff eff a
299326

300327
type BracketConditions eff a b =

0 commit comments

Comments
 (0)