<html><head><style>body{font-family:Helvetica,Arial;font-size:13px}</style></head><body style="word-wrap:break-word"><div id="bloop_customfont" style="font-family:Helvetica,Arial;font-size:13px;color:rgba(0,0,0,1.0);margin:0px;line-height:auto"><br>On March 26, 2017 at 12:09:55 AM, Brent Royal-Gordon (<a href="mailto:brent@architechies.com">brent@architechies.com</a>) wrote:</div> <blockquote type="cite" class="clean_bq"><span><div style="word-wrap:break-word" class=""><div></div><div>



<title></title>


<div>
<blockquote type="cite" class="">
<div class="">On Mar 23, 2017, at 9:01 AM, Joe Groff via
swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div>
<br class="Apple-interchange-newline">
<div class=""><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important" class="">setjmp and longjmp do *not* work well with Swift since
they need compiler support to implement their semantics, and since
Swift does not provide this support, setjmp-ing from Swift is
undefined behavior. Empirical evidence that small examples appear
to work is not a good way of evaluating UB, since any changes to
Swift or LLVM optimizations may break it. Ease of implementation is
also not a good criterion for designing things. *Supporting* a trap
hook is not easy; it still has serious language semantics and
runtime design issues, and may limit our ability to do something
better.</span><br class="Apple-interchange-newline"></div>
</blockquote>
</div>
<div class=""><br class=""></div>
<div class="">Could we do something useful here without
setjmp/longjmp? Suppose we had a function in the standard library
that was roughly equivalent to this:</div>
<div class=""><br class=""></div>
<div class="">typealias UnsafeFatalErrorCleanupHandler = () -&gt;
Void</div>
<div class=""></div>
<div class="">// Note the imaginary @_thread_local property
behavior</div>
<div class="">@_thread_local var _fatalErrorCleanupHandlers:
[UnsafeFatalErrorCleanupHandler] = []</div>
<div class=""></div>
<div class="">func withUnsafeFatalErrorCleanupHandler&lt;R&gt;(_
handler: UnsafeFatalErrorCleanupHandler, do body: () throws -&gt;
R) rethrows -&gt; R {</div>
<div class="">_fatalErrorCleanupHandlers.append(handler)</div>
<div class="">defer { _fatalErrorCleanupHandlers.removeLast()
}</div>
<div class="">return try body()</div>
<div class="">}</div>
<div class=""><br class=""></div>
<div class="">And then, just before we trap, we do something like
this:</div>
<div class=""><br class=""></div>
<div class="">// Mutating it this way ensures that, if we reenter
fatalError() in one of the handlers, </div>
<div class="">// it will pick up with the next handler.</div>
<div class="">while let handler =
_fatalErrorCleanupHandlers.popLast() {</div>
<div class="">handler()</div>
<div class="">}</div>
<div class=""><br class=""></div>
<div class="">I think that would allow frameworks to do something
like:</div>
<div class=""><br class=""></div>
<div class="">class Worker {</div>
<div class="">let queue = DispatchQueue(label: &quot;Worker&quot;)</div>
<div class="">typealias RequestCompletion = (RequestStatus) -&gt;
Void</div>
<div class=""><br class=""></div>
<div class="">enum RequestStatus {</div>
<div class="">case responded</div>
<div class="">case crashing</div>
<div class="">}</div>
<div class=""></div>
<div class="">func beginRequest(from conn: IOHandle, then
completion: RequestCompletion) {</div>
<div class="">queue.async {</div>
<div class="">
withUnsafeFatalErrorCleanupHandler(fatalErrorHandler(completion))
{</div>
<div class="">// Handle the request, potentially crashing</div>
<div class="">}</div>
<div class="">}</div>
<div class="">}</div>
<div class=""><br class=""></div>
<div class="">func fatalErrorHandler(_ completion:
RequestCompletion) -&gt; UnsafeFatalErrorCleanupHandler {</div>
<div class="">return { completion(.crashing) }</div>
<div class="">}</div>
<div class="">}</div>
<div class=""><br class=""></div>
<div class="">class Supervisor {</div>
<div class="">let queue = DispatchQueue(label: &quot;Supervisor&quot;)</div>
<div class="">var workerPool: Pool&lt;Worker&gt;</div>
<div class=""><br class=""></div>
<div class="">func startListening(to sockets: [IOHandle]) { …
}</div>
<div class="">func stopListening() { … }</div>
<div class=""></div>
<div class="">func bootReplacement() { … }</div>
<div class=""></div>
<div class="">func connected(by conn: IOHandle) {</div>
<div class="">dispatchPrecondition(condition:
.onQueue(queue))</div>
<div class=""></div>
<div class="">let worker = workerPool.reserve()</div>
<div class=""></div>
<div class="">worker.beginRequest(from: conn) { status in</div>
<div class="">switch status {</div>
<div class="">case .responded:</div>
<div class="">conn.close()</div>
<div class="">self.queue.sync {</div>
<div class="">self.workerPool.relinquish(worker)</div>
<div class="">}</div>
<div class=""></div>
<div class="">case .crashing:</div>
<div class="">// Uh oh, we&#39;re in trouble.</div>
<div class="">// </div>
<div class="">// This process is toast; it will not survive long
beyond this stack frame.</div>
<div class="">// We want to close our listening socket, start a
replacement server, </div>
<div class="">// and then just try to hang on until the other
workers have finished their </div>
<div class="">// current requests.</div>
<div class="">// </div>
<div class="">// It&#39;d be nice to send an error message and close
the connection, </div>
<div class="">// but we shouldn&#39;t. We don&#39;t know what state
the connection or the </div>
<div class="">// worker are in, so we don&#39;t want to do
anything to them.We risk a </div>
<div class="">// `!==` check because it only involves a memory
address stored in </div>
<div class="">// our closure context, not the actual object
being referenced by it.</div>
<div class=""></div>
<div class="">// Go exclusive on the supervisor&#39;s queue so we don&#39;t
try to handle </div>
<div class="">// two crashes at once (or a crash and something
else, for that matter).</div>
<div class="">self.queue.sync {</div>
<div class="">self.stopListening()</div>
<div class="">self.bootReplacement()</div>
<div class=""></div>
<div class="">// Try to keep the process alive until all of the
surviving workers have </div>
<div class="">// finished their current requests. To do this, we&#39;ll
perform barrier blocks </div>
<div class="">// on all of their queues, attached to a single
dispatch group, and then </div>
<div class="">// wait for the group to complete.</div>
<div class="">let group = DispatchGroup()</div>
<div class=""></div>
<div class="">for otherWorker in self.workerPool.all where
otherWorker !== worker {</div>
<div class="">// We run this as `.background` to try to let
anything else the request might </div>
<div class="">// enqueue run first, and `.barrier` to make sure
we&#39;re the only thing running.</div>
<div class="">otherWorker.queue.async(group: group, qos:
.background, flags: .barrier) {</div>
<div class="">// Make sure we don&#39;t do anything else.</div>
<div class="">otherWorker.queue.suspend()</div>
<div class="">}</div>
<div class="">}</div>
<div class=""></div>
<div class="">// We do not use `notify` because we need this stack
frame to keep </div>
<div class="">// running so we don&#39;t trap yet.</div>
<div class="">group.wait(timeout: .now() + .seconds(15))</div>
<div class="">}</div>
<div class=""></div>
<div class="">// Okay, we can now return, and probably crash.</div>
<div class="">}</div>
<div class="">}</div>
<div class="">}</div>
<div class="">}</div>
<div class=""><br class=""></div>
<div class="">It&#39;s definitely not a full actor model, and you have
to be very careful, but it might be a useful subset.</div>
<br class="">
<div class="">
<div class="">
<div style="font-size:12px" class=""><span class="Apple-style-span" style="border-collapse:separate;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;line-height:normal;border-spacing:0px">
-- </span></div>
<div style="font-size:12px" class=""><span class="Apple-style-span" style="border-collapse:separate;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;line-height:normal;border-spacing:0px">
Brent Royal-Gordon</span></div>
<div style="font-size:12px" class=""><span class="Apple-style-span" style="border-collapse:separate;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;line-height:normal;border-spacing:0px">
Architechies</span></div>
</div>
</div>
<br class="">


</div></div></span></blockquote><br><div><div id="bloop_customfont" style="margin:0px">Well, it seems like it would work pretty well since a thread would be needed anyway to do the cleanup. At the end it still boils down to a fatalError handling proposal and the web framework developer(s) put the implmentation.</div><div id="bloop_customfont" style="margin:0px"><br></div><div id="bloop_customfont" style="margin:0px">If the actor model sufficiently replaces it, then it makes still a good bridge between now and then ie. Swift 5-7. If a shared actor trips, then it also trips the rest of the non-shared actors who use it, so it still has some potential to hold that shared actor open until the requests using it finish execution.</div></div></body></html>