Change:
This can just be done by attempting the system call and falling back if it fails at runtime.
IIRC, getrandom() is not about speed (I-slow label), but about security from file description exhaustion attacks. It uses the urandom pool. See patch:
I'm aware that it's the same pool. The I-slow label is sensible for an improvement that would reduce the number of system calls and necessary file descriptors.
thanks, now I got it. I'll try to fix it tomorrow if it'll still be open/untouched.
Relevant Go patch:

Discussion:
//!     so the "quality" of `/dev/random` is not better than `/dev/urandom` in most cases. //!     However, this means that `/dev/urandom` can yield somewhat predictable randomness //!     if the entropy pool is very small, such as immediately after first booting. <del> //!     If an application likely to be run soon after first booting, or on a system with very //!     few entropy sources, one should consider using `/dev/random` via `ReaderRng`. </del> <ins> //!     Linux 3,17 added `getrandom(2)` system call which solves the issue: it blocks if entropy //!     pool is not initialized yet, but it does not block once initialized. //!     `OsRng` tries to use `getrandom(2)` if available, and use `/dev/urandom` fallback if not. //!     If an application does not have `getrandom` and likely to be run soon after first booting, //!     or on a system with very few entropy sources, one should consider using `/dev/random` via //!     `ReaderRng`. </ins> //! -   On some systems (e.g. FreeBSD, OpenBSD and Mac OS X) there is no difference //!     between the two sources. (Also note that, on some systems e.g. FreeBSD, both `/dev/random` //!     and `/dev/urandom` may block once if the CSPRNG has not seeded yet.)

#[cfg(all(unix, not(target_os = "ios")))] mod imp { <ins> extern crate libc; </ins> use io::{IoResult, File}; use path::Path; use rand::Rng; use rand::reader::ReaderRng; use result::{Ok, Err}; <ins> use slice::{ImmutableSlice, MutableSlice}; use mem; use os::errno; #[cfg(all(target_os = "linux", any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))] fn getrandom(buf: &mut [u8]) -> libc::c_long { extern "C" { fn syscall(number: libc::c_long, ...) -> libc::c_long; } #[cfg(target_arch = "x86_64")] const NR_GETRANDOM: libc::c_long = 318; #[cfg(target_arch = "x86")] const NR_GETRANDOM: libc::c_long = 355; #[cfg(target_arch = "arm")] const NR_GETRANDOM: libc::c_long = 384; unsafe { syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0u) } } #[cfg(not(all(target_os = "linux", any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))] fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 } fn getrandom_fill_bytes(v: &mut [u8]) { let mut read = 0; let len = v.len(); while read < len { let result = getrandom(v[mut read..]); if result == -1 { let err = errno() as libc::c_int; if err == libc::EINTR { continue; } else { panic!("unexpected getrandom error: {}", err); } } else { read += result as uint; } } } fn getrandom_next_u32() -> u32 { let mut buf: [u8, ..4] = [0u8, ..4]; getrandom_fill_bytes(&mut buf); unsafe { mem::transmute::<[u8, ..4], u32>(buf) } } fn getrandom_next_u64() -> u64 { let mut buf: [u8, ..8] = [0u8, ..8]; getrandom_fill_bytes(&mut buf); unsafe { mem::transmute::<[u8, ..8], u64>(buf) } } #[cfg(all(target_os = "linux", any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))] fn is_getrandom_available() -> bool { use sync::atomic::{AtomicBool, INIT_ATOMIC_BOOL, Relaxed}; static GETRANDOM_CHECKED: AtomicBool = INIT_ATOMIC_BOOL; static GETRANDOM_AVAILABLE: AtomicBool = INIT_ATOMIC_BOOL; if !GETRANDOM_CHECKED.load(Relaxed) { let mut buf: [u8, ..0] = []; let result = getrandom(&mut buf); let available = if result == -1 { let err = errno() as libc::c_int; err != libc::ENOSYS } else { true }; GETRANDOM_AVAILABLE.store(available, Relaxed); GETRANDOM_CHECKED.store(true, Relaxed); available } else { GETRANDOM_AVAILABLE.load(Relaxed) } } #[cfg(not(all(target_os = "linux", any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))] fn is_getrandom_available() -> bool { false } </ins> /// A random number generator that retrieves randomness straight from /// the operating system. Platform sources: /// /// - Unix-like systems (Linux, Android, Mac OSX): read directly from <del> ///   `/dev/urandom`. </del> <ins> ///   `/dev/urandom`, or from `getrandom(2)` system call if available. </ins> /// - Windows: calls `CryptGenRandom`, using the default cryptographic ///   service provider with the `PROV_RSA_FULL` type. /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed /// This does not block. <del> #[cfg(unix)] </del> pub struct OsRng { <del> inner: ReaderRng<File> </del> <ins> inner: OsRngInner, } enum OsRngInner { OsGetrandomRng, OsReaderRng(ReaderRng<File>), </ins> } impl OsRng { /// Create a new `OsRng`. pub fn new() -> IoResult<OsRng> { <ins> if is_getrandom_available() { return Ok(OsRng { inner: OsGetrandomRng }); } </ins> let reader = try!(File::open(&Path::new("/dev/urandom"))); let reader_rng = ReaderRng::new(reader); <del> Ok(OsRng { inner: reader_rng }) </del> <ins> Ok(OsRng { inner: OsReaderRng(reader_rng) }) </ins> } } impl Rng for OsRng { fn next_u32(&mut self) -> u32 { <del> self.inner.next_u32() </del> <ins> match self.inner { OsGetrandomRng => getrandom_next_u32(), OsReaderRng(ref mut rng) => rng.next_u32(), } </ins> } fn next_u64(&mut self) -> u64 { <del> self.inner.next_u64() </del> <ins> match self.inner { OsGetrandomRng => getrandom_next_u64(), OsReaderRng(ref mut rng) => rng.next_u64(), } </ins> } fn fill_bytes(&mut self, v: &mut [u8]) { <del> self.inner.fill_bytes(v) </del> <ins> match self.inner { OsGetrandomRng => getrandom_fill_bytes(v), OsReaderRng(ref mut rng) => rng.fill_bytes(v) } </ins> } } }

/// the operating system. Platform sources: /// /// - Unix-like systems (Linux, Android, Mac OSX): read directly from <del> ///   `/dev/urandom`. </del> <ins> ///   `/dev/urandom`, or from `getrandom(2)` system call if available. </ins> /// - Windows: calls `CryptGenRandom`, using the default cryptographic ///   service provider with the `PROV_RSA_FULL` type. /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed

/// the operating system. Platform sources: /// /// - Unix-like systems (Linux, Android, Mac OSX): read directly from <del> ///   `/dev/urandom`. </del> <ins> ///   `/dev/urandom`, or from `getrandom(2)` system call if available. </ins> /// - Windows: calls `CryptGenRandom`, using the default cryptographic ///   service provider with the `PROV_RSA_FULL` type. <del> /// </del> <ins> /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed </ins> /// This does not block. pub struct OsRng { hcryptprov: HCRYPTPROV