On Fri, 20 Sep 2013 Brian Anderson  wrote:
>> On 09/19/2013 11:40 PM, Jason E. Aten wrote:
>> Perhaps the best thing is just to fork(2), so we get a new (OS level)
>> process that has copy-on-write (virtual) memory, and if the
>> compilation + run succeeds in the child, then have the child "take
>> over". Otherwise the child dies with an fail! + location message, and
>> we return to the parent exactly before the child was spawned.
>
> It seems a shame to be relying on process isolation instead of tasks. If
> I were to just imagine the architecture of a repl that used task
> isolation for crash recovery it might have one task for accepting input
> and another as a sandbox that maintains the repl state and executes
> commands in a loop.

Yes, it seems a shame. It's even worse than a shame. It adds demands. Using
fork(2) demands a single-threaded runtime. Tasks don't require a single
threaded runtime. And tasks are more portable. Using fork(2) might mean
only supporting Linux or Linux & OSX at first.  Windows support might
require cygwin's fork implementation, whereas tasks are everywhere.

So I agree. It seems a shame. I want to do it with tasks only. I just don't
see how. How can we do this with tasks and get the desired rollback on
fail!()?

I'll detail the problem a little. With only tasks, how do we rollback
changes to global state made by pre-compiled library functions that are
called from JIT-ed and run code? The task doesn't know what the arbitrary
code has done, so the task can't roll it back. Any functions in an
arbitrary C library, any unsafe Rust functions, and the JIT-compilation
itself will have updated global memory, the llvm module's symbols, etc.
Since we've fail!-ed at the end of an arbitrarily long sequence of code,
now we want that reverted all that cleanly and completely. How would a task
do that?

I've been down that road for syntax errors before. I've implemented
rollback of everything that the LLVM-JIT added to an llvm module. It was a
pain, I had to track everything that the llvm jit-compiler did, so I could
roll back on syntax error. It was brittle, introducing a myraid of
undersirable code-interactions and logging to the current transaction code
intertwined with every llvm call. It was a pain, but it worked--for syntax
error rollback.

But here we're not talking about *just* rolling back on syntax error. We
want to roll back not only the effects of a partial JIT-compilation, but to
also rollback after *running that code*.  That code can call into
*arbitrary global memory modifying code*. All that we know is that an
arbitrary set of changes to the process image has ended in a fail!().

I'm certainly open to alternatives.  How will that alternative address the
rollback on fail!() problem?

Process isolation and using the copy-on-write/hardware (MMU) support for
copy-on-write virtual memory has been engineered for just this job. It fits
the situation like a glove. As a bonus: we get rollback of file handle
changes and all the other OS objects that are duplicated by fork(2).

Jason
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to