They don't share state.   The language-level semantics of greenlets is the
same as that of tasks, except that they are scheduled cooperatively.    All
these games with the stack should be unobservable on Rust level.


On Wed, Nov 13, 2013 at 1:01 AM, Eric Reed <ecr...@cs.washington.edu> wrote:

> The big issue I see right away (assuming I read this correctly and
> greenlets can still access the stack that existed when they were created),
> is that now mutable state on the stack is *shared* between greenlets and
> therefore can experience *data races* (impossible for tasks b/c they
> don't share memory), so they sound wildly unsafe to me.
>
> There may be some other issues that arise from the shared stack prefix
> property:
> - If a greenlet moves something on the stack, then other greenlets now
> have access to invalidated memory
> - You can no longer assume that you have sole access things pointed to by
> unique pointers, which would probably invalidate a lot of existing
> assumptions.
>
> Eric
>
>
> On Wed, Nov 13, 2013 at 12:02 AM, Vadim <vadi...@gmail.com> 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<http://greenlet.readthedocs.org/>are
>> implemented <http://stackoverflow.com/a/17447308>.  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
>>
>>
>> On Tue, Nov 5, 2013 at 9:18 AM, Patrick Walton <pcwal...@mozilla.com>wrote:
>>
>>> On 11/5/13 8:32 AM, David Piepgrass wrote:
>>>
>>>> Segmented stacks aren't the only solution though.
>>>>
>>>> If the concern is many tasks that block for a long time, I imagine a
>>>> mechanism to bundle a bunch of small, dormant stacks into a single page
>>>> so that the original pages could be released to the OS.
>>>>
>>>>
>>>>
>>>> *If stacks were additionally relocatable (which requires similar
>>>> machinery as precise moving GC, if I'm not mistaken) *
>>>
>>>
>>> This is correct. It's conceivable (although I can't make any promises)
>>> that if and when LLVM supports this, we could experiment with doing what Go
>>> does.
>>>
>>> Patrick
>>> _______________________________________________
>>> Rust-dev mailing list
>>> Rust-dev@mozilla.org
>>> https://mail.mozilla.org/listinfo/rust-dev
>>>
>>
>>
>> _______________________________________________
>> Rust-dev mailing list
>> Rust-dev@mozilla.org
>> https://mail.mozilla.org/listinfo/rust-dev
>>
>>
>
> _______________________________________________
> Rust-dev mailing list
> Rust-dev@mozilla.org
> https://mail.mozilla.org/listinfo/rust-dev
>
>
_______________________________________________
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to