Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for no_std? #101

Open
Lol3rrr opened this issue Mar 17, 2022 · 5 comments
Open

Support for no_std? #101

Lol3rrr opened this issue Mar 17, 2022 · 5 comments

Comments

@Lol3rrr
Copy link

Lol3rrr commented Mar 17, 2022

Motivation

Im currently working on a Hobby project where this might be very useful, however the Project is written for a no_std environment meaning that I currently can not use this Crate.

Situation

From quickly looking through the Code I found that most of the uses of std can be easily replaced by either core or alloc, expect for the use of std::thread::yield_now in this line for the WriteHandle

Ideas

Boxed yield closure

We could store a boxed closure for yield in the Write Handle, which would by default just call std::thread::yield_now but could then also be changed to support other mechanisms, which might also enable an async refresh where we dont block the thread but rather yield the current future.

However this would also introduce the extra Cost of another Allocation + calling the closure through the Box for everyone, although the writer is usually not that important for speed in this crate I would rather avoid unnecessary overhead where possible.

Generic-Type-Parameter yield closure

This idea is basically the same as the Boxed yield closure one, although instead of boxing a closure we would instead store the closure or function-pointer in a field and have its type specified using a Generic-Type-Parameter, which would avoid the Cost of the Box + overhead. However this would increase the overall Complexity of the WriteHandle Type, which might not be desireable. However this also gives the most flexability for consumers of the library.

Function Pointers

This idea is again like the previous 2, but we now store a simple function-pointer instead of a closure. This would mitigate both the Problem of extra heap allocations and also not increase the complexity of the WriteHandle Type. However this might limit the consumers of the Library as the function has to be stateless, but this might not matter much as the current function is also stateless.

These were just my initial thoughts on this and I would love to hear others thoughts about it as well. If we come to a conclusion everyone is happy with, I would also happily make these changes and implement it

@Lol3rrr
Copy link
Author

Lol3rrr commented Mar 18, 2022

After looking at the Code more closely, I also found that it uses the std::Mutex for epochs and I dont really know how we can adjust that without adding a new dependency like spin which I would like to avoid for now. Any ideas would be welcome

@jonhoo
Copy link
Owner

jonhoo commented Mar 19, 2022

It'd definitely be nice if left-right could work in a no_std environment! For yielding, I think the function pointer approach is a good one. For the Mutex, I wonder if the way to go about it is the disallow creating a dynamic number of read/write handles, and instead have a constructor that takes a const generic <const R: usize> of the number of read handles to create, and then back it by an R-length array. The Mutex is only there to allow new handles to be added on the fly. Now, having both the dynamic and non-dynamic versions co-exist may end up being a little tricky, but I think it's probably doable.

@Lol3rrr
Copy link
Author

Lol3rrr commented Mar 19, 2022

Although the Array approach could definetly work I dont know if it may be too restrictive because you may not know how many readers there will be.
One quick thought I had was maybe using a "simple" lock free linked list, which could only grow or entries could be set to "free/vacant" to allow new read handles to pick them up again. This way we could have an unlimited number of Handles will still avoiding the Lock, however Im not sure if this would work with the writer as it can take like a "snapshot" and see all the read handles, but that may be fine because if a new one gets added while looking through the entries it should already see the new Pointer as well and therefore be save, but this definitely needs some more thought put into it.

Otherwise I could probably already start with some of the other changes and see how that looks in the meantime

@jonhoo
Copy link
Owner

jonhoo commented Mar 26, 2022

Hmm, I think that could work, since the tail of the list still represents a snapshot. I'm imagining a lock free linked list where new ones are always added at the head — then to take a snapshot the writer simply reads the current head and iterates on the list from there and onwards. We may need to do some due diligence to make sure we get the right semantics, but on the surface it looks like a reasonable approach!

@Lol3rrr
Copy link
Author

Lol3rrr commented Aug 25, 2023

Hi, sorry for the "delay" since the last activity on this. I now got the chance to take a look at the sento crate and I dont think that would currently fit into the approach here, as you cant get a "snapshot" of the currently acquired elements.

If I am not missing anything here, I will probably look into continue rolling a custom linked list here that supports the snapshots we would need or we could adapt the sento crate, but I am not sure that would be the right way about this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants