On Wed, Nov 13, 2013 at 3:02 AM, Vadim <[email protected]> wrote:
> Hi,
> I would like to float a proposal (or three :-), regarding "greenlets" in
> Rust.  For those unfamiliar with greenlets, they are a tool for writing
> concurrent code, similar to Rust's tasks, but much more light-weight in
> terms of memory consumption (especially now that segmented stacks are no
> more).
>
> I think there are some scenarios where low memory consumption per-task is
> still important, 64-bit address spaces notwithstanding.   A typical one
> would be a pub-sub server, which needs to maintain a massive number of
> simple I/O workflows, where I/O channels are idle most of the time.
>
> So here we go (in the order of increasing craziness):
>
> 1. Recently I've learned how Python greenlets are implemented.  I believe
> that the same approach could work in Rust:
>
> Basically, greenlets are spawned using the same stack as the parent
> greenlet, just like a normal function call.  When a greenlet is suspended,
> it copies the portion of the stack used up since its' spawning to the heap.
> When one is re-activated, the saved memory is copied back where it came from
> (having first saved stack of the previous active greenlet,- if they
> overlap).
>
> Since greenlets don't need to save "red zone" of the stack, the amount of
> data per instance is precisely what is actually used.
>
> There are also downsides, of course:
> - greenlets are bound to the thread that spawned them,
> - two memcpy's are needed when switching between them.
>
> In the case of Python, though, there's one further optimization: since
> Python's stack frames live on the heap, in most cases, there nothing on the
> hardware stack that a greenlet needs saving!   As a bonus, it can now be
> resumed at any stack position, so no saving of previous greenlet's stack is
> needed.  The only time when a full save occurs is when there are foreign
> stack frames on the stack.
>
>
> 2. Well, can Rust do the same?   What if we came up with an attribute, say,
> [#stackless], which causes a function to allocate it's stack frame on the
> heap and put all local vars there?    The only things on the actual hardware
> stack would then be the function's arguments, the return address, the saved
> base pointer and the pointer to that heap-alllocated frame.   With the
> exception of base pointers, all these things are position-independent, I
> believe.   And base pointer chain can be easily fixed up if/when stack is
> moved.
>
> So if we had that, and the whole greenlet's stack consisted of such
> functions, and there was a way for the "switch_to_greenlet()" function to
> detect that, then such greenlet's stack would be relocatable and could be
> resumed at any position in the thread's stack (or even in another thread!)
> with minimal memory copying, just like in Python.
>
> Of course, the [#stackless] functions would be slower than the normal ones,
> but in the scenario I've outlined in the beginning, it shouldn't be a
> problem.
>
>
> 3.  Unfortunately, in order for the above scheme to work, all I/O methods,
> (which are typically where yields happen), would need to be marked as
> [#stackless]...  This would affect the performance of "normal" code using
> the same API, which is undesirable.
>
> Okay, but usually there are not that many things that point into the stack
> in a typical program.  I can think of only three things: references to
> stack-allocated buffers, base pointer chains and references to
> caller-allocated return values.
> - The first one can be lived without - just allocate buffers on the heap.
> - The second one - see above.
> - The last one is more tricky, but for the sake of argument, let's assume
> that we restricted function signatures such that only register-allocated
> types can be returned.
>
> Let's say we came up with a way to mark up functions that may yield to
> another greenlet, and also with a way to prohibit taking address of
> stack-allocated variables for the duration of calls to yielding functions.
> These restrictions would be annoying, but not overly so, as long as you had
> to obey them only in functions that are intended to be run in a greenlet.
> On the plus side, the hardware stack contents would now be relocatable.
>
> In this setup, everything could proceed as usual, using the hardware stack,
> until execution came to a  blocking I/O call.   At that point, the scheduler
> would check if running inside a greenlet, copy greenlet's stack to the heap
> and switch off to another greenlet.  Otherwise, it would do the same thing
> it does now, i.e. switch tasks.
>
>
> So, what do you say, rustafarians?   Does any of that make any sense?
>
> Vadim

Rust has no way to move a stack/value and update the pointers to it. A
fundamental property of borrowed pointers is that they're just
integers in memory at runtime without any boxing or type information.
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to