Repository: tokio-rs/tokio
File: tokio/tests/macros_select.rs (Rust)

Code before:
            .unwrap();
        let rt1_values = rt1.block_on(async { (select_0_to_9().await, select_0_to_9().await) });

        let rt2 = tokio::runtime::Builder::new_current_thread()
            .rng_seed(RngSeed::from_bytes(seed))
            .build()
            .unwrap();
        let rt2_values = rt2.block_on(async { (select_0_to_9().await, select_0_to_9().await) });

        assert_eq!(rt1_values, rt2_values);
    }

    #[test]
    #[cfg(all(feature = "rt-multi-thread", not(target_os = "wasi")))]
    fn deterministic_select_multi_thread() {
        let seed = b"bytes used to generate seed";
        let (tx, rx) = std::sync::mpsc::channel();
        let rt1 = tokio::runtime::Builder::new_multi_thread()
            .worker_threads(1)
            .on_thread_park(move || tx.send(()).unwrap())
            .rng_seed(RngSeed::from_bytes(seed))
            .build()
            .unwrap();

        // This makes sure that `enter_runtime()` from worker thread is called before the one from main thread,
        // ensuring that the RNG state is consistent.
        rx.recv().unwrap();

        let rt1_values = rt1.block_on(async {
            tokio::spawn(async { (select_0_to_9().await, select_0_to_9().await) })
                .await
                .unwrap()
        });

        let (tx, rx) = std::sync::mpsc::channel();
        let rt2 = tokio::runtime::Builder::new_multi_thread()
            .worker_threads(1)
            .on_thread_park(move || tx.send(()).unwrap())
            .rng_seed(RngSeed::from_bytes(seed))
            .build()
            .unwrap();

        // This makes sure that `enter_runtime()` from worker thread is called before the one from main thread,
        // ensuring that the RNG state is consistent.
        rx.recv().unwrap();

        let rt2_values = rt2.block_on(async {
            tokio::spawn(async { (select_0_to_9().await, select_0_to_9().await) })
                .await
                .unwrap()
        });

Review comment (bug):
There are two places to consume the `rng_seed` for multi thread runtime.

1. `block_on`
2. Launching worker threads.

Once the `on_thread_park` called, it is very likely that all worker_threads have started running, so this change reduces flakiness.

I leave more context here to help future developers debugging this test, it would be better adding this into the code, but this is not a blocker.

Code after:
            .unwrap();
        let rt1_values = rt1.block_on(async { (select_0_to_9().await, select_0_to_9().await) });

        let rt2 = tokio::runtime::Builder::new_current_thread()
            .rng_seed(RngSeed::from_bytes(seed))
            .build()
            .unwrap();
        let rt2_values = rt2.block_on(async { (select_0_to_9().await, select_0_to_9().await) });

        assert_eq!(rt1_values, rt2_values);
    }

    #[test]
    #[cfg(all(feature = "rt-multi-thread", not(target_os = "wasi")))]
    fn deterministic_select_multi_thread() {
        let seed = b"bytes used to generate seed";
        let (tx, rx) = std::sync::mpsc::channel();
        let rt1 = tokio::runtime::Builder::new_multi_thread()
            .worker_threads(1)
            .on_thread_park(move || tx.send(()).unwrap())
            .rng_seed(RngSeed::from_bytes(seed))
            .build()
            .unwrap();

        // This makes sure that `enter_runtime()` from worker thread is called before the one from main thread,
        // ensuring that the RNG state is consistent. See also https://github.com/tokio-rs/tokio/pull/7495.
        rx.recv().unwrap();

        let rt1_values = rt1.block_on(async {
            tokio::spawn(async { (select_0_to_9().await, select_0_to_9().await) })
                .await
                .unwrap()
        });

        let (tx, rx) = std::sync::mpsc::channel();
        let rt2 = tokio::runtime::Builder::new_multi_thread()
            .worker_threads(1)
            .on_thread_park(move || tx.send(()).unwrap())
            .rng_seed(RngSeed::from_bytes(seed))
            .build()
            .unwrap();

        // This makes sure that `enter_runtime()` from worker thread is called before the one from main thread,
        // ensuring that the RNG state is consistent. See also https://github.com/tokio-rs/tokio/pull/7495.
        rx.recv().unwrap();

        let rt2_values = rt2.block_on(async {
            tokio::spawn(async { (select_0_to_9().await, select_0_to_9().await) })
                .await
                .unwrap()
        });