Andrew and I are on the same thinking path.. a REPL does not have to crash,
nor a process that it tries to understand, and the word should not be in
its vocabulary...just make sure it can handle the idea of "I do not know
what to do here...so I will just ignore this process and continue on with
my life and processes that I do understand to execute".

Erlang got high marks because of very simple handling of Andrew's idea,
it's black message boxing works in a similar fashion, if I recall ...
"crash is not in the vocabulary".

Why is the implementation process so hard ?  Seems easy enough to type
above, anyways.


On Sun, Sep 22, 2013 at 1:27 AM, Andrew Dunham <[email protected]> wrote:

> If you'll excuse my jumping in randomly:
>
> The more I think about "rolling back", the more I think this might not be
> the only solution.  What about something like this:
> - rusti starts a subprocess, communicating with it via pipes
> - Whenever the user types something, the subprocess receives the code and
> actually runs it
> - Whenever something fail!()'s, or a segfault happens, the child process
> can just outright exit, and then rusti can restart it
>
> The downside is that you lose all rollback capabilities - but in most
> cases, REPLs in other languages don't actually roll everything back.  For
> example, it's perfectly possible to have code in the Python REPL that
> changes a global variable, and then raises an exception.  For more advanced
> use, it might be possible to define something like "transactions", such
> that when the child process dies, the superprocess can automatically re-run
> previously executed code.
>
> Obviously this isn't ideal, but it solves a whole host of problems,
> especially regarding multi-threading and use on Windows.
>
> --Andrew D
>
>
> On Sat, Sep 21, 2013 at 10:40 PM, Jason E. Aten <[email protected]>wrote:
>
>> // Bah. Resending with the correct title, in hopes this gets threaded
>> properly in the archives. Sorry for the duplication.
>>
>> On Sat, Sep 21, 2013 at 10:37 PM, Jason E. Aten <[email protected]>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?
>>>
>>> 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
>>
>>
>
> _______________________________________________
> Rust-dev mailing list
> [email protected]
> https://mail.mozilla.org/listinfo/rust-dev
>
>


-- 
-Thad
Thad on Freebase.com <http://www.freebase.com/view/en/thad_guidry>
Thad on LinkedIn <http://www.linkedin.com/in/thadguidry/>
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to