Merge pull request #928 from dhardy/libc

Make libc dependency optional
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 57bb361..3ec7462 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,10 @@
 ### Fixes
 - The `Bernoulli` distribution constructors now reports an error on NaN and on
   `denominator == 0`. (#925)
+- Use `std::sync::Once` to register fork handler, avoiding possible atomicity violation (#928)
+
+### Changes
+- Unix: make libc dependency optional; only use fork protection with std feature (#928)
 
 ### Additions
 - Implement `std::error::Error` for `BernoulliError` (#919)
diff --git a/Cargo.toml b/Cargo.toml
index e6af38d..03d5e35 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -27,7 +27,7 @@
 serde1 = [] # does nothing, deprecated
 
 # Optional dependencies:
-std = ["rand_core/std", "rand_chacha/std", "alloc", "getrandom"]
+std = ["rand_core/std", "rand_chacha/std", "alloc", "getrandom", "libc"]
 alloc = ["rand_core/alloc"]  # enables Vec and Box support (without std)
 # re-export optional WASM dependencies to avoid breakage:
 # Warning: wasm-bindgen and stdweb features will be removed in rand 0.8;
@@ -68,7 +68,7 @@
 
 [target.'cfg(unix)'.dependencies]
 # Used for fork protection (reseeding.rs)
-libc = { version = "0.2.22", default-features = false }
+libc = { version = "0.2.22", optional = true, default-features = false }
 
 # Emscripten does not support 128-bit integers, which are used by ChaCha code.
 # We work around this by using a different RNG.
diff --git a/src/rngs/adapter/reseeding.rs b/src/rngs/adapter/reseeding.rs
index f7a694f..5460e34 100644
--- a/src/rngs/adapter/reseeding.rs
+++ b/src/rngs/adapter/reseeding.rs
@@ -279,11 +279,10 @@
 }
 
 
-#[cfg(all(unix, not(target_os = "emscripten")))]
+#[cfg(all(unix, feature = "std", not(target_os = "emscripten")))]
 mod fork {
-    use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
-    #[allow(deprecated)] // Required for compatibility with Rust < 1.24.
-    use core::sync::atomic::{ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT};
+    use core::sync::atomic::{AtomicUsize, Ordering};
+    use std::sync::Once;
 
     // Fork protection
     //
@@ -297,16 +296,12 @@
     // don't update `fork_counter`, so a reseed is attempted as soon as
     // possible.
 
-    #[allow(deprecated)]
-    static RESEEDING_RNG_FORK_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
+    static RESEEDING_RNG_FORK_COUNTER: AtomicUsize = AtomicUsize::new(0);
 
     pub fn get_fork_counter() -> usize {
         RESEEDING_RNG_FORK_COUNTER.load(Ordering::Relaxed)
     }
 
-    #[allow(deprecated)]
-    static FORK_HANDLER_REGISTERED: AtomicBool = ATOMIC_BOOL_INIT;
-
     extern "C" fn fork_handler() {
         // Note: fetch_add is defined to wrap on overflow
         // (which is what we want).
@@ -314,14 +309,14 @@
     }
 
     pub fn register_fork_handler() {
-        if !FORK_HANDLER_REGISTERED.load(Ordering::Relaxed) {
-            unsafe { libc::pthread_atfork(None, None, Some(fork_handler)) };
-            FORK_HANDLER_REGISTERED.store(true, Ordering::Relaxed);
-        }
+        static REGISTER: Once = Once::new();
+        REGISTER.call_once(|| unsafe {
+            libc::pthread_atfork(None, None, Some(fork_handler));
+        });
     }
 }
 
-#[cfg(not(all(unix, not(target_os = "emscripten"))))]
+#[cfg(not(all(unix, feature = "std", not(target_os = "emscripten"))))]
 mod fork {
     pub fn get_fork_counter() -> usize {
         0