I do realize that. What I am proposing does not require updating pointers to the moved stack, because there would be none (I believe).
On Wed, Nov 13, 2013 at 10:20 AM, Daniel Micay <danielmi...@gmail.com>wrote: > On Wed, Nov 13, 2013 at 3: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 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 Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev