-
Notifications
You must be signed in to change notification settings - Fork 13
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
Add rand, srand, and rand_r implementations #31
Conversation
344 32-bit words? On the stack? Oof. I'd prefer something a little less heavyweight. Like an LFSR we can store in a portable AtomicU32. |
I think there are also serious licence questions about transliterating LGPL code from glibc into Rust and labelling it as Blue Oak licensed. |
I thought compatibility with glibc would be nice. It's also a tested solution. But you are correct, that it has some drawbacks including the licensing issue. If you are interested I could look into implementing |
I would prefer that, thanks. |
There's also a question about how we work out what
|
The problem with Apart from that, what do you think about using the same implementation as |
That seems like a good idea. I'd use a |
d0c6daa
to
251d7dc
Compare
I tested the The maximum value is exported as All in all it seems Good Enough™ for anything non-cryptographic. |
I thought portable-atomic could emulate CAS using a critical section? Then we'd only need one version of this code and it would never be a race hazard. |
You are right. |
I think it's ok to leave it to the binary to set those flags. Edit: ok I looked and the rand-cs flag is fine. |
Done. |
src/rand.rs
Outdated
match RAND_STATE.compare_exchange_weak( | ||
current_state, | ||
new_state, | ||
Ordering::SeqCst, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this required? No other accesses are gated on this CAS operation so I think Relaxed is OK.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Honestly, I am not sure and wanted to play it safe. I basically copied the code from the docs. If you are sure, I can change it though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reading https://marabos.nl/atomics/memory-ordering.html I'm pretty sure that Relaxed for both is OK here. We're only modifying that single value, and nothing else related to it. So there are no other writes that must happen strictly before or strictly after we modify this one value.
|
||
#[cfg_attr(not(feature = "rand_r"), export_name = "tinyrlibc_RAND_MAX")] | ||
#[cfg_attr(feature = "rand_r", no_mangle)] | ||
pub static RAND_MAX: c_int = 0x7FFF_FFFC as _; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be odd.
As you're pulling 31 random bits, I'm pretty sure this should be 0x7fff_ffff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tested all 2^32
possible seeds and the value never went over 0x7FFF_FFFC
. This seemed strange to me and I didn't really know what to do with RAND_MAX
in that case. The original algorithm goes to up 0x7FFF_FFFD
, but does not include 0
. That is why I subtracted 1
, because I thought it would be way more unexpected to never get 0
then to never get 0x7FFF_FFFD
.
Since it may be odd to have RAND_MAX
not be 2^n - 1
, we could either reduce it to 30 bits at 0x3FFF_FFFF
or "lie" and set it to 0x7FFF_FFFF
which could be bad, because knowing RAND_MAX
is necessary if you want to use rand
to get a non-biased distribution.
Since tinyrlibc
is mainly used by C code, RAND_MAX
will probably never be used directly, because in C RAND_MAX
is a ´#defineanyway, so this value will not be seen by the code using
rand`.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How many times did you call rand()? The 10 or 11 bits that get pulled should be relatively uniform. It might be worth logging them individually. Then if they are uniform, you should get values from 0 to 2^31 - 1 by combining 31 random bits together.
OK, I did some digging on this one.
|
See https://github.com/rust-embedded-community/tinyrlibc/tree/updated-rand as an example of what I was thinking. |
This went quiet, so I opened a PR with my proposed updates: #32 |
I tried to optimized it for a while, but wasn't 100% happy with the results. I will test your version this week. |
The other PR was approved. If you'd like some changes, feel free to open another PR. |
This PR adds implementations for the C functions
rand
,srand
, andrand_r
. They all return the same deterministic values as glibc would.rand_r
is quite straightforward, butrand
andsrand
require global mutable state to be implemented according to the standard. I chose to usecritical-section
to implement this safely, because it is platform independent and should work almost everywhere.