On 09/21/2013 10:37 PM, Jason E. Aten wrote:
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?
A task can't do that, but I'd suggest that perhaps rolling back global
state doesn't need to be a requirement. Most computation in Rust is
task-local.
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.
I must defer to your judgement on the issue of JIT rollback, because I
don't understand it.
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!().
What is partial JIT compilation? As to the issue of arbitrary global
memory modifying code, only unsafe Rust code will do that, and it's
understood that when running unsafe code there is no safety net.
I'm certainly open to alternatives. How will that alternative address
the rollback on fail!() problem?
All my thoughts on this subject are above. Tasks don't address all the
problems you want to solve, but I suggest it may be ok not to solve them.
Regards,
Brian
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev