├── tokio-util ├── src │ ├── sync │ │ ├── tests │ │ │ └── mod.rs │ │ ├── mod.rs │ │ └── cancellation_token │ │ │ └── guard.rs │ ├── loom.rs │ ├── udp │ │ └── mod.rs │ ├── util │ │ └── mod.rs │ ├── task │ │ └── mod.rs │ ├── net │ │ └── unix │ │ │ └── mod.rs │ ├── codec │ │ └── encoder.rs │ ├── time │ │ └── wheel │ │ │ └── stack.rs │ ├── io │ │ └── mod.rs │ └── lib.rs ├── tests │ ├── _require_full.rs │ ├── context.rs │ ├── io_stream_reader.rs │ ├── framed_stream.rs │ └── compat.rs ├── README.md └── LICENSE ├── tests-build ├── src │ └── lib.rs ├── tests │ ├── fail │ │ ├── macros_core_no_default.rs │ │ ├── macros_dead_code.rs │ │ ├── macros_dead_code.stderr │ │ ├── macros_core_no_default.stderr │ │ ├── macros_type_mismatch.rs │ │ └── macros_invalid_input.rs │ ├── pass │ │ ├── macros_main_return.rs │ │ ├── macros_main_loop.rs │ │ └── forward_args_and_output.rs │ ├── macros_clippy.rs │ └── macros.rs ├── Cargo.toml └── README.md ├── tokio ├── fuzz │ ├── .gitignore │ ├── fuzz_targets │ │ └── fuzz_linked_list.rs │ └── Cargo.toml ├── src │ ├── fuzz.rs │ ├── net │ │ ├── unix │ │ │ ├── datagram │ │ │ │ └── mod.rs │ │ │ ├── socketaddr.rs │ │ │ └── mod.rs │ │ ├── windows │ │ │ └── mod.rs │ │ ├── tcp │ │ │ └── mod.rs │ │ └── lookup_host.rs │ ├── sync │ │ ├── task │ │ │ └── mod.rs │ │ └── tests │ │ │ ├── mod.rs │ │ │ └── loom_list.rs │ ├── macros │ │ ├── loom.rs │ │ ├── ready.rs │ │ ├── support.rs │ │ ├── thread_local.rs │ │ ├── mod.rs │ │ ├── trace.rs │ │ └── addr_of.rs │ ├── runtime │ │ ├── scheduler │ │ │ ├── lock.rs │ │ │ ├── inject │ │ │ │ ├── metrics.rs │ │ │ │ ├── synced.rs │ │ │ │ └── pop.rs │ │ │ ├── multi_thread │ │ │ │ ├── worker │ │ │ │ │ ├── taskdump_mock.rs │ │ │ │ │ └── metrics.rs │ │ │ │ ├── trace_mock.rs │ │ │ │ ├── overflow.rs │ │ │ │ └── handle │ │ │ │ │ ├── taskdump.rs │ │ │ │ │ └── metrics.rs │ │ │ ├── multi_thread_alt │ │ │ │ ├── worker │ │ │ │ │ ├── taskdump_mock.rs │ │ │ │ │ └── metrics.rs │ │ │ │ ├── trace_mock.rs │ │ │ │ ├── overflow.rs │ │ │ │ └── handle │ │ │ │ │ ├── taskdump.rs │ │ │ │ │ └── metrics.rs │ │ │ ├── block_in_place.rs │ │ │ └── defer.rs │ │ ├── io │ │ │ ├── mod.rs │ │ │ ├── driver │ │ │ │ └── signal.rs │ │ │ └── metrics.rs │ │ ├── metrics │ │ │ ├── io.rs │ │ │ ├── mod.rs │ │ │ └── scheduler.rs │ │ ├── blocking │ │ │ └── mod.rs │ │ ├── tests │ │ │ ├── loom_multi_thread │ │ │ │ ├── shutdown.rs │ │ │ │ └── yield_now.rs │ │ │ ├── loom_multi_thread_alt │ │ │ │ ├── shutdown.rs │ │ │ │ └── yield_now.rs │ │ │ ├── loom_oneshot.rs │ │ │ └── loom_current_thread │ │ │ │ └── yield_now.rs │ │ ├── thread_id.rs │ │ ├── context │ │ │ ├── runtime_mt.rs │ │ │ └── scoped.rs │ │ ├── time │ │ │ └── source.rs │ │ └── process.rs │ ├── loom │ │ ├── std │ │ │ ├── atomic_u64_native.rs │ │ │ ├── atomic_u64_static_const_new.rs │ │ │ ├── unsafe_cell.rs │ │ │ ├── atomic_u64.rs │ │ │ ├── mutex.rs │ │ │ ├── atomic_u16.rs │ │ │ └── atomic_u32.rs │ │ ├── mod.rs │ │ └── mocked.rs │ ├── util │ │ ├── markers.rs │ │ ├── rand │ │ │ └── rt_unstable.rs │ │ ├── sync_wrapper.rs │ │ ├── error.rs │ │ └── atomic_cell.rs │ ├── future │ │ ├── trace.rs │ │ ├── mod.rs │ │ └── block_on.rs │ ├── process │ │ └── kill.rs │ ├── fs │ │ ├── remove_dir.rs │ │ ├── read_link.rs │ │ ├── remove_dir_all.rs │ │ ├── symlink_metadata.rs │ │ ├── set_permissions.rs │ │ ├── symlink.rs │ │ ├── remove_file.rs │ │ ├── rename.rs │ │ ├── symlink_dir.rs │ │ ├── symlink_file.rs │ │ ├── copy.rs │ │ ├── write.rs │ │ ├── read_to_string.rs │ │ ├── try_exists.rs │ │ └── hard_link.rs │ ├── signal │ │ └── windows │ │ │ └── stub.rs │ ├── io │ │ └── util │ │ │ ├── flush.rs │ │ │ ├── shutdown.rs │ │ │ ├── write.rs │ │ │ └── write_vectored.rs │ └── doc │ │ └── mod.rs ├── tests │ ├── support │ │ ├── signal.rs │ │ ├── leaked_buffers.rs │ │ ├── panic.rs │ │ ├── mpsc_stream.rs │ │ └── io_vec.rs │ ├── io_async_read.rs │ ├── signal_no_rt.rs │ ├── process_arg0.rs │ ├── io_read_exact.rs │ ├── io_chain.rs │ ├── rt_time_start_paused.rs │ ├── net_bind_resource.rs │ ├── _require_full.rs │ ├── task_yield_now.rs │ ├── io_repeat.rs │ ├── signal_twice.rs │ ├── signal_usr1.rs │ ├── macros_pin.rs │ ├── fs.rs │ ├── signal_drop_recv.rs │ ├── io_lines.rs │ ├── signal_notify_both.rs │ ├── tracing-instrumentation │ │ └── Cargo.toml │ ├── process_raw_handle.rs │ ├── join_handle_panic.rs │ ├── fs_canonicalize_dir.rs │ ├── uds_cred.rs │ ├── fs_remove_file.rs │ ├── sync_errors.rs │ ├── signal_ctrl_c.rs │ ├── fs_symlink_file_windows.rs │ ├── signal_panic.rs │ ├── macros_rename_test.rs │ ├── io_util_empty.rs │ ├── signal_drop_signal.rs │ ├── fs_rename.rs │ ├── fs_symlink_dir_windows.rs │ ├── tcp_shutdown.rs │ ├── tcp_peek.rs │ ├── io_fill_buf.rs │ ├── process_smoke.rs │ ├── fs_remove_dir_all.rs │ ├── io_write_int.rs │ ├── io_sink.rs │ ├── process_change_of_runtime.rs │ ├── signal_drop_rt.rs │ ├── process_kill_on_drop.rs │ ├── net_lookup_host.rs │ ├── unwindsafe.rs │ ├── fs_copy.rs │ ├── tcp_echo.rs │ ├── no_rt.rs │ ├── io_write_all.rs │ ├── io_driver_drop.rs │ ├── process_issue_42.rs │ ├── uds_split.rs │ ├── duplex_stream.rs │ └── tcp_split.rs └── LICENSE ├── tokio-stream ├── fuzz │ ├── .gitignore │ └── Cargo.toml ├── tests │ ├── stream_empty.rs │ ├── stream_once.rs │ ├── stream_close.rs │ ├── stream_iter.rs │ ├── stream_pending.rs │ ├── support │ │ └── mpsc.rs │ └── time_throttle.rs ├── LICENSE └── src │ ├── wrappers │ ├── signal_unix.rs │ ├── read_dir.rs │ └── interval.rs │ ├── stream_ext │ ├── chain.rs │ ├── map.rs │ ├── next.rs │ ├── fuse.rs │ ├── peekable.rs │ ├── map_while.rs │ └── try_next.rs │ ├── empty.rs │ ├── once.rs │ └── wrappers.rs ├── .gitignore ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── feature_request.md │ └── bug_report.md ├── workflows │ ├── labeler.yml │ ├── pr-audit.yml │ ├── audit.yml │ └── stress-test.yml ├── labeler.yml └── PULL_REQUEST_TEMPLATE.md ├── Cross.toml ├── tests-integration ├── README.md ├── src │ ├── lib.rs │ └── bin │ │ ├── test-process-signal.rs │ │ ├── test-cat.rs │ │ └── test-mem.rs └── tests │ ├── macros_pin.rs │ ├── macros_main.rs │ ├── rt_yield.rs │ └── macros_select.rs ├── Cargo.toml ├── CODE_OF_CONDUCT.md ├── tokio-macros ├── README.md └── Cargo.toml ├── tokio-test ├── README.md ├── tests │ └── block_on.rs ├── Cargo.toml ├── src │ └── lib.rs ├── LICENSE └── CHANGELOG.md ├── stress-test └── Cargo.toml ├── netlify.toml ├── .circleci └── config.yml ├── benches └── time_now.rs ├── examples ├── README.md ├── hello_world.rs └── custom-executor-tokio-context.rs ├── target-specs └── i686-unknown-linux-gnu.json └── LICENSE /tokio-util/src/sync/tests/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tokio-util/src/loom.rs: -------------------------------------------------------------------------------- 1 | pub(crate) use std::sync; 2 | -------------------------------------------------------------------------------- /tests-build/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "tokio")] 2 | pub use tokio; 3 | -------------------------------------------------------------------------------- /tokio/fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | corpus 3 | artifacts 4 | coverage 5 | -------------------------------------------------------------------------------- /tokio-stream/fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | corpus 3 | artifacts 4 | coverage 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | 4 | .cargo/config.toml 5 | .cargo/config 6 | -------------------------------------------------------------------------------- /tokio/src/fuzz.rs: -------------------------------------------------------------------------------- 1 | pub use crate::util::linked_list::tests::fuzz_linked_list; 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [tokio-rs] 4 | -------------------------------------------------------------------------------- /tokio-util/src/udp/mod.rs: -------------------------------------------------------------------------------- 1 | //! UDP framing 2 | 3 | mod frame; 4 | pub use frame::UdpFramed; 5 | -------------------------------------------------------------------------------- /tokio/src/net/unix/datagram/mod.rs: -------------------------------------------------------------------------------- 1 | //! Unix datagram types. 2 | 3 | pub(crate) mod socket; 4 | -------------------------------------------------------------------------------- /tokio/src/net/windows/mod.rs: -------------------------------------------------------------------------------- 1 | //! Windows specific network types. 2 | 3 | pub mod named_pipe; 4 | -------------------------------------------------------------------------------- /Cross.toml: -------------------------------------------------------------------------------- 1 | [build.env] 2 | passthrough = [ 3 | "RUSTFLAGS", 4 | "RUST_BACKTRACE", 5 | ] 6 | -------------------------------------------------------------------------------- /tests-integration/README.md: -------------------------------------------------------------------------------- 1 | Tests that require additional components than just the `tokio` crate. 2 | -------------------------------------------------------------------------------- /tests-integration/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "full")] 2 | doc_comment::doc_comment!(include_str!("../../README.md")); 3 | -------------------------------------------------------------------------------- /tokio-util/tests/_require_full.rs: -------------------------------------------------------------------------------- 1 | #![cfg(not(feature = "full"))] 2 | compile_error!("run tokio-util tests with `--features full`"); 3 | -------------------------------------------------------------------------------- /tests-build/tests/fail/macros_core_no_default.rs: -------------------------------------------------------------------------------- 1 | use tests_build::tokio; 2 | 3 | #[tokio::main] 4 | async fn my_fn() {} 5 | 6 | fn main() {} 7 | -------------------------------------------------------------------------------- /tokio/src/sync/task/mod.rs: -------------------------------------------------------------------------------- 1 | //! Thread-safe task notification primitives. 2 | 3 | mod atomic_waker; 4 | pub(crate) use self::atomic_waker::AtomicWaker; 5 | -------------------------------------------------------------------------------- /tests-build/tests/fail/macros_dead_code.rs: -------------------------------------------------------------------------------- 1 | #![deny(dead_code)] 2 | 3 | use tests_build::tokio; 4 | 5 | #[tokio::main] 6 | async fn f() {} 7 | 8 | fn main() {} 9 | -------------------------------------------------------------------------------- /tests-build/tests/pass/macros_main_return.rs: -------------------------------------------------------------------------------- 1 | use tests_build::tokio; 2 | 3 | #[tokio::main] 4 | async fn main() -> Result<(), ()> { 5 | return Ok(()); 6 | } 7 | -------------------------------------------------------------------------------- /tokio/src/macros/loom.rs: -------------------------------------------------------------------------------- 1 | macro_rules! if_loom { 2 | ($($t:tt)*) => {{ 3 | #[cfg(loom)] 4 | { 5 | $($t)* 6 | } 7 | }} 8 | } 9 | -------------------------------------------------------------------------------- /tokio/fuzz/fuzz_targets/fuzz_linked_list.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | 3 | use libfuzzer_sys::fuzz_target; 4 | 5 | fuzz_target!(|data: &[u8]| { 6 | tokio::fuzz::fuzz_linked_list(data); 7 | }); 8 | -------------------------------------------------------------------------------- /tokio/src/runtime/scheduler/lock.rs: -------------------------------------------------------------------------------- 1 | /// A lock (mutex) yielding generic data. 2 | pub(crate) trait Lock { 3 | type Handle: AsMut; 4 | 5 | fn lock(self) -> Self::Handle; 6 | } 7 | -------------------------------------------------------------------------------- /tokio/src/runtime/scheduler/inject/metrics.rs: -------------------------------------------------------------------------------- 1 | use super::Inject; 2 | 3 | impl Inject { 4 | pub(crate) fn len(&self) -> usize { 5 | self.shared.len() 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tokio/tests/support/signal.rs: -------------------------------------------------------------------------------- 1 | pub fn send_signal(signal: libc::c_int) { 2 | use libc::{getpid, kill}; 3 | 4 | unsafe { 5 | assert_eq!(kill(getpid(), signal), 0); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tokio/src/loom/std/atomic_u64_native.rs: -------------------------------------------------------------------------------- 1 | pub(crate) use std::sync::atomic::{AtomicU64, Ordering}; 2 | 3 | /// Alias `AtomicU64` to `StaticAtomicU64` 4 | pub(crate) type StaticAtomicU64 = AtomicU64; 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | contact_links: 2 | - name: Question 3 | url: https://github.com/tokio-rs/tokio/discussions 4 | about: Questions about Tokio should be posted as a GitHub discussion. 5 | -------------------------------------------------------------------------------- /tests-build/tests/macros_clippy.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "full")] 2 | #[tokio::test] 3 | async fn test_with_semicolon_without_return_type() { 4 | #![deny(clippy::semicolon_if_nothing_returned)] 5 | 6 | dbg!(0); 7 | } 8 | -------------------------------------------------------------------------------- /tokio/src/runtime/scheduler/multi_thread/worker/taskdump_mock.rs: -------------------------------------------------------------------------------- 1 | use super::{Core, Handle}; 2 | 3 | impl Handle { 4 | pub(super) fn trace_core(&self, core: Box) -> Box { 5 | core 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tokio/src/runtime/scheduler/multi_thread_alt/worker/taskdump_mock.rs: -------------------------------------------------------------------------------- 1 | use super::{Core, Handle}; 2 | 3 | impl Handle { 4 | pub(super) fn trace_core(&self, core: Box) -> Box { 5 | core 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tokio/src/util/markers.rs: -------------------------------------------------------------------------------- 1 | /// Marker for types that are `Sync` but not `Send` 2 | pub(crate) struct SyncNotSend(*mut ()); 3 | 4 | unsafe impl Sync for SyncNotSend {} 5 | 6 | cfg_rt! { 7 | pub(crate) struct NotSendOrSync(*mut ()); 8 | } 9 | -------------------------------------------------------------------------------- /tokio/tests/io_async_read.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | 4 | use tokio::io::AsyncRead; 5 | 6 | #[test] 7 | fn assert_obj_safe() { 8 | fn _assert() {} 9 | _assert::>(); 10 | } 11 | -------------------------------------------------------------------------------- /tokio/src/macros/ready.rs: -------------------------------------------------------------------------------- 1 | macro_rules! ready { 2 | ($e:expr $(,)?) => { 3 | match $e { 4 | std::task::Poll::Ready(t) => t, 5 | std::task::Poll::Pending => return std::task::Poll::Pending, 6 | } 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /tests-integration/tests/macros_pin.rs: -------------------------------------------------------------------------------- 1 | use futures::executor::block_on; 2 | 3 | async fn my_async_fn() {} 4 | 5 | #[test] 6 | fn pin() { 7 | block_on(async { 8 | let future = my_async_fn(); 9 | tokio::pin!(future); 10 | (&mut future).await 11 | }); 12 | } 13 | -------------------------------------------------------------------------------- /tokio/src/runtime/scheduler/multi_thread/trace_mock.rs: -------------------------------------------------------------------------------- 1 | pub(super) struct TraceStatus {} 2 | 3 | impl TraceStatus { 4 | pub(super) fn new(_: usize) -> Self { 5 | Self {} 6 | } 7 | 8 | pub(super) fn trace_requested(&self) -> bool { 9 | false 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tokio/src/runtime/scheduler/multi_thread_alt/trace_mock.rs: -------------------------------------------------------------------------------- 1 | pub(super) struct TraceStatus {} 2 | 3 | impl TraceStatus { 4 | pub(super) fn new(_: usize) -> Self { 5 | Self {} 6 | } 7 | 8 | pub(super) fn trace_requested(&self) -> bool { 9 | false 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "tokio", 5 | "tokio-macros", 6 | "tokio-test", 7 | "tokio-stream", 8 | "tokio-util", 9 | 10 | # Internal 11 | "benches", 12 | "examples", 13 | "stress-test", 14 | "tests-build", 15 | "tests-integration", 16 | ] 17 | -------------------------------------------------------------------------------- /tests-build/tests/fail/macros_dead_code.stderr: -------------------------------------------------------------------------------- 1 | error: function `f` is never used 2 | --> $DIR/macros_dead_code.rs:6:10 3 | | 4 | 6 | async fn f() {} 5 | | ^ 6 | | 7 | note: the lint level is defined here 8 | --> $DIR/macros_dead_code.rs:1:9 9 | | 10 | 1 | #![deny(dead_code)] 11 | | ^^^^^^^^^ 12 | -------------------------------------------------------------------------------- /tokio-util/src/util/mod.rs: -------------------------------------------------------------------------------- 1 | mod maybe_dangling; 2 | #[cfg(any(feature = "io", feature = "codec"))] 3 | mod poll_buf; 4 | 5 | pub(crate) use maybe_dangling::MaybeDangling; 6 | #[cfg(any(feature = "io", feature = "codec"))] 7 | #[cfg_attr(not(feature = "io"), allow(unreachable_pub))] 8 | pub use poll_buf::{poll_read_buf, poll_write_buf}; 9 | -------------------------------------------------------------------------------- /tests-integration/src/bin/test-process-signal.rs: -------------------------------------------------------------------------------- 1 | // https://github.com/tokio-rs/tokio/issues/3550 2 | fn main() { 3 | for _ in 0..1000 { 4 | let rt = tokio::runtime::Builder::new_current_thread() 5 | .enable_all() 6 | .build() 7 | .unwrap(); 8 | 9 | drop(rt); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests-build/tests/pass/macros_main_loop.rs: -------------------------------------------------------------------------------- 1 | use tests_build::tokio; 2 | 3 | #[tokio::main] 4 | async fn main() -> Result<(), ()> { 5 | loop { 6 | if !never() { 7 | return Ok(()); 8 | } 9 | } 10 | } 11 | 12 | fn never() -> bool { 13 | std::time::Instant::now() > std::time::Instant::now() 14 | } 15 | -------------------------------------------------------------------------------- /tokio/src/future/trace.rs: -------------------------------------------------------------------------------- 1 | use std::future::Future; 2 | 3 | pub(crate) trait InstrumentedFuture: Future { 4 | fn id(&self) -> Option; 5 | } 6 | 7 | impl InstrumentedFuture for tracing::instrument::Instrumented { 8 | fn id(&self) -> Option { 9 | self.span().id() 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tokio/src/loom/std/atomic_u64_static_const_new.rs: -------------------------------------------------------------------------------- 1 | use super::AtomicU64; 2 | use crate::loom::sync::Mutex; 3 | 4 | pub(crate) type StaticAtomicU64 = AtomicU64; 5 | 6 | impl AtomicU64 { 7 | pub(crate) const fn new(val: u64) -> Self { 8 | Self { 9 | inner: Mutex::const_new(val), 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tokio-stream/tests/stream_empty.rs: -------------------------------------------------------------------------------- 1 | use tokio_stream::{self as stream, Stream, StreamExt}; 2 | 3 | #[tokio::test] 4 | async fn basic_usage() { 5 | let mut stream = stream::empty::(); 6 | 7 | for _ in 0..2 { 8 | assert_eq!(stream.size_hint(), (0, Some(0))); 9 | assert_eq!(None, stream.next().await); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tokio/src/process/kill.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | 3 | /// An interface for killing a running process. 4 | pub(crate) trait Kill { 5 | /// Forcefully kills the process. 6 | fn kill(&mut self) -> io::Result<()>; 7 | } 8 | 9 | impl Kill for &mut T { 10 | fn kill(&mut self) -> io::Result<()> { 11 | (**self).kill() 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tokio/src/runtime/scheduler/multi_thread/worker/metrics.rs: -------------------------------------------------------------------------------- 1 | use super::Shared; 2 | 3 | impl Shared { 4 | pub(crate) fn injection_queue_depth(&self) -> usize { 5 | self.inject.len() 6 | } 7 | 8 | pub(crate) fn worker_local_queue_depth(&self, worker: usize) -> usize { 9 | self.remotes[worker].steal.len() 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tokio/src/runtime/scheduler/multi_thread_alt/worker/metrics.rs: -------------------------------------------------------------------------------- 1 | use super::Shared; 2 | 3 | impl Shared { 4 | pub(crate) fn injection_queue_depth(&self) -> usize { 5 | self.inject.len() 6 | } 7 | 8 | pub(crate) fn worker_local_queue_depth(&self, worker: usize) -> usize { 9 | self.remotes[worker].steal.len() 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests-build/tests/pass/forward_args_and_output.rs: -------------------------------------------------------------------------------- 1 | use tests_build::tokio; 2 | 3 | fn main() {} 4 | 5 | // arguments and output type is forwarded so other macros can access them 6 | 7 | #[tokio::test] 8 | async fn test_fn_has_args(_x: u8) {} 9 | 10 | #[tokio::test] 11 | async fn test_has_output() -> Result<(), Box> { 12 | Ok(()) 13 | } 14 | -------------------------------------------------------------------------------- /tokio/src/macros/support.rs: -------------------------------------------------------------------------------- 1 | cfg_macros! { 2 | pub use crate::future::poll_fn; 3 | pub use crate::future::maybe_done::maybe_done; 4 | 5 | #[doc(hidden)] 6 | pub fn thread_rng_n(n: u32) -> u32 { 7 | crate::runtime::context::thread_rng_n(n) 8 | } 9 | } 10 | 11 | pub use std::future::Future; 12 | pub use std::pin::Pin; 13 | pub use std::task::Poll; 14 | -------------------------------------------------------------------------------- /tests-build/tests/fail/macros_core_no_default.stderr: -------------------------------------------------------------------------------- 1 | error: The default runtime flavor is `multi_thread`, but the `rt-multi-thread` feature is disabled. 2 | --> $DIR/macros_core_no_default.rs:3:1 3 | | 4 | 3 | #[tokio::main] 5 | | ^^^^^^^^^^^^^^ 6 | | 7 | = note: this error originates in the attribute macro `tokio::main` (in Nightly builds, run with -Z macro-backtrace for more info) 8 | -------------------------------------------------------------------------------- /tokio/src/net/tcp/mod.rs: -------------------------------------------------------------------------------- 1 | //! TCP utility types. 2 | 3 | pub(crate) mod listener; 4 | 5 | cfg_not_wasi! { 6 | pub(crate) mod socket; 7 | } 8 | 9 | mod split; 10 | pub use split::{ReadHalf, WriteHalf}; 11 | 12 | mod split_owned; 13 | pub use split_owned::{OwnedReadHalf, OwnedWriteHalf, ReuniteError}; 14 | 15 | pub(crate) mod stream; 16 | pub(crate) use stream::TcpStream; 17 | -------------------------------------------------------------------------------- /tokio/tests/signal_no_rt.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(unix)] 4 | 5 | use tokio::signal::unix::{signal, SignalKind}; 6 | 7 | #[cfg_attr(target_os = "wasi", ignore = "Wasi does not support panic recovery")] 8 | #[test] 9 | #[should_panic] 10 | fn no_runtime_panics_creating_signals() { 11 | let _ = signal(SignalKind::hangup()); 12 | } 13 | -------------------------------------------------------------------------------- /tests-build/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tests-build" 3 | version = "0.1.0" 4 | authors = ["Tokio Contributors "] 5 | edition = "2021" 6 | publish = false 7 | 8 | [features] 9 | full = ["tokio/full"] 10 | rt = ["tokio/rt", "tokio/macros"] 11 | 12 | [dependencies] 13 | tokio = { path = "../tokio", optional = true } 14 | 15 | [dev-dependencies] 16 | trybuild = "1.0" 17 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | The Tokio project adheres to the [Rust Code of Conduct](https://www.rust-lang.org/policies/code-of-conduct). This describes the minimum behavior expected from all contributors. 4 | 5 | ## Enforcement 6 | 7 | Instances of violations of the Code of Conduct can be reported by contacting the project team at [moderation@tokio.rs](mailto:moderation@tokio.rs). 8 | -------------------------------------------------------------------------------- /tokio-stream/tests/stream_once.rs: -------------------------------------------------------------------------------- 1 | use tokio_stream::{self as stream, Stream, StreamExt}; 2 | 3 | #[tokio::test] 4 | async fn basic_usage() { 5 | let mut one = stream::once(1); 6 | 7 | assert_eq!(one.size_hint(), (1, Some(1))); 8 | assert_eq!(Some(1), one.next().await); 9 | 10 | assert_eq!(one.size_hint(), (0, Some(0))); 11 | assert_eq!(None, one.next().await); 12 | } 13 | -------------------------------------------------------------------------------- /tokio-util/README.md: -------------------------------------------------------------------------------- 1 | # tokio-util 2 | 3 | Utilities for working with Tokio. 4 | 5 | ## License 6 | 7 | This project is licensed under the [MIT license](LICENSE). 8 | 9 | ### Contribution 10 | 11 | Unless you explicitly state otherwise, any contribution intentionally submitted 12 | for inclusion in Tokio by you, shall be licensed as MIT, without any additional 13 | terms or conditions. 14 | -------------------------------------------------------------------------------- /tokio-macros/README.md: -------------------------------------------------------------------------------- 1 | # Tokio Macros 2 | 3 | Procedural macros for use with Tokio 4 | 5 | ## License 6 | 7 | This project is licensed under the [MIT license](LICENSE). 8 | 9 | ### Contribution 10 | 11 | Unless you explicitly state otherwise, any contribution intentionally submitted 12 | for inclusion in Tokio by you, shall be licensed as MIT, without any additional 13 | terms or conditions. 14 | -------------------------------------------------------------------------------- /tokio/src/loom/mod.rs: -------------------------------------------------------------------------------- 1 | //! This module abstracts over `loom` and `std::sync` depending on whether we 2 | //! are running tests or not. 3 | 4 | #![allow(unused)] 5 | 6 | #[cfg(not(all(test, loom)))] 7 | mod std; 8 | #[cfg(not(all(test, loom)))] 9 | pub(crate) use self::std::*; 10 | 11 | #[cfg(all(test, loom))] 12 | mod mocked; 13 | #[cfg(all(test, loom))] 14 | pub(crate) use self::mocked::*; 15 | -------------------------------------------------------------------------------- /tokio/src/sync/tests/mod.rs: -------------------------------------------------------------------------------- 1 | cfg_not_loom! { 2 | mod atomic_waker; 3 | mod notify; 4 | mod semaphore_batch; 5 | } 6 | 7 | cfg_loom! { 8 | mod loom_atomic_waker; 9 | mod loom_broadcast; 10 | mod loom_list; 11 | mod loom_mpsc; 12 | mod loom_notify; 13 | mod loom_oneshot; 14 | mod loom_semaphore_batch; 15 | mod loom_watch; 16 | mod loom_rwlock; 17 | } 18 | -------------------------------------------------------------------------------- /tokio/tests/process_arg0.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", unix))] 3 | 4 | use tokio::process::Command; 5 | 6 | #[tokio::test] 7 | async fn arg0() { 8 | let mut cmd = Command::new("sh"); 9 | cmd.arg0("test_string").arg("-c").arg("echo $0"); 10 | 11 | let output = cmd.output().await.unwrap(); 12 | assert_eq!(output.stdout, b"test_string\n"); 13 | } 14 | -------------------------------------------------------------------------------- /tokio-test/README.md: -------------------------------------------------------------------------------- 1 | # tokio-test 2 | 3 | Tokio and Futures based testing utilities 4 | 5 | ## License 6 | 7 | This project is licensed under the [MIT license](LICENSE). 8 | 9 | ### Contribution 10 | 11 | Unless you explicitly state otherwise, any contribution intentionally submitted 12 | for inclusion in Tokio by you, shall be licensed as MIT, without any additional 13 | terms or conditions. 14 | -------------------------------------------------------------------------------- /tokio/src/fs/remove_dir.rs: -------------------------------------------------------------------------------- 1 | use crate::fs::asyncify; 2 | 3 | use std::io; 4 | use std::path::Path; 5 | 6 | /// Removes an existing, empty directory. 7 | /// 8 | /// This is an async version of [`std::fs::remove_dir`]. 9 | pub async fn remove_dir(path: impl AsRef) -> io::Result<()> { 10 | let path = path.as_ref().to_owned(); 11 | asyncify(move || std::fs::remove_dir(path)).await 12 | } 13 | -------------------------------------------------------------------------------- /stress-test/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stress-test" 3 | version = "0.1.0" 4 | authors = ["Tokio Contributors "] 5 | edition = "2021" 6 | publish = false 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | tokio = { path = "../tokio/", features = ["full"] } 12 | 13 | [dev-dependencies] 14 | rand = "0.8" 15 | -------------------------------------------------------------------------------- /tokio-stream/tests/stream_close.rs: -------------------------------------------------------------------------------- 1 | use tokio_stream::{StreamExt, StreamNotifyClose}; 2 | 3 | #[tokio::test] 4 | async fn basic_usage() { 5 | let mut stream = StreamNotifyClose::new(tokio_stream::iter(vec![0, 1])); 6 | 7 | assert_eq!(stream.next().await, Some(Some(0))); 8 | assert_eq!(stream.next().await, Some(Some(1))); 9 | assert_eq!(stream.next().await, Some(None)); 10 | assert_eq!(stream.next().await, None); 11 | } 12 | -------------------------------------------------------------------------------- /tokio/src/fs/read_link.rs: -------------------------------------------------------------------------------- 1 | use crate::fs::asyncify; 2 | 3 | use std::io; 4 | use std::path::{Path, PathBuf}; 5 | 6 | /// Reads a symbolic link, returning the file that the link points to. 7 | /// 8 | /// This is an async version of [`std::fs::read_link`]. 9 | pub async fn read_link(path: impl AsRef) -> io::Result { 10 | let path = path.as_ref().to_owned(); 11 | asyncify(move || std::fs::read_link(path)).await 12 | } 13 | -------------------------------------------------------------------------------- /tokio/tests/io_read_exact.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | 4 | use tokio::io::AsyncReadExt; 5 | use tokio_test::assert_ok; 6 | 7 | #[tokio::test] 8 | async fn read_exact() { 9 | let mut buf = Box::new([0; 8]); 10 | let mut rd: &[u8] = b"hello world"; 11 | 12 | let n = assert_ok!(rd.read_exact(&mut buf[..]).await); 13 | assert_eq!(n, 8); 14 | assert_eq!(buf[..], b"hello wo"[..]); 15 | } 16 | -------------------------------------------------------------------------------- /tokio/tests/io_chain.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | 4 | use tokio::io::AsyncReadExt; 5 | use tokio_test::assert_ok; 6 | 7 | #[tokio::test] 8 | async fn chain() { 9 | let mut buf = Vec::new(); 10 | let rd1: &[u8] = b"hello "; 11 | let rd2: &[u8] = b"world"; 12 | 13 | let mut rd = rd1.chain(rd2); 14 | assert_ok!(rd.read_to_end(&mut buf).await); 15 | assert_eq!(buf, b"hello world"); 16 | } 17 | -------------------------------------------------------------------------------- /tokio/tests/rt_time_start_paused.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "full")] 2 | 3 | use tokio::time::{Duration, Instant}; 4 | 5 | #[tokio::test(start_paused = true)] 6 | async fn test_start_paused() { 7 | let now = Instant::now(); 8 | 9 | // Pause a few times w/ std sleep and ensure `now` stays the same 10 | for _ in 0..5 { 11 | std::thread::sleep(Duration::from_millis(1)); 12 | assert_eq!(now, Instant::now()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tokio-stream/tests/stream_iter.rs: -------------------------------------------------------------------------------- 1 | use tokio_stream as stream; 2 | use tokio_test::task; 3 | 4 | use std::iter; 5 | 6 | #[tokio::test] 7 | async fn coop() { 8 | let mut stream = task::spawn(stream::iter(iter::repeat(1))); 9 | 10 | for _ in 0..10_000 { 11 | if stream.poll_next().is_pending() { 12 | assert!(stream.is_woken()); 13 | return; 14 | } 15 | } 16 | 17 | panic!("did not yield"); 18 | } 19 | -------------------------------------------------------------------------------- /tokio-util/src/sync/mod.rs: -------------------------------------------------------------------------------- 1 | //! Synchronization primitives 2 | 3 | mod cancellation_token; 4 | pub use cancellation_token::{ 5 | guard::DropGuard, CancellationToken, WaitForCancellationFuture, WaitForCancellationFutureOwned, 6 | }; 7 | 8 | mod mpsc; 9 | pub use mpsc::{PollSendError, PollSender}; 10 | 11 | mod poll_semaphore; 12 | pub use poll_semaphore::PollSemaphore; 13 | 14 | mod reusable_box; 15 | pub use reusable_box::ReusableBoxFuture; 16 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | command = """ 3 | rustup install nightly --profile minimal && cargo doc --no-deps --all-features 4 | """ 5 | publish = "target/doc" 6 | 7 | [build.environment] 8 | RUSTDOCFLAGS=""" 9 | --cfg docsrs \ 10 | --cfg tokio_unstable \ 11 | --cfg tokio_taskdump \ 12 | """ 13 | RUSTFLAGS="--cfg tokio_unstable --cfg tokio_taskdump --cfg docsrs" 14 | 15 | [[redirects]] 16 | from = "/" 17 | to = "/tokio" 18 | -------------------------------------------------------------------------------- /tests-build/README.md: -------------------------------------------------------------------------------- 1 | Tests the various combination of feature flags. This is broken out to a separate 2 | crate to work around limitations with cargo features. 3 | 4 | To run all of the tests in this directory, run the following commands: 5 | ``` 6 | cargo test --features full 7 | cargo test --features rt 8 | ``` 9 | If one of the tests fail, you can pass `TRYBUILD=overwrite` to the `cargo test` 10 | command that failed to have it regenerate the test output. 11 | -------------------------------------------------------------------------------- /tokio-stream/tests/stream_pending.rs: -------------------------------------------------------------------------------- 1 | use tokio_stream::{self as stream, Stream, StreamExt}; 2 | use tokio_test::{assert_pending, task}; 3 | 4 | #[tokio::test] 5 | async fn basic_usage() { 6 | let mut stream = stream::pending::(); 7 | 8 | for _ in 0..2 { 9 | assert_eq!(stream.size_hint(), (0, None)); 10 | 11 | let mut next = task::spawn(async { stream.next().await }); 12 | assert_pending!(next.poll()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tokio/tests/net_bind_resource.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", not(target_os = "wasi")))] // Wasi doesn't support panic recovery or bind 3 | 4 | use tokio::net::TcpListener; 5 | 6 | use std::net; 7 | 8 | #[test] 9 | #[should_panic] 10 | fn no_runtime_panics_binding_net_tcp_listener() { 11 | let listener = net::TcpListener::bind("127.0.0.1:0").expect("failed to bind listener"); 12 | let _ = TcpListener::try_from(listener); 13 | } 14 | -------------------------------------------------------------------------------- /tokio-stream/tests/support/mpsc.rs: -------------------------------------------------------------------------------- 1 | use async_stream::stream; 2 | use tokio::sync::mpsc::{self, UnboundedSender}; 3 | use tokio_stream::Stream; 4 | 5 | pub fn unbounded_channel_stream() -> (UnboundedSender, impl Stream) { 6 | let (tx, mut rx) = mpsc::unbounded_channel(); 7 | 8 | let stream = stream! { 9 | while let Some(item) = rx.recv().await { 10 | yield item; 11 | } 12 | }; 13 | 14 | (tx, stream) 15 | } 16 | -------------------------------------------------------------------------------- /tokio-util/src/task/mod.rs: -------------------------------------------------------------------------------- 1 | //! Extra utilities for spawning tasks 2 | 3 | #[cfg(tokio_unstable)] 4 | mod join_map; 5 | #[cfg(not(target_os = "wasi"))] 6 | mod spawn_pinned; 7 | #[cfg(not(target_os = "wasi"))] 8 | pub use spawn_pinned::LocalPoolHandle; 9 | 10 | #[cfg(tokio_unstable)] 11 | #[cfg_attr(docsrs, doc(cfg(all(tokio_unstable, feature = "rt"))))] 12 | pub use join_map::{JoinMap, JoinMapKeys}; 13 | 14 | pub mod task_tracker; 15 | pub use task_tracker::TaskTracker; 16 | -------------------------------------------------------------------------------- /tokio/tests/_require_full.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(any(feature = "full", target_family = "wasm")))] 2 | compile_error!("run main Tokio tests with `--features full`"); 3 | 4 | // CI sets `--cfg tokio_no_parking_lot` when trying to run tests with 5 | // `parking_lot` disabled. This check prevents "silent failure" if `parking_lot` 6 | // accidentally gets enabled. 7 | #[cfg(all(tokio_no_parking_lot, feature = "parking_lot"))] 8 | compile_error!("parking_lot feature enabled when it should not be"); 9 | -------------------------------------------------------------------------------- /tokio/tests/task_yield_now.rs: -------------------------------------------------------------------------------- 1 | #![cfg(all(feature = "full", tokio_unstable))] 2 | 3 | use tokio::task; 4 | use tokio_test::task::spawn; 5 | 6 | // `yield_now` is tested within the runtime in `rt_common`. 7 | #[test] 8 | fn yield_now_outside_of_runtime() { 9 | let mut task = spawn(async { 10 | task::yield_now().await; 11 | }); 12 | 13 | assert!(task.poll().is_pending()); 14 | assert!(task.is_woken()); 15 | assert!(task.poll().is_ready()); 16 | } 17 | -------------------------------------------------------------------------------- /tokio/src/runtime/io/mod.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(all(feature = "rt", feature = "net")), allow(dead_code))] 2 | mod driver; 3 | use driver::{Direction, Tick}; 4 | pub(crate) use driver::{Driver, Handle, ReadyEvent}; 5 | 6 | mod registration; 7 | pub(crate) use registration::Registration; 8 | 9 | mod registration_set; 10 | use registration_set::RegistrationSet; 11 | 12 | mod scheduled_io; 13 | use scheduled_io::ScheduledIo; 14 | 15 | mod metrics; 16 | use metrics::IoDriverMetrics; 17 | -------------------------------------------------------------------------------- /tokio/src/fs/remove_dir_all.rs: -------------------------------------------------------------------------------- 1 | use crate::fs::asyncify; 2 | 3 | use std::io; 4 | use std::path::Path; 5 | 6 | /// Removes a directory at this path, after removing all its contents. Use carefully! 7 | /// 8 | /// This is an async version of [`std::fs::remove_dir_all`][std] 9 | /// 10 | /// [std]: fn@std::fs::remove_dir_all 11 | pub async fn remove_dir_all(path: impl AsRef) -> io::Result<()> { 12 | let path = path.as_ref().to_owned(); 13 | asyncify(move || std::fs::remove_dir_all(path)).await 14 | } 15 | -------------------------------------------------------------------------------- /tokio/src/fs/symlink_metadata.rs: -------------------------------------------------------------------------------- 1 | use crate::fs::asyncify; 2 | 3 | use std::fs::Metadata; 4 | use std::io; 5 | use std::path::Path; 6 | 7 | /// Queries the file system metadata for a path. 8 | /// 9 | /// This is an async version of [`std::fs::symlink_metadata`][std] 10 | /// 11 | /// [std]: fn@std::fs::symlink_metadata 12 | pub async fn symlink_metadata(path: impl AsRef) -> io::Result { 13 | let path = path.as_ref().to_owned(); 14 | asyncify(|| std::fs::symlink_metadata(path)).await 15 | } 16 | -------------------------------------------------------------------------------- /tokio/tests/io_repeat.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | 4 | use tokio::io::AsyncReadExt; 5 | 6 | #[tokio::test] 7 | async fn repeat_poll_read_is_cooperative() { 8 | tokio::select! { 9 | biased; 10 | _ = async { 11 | loop { 12 | let mut buf = [0u8; 4096]; 13 | tokio::io::repeat(0b101).read_exact(&mut buf).await.unwrap(); 14 | } 15 | } => {}, 16 | _ = tokio::task::yield_now() => {} 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tokio/src/fs/set_permissions.rs: -------------------------------------------------------------------------------- 1 | use crate::fs::asyncify; 2 | 3 | use std::fs::Permissions; 4 | use std::io; 5 | use std::path::Path; 6 | 7 | /// Changes the permissions found on a file or a directory. 8 | /// 9 | /// This is an async version of [`std::fs::set_permissions`][std] 10 | /// 11 | /// [std]: fn@std::fs::set_permissions 12 | pub async fn set_permissions(path: impl AsRef, perm: Permissions) -> io::Result<()> { 13 | let path = path.as_ref().to_owned(); 14 | asyncify(|| std::fs::set_permissions(path, perm)).await 15 | } 16 | -------------------------------------------------------------------------------- /tokio/tests/signal_twice.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(unix)] 4 | 5 | mod support { 6 | pub mod signal; 7 | } 8 | use support::signal::send_signal; 9 | 10 | use tokio::signal::unix::{signal, SignalKind}; 11 | 12 | #[tokio::test] 13 | async fn twice() { 14 | let kind = SignalKind::user_defined1(); 15 | let mut sig = signal(kind).expect("failed to get signal"); 16 | 17 | for _ in 0..2 { 18 | send_signal(libc::SIGUSR1); 19 | 20 | assert!(sig.recv().await.is_some()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tokio/tests/signal_usr1.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(unix)] 4 | 5 | mod support { 6 | pub mod signal; 7 | } 8 | use support::signal::send_signal; 9 | 10 | use tokio::signal::unix::{signal, SignalKind}; 11 | use tokio_test::assert_ok; 12 | 13 | #[tokio::test] 14 | async fn signal_usr1() { 15 | let mut signal = assert_ok!( 16 | signal(SignalKind::user_defined1()), 17 | "failed to create signal" 18 | ); 19 | 20 | send_signal(libc::SIGUSR1); 21 | 22 | signal.recv().await; 23 | } 24 | -------------------------------------------------------------------------------- /tokio/tests/macros_pin.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "macros")] 2 | 3 | #[cfg(all(target_family = "wasm", not(target_os = "wasi")))] 4 | use wasm_bindgen_test::wasm_bindgen_test as maybe_tokio_test; 5 | 6 | #[cfg(not(all(target_family = "wasm", not(target_os = "wasi"))))] 7 | use tokio::test as maybe_tokio_test; 8 | 9 | async fn one() {} 10 | async fn two() {} 11 | 12 | #[maybe_tokio_test] 13 | async fn multi_pin() { 14 | tokio::pin! { 15 | let f1 = one(); 16 | let f2 = two(); 17 | } 18 | 19 | (&mut f1).await; 20 | (&mut f2).await; 21 | } 22 | -------------------------------------------------------------------------------- /tokio/src/fs/symlink.rs: -------------------------------------------------------------------------------- 1 | use crate::fs::asyncify; 2 | 3 | use std::io; 4 | use std::path::Path; 5 | 6 | /// Creates a new symbolic link on the filesystem. 7 | /// 8 | /// The `dst` path will be a symbolic link pointing to the `src` path. 9 | /// 10 | /// This is an async version of [`std::os::unix::fs::symlink`]. 11 | pub async fn symlink(src: impl AsRef, dst: impl AsRef) -> io::Result<()> { 12 | let src = src.as_ref().to_owned(); 13 | let dst = dst.as_ref().to_owned(); 14 | 15 | asyncify(move || std::os::unix::fs::symlink(src, dst)).await 16 | } 17 | -------------------------------------------------------------------------------- /tokio/src/loom/std/unsafe_cell.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | pub(crate) struct UnsafeCell(std::cell::UnsafeCell); 3 | 4 | impl UnsafeCell { 5 | pub(crate) const fn new(data: T) -> UnsafeCell { 6 | UnsafeCell(std::cell::UnsafeCell::new(data)) 7 | } 8 | 9 | #[inline(always)] 10 | pub(crate) fn with(&self, f: impl FnOnce(*const T) -> R) -> R { 11 | f(self.0.get()) 12 | } 13 | 14 | #[inline(always)] 15 | pub(crate) fn with_mut(&self, f: impl FnOnce(*mut T) -> R) -> R { 16 | f(self.0.get()) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tokio/src/macros/thread_local.rs: -------------------------------------------------------------------------------- 1 | #[cfg(all(loom, test))] 2 | macro_rules! tokio_thread_local { 3 | ($(#[$attrs:meta])* $vis:vis static $name:ident: $ty:ty = const { $expr:expr } $(;)?) => { 4 | loom::thread_local! { 5 | $(#[$attrs])* 6 | $vis static $name: $ty = $expr; 7 | } 8 | }; 9 | 10 | ($($tts:tt)+) => { loom::thread_local!{ $($tts)+ } } 11 | } 12 | 13 | #[cfg(not(all(loom, test)))] 14 | macro_rules! tokio_thread_local { 15 | ($($tts:tt)+) => { 16 | ::std::thread_local!{ $($tts)+ } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tokio-test/tests/block_on.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | 3 | use tokio::time::{sleep_until, Duration, Instant}; 4 | use tokio_test::block_on; 5 | 6 | #[test] 7 | fn async_block() { 8 | assert_eq!(4, block_on(async { 4 })); 9 | } 10 | 11 | async fn five() -> u8 { 12 | 5 13 | } 14 | 15 | #[test] 16 | fn async_fn() { 17 | assert_eq!(5, block_on(five())); 18 | } 19 | 20 | #[test] 21 | fn test_sleep() { 22 | let deadline = Instant::now() + Duration::from_millis(100); 23 | 24 | block_on(async { 25 | sleep_until(deadline).await; 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /tokio-util/src/net/unix/mod.rs: -------------------------------------------------------------------------------- 1 | //! Unix domain socket helpers. 2 | 3 | use super::Listener; 4 | use std::io::Result; 5 | use std::task::{Context, Poll}; 6 | 7 | impl Listener for tokio::net::UnixListener { 8 | type Io = tokio::net::UnixStream; 9 | type Addr = tokio::net::unix::SocketAddr; 10 | 11 | fn poll_accept(&mut self, cx: &mut Context<'_>) -> Poll> { 12 | Self::poll_accept(self, cx) 13 | } 14 | 15 | fn local_addr(&self) -> Result { 16 | self.local_addr().map(Into::into) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests-integration/src/bin/test-cat.rs: -------------------------------------------------------------------------------- 1 | //! A cat-like utility that can be used as a subprocess to test I/O 2 | //! stream communication. 3 | 4 | use std::io; 5 | use std::io::Write; 6 | 7 | fn main() { 8 | let stdin = io::stdin(); 9 | let mut stdout = io::stdout(); 10 | let mut line = String::new(); 11 | loop { 12 | line.clear(); 13 | stdin.read_line(&mut line).unwrap(); 14 | if line.is_empty() { 15 | break; 16 | } 17 | stdout.write_all(line.as_bytes()).unwrap(); 18 | } 19 | stdout.flush().unwrap(); 20 | } 21 | -------------------------------------------------------------------------------- /tokio/src/fs/remove_file.rs: -------------------------------------------------------------------------------- 1 | use crate::fs::asyncify; 2 | 3 | use std::io; 4 | use std::path::Path; 5 | 6 | /// Removes a file from the filesystem. 7 | /// 8 | /// Note that there is no guarantee that the file is immediately deleted (e.g. 9 | /// depending on platform, other open file descriptors may prevent immediate 10 | /// removal). 11 | /// 12 | /// This is an async version of [`std::fs::remove_file`]. 13 | pub async fn remove_file(path: impl AsRef) -> io::Result<()> { 14 | let path = path.as_ref().to_owned(); 15 | asyncify(move || std::fs::remove_file(path)).await 16 | } 17 | -------------------------------------------------------------------------------- /tokio/tests/fs.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", not(target_os = "wasi")))] // Wasi does not support file operations 3 | 4 | use tokio::fs; 5 | use tokio_test::assert_ok; 6 | 7 | #[tokio::test] 8 | async fn path_read_write() { 9 | let temp = tempdir(); 10 | let dir = temp.path(); 11 | 12 | assert_ok!(fs::write(dir.join("bar"), b"bytes").await); 13 | let out = assert_ok!(fs::read(dir.join("bar")).await); 14 | 15 | assert_eq!(out, b"bytes"); 16 | } 17 | 18 | fn tempdir() -> tempfile::TempDir { 19 | tempfile::tempdir().unwrap() 20 | } 21 | -------------------------------------------------------------------------------- /tokio/src/fs/rename.rs: -------------------------------------------------------------------------------- 1 | use crate::fs::asyncify; 2 | 3 | use std::io; 4 | use std::path::Path; 5 | 6 | /// Renames a file or directory to a new name, replacing the original file if 7 | /// `to` already exists. 8 | /// 9 | /// This will not work if the new name is on a different mount point. 10 | /// 11 | /// This is an async version of [`std::fs::rename`]. 12 | pub async fn rename(from: impl AsRef, to: impl AsRef) -> io::Result<()> { 13 | let from = from.as_ref().to_owned(); 14 | let to = to.as_ref().to_owned(); 15 | 16 | asyncify(move || std::fs::rename(from, to)).await 17 | } 18 | -------------------------------------------------------------------------------- /tokio/src/util/rand/rt_unstable.rs: -------------------------------------------------------------------------------- 1 | use super::RngSeed; 2 | 3 | use std::collections::hash_map::DefaultHasher; 4 | use std::hash::Hasher; 5 | 6 | impl RngSeed { 7 | /// Generates a seed from the provided byte slice. 8 | /// 9 | /// # Example 10 | /// 11 | /// ``` 12 | /// # use tokio::runtime::RngSeed; 13 | /// let seed = RngSeed::from_bytes(b"make me a seed"); 14 | /// ``` 15 | pub fn from_bytes(bytes: &[u8]) -> Self { 16 | let mut hasher = DefaultHasher::default(); 17 | hasher.write(bytes); 18 | Self::from_u64(hasher.finish()) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tokio-stream/fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tokio-stream-fuzz" 3 | version = "0.0.0" 4 | publish = false 5 | edition = "2021" 6 | 7 | [package.metadata] 8 | cargo-fuzz = true 9 | 10 | [dependencies] 11 | libfuzzer-sys = "0.4" 12 | tokio-test = { path = "../../tokio-test" } 13 | 14 | [dependencies.tokio-stream] 15 | path = ".." 16 | 17 | 18 | # Prevent this from interfering with workspaces 19 | [workspace] 20 | members = ["."] 21 | 22 | [profile.release] 23 | debug = 1 24 | 25 | [[bin]] 26 | name = "fuzz_stream_map" 27 | path = "fuzz_targets/fuzz_stream_map.rs" 28 | test = false 29 | doc = false 30 | -------------------------------------------------------------------------------- /tokio/fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tokio-fuzz" 3 | version = "0.0.0" 4 | publish = false 5 | edition = "2021" 6 | 7 | [package.metadata] 8 | cargo-fuzz = true 9 | 10 | [dependencies] 11 | libfuzzer-sys = "0.4" 12 | 13 | [dependencies.tokio] 14 | path = ".." 15 | features = ["fs","net","process","rt","sync","signal","time"] 16 | 17 | 18 | # Prevent this from interfering with workspaces 19 | [workspace] 20 | members = ["."] 21 | 22 | [profile.release] 23 | debug = 1 24 | 25 | [[bin]] 26 | name = "fuzz_linked_list" 27 | path = "fuzz_targets/fuzz_linked_list.rs" 28 | test = false 29 | doc = false 30 | -------------------------------------------------------------------------------- /tokio/src/runtime/io/driver/signal.rs: -------------------------------------------------------------------------------- 1 | use super::{Driver, Handle, TOKEN_SIGNAL}; 2 | 3 | use std::io; 4 | 5 | impl Handle { 6 | pub(crate) fn register_signal_receiver( 7 | &self, 8 | receiver: &mut mio::net::UnixStream, 9 | ) -> io::Result<()> { 10 | self.registry 11 | .register(receiver, TOKEN_SIGNAL, mio::Interest::READABLE)?; 12 | Ok(()) 13 | } 14 | } 15 | 16 | impl Driver { 17 | pub(crate) fn consume_signal_ready(&mut self) -> bool { 18 | let ret = self.signal_ready; 19 | self.signal_ready = false; 20 | ret 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tokio/tests/signal_drop_recv.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(unix)] 4 | 5 | mod support { 6 | pub mod signal; 7 | } 8 | use support::signal::send_signal; 9 | 10 | use tokio::signal::unix::{signal, SignalKind}; 11 | 12 | #[tokio::test] 13 | async fn drop_then_get_a_signal() { 14 | let kind = SignalKind::user_defined1(); 15 | let sig = signal(kind).expect("failed to create first signal"); 16 | drop(sig); 17 | 18 | send_signal(libc::SIGUSR1); 19 | let mut sig = signal(kind).expect("failed to create second signal"); 20 | 21 | let _ = sig.recv().await; 22 | } 23 | -------------------------------------------------------------------------------- /tokio/src/runtime/scheduler/block_in_place.rs: -------------------------------------------------------------------------------- 1 | use crate::runtime::scheduler; 2 | 3 | #[track_caller] 4 | pub(crate) fn block_in_place(f: F) -> R 5 | where 6 | F: FnOnce() -> R, 7 | { 8 | #[cfg(tokio_unstable)] 9 | { 10 | use crate::runtime::{Handle, RuntimeFlavor::MultiThreadAlt}; 11 | 12 | match Handle::try_current().map(|h| h.runtime_flavor()) { 13 | Ok(MultiThreadAlt) => { 14 | return scheduler::multi_thread_alt::block_in_place(f); 15 | } 16 | _ => {} 17 | } 18 | } 19 | 20 | scheduler::multi_thread::block_in_place(f) 21 | } 22 | -------------------------------------------------------------------------------- /tokio/tests/io_lines.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | 4 | use tokio::io::AsyncBufReadExt; 5 | use tokio_test::assert_ok; 6 | 7 | #[tokio::test] 8 | async fn lines_inherent() { 9 | let rd: &[u8] = b"hello\r\nworld\n\n"; 10 | let mut st = rd.lines(); 11 | 12 | let b = assert_ok!(st.next_line().await).unwrap(); 13 | assert_eq!(b, "hello"); 14 | let b = assert_ok!(st.next_line().await).unwrap(); 15 | assert_eq!(b, "world"); 16 | let b = assert_ok!(st.next_line().await).unwrap(); 17 | assert_eq!(b, ""); 18 | assert!(assert_ok!(st.next_line().await).is_none()); 19 | } 20 | -------------------------------------------------------------------------------- /tokio/tests/signal_notify_both.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(unix)] 4 | 5 | mod support { 6 | pub mod signal; 7 | } 8 | use support::signal::send_signal; 9 | 10 | use tokio::signal::unix::{signal, SignalKind}; 11 | 12 | #[tokio::test] 13 | async fn notify_both() { 14 | let kind = SignalKind::user_defined2(); 15 | 16 | let mut signal1 = signal(kind).expect("failed to create signal1"); 17 | let mut signal2 = signal(kind).expect("failed to create signal2"); 18 | 19 | send_signal(libc::SIGUSR2); 20 | 21 | signal1.recv().await; 22 | signal2.recv().await; 23 | } 24 | -------------------------------------------------------------------------------- /tests-integration/src/bin/test-mem.rs: -------------------------------------------------------------------------------- 1 | use futures::future::poll_fn; 2 | 3 | fn main() { 4 | let rt = tokio::runtime::Builder::new_multi_thread() 5 | .worker_threads(1) 6 | .enable_io() 7 | .build() 8 | .unwrap(); 9 | 10 | rt.block_on(async { 11 | let listener = tokio::net::TcpListener::bind("0.0.0.0:0").await.unwrap(); 12 | tokio::spawn(async move { 13 | loop { 14 | poll_fn(|cx| listener.poll_accept(cx)).await.unwrap(); 15 | } 16 | }); 17 | }); 18 | 19 | std::thread::sleep(std::time::Duration::from_millis(50)); 20 | drop(rt); 21 | } 22 | -------------------------------------------------------------------------------- /tokio/src/signal/windows/stub.rs: -------------------------------------------------------------------------------- 1 | //! Stub implementations for the platform API so that rustdoc can build linkable 2 | //! documentation on non-windows platforms. 3 | 4 | use crate::signal::RxFuture; 5 | use std::io; 6 | 7 | pub(super) fn ctrl_break() -> io::Result { 8 | panic!() 9 | } 10 | 11 | pub(super) fn ctrl_close() -> io::Result { 12 | panic!() 13 | } 14 | 15 | pub(super) fn ctrl_c() -> io::Result { 16 | panic!() 17 | } 18 | 19 | pub(super) fn ctrl_logoff() -> io::Result { 20 | panic!() 21 | } 22 | 23 | pub(super) fn ctrl_shutdown() -> io::Result { 24 | panic!() 25 | } 26 | -------------------------------------------------------------------------------- /tokio/src/macros/mod.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "full"), allow(unused_macros))] 2 | 3 | #[macro_use] 4 | mod cfg; 5 | 6 | #[macro_use] 7 | mod loom; 8 | 9 | #[macro_use] 10 | mod pin; 11 | 12 | #[macro_use] 13 | mod ready; 14 | 15 | #[macro_use] 16 | mod thread_local; 17 | 18 | #[macro_use] 19 | mod addr_of; 20 | 21 | cfg_trace! { 22 | #[macro_use] 23 | mod trace; 24 | } 25 | 26 | cfg_macros! { 27 | #[macro_use] 28 | mod select; 29 | 30 | #[macro_use] 31 | mod join; 32 | 33 | #[macro_use] 34 | mod try_join; 35 | } 36 | 37 | // Includes re-exports needed to implement macros 38 | #[doc(hidden)] 39 | pub mod support; 40 | -------------------------------------------------------------------------------- /tokio/tests/tracing-instrumentation/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tracing-instrumentation" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | 8 | [dev-dependencies] 9 | futures = { version = "0.3.0", features = ["async-await"] } 10 | tokio = { version = "1.33.0", path = "../..", features = ["full", "tracing"] } 11 | tracing = { version = "0.1.40", git = "https://github.com/tokio-rs/tracing.git", tag = "tracing-0.1.40" } 12 | tracing-mock = { version = "0.1.0", git = "https://github.com/tokio-rs/tracing.git", tag = "tracing-0.1.40" } 13 | 14 | [patch.crates-io] 15 | tracing = { git = "https://github.com/tokio-rs/tracing.git", tag = "tracing-0.1.40" } 16 | 17 | [workspace] 18 | -------------------------------------------------------------------------------- /tests-integration/tests/macros_main.rs: -------------------------------------------------------------------------------- 1 | #![cfg(all( 2 | feature = "macros", 3 | feature = "rt-multi-thread", 4 | not(target_os = "wasi") 5 | ))] 6 | 7 | #[tokio::main] 8 | async fn basic_main() -> usize { 9 | 1 10 | } 11 | 12 | #[tokio::main] 13 | async fn generic_fun() -> T { 14 | T::default() 15 | } 16 | 17 | #[tokio::main] 18 | async fn spawning() -> usize { 19 | let join = tokio::spawn(async { 1 }); 20 | join.await.unwrap() 21 | } 22 | 23 | #[test] 24 | fn main_with_spawn() { 25 | assert_eq!(1, spawning()); 26 | } 27 | 28 | #[test] 29 | fn shell() { 30 | assert_eq!(1, basic_main()); 31 | assert_eq!(bool::default(), generic_fun::()) 32 | } 33 | -------------------------------------------------------------------------------- /tokio/src/fs/symlink_dir.rs: -------------------------------------------------------------------------------- 1 | use crate::fs::asyncify; 2 | 3 | use std::io; 4 | use std::path::Path; 5 | 6 | /// Creates a new directory symlink on the filesystem. 7 | /// 8 | /// The `dst` path will be a directory symbolic link pointing to the `src` 9 | /// path. 10 | /// 11 | /// This is an async version of [`std::os::windows::fs::symlink_dir`][std] 12 | /// 13 | /// [std]: https://doc.rust-lang.org/std/os/windows/fs/fn.symlink_dir.html 14 | pub async fn symlink_dir(src: impl AsRef, dst: impl AsRef) -> io::Result<()> { 15 | let src = src.as_ref().to_owned(); 16 | let dst = dst.as_ref().to_owned(); 17 | 18 | asyncify(move || std::os::windows::fs::symlink_dir(src, dst)).await 19 | } 20 | -------------------------------------------------------------------------------- /tokio/src/fs/symlink_file.rs: -------------------------------------------------------------------------------- 1 | use crate::fs::asyncify; 2 | 3 | use std::io; 4 | use std::path::Path; 5 | 6 | /// Creates a new file symbolic link on the filesystem. 7 | /// 8 | /// The `dst` path will be a file symbolic link pointing to the `src` 9 | /// path. 10 | /// 11 | /// This is an async version of [`std::os::windows::fs::symlink_file`][std] 12 | /// 13 | /// [std]: https://doc.rust-lang.org/std/os/windows/fs/fn.symlink_file.html 14 | pub async fn symlink_file(src: impl AsRef, dst: impl AsRef) -> io::Result<()> { 15 | let src = src.as_ref().to_owned(); 16 | let dst = dst.as_ref().to_owned(); 17 | 18 | asyncify(move || std::os::windows::fs::symlink_file(src, dst)).await 19 | } 20 | -------------------------------------------------------------------------------- /tokio/tests/process_raw_handle.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(windows)] 4 | 5 | use tokio::process::Command; 6 | use windows_sys::Win32::System::Threading::GetProcessId; 7 | 8 | #[tokio::test] 9 | async fn obtain_raw_handle() { 10 | let mut cmd = Command::new("cmd"); 11 | cmd.kill_on_drop(true); 12 | cmd.arg("/c"); 13 | cmd.arg("pause"); 14 | 15 | let child = cmd.spawn().unwrap(); 16 | 17 | let orig_id = child.id().expect("missing id"); 18 | assert!(orig_id > 0); 19 | 20 | let handle = child.raw_handle().expect("process stopped"); 21 | let handled_id = unsafe { GetProcessId(handle as _) }; 22 | assert_eq!(handled_id, orig_id); 23 | } 24 | -------------------------------------------------------------------------------- /tokio/src/runtime/scheduler/multi_thread/overflow.rs: -------------------------------------------------------------------------------- 1 | use crate::runtime::task; 2 | 3 | #[cfg(test)] 4 | use std::cell::RefCell; 5 | 6 | pub(crate) trait Overflow { 7 | fn push(&self, task: task::Notified); 8 | 9 | fn push_batch(&self, iter: I) 10 | where 11 | I: Iterator>; 12 | } 13 | 14 | #[cfg(test)] 15 | impl Overflow for RefCell>> { 16 | fn push(&self, task: task::Notified) { 17 | self.borrow_mut().push(task); 18 | } 19 | 20 | fn push_batch(&self, iter: I) 21 | where 22 | I: Iterator>, 23 | { 24 | self.borrow_mut().extend(iter); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tokio/src/runtime/scheduler/multi_thread_alt/overflow.rs: -------------------------------------------------------------------------------- 1 | use crate::runtime::task; 2 | 3 | #[cfg(test)] 4 | use std::cell::RefCell; 5 | 6 | pub(crate) trait Overflow { 7 | fn push(&self, task: task::Notified); 8 | 9 | fn push_batch(&self, iter: I) 10 | where 11 | I: Iterator>; 12 | } 13 | 14 | #[cfg(test)] 15 | impl Overflow for RefCell>> { 16 | fn push(&self, task: task::Notified) { 17 | self.borrow_mut().push(task); 18 | } 19 | 20 | fn push_batch(&self, iter: I) 21 | where 22 | I: Iterator>, 23 | { 24 | self.borrow_mut().extend(iter); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: A-tokio, C-feature-request 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /tokio/tests/join_handle_panic.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", not(target_os = "wasi")))] // Wasi doesn't support panic recovery 3 | #![cfg(panic = "unwind")] 4 | 5 | struct PanicsOnDrop; 6 | 7 | impl Drop for PanicsOnDrop { 8 | fn drop(&mut self) { 9 | panic!("I told you so"); 10 | } 11 | } 12 | 13 | #[tokio::test] 14 | async fn test_panics_do_not_propagate_when_dropping_join_handle() { 15 | let join_handle = tokio::spawn(async move { PanicsOnDrop }); 16 | 17 | // only drop the JoinHandle when the task has completed 18 | // (which is difficult to synchronize precisely) 19 | tokio::time::sleep(std::time::Duration::from_millis(3)).await; 20 | drop(join_handle); 21 | } 22 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | jobs: 3 | test-arm: 4 | machine: 5 | image: ubuntu-2004:202101-01 6 | resource_class: arm.medium 7 | environment: 8 | # Change to pin rust version 9 | RUST_STABLE: stable 10 | steps: 11 | - checkout 12 | - run: 13 | name: Install Rust 14 | command: | 15 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o rustup.sh 16 | chmod +x rustup.sh 17 | ./rustup.sh -y --default-toolchain $RUST_STABLE 18 | source "$HOME"/.cargo/env 19 | # Only run Tokio tests 20 | - run: cargo test --all-features -p tokio 21 | 22 | workflows: 23 | ci: 24 | jobs: 25 | - test-arm 26 | -------------------------------------------------------------------------------- /tokio/src/future/mod.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "macros"), allow(unreachable_pub))] 2 | 3 | //! Asynchronous values. 4 | 5 | #[cfg(any(feature = "macros", feature = "process"))] 6 | pub(crate) mod maybe_done; 7 | 8 | mod poll_fn; 9 | #[allow(unused_imports)] 10 | pub use poll_fn::poll_fn; 11 | 12 | cfg_process! { 13 | mod try_join; 14 | pub(crate) use try_join::try_join3; 15 | } 16 | 17 | cfg_sync! { 18 | mod block_on; 19 | pub(crate) use block_on::block_on; 20 | } 21 | 22 | cfg_trace! { 23 | mod trace; 24 | #[allow(unused_imports)] 25 | pub(crate) use trace::InstrumentedFuture as Future; 26 | } 27 | 28 | cfg_not_trace! { 29 | cfg_rt! { 30 | pub(crate) use std::future::Future; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tokio/tests/fs_canonicalize_dir.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", not(target_os = "wasi")))] // WASI does not support all fs operations 3 | 4 | use tokio::fs; 5 | 6 | #[tokio::test] 7 | #[cfg(unix)] 8 | async fn canonicalize_root_dir_unix() { 9 | assert_eq!(fs::canonicalize("/.").await.unwrap().to_str().unwrap(), "/"); 10 | } 11 | 12 | #[tokio::test] 13 | #[cfg(windows)] 14 | async fn canonicalize_root_dir_windows() { 15 | // 2-step let bindings due to Rust memory semantics 16 | let dir_path = fs::canonicalize("C:\\.\\").await.unwrap(); 17 | 18 | let dir_name = dir_path.to_str().unwrap(); 19 | 20 | assert!(dir_name.starts_with("\\\\")); 21 | assert!(dir_name.ends_with("C:\\")); 22 | } 23 | -------------------------------------------------------------------------------- /tokio/src/loom/std/atomic_u64.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of an atomic u64 cell. On 64 bit platforms, this is a 2 | //! re-export of `AtomicU64`. On 32 bit platforms, this is implemented using a 3 | //! `Mutex`. 4 | 5 | // `AtomicU64` can only be used on targets with `target_has_atomic` is 64 or greater. 6 | // Once `cfg_target_has_atomic` feature is stable, we can replace it with 7 | // `#[cfg(target_has_atomic = "64")]`. 8 | // Refs: https://github.com/rust-lang/rust/tree/master/src/librustc_target 9 | cfg_has_atomic_u64! { 10 | #[path = "atomic_u64_native.rs"] 11 | mod imp; 12 | } 13 | 14 | cfg_not_has_atomic_u64! { 15 | #[path = "atomic_u64_as_mutex.rs"] 16 | mod imp; 17 | } 18 | 19 | pub(crate) use imp::{AtomicU64, StaticAtomicU64}; 20 | -------------------------------------------------------------------------------- /.github/workflows/labeler.yml: -------------------------------------------------------------------------------- 1 | name: "Pull Request Labeler" 2 | on: 3 | - pull_request_target 4 | 5 | # See .github/labeler.yml file 6 | 7 | concurrency: 8 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} 9 | cancel-in-progress: true 10 | 11 | permissions: 12 | contents: read 13 | 14 | jobs: 15 | triage: 16 | permissions: 17 | contents: read # for actions/labeler to determine modified files 18 | pull-requests: write # for actions/labeler to add labels to PRs 19 | runs-on: ubuntu-latest 20 | if: github.repository_owner == 'tokio-rs' 21 | steps: 22 | - uses: actions/labeler@v3 23 | with: 24 | repo-token: "${{ secrets.GITHUB_TOKEN }}" 25 | sync-labels: true 26 | -------------------------------------------------------------------------------- /tokio/src/runtime/io/metrics.rs: -------------------------------------------------------------------------------- 1 | //! This file contains mocks of the metrics types used in the I/O driver. 2 | //! 3 | //! The reason these mocks don't live in `src/runtime/mock.rs` is because 4 | //! these need to be available in the case when `net` is enabled but 5 | //! `rt` is not. 6 | 7 | cfg_not_rt_and_metrics_and_net! { 8 | #[derive(Default)] 9 | pub(crate) struct IoDriverMetrics {} 10 | 11 | impl IoDriverMetrics { 12 | pub(crate) fn incr_fd_count(&self) {} 13 | pub(crate) fn dec_fd_count(&self) {} 14 | pub(crate) fn incr_ready_count_by(&self, _amt: u64) {} 15 | } 16 | } 17 | 18 | cfg_net! { 19 | cfg_rt! { 20 | cfg_metrics! { 21 | pub(crate) use crate::runtime::IoDriverMetrics; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tokio/tests/uds_cred.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(all(unix, not(target_os = "dragonfly")))] 4 | 5 | use tokio::net::UnixStream; 6 | 7 | use libc::getegid; 8 | use libc::geteuid; 9 | 10 | #[tokio::test] 11 | #[cfg_attr( 12 | target_os = "netbsd", 13 | ignore = "NetBSD does not support getpeereid() for sockets created by socketpair()" 14 | )] 15 | async fn test_socket_pair() { 16 | let (a, b) = UnixStream::pair().unwrap(); 17 | let cred_a = a.peer_cred().unwrap(); 18 | let cred_b = b.peer_cred().unwrap(); 19 | assert_eq!(cred_a, cred_b); 20 | 21 | let uid = unsafe { geteuid() }; 22 | let gid = unsafe { getegid() }; 23 | 24 | assert_eq!(cred_a.uid(), uid); 25 | assert_eq!(cred_a.gid(), gid); 26 | } 27 | -------------------------------------------------------------------------------- /tokio/src/runtime/metrics/io.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "net"), allow(dead_code))] 2 | 3 | use crate::loom::sync::atomic::{AtomicU64, Ordering::Relaxed}; 4 | 5 | #[derive(Default)] 6 | pub(crate) struct IoDriverMetrics { 7 | pub(super) fd_registered_count: AtomicU64, 8 | pub(super) fd_deregistered_count: AtomicU64, 9 | pub(super) ready_count: AtomicU64, 10 | } 11 | 12 | impl IoDriverMetrics { 13 | pub(crate) fn incr_fd_count(&self) { 14 | self.fd_registered_count.fetch_add(1, Relaxed); 15 | } 16 | 17 | pub(crate) fn dec_fd_count(&self) { 18 | self.fd_deregistered_count.fetch_add(1, Relaxed); 19 | } 20 | 21 | pub(crate) fn incr_ready_count_by(&self, amt: u64) { 22 | self.ready_count.fetch_add(amt, Relaxed); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tokio/tests/fs_remove_file.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", not(target_os = "wasi")))] // WASI does not support all fs operations 3 | 4 | use tempfile::tempdir; 5 | use tokio::fs; 6 | 7 | #[tokio::test] 8 | async fn remove_file() { 9 | let temp_dir = tempdir().unwrap(); 10 | 11 | let file_path = temp_dir.path().join("a.txt"); 12 | 13 | fs::write(&file_path, b"Hello File!").await.unwrap(); 14 | 15 | assert!(fs::try_exists(&file_path).await.unwrap()); 16 | 17 | fs::remove_file(&file_path).await.unwrap(); 18 | 19 | // should no longer exist 20 | match fs::try_exists(file_path).await { 21 | Ok(exists) => assert!(!exists), 22 | Err(_) => println!("ignored try_exists error after remove_file"), 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /tokio/tests/sync_errors.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "sync")] 3 | 4 | #[cfg(all(target_family = "wasm", not(target_os = "wasi")))] 5 | use wasm_bindgen_test::wasm_bindgen_test as test; 6 | 7 | fn is_error() {} 8 | 9 | #[test] 10 | fn mpsc_error_bound() { 11 | use tokio::sync::mpsc::error; 12 | 13 | is_error::>(); 14 | is_error::>(); 15 | } 16 | 17 | #[test] 18 | fn oneshot_error_bound() { 19 | use tokio::sync::oneshot::error; 20 | 21 | is_error::(); 22 | is_error::(); 23 | } 24 | 25 | #[test] 26 | fn watch_error_bound() { 27 | use tokio::sync::watch::error; 28 | 29 | is_error::>(); 30 | } 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: A-tokio, C-bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Version** 11 | List the versions of all `tokio` crates you are using. The easiest way to get 12 | this information is using `cargo tree` subcommand: 13 | 14 | `cargo tree | grep tokio` 15 | 16 | **Platform** 17 | The output of `uname -a` (UNIX), or version and 32 or 64-bit (Windows) 18 | 19 | **Description** 20 | Enter your issue details here. 21 | One way to structure the description: 22 | 23 | [short summary of the bug] 24 | 25 | I tried this code: 26 | 27 | [code sample that causes the bug] 28 | 29 | I expected to see this happen: [explanation] 30 | 31 | Instead, this happened: [explanation] 32 | -------------------------------------------------------------------------------- /tokio/tests/signal_ctrl_c.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(unix)] 4 | 5 | mod support { 6 | pub mod signal; 7 | } 8 | use support::signal::send_signal; 9 | 10 | use tokio::signal; 11 | use tokio::sync::oneshot; 12 | use tokio_test::assert_ok; 13 | 14 | #[tokio::test] 15 | async fn ctrl_c() { 16 | let ctrl_c = signal::ctrl_c(); 17 | 18 | let (fire, wait) = oneshot::channel(); 19 | 20 | // NB: simulate a signal coming in by exercising our signal handler 21 | // to avoid complications with sending SIGINT to the test process 22 | tokio::spawn(async { 23 | wait.await.expect("wait failed"); 24 | send_signal(libc::SIGINT); 25 | }); 26 | 27 | let _ = fire.send(()); 28 | 29 | assert_ok!(ctrl_c.await); 30 | } 31 | -------------------------------------------------------------------------------- /benches/time_now.rs: -------------------------------------------------------------------------------- 1 | //! Benchmark spawning a task onto the basic and threaded Tokio executors. 2 | //! This essentially measure the time to enqueue a task in the local and remote 3 | //! case. 4 | 5 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 6 | 7 | fn time_now_current_thread(c: &mut Criterion) { 8 | let rt = tokio::runtime::Builder::new_current_thread() 9 | .enable_time() 10 | .build() 11 | .unwrap(); 12 | 13 | c.bench_function("time_now_current_thread", |b| { 14 | b.iter(|| { 15 | rt.block_on(async { 16 | black_box(tokio::time::Instant::now()); 17 | }) 18 | }) 19 | }); 20 | } 21 | 22 | criterion_group!(time_now, time_now_current_thread); 23 | 24 | criterion_main!(time_now); 25 | -------------------------------------------------------------------------------- /tests-build/tests/fail/macros_type_mismatch.rs: -------------------------------------------------------------------------------- 1 | use tests_build::tokio; 2 | 3 | #[tokio::main] 4 | async fn missing_semicolon_or_return_type() { 5 | Ok(()) 6 | } 7 | 8 | #[tokio::main] 9 | async fn missing_return_type() { 10 | return Ok(()); 11 | } 12 | 13 | #[tokio::main] 14 | async fn extra_semicolon() -> Result<(), ()> { 15 | /* TODO(taiki-e): help message still wrong 16 | help: try using a variant of the expected enum 17 | | 18 | 23 | Ok(Ok(());) 19 | | 20 | 23 | Err(Ok(());) 21 | | 22 | */ 23 | Ok(()); 24 | } 25 | 26 | // https://github.com/tokio-rs/tokio/issues/4635 27 | #[allow(redundant_semicolons)] 28 | #[rustfmt::skip] 29 | #[tokio::main] 30 | async fn issue_4635() { 31 | return 1; 32 | ; 33 | } 34 | 35 | fn main() {} 36 | -------------------------------------------------------------------------------- /tokio-stream/tests/time_throttle.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "time", feature = "sync", feature = "io-util"))] 3 | 4 | use tokio::time; 5 | use tokio_stream::StreamExt; 6 | use tokio_test::*; 7 | 8 | use std::time::Duration; 9 | 10 | #[tokio::test] 11 | async fn usage() { 12 | time::pause(); 13 | 14 | let mut stream = task::spawn(futures::stream::repeat(()).throttle(Duration::from_millis(100))); 15 | 16 | assert_ready!(stream.poll_next()); 17 | assert_pending!(stream.poll_next()); 18 | 19 | time::advance(Duration::from_millis(90)).await; 20 | 21 | assert_pending!(stream.poll_next()); 22 | 23 | time::advance(Duration::from_millis(101)).await; 24 | 25 | assert!(stream.is_woken()); 26 | 27 | assert_ready!(stream.poll_next()); 28 | } 29 | -------------------------------------------------------------------------------- /tokio/src/future/block_on.rs: -------------------------------------------------------------------------------- 1 | use std::future::Future; 2 | 3 | cfg_rt! { 4 | #[track_caller] 5 | pub(crate) fn block_on(f: F) -> F::Output { 6 | let mut e = crate::runtime::context::try_enter_blocking_region().expect( 7 | "Cannot block the current thread from within a runtime. This \ 8 | happens because a function attempted to block the current \ 9 | thread while the thread is being used to drive asynchronous \ 10 | tasks." 11 | ); 12 | e.block_on(f).unwrap() 13 | } 14 | } 15 | 16 | cfg_not_rt! { 17 | #[track_caller] 18 | pub(crate) fn block_on(f: F) -> F::Output { 19 | let mut park = crate::runtime::park::CachedParkThread::new(); 20 | park.block_on(f).unwrap() 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tokio/src/runtime/blocking/mod.rs: -------------------------------------------------------------------------------- 1 | //! Abstracts out the APIs necessary to `Runtime` for integrating the blocking 2 | //! pool. When the `blocking` feature flag is **not** enabled, these APIs are 3 | //! shells. This isolates the complexity of dealing with conditional 4 | //! compilation. 5 | 6 | mod pool; 7 | pub(crate) use pool::{spawn_blocking, BlockingPool, Spawner}; 8 | 9 | cfg_fs! { 10 | pub(crate) use pool::spawn_mandatory_blocking; 11 | } 12 | 13 | cfg_trace! { 14 | pub(crate) use pool::Mandatory; 15 | } 16 | 17 | mod schedule; 18 | mod shutdown; 19 | mod task; 20 | pub(crate) use task::BlockingTask; 21 | 22 | use crate::runtime::Builder; 23 | 24 | pub(crate) fn create_blocking_pool(builder: &Builder, thread_cap: usize) -> BlockingPool { 25 | BlockingPool::new(builder, thread_cap) 26 | } 27 | -------------------------------------------------------------------------------- /tokio/src/runtime/scheduler/multi_thread/handle/taskdump.rs: -------------------------------------------------------------------------------- 1 | use super::Handle; 2 | 3 | use crate::runtime::Dump; 4 | 5 | impl Handle { 6 | pub(crate) async fn dump(&self) -> Dump { 7 | let trace_status = &self.shared.trace_status; 8 | 9 | // If a dump is in progress, block. 10 | trace_status.start_trace_request(&self).await; 11 | 12 | let result = loop { 13 | if let Some(result) = trace_status.take_result() { 14 | break result; 15 | } else { 16 | self.notify_all(); 17 | trace_status.result_ready.notified().await; 18 | } 19 | }; 20 | 21 | // Allow other queued dumps to proceed. 22 | trace_status.end_trace_request(&self).await; 23 | 24 | result 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tokio/tests/fs_symlink_file_windows.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", not(target_os = "wasi")))] // WASI does not support all fs operations 3 | #![cfg(windows)] 4 | 5 | use tempfile::tempdir; 6 | use tokio::fs; 7 | 8 | #[tokio::test] 9 | async fn symlink_file_windows() { 10 | let dir = tempdir().unwrap(); 11 | 12 | let source_path = dir.path().join("foo.txt"); 13 | let dest_path = dir.path().join("bar.txt"); 14 | 15 | fs::write(&source_path, b"Hello File!").await.unwrap(); 16 | fs::symlink_file(&source_path, &dest_path).await.unwrap(); 17 | 18 | fs::write(&source_path, b"new data!").await.unwrap(); 19 | 20 | let from = fs::read(&source_path).await.unwrap(); 21 | let to = fs::read(&dest_path).await.unwrap(); 22 | 23 | assert_eq!(from, to); 24 | } 25 | -------------------------------------------------------------------------------- /.github/workflows/pr-audit.yml: -------------------------------------------------------------------------------- 1 | name: Pull Request Security Audit 2 | 3 | on: 4 | push: 5 | paths: 6 | - '**/Cargo.toml' 7 | pull_request: 8 | paths: 9 | - '**/Cargo.toml' 10 | 11 | concurrency: 12 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} 13 | cancel-in-progress: true 14 | 15 | permissions: 16 | contents: read 17 | 18 | jobs: 19 | security-audit: 20 | runs-on: ubuntu-latest 21 | if: "!contains(github.event.head_commit.message, 'ci skip')" 22 | steps: 23 | - uses: actions/checkout@v4 24 | 25 | - name: Install cargo-audit 26 | run: cargo install cargo-audit 27 | 28 | - name: Generate lockfile 29 | run: cargo generate-lockfile 30 | 31 | - name: Audit dependencies 32 | run: cargo audit 33 | -------------------------------------------------------------------------------- /tokio/src/runtime/scheduler/multi_thread_alt/handle/taskdump.rs: -------------------------------------------------------------------------------- 1 | use super::Handle; 2 | 3 | use crate::runtime::Dump; 4 | 5 | impl Handle { 6 | pub(crate) async fn dump(&self) -> Dump { 7 | let trace_status = &self.shared.trace_status; 8 | 9 | // If a dump is in progress, block. 10 | trace_status.start_trace_request(&self).await; 11 | 12 | let result = loop { 13 | if let Some(result) = trace_status.take_result() { 14 | break result; 15 | } else { 16 | self.notify_all(); 17 | trace_status.result_ready.notified().await; 18 | } 19 | }; 20 | 21 | // Allow other queued dumps to proceed. 22 | trace_status.end_trace_request(&self).await; 23 | 24 | result 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tokio/src/fs/copy.rs: -------------------------------------------------------------------------------- 1 | use crate::fs::asyncify; 2 | use std::path::Path; 3 | 4 | /// Copies the contents of one file to another. This function will also copy the permission bits 5 | /// of the original file to the destination file. 6 | /// This function will overwrite the contents of to. 7 | /// 8 | /// This is the async equivalent of [`std::fs::copy`]. 9 | /// 10 | /// # Examples 11 | /// 12 | /// ```no_run 13 | /// use tokio::fs; 14 | /// 15 | /// # async fn dox() -> std::io::Result<()> { 16 | /// fs::copy("foo.txt", "bar.txt").await?; 17 | /// # Ok(()) 18 | /// # } 19 | /// ``` 20 | 21 | pub async fn copy(from: impl AsRef, to: impl AsRef) -> Result { 22 | let from = from.as_ref().to_owned(); 23 | let to = to.as_ref().to_owned(); 24 | asyncify(|| std::fs::copy(from, to)).await 25 | } 26 | -------------------------------------------------------------------------------- /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | 2 | R-loom-sync: 3 | - tokio/src/sync/* 4 | - tokio/src/sync/**/* 5 | 6 | R-loom-time-driver: 7 | - tokio/src/runtime/time/* 8 | - tokio/src/runtime/time/**/* 9 | 10 | R-loom-current-thread: 11 | - tokio/src/runtime/scheduler/* 12 | - tokio/src/runtime/scheduler/current_thread/* 13 | - tokio/src/runtime/task/* 14 | - tokio/src/runtime/task/** 15 | 16 | R-loom-multi-thread: 17 | - tokio/src/runtime/scheduler/* 18 | - tokio/src/runtime/scheduler/multi_thread/* 19 | - tokio/src/runtime/scheduler/multi_thread/** 20 | - tokio/src/runtime/task/* 21 | - tokio/src/runtime/task/** 22 | 23 | R-loom-multi-thread-alt: 24 | - tokio/src/runtime/scheduler/* 25 | - tokio/src/runtime/scheduler/multi_thread_alt/* 26 | - tokio/src/runtime/scheduler/multi_thread_alt/** 27 | - tokio/src/runtime/task/* 28 | - tokio/src/runtime/task/** 29 | -------------------------------------------------------------------------------- /tests-build/tests/macros.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn compile_fail_full() { 3 | let t = trybuild::TestCases::new(); 4 | 5 | #[cfg(feature = "full")] 6 | t.pass("tests/pass/forward_args_and_output.rs"); 7 | 8 | #[cfg(feature = "full")] 9 | t.pass("tests/pass/macros_main_return.rs"); 10 | 11 | #[cfg(feature = "full")] 12 | t.pass("tests/pass/macros_main_loop.rs"); 13 | 14 | #[cfg(feature = "full")] 15 | t.compile_fail("tests/fail/macros_invalid_input.rs"); 16 | 17 | #[cfg(feature = "full")] 18 | t.compile_fail("tests/fail/macros_dead_code.rs"); 19 | 20 | #[cfg(feature = "full")] 21 | t.compile_fail("tests/fail/macros_type_mismatch.rs"); 22 | 23 | #[cfg(all(feature = "rt", not(feature = "full")))] 24 | t.compile_fail("tests/fail/macros_core_no_default.rs"); 25 | 26 | drop(t); 27 | } 28 | -------------------------------------------------------------------------------- /tokio/tests/signal_panic.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(unix)] 4 | #![cfg(panic = "unwind")] 5 | 6 | use std::error::Error; 7 | use tokio::runtime::Builder; 8 | use tokio::signal::unix::{signal, SignalKind}; 9 | 10 | mod support { 11 | pub mod panic; 12 | } 13 | use support::panic::test_panic; 14 | 15 | #[test] 16 | fn signal_panic_caller() -> Result<(), Box> { 17 | let panic_location_file = test_panic(|| { 18 | let rt = Builder::new_current_thread().build().unwrap(); 19 | 20 | rt.block_on(async { 21 | let kind = SignalKind::from_raw(-1); 22 | let _ = signal(kind); 23 | }); 24 | }); 25 | 26 | // The panic location should be in this file 27 | assert_eq!(&panic_location_file.unwrap(), file!()); 28 | 29 | Ok(()) 30 | } 31 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | ## Examples of how to use Tokio 2 | 3 | This directory contains a number of examples showcasing various capabilities of 4 | the `tokio` crate. 5 | 6 | All examples can be executed with: 7 | 8 | ``` 9 | cargo run --example $name 10 | ``` 11 | 12 | A good starting point for the examples would be [`hello_world`](hello_world.rs) 13 | and [`echo`](echo.rs). Additionally [the tokio website][tokioweb] contains 14 | additional guides for some of the examples. 15 | 16 | For a larger "real world" example, see the [`mini-redis`][redis] repository. 17 | 18 | If you've got an example you'd like to see here, please feel free to open an 19 | issue. Otherwise if you've got an example you'd like to add, please feel free 20 | to make a PR! 21 | 22 | [tokioweb]: https://tokio.rs/tokio/tutorial 23 | [redis]: https://github.com/tokio-rs/mini-redis 24 | -------------------------------------------------------------------------------- /tokio/src/macros/trace.rs: -------------------------------------------------------------------------------- 1 | cfg_trace! { 2 | macro_rules! trace_op { 3 | ($name:expr, $readiness:literal) => { 4 | tracing::trace!( 5 | target: "runtime::resource::poll_op", 6 | op_name = $name, 7 | is_ready = $readiness 8 | ); 9 | } 10 | } 11 | 12 | macro_rules! trace_poll_op { 13 | ($name:expr, $poll:expr $(,)*) => { 14 | match $poll { 15 | std::task::Poll::Ready(t) => { 16 | trace_op!($name, true); 17 | std::task::Poll::Ready(t) 18 | } 19 | std::task::Poll::Pending => { 20 | trace_op!($name, false); 21 | return std::task::Poll::Pending; 22 | } 23 | } 24 | }; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tokio/tests/macros_rename_test.rs: -------------------------------------------------------------------------------- 1 | #![cfg(all(feature = "full", not(target_os = "wasi")))] // Wasi doesn't support threading 2 | 3 | #[allow(unused_imports)] 4 | use std as tokio; 5 | 6 | use ::tokio as tokio1; 7 | 8 | mod test { 9 | pub use ::tokio; 10 | } 11 | 12 | async fn compute() -> usize { 13 | let join = tokio1::spawn(async { 1 }); 14 | join.await.unwrap() 15 | } 16 | 17 | #[tokio1::main(crate = "tokio1")] 18 | async fn compute_main() -> usize { 19 | compute().await 20 | } 21 | 22 | #[test] 23 | fn crate_rename_main() { 24 | assert_eq!(1, compute_main()); 25 | } 26 | 27 | #[tokio1::test(crate = "tokio1")] 28 | async fn crate_rename_test() { 29 | assert_eq!(1, compute().await); 30 | } 31 | 32 | #[test::tokio::test(crate = "test::tokio")] 33 | async fn crate_path_test() { 34 | assert_eq!(1, compute().await); 35 | } 36 | -------------------------------------------------------------------------------- /tokio-util/tests/context.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "rt")] 2 | #![cfg(not(target_os = "wasi"))] // Wasi doesn't support threads 3 | #![warn(rust_2018_idioms)] 4 | 5 | use tokio::runtime::Builder; 6 | use tokio::time::*; 7 | use tokio_util::context::RuntimeExt; 8 | 9 | #[test] 10 | fn tokio_context_with_another_runtime() { 11 | let rt1 = Builder::new_multi_thread() 12 | .worker_threads(1) 13 | // no timer! 14 | .build() 15 | .unwrap(); 16 | let rt2 = Builder::new_multi_thread() 17 | .worker_threads(1) 18 | .enable_all() 19 | .build() 20 | .unwrap(); 21 | 22 | // Without the `HandleExt.wrap()` there would be a panic because there is 23 | // no timer running, since it would be referencing runtime r1. 24 | rt1.block_on(rt2.wrap(async move { sleep(Duration::from_millis(2)).await })); 25 | } 26 | -------------------------------------------------------------------------------- /tokio-macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tokio-macros" 3 | # When releasing to crates.io: 4 | # - Remove path dependencies 5 | # - Update CHANGELOG.md. 6 | # - Create "tokio-macros-1.x.y" git tag. 7 | version = "2.2.0" 8 | edition = "2021" 9 | rust-version = "1.63" 10 | authors = ["Tokio Contributors "] 11 | license = "MIT" 12 | repository = "https://github.com/tokio-rs/tokio" 13 | homepage = "https://tokio.rs" 14 | description = """ 15 | Tokio's proc macros. 16 | """ 17 | categories = ["asynchronous"] 18 | 19 | [lib] 20 | proc-macro = true 21 | 22 | [features] 23 | 24 | [dependencies] 25 | proc-macro2 = "1.0.60" 26 | quote = "1" 27 | syn = { version = "2.0", features = ["full"] } 28 | 29 | [dev-dependencies] 30 | tokio = { version = "1.0.0", path = "../tokio", features = ["full"] } 31 | 32 | [package.metadata.docs.rs] 33 | all-features = true 34 | -------------------------------------------------------------------------------- /tokio/src/util/sync_wrapper.rs: -------------------------------------------------------------------------------- 1 | //! This module contains a type that can make `Send + !Sync` types `Sync` by 2 | //! disallowing all immutable access to the value. 3 | //! 4 | //! A similar primitive is provided in the `sync_wrapper` crate. 5 | 6 | pub(crate) struct SyncWrapper { 7 | value: T, 8 | } 9 | 10 | // safety: The SyncWrapper being send allows you to send the inner value across 11 | // thread boundaries. 12 | unsafe impl Send for SyncWrapper {} 13 | 14 | // safety: An immutable reference to a SyncWrapper is useless, so moving such an 15 | // immutable reference across threads is safe. 16 | unsafe impl Sync for SyncWrapper {} 17 | 18 | impl SyncWrapper { 19 | pub(crate) fn new(value: T) -> Self { 20 | Self { value } 21 | } 22 | 23 | pub(crate) fn into_inner(self) -> T { 24 | self.value 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.github/workflows/audit.yml: -------------------------------------------------------------------------------- 1 | name: Security Audit 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths: 8 | - '**/Cargo.toml' 9 | schedule: 10 | - cron: '0 2 * * *' # run at 2 AM UTC 11 | 12 | permissions: 13 | contents: read 14 | 15 | jobs: 16 | security-audit: 17 | permissions: 18 | checks: write # for rustsec/audit-check to create check 19 | contents: read # for actions/checkout to fetch code 20 | issues: write # for rustsec/audit-check to create issues 21 | runs-on: ubuntu-latest 22 | if: "!contains(github.event.head_commit.message, 'ci skip')" 23 | steps: 24 | - uses: actions/checkout@v4 25 | 26 | - name: Audit Check 27 | # https://github.com/rustsec/audit-check/issues/2 28 | uses: rustsec/audit-check@master 29 | with: 30 | token: ${{ secrets.GITHUB_TOKEN }} 31 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 12 | 13 | ## Motivation 14 | 15 | 20 | 21 | ## Solution 22 | 23 | 27 | -------------------------------------------------------------------------------- /tokio/tests/io_util_empty.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "full")] 2 | use tokio::io::{AsyncBufReadExt, AsyncReadExt}; 3 | 4 | #[tokio::test] 5 | async fn empty_read_is_cooperative() { 6 | tokio::select! { 7 | biased; 8 | 9 | _ = async { 10 | loop { 11 | let mut buf = [0u8; 4096]; 12 | let _ = tokio::io::empty().read(&mut buf).await; 13 | } 14 | } => {}, 15 | _ = tokio::task::yield_now() => {} 16 | } 17 | } 18 | 19 | #[tokio::test] 20 | async fn empty_buf_reads_are_cooperative() { 21 | tokio::select! { 22 | biased; 23 | 24 | _ = async { 25 | loop { 26 | let mut buf = String::new(); 27 | let _ = tokio::io::empty().read_line(&mut buf).await; 28 | } 29 | } => {}, 30 | _ = tokio::task::yield_now() => {} 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tokio/src/macros/addr_of.rs: -------------------------------------------------------------------------------- 1 | //! This module defines a macro that lets you go from a raw pointer to a struct 2 | //! to a raw pointer to a field of the struct. 3 | 4 | macro_rules! generate_addr_of_methods { 5 | ( 6 | impl<$($gen:ident)*> $struct_name:ty {$( 7 | $(#[$attrs:meta])* 8 | $vis:vis unsafe fn $fn_name:ident(self: NonNull) -> NonNull<$field_type:ty> { 9 | &self$(.$field_name:tt)+ 10 | } 11 | )*} 12 | ) => { 13 | impl<$($gen)*> $struct_name {$( 14 | $(#[$attrs])* 15 | $vis unsafe fn $fn_name(me: ::core::ptr::NonNull) -> ::core::ptr::NonNull<$field_type> { 16 | let me = me.as_ptr(); 17 | let field = ::std::ptr::addr_of_mut!((*me) $(.$field_name)+ ); 18 | ::core::ptr::NonNull::new_unchecked(field) 19 | } 20 | )*} 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /tokio/tests/signal_drop_signal.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(unix)] 4 | 5 | mod support { 6 | pub mod signal; 7 | } 8 | use support::signal::send_signal; 9 | 10 | use tokio::signal::unix::{signal, SignalKind}; 11 | 12 | #[tokio::test] 13 | async fn dropping_signal_does_not_deregister_any_other_instances() { 14 | let kind = SignalKind::user_defined1(); 15 | 16 | // Signals should not starve based on ordering 17 | let first_duplicate_signal = signal(kind).expect("failed to register first duplicate signal"); 18 | let mut sig = signal(kind).expect("failed to register signal"); 19 | let second_duplicate_signal = signal(kind).expect("failed to register second duplicate signal"); 20 | 21 | drop(first_duplicate_signal); 22 | drop(second_duplicate_signal); 23 | 24 | send_signal(libc::SIGUSR1); 25 | let _ = sig.recv().await; 26 | } 27 | -------------------------------------------------------------------------------- /tests-integration/tests/rt_yield.rs: -------------------------------------------------------------------------------- 1 | use tokio::sync::oneshot; 2 | use tokio::task; 3 | 4 | async fn spawn_send() { 5 | let (tx, rx) = oneshot::channel(); 6 | 7 | let task = tokio::spawn(async { 8 | for _ in 0..10 { 9 | task::yield_now().await; 10 | } 11 | 12 | tx.send("done").unwrap(); 13 | }); 14 | 15 | assert_eq!("done", rx.await.unwrap()); 16 | task.await.unwrap(); 17 | } 18 | 19 | #[tokio::main(flavor = "current_thread")] 20 | async fn entry_point() { 21 | spawn_send().await; 22 | } 23 | 24 | #[tokio::test] 25 | async fn test_macro() { 26 | spawn_send().await; 27 | } 28 | 29 | #[test] 30 | fn main_macro() { 31 | entry_point(); 32 | } 33 | 34 | #[test] 35 | fn manual_rt() { 36 | let rt = tokio::runtime::Builder::new_current_thread() 37 | .build() 38 | .unwrap(); 39 | 40 | rt.block_on(async { spawn_send().await }); 41 | } 42 | -------------------------------------------------------------------------------- /tokio-util/src/sync/cancellation_token/guard.rs: -------------------------------------------------------------------------------- 1 | use crate::sync::CancellationToken; 2 | 3 | /// A wrapper for cancellation token which automatically cancels 4 | /// it on drop. It is created using `drop_guard` method on the `CancellationToken`. 5 | #[derive(Debug)] 6 | pub struct DropGuard { 7 | pub(super) inner: Option, 8 | } 9 | 10 | impl DropGuard { 11 | /// Returns stored cancellation token and removes this drop guard instance 12 | /// (i.e. it will no longer cancel token). Other guards for this token 13 | /// are not affected. 14 | pub fn disarm(mut self) -> CancellationToken { 15 | self.inner 16 | .take() 17 | .expect("`inner` can be only None in a destructor") 18 | } 19 | } 20 | 21 | impl Drop for DropGuard { 22 | fn drop(&mut self) { 23 | if let Some(inner) = &self.inner { 24 | inner.cancel(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tokio/tests/fs_rename.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", not(target_os = "wasi")))] // WASI does not support all fs operations 3 | 4 | use tempfile::tempdir; 5 | use tokio::fs; 6 | 7 | #[tokio::test] 8 | async fn rename_file() { 9 | let temp_dir = tempdir().unwrap(); 10 | 11 | let file_path = temp_dir.path().join("a.txt"); 12 | 13 | fs::write(&file_path, b"Hello File!").await.unwrap(); 14 | 15 | assert!(fs::try_exists(&file_path).await.unwrap()); 16 | 17 | let new_file_path = temp_dir.path().join("b.txt"); 18 | 19 | fs::rename(&file_path, &new_file_path).await.unwrap(); 20 | 21 | assert!(fs::try_exists(new_file_path).await.unwrap()); 22 | 23 | // original file should no longer exist 24 | match fs::try_exists(file_path).await { 25 | Ok(exists) => assert!(!exists), 26 | Err(_) => println!("ignored try_exists error after rename"), 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /tokio/src/util/error.rs: -------------------------------------------------------------------------------- 1 | // Some combinations of features may not use these constants. 2 | #![cfg_attr(not(feature = "full"), allow(dead_code))] 3 | 4 | /// Error string explaining that the Tokio context hasn't been instantiated. 5 | pub(crate) const CONTEXT_MISSING_ERROR: &str = 6 | "there is no reactor running, must be called from the context of a Tokio 1.x runtime"; 7 | 8 | /// Error string explaining that the Tokio context is shutting down and cannot drive timers. 9 | pub(crate) const RUNTIME_SHUTTING_DOWN_ERROR: &str = 10 | "A Tokio 1.x context was found, but it is being shutdown."; 11 | 12 | /// Error string explaining that the Tokio context is not available because the 13 | /// thread-local storing it has been destroyed. This usually only happens during 14 | /// destructors of other thread-locals. 15 | pub(crate) const THREAD_LOCAL_DESTROYED_ERROR: &str = 16 | "The Tokio context thread-local variable has been destroyed."; 17 | -------------------------------------------------------------------------------- /tokio/src/runtime/tests/loom_multi_thread/shutdown.rs: -------------------------------------------------------------------------------- 1 | use crate::runtime::{Builder, Handle}; 2 | 3 | #[test] 4 | fn join_handle_cancel_on_shutdown() { 5 | let mut builder = loom::model::Builder::new(); 6 | builder.preemption_bound = Some(2); 7 | builder.check(|| { 8 | use futures::future::FutureExt; 9 | 10 | let rt = Builder::new_multi_thread() 11 | .worker_threads(2) 12 | .build() 13 | .unwrap(); 14 | 15 | let handle = rt.block_on(async move { Handle::current() }); 16 | 17 | let jh1 = handle.spawn(futures::future::pending::<()>()); 18 | 19 | drop(rt); 20 | 21 | let jh2 = handle.spawn(futures::future::pending::<()>()); 22 | 23 | let err1 = jh1.now_or_never().unwrap().unwrap_err(); 24 | let err2 = jh2.now_or_never().unwrap().unwrap_err(); 25 | assert!(err1.is_cancelled()); 26 | assert!(err2.is_cancelled()); 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /tokio/src/runtime/tests/loom_multi_thread_alt/shutdown.rs: -------------------------------------------------------------------------------- 1 | use crate::runtime::{Builder, Handle}; 2 | 3 | #[test] 4 | fn join_handle_cancel_on_shutdown() { 5 | let mut builder = loom::model::Builder::new(); 6 | builder.preemption_bound = Some(2); 7 | builder.check(|| { 8 | use futures::future::FutureExt; 9 | 10 | let rt = Builder::new_multi_thread() 11 | .worker_threads(2) 12 | .build() 13 | .unwrap(); 14 | 15 | let handle = rt.block_on(async move { Handle::current() }); 16 | 17 | let jh1 = handle.spawn(futures::future::pending::<()>()); 18 | 19 | drop(rt); 20 | 21 | let jh2 = handle.spawn(futures::future::pending::<()>()); 22 | 23 | let err1 = jh1.now_or_never().unwrap().unwrap_err(); 24 | let err2 = jh2.now_or_never().unwrap().unwrap_err(); 25 | assert!(err1.is_cancelled()); 26 | assert!(err2.is_cancelled()); 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /tokio/tests/support/leaked_buffers.rs: -------------------------------------------------------------------------------- 1 | /// Can create buffers of arbitrary lifetime. 2 | /// Frees created buffers when dropped. 3 | /// 4 | /// This struct is of course unsafe and the fact that 5 | /// it must outlive the created slices has to be ensured by 6 | /// the programmer. 7 | /// 8 | /// Used at certain test scenarios as a safer version of 9 | /// Vec::leak, to satisfy the address sanitizer. 10 | pub struct LeakedBuffers { 11 | leaked_vecs: Vec>, 12 | } 13 | 14 | impl LeakedBuffers { 15 | pub fn new() -> Self { 16 | Self { 17 | leaked_vecs: vec![], 18 | } 19 | } 20 | pub unsafe fn create<'a>(&mut self, size: usize) -> &'a mut [u8] { 21 | let new_mem = vec![0u8; size].into_boxed_slice(); 22 | self.leaked_vecs.push(new_mem); 23 | let new_mem = self.leaked_vecs.last_mut().unwrap(); 24 | std::slice::from_raw_parts_mut(new_mem.as_mut_ptr(), new_mem.len()) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tokio/src/net/unix/socketaddr.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::path::Path; 3 | 4 | /// An address associated with a Tokio Unix socket. 5 | pub struct SocketAddr(pub(super) mio::net::SocketAddr); 6 | 7 | impl SocketAddr { 8 | /// Returns `true` if the address is unnamed. 9 | /// 10 | /// Documentation reflected in [`SocketAddr`] 11 | /// 12 | /// [`SocketAddr`]: std::os::unix::net::SocketAddr 13 | pub fn is_unnamed(&self) -> bool { 14 | self.0.is_unnamed() 15 | } 16 | 17 | /// Returns the contents of this address if it is a `pathname` address. 18 | /// 19 | /// Documentation reflected in [`SocketAddr`] 20 | /// 21 | /// [`SocketAddr`]: std::os::unix::net::SocketAddr 22 | pub fn as_pathname(&self) -> Option<&Path> { 23 | self.0.as_pathname() 24 | } 25 | } 26 | 27 | impl fmt::Debug for SocketAddr { 28 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 29 | self.0.fmt(fmt) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tokio/tests/fs_symlink_dir_windows.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", not(target_os = "wasi")))] // WASI does not support all fs operations 3 | #![cfg(windows)] 4 | 5 | use tempfile::tempdir; 6 | use tokio::fs; 7 | 8 | #[tokio::test] 9 | async fn symlink_file_windows() { 10 | const FILE_NAME: &str = "abc.txt"; 11 | 12 | let temp_dir = tempdir().unwrap(); 13 | 14 | let dir1 = temp_dir.path().join("a"); 15 | fs::create_dir(&dir1).await.unwrap(); 16 | 17 | let file1 = dir1.as_path().join(FILE_NAME); 18 | fs::write(&file1, b"Hello File!").await.unwrap(); 19 | 20 | let dir2 = temp_dir.path().join("b"); 21 | fs::symlink_dir(&dir1, &dir2).await.unwrap(); 22 | 23 | fs::write(&file1, b"new data!").await.unwrap(); 24 | 25 | let file2 = dir2.as_path().join(FILE_NAME); 26 | 27 | let from = fs::read(&file1).await.unwrap(); 28 | let to = fs::read(&file2).await.unwrap(); 29 | 30 | assert_eq!(from, to); 31 | } 32 | -------------------------------------------------------------------------------- /examples/hello_world.rs: -------------------------------------------------------------------------------- 1 | //! A simple client that opens a TCP stream, writes "hello world\n", and closes 2 | //! the connection. 3 | //! 4 | //! To start a server that this client can talk to on port 6142, you can use this command: 5 | //! 6 | //! ncat -l 6142 7 | //! 8 | //! And then in another terminal run: 9 | //! 10 | //! cargo run --example hello_world 11 | 12 | #![warn(rust_2018_idioms)] 13 | 14 | use tokio::io::AsyncWriteExt; 15 | use tokio::net::TcpStream; 16 | 17 | use std::error::Error; 18 | 19 | #[tokio::main] 20 | pub async fn main() -> Result<(), Box> { 21 | // Open a TCP stream to the socket address. 22 | // 23 | // Note that this is the Tokio TcpStream, which is fully async. 24 | let mut stream = TcpStream::connect("127.0.0.1:6142").await?; 25 | println!("created stream"); 26 | 27 | let result = stream.write_all(b"hello world\n").await; 28 | println!("wrote to stream; success={:?}", result.is_ok()); 29 | 30 | Ok(()) 31 | } 32 | -------------------------------------------------------------------------------- /tokio/tests/tcp_shutdown.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", not(target_os = "wasi")))] // Wasi doesn't support bind 3 | 4 | use tokio::io::{self, AsyncReadExt, AsyncWriteExt}; 5 | use tokio::net::{TcpListener, TcpStream}; 6 | use tokio_test::assert_ok; 7 | 8 | #[tokio::test] 9 | async fn shutdown() { 10 | let srv = assert_ok!(TcpListener::bind("127.0.0.1:0").await); 11 | let addr = assert_ok!(srv.local_addr()); 12 | 13 | tokio::spawn(async move { 14 | let mut stream = assert_ok!(TcpStream::connect(&addr).await); 15 | 16 | assert_ok!(AsyncWriteExt::shutdown(&mut stream).await); 17 | 18 | let mut buf = [0u8; 1]; 19 | let n = assert_ok!(stream.read(&mut buf).await); 20 | assert_eq!(n, 0); 21 | }); 22 | 23 | let (mut stream, _) = assert_ok!(srv.accept().await); 24 | let (mut rd, mut wr) = stream.split(); 25 | 26 | let n = assert_ok!(io::copy(&mut rd, &mut wr).await); 27 | assert_eq!(n, 0); 28 | } 29 | -------------------------------------------------------------------------------- /target-specs/i686-unknown-linux-gnu.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "x86", 3 | "cpu": "pentium4", 4 | "crt-static-respected": true, 5 | "data-layout": "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128", 6 | "dynamic-linking": true, 7 | "env": "gnu", 8 | "has-rpath": true, 9 | "has-thread-local": true, 10 | "llvm-target": "i686-unknown-linux-gnu", 11 | "max-atomic-width": 32, 12 | "os": "linux", 13 | "position-independent-executables": true, 14 | "pre-link-args": { 15 | "gcc": [ 16 | "-m32" 17 | ] 18 | }, 19 | "relro-level": "full", 20 | "stack-probes": { 21 | "kind": "inline-or-call", 22 | "min-llvm-version-for-inline": [ 23 | 16, 24 | 0, 25 | 0 26 | ] 27 | }, 28 | "supported-sanitizers": [ 29 | "address" 30 | ], 31 | "supported-split-debuginfo": [ 32 | "packed", 33 | "unpacked", 34 | "off" 35 | ], 36 | "target-family": [ 37 | "unix" 38 | ], 39 | "target-pointer-width": "32" 40 | } 41 | -------------------------------------------------------------------------------- /tokio/src/runtime/thread_id.rs: -------------------------------------------------------------------------------- 1 | use std::num::NonZeroU64; 2 | 3 | #[derive(Eq, PartialEq, Clone, Copy, Hash, Debug)] 4 | pub(crate) struct ThreadId(NonZeroU64); 5 | 6 | impl ThreadId { 7 | pub(crate) fn next() -> Self { 8 | use crate::loom::sync::atomic::{Ordering::Relaxed, StaticAtomicU64}; 9 | 10 | static NEXT_ID: StaticAtomicU64 = StaticAtomicU64::new(0); 11 | 12 | let mut last = NEXT_ID.load(Relaxed); 13 | loop { 14 | let id = match last.checked_add(1) { 15 | Some(id) => id, 16 | None => exhausted(), 17 | }; 18 | 19 | match NEXT_ID.compare_exchange_weak(last, id, Relaxed, Relaxed) { 20 | Ok(_) => return ThreadId(NonZeroU64::new(id).unwrap()), 21 | Err(id) => last = id, 22 | } 23 | } 24 | } 25 | } 26 | 27 | #[cold] 28 | #[allow(dead_code)] 29 | fn exhausted() -> ! { 30 | panic!("failed to generate unique thread ID: bitspace exhausted") 31 | } 32 | -------------------------------------------------------------------------------- /tokio/tests/tcp_peek.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", not(target_os = "wasi")))] // Wasi doesn't support bind 3 | 4 | use tokio::io::AsyncReadExt; 5 | use tokio::net::TcpStream; 6 | 7 | use tokio_test::assert_ok; 8 | 9 | use std::thread; 10 | use std::{io::Write, net}; 11 | 12 | #[tokio::test] 13 | async fn peek() { 14 | let listener = net::TcpListener::bind("127.0.0.1:0").unwrap(); 15 | let addr = listener.local_addr().unwrap(); 16 | let t = thread::spawn(move || assert_ok!(listener.accept()).0); 17 | 18 | let left = net::TcpStream::connect(addr).unwrap(); 19 | let mut right = t.join().unwrap(); 20 | let _ = right.write(&[1, 2, 3, 4]).unwrap(); 21 | 22 | let mut left: TcpStream = left.try_into().unwrap(); 23 | let mut buf = [0u8; 16]; 24 | let n = assert_ok!(left.peek(&mut buf).await); 25 | assert_eq!([1, 2, 3, 4], buf[..n]); 26 | 27 | let n = assert_ok!(left.read(&mut buf).await); 28 | assert_eq!([1, 2, 3, 4], buf[..n]); 29 | } 30 | -------------------------------------------------------------------------------- /tokio-util/src/codec/encoder.rs: -------------------------------------------------------------------------------- 1 | use bytes::BytesMut; 2 | use std::io; 3 | 4 | /// Trait of helper objects to write out messages as bytes, for use with 5 | /// [`FramedWrite`]. 6 | /// 7 | /// [`FramedWrite`]: crate::codec::FramedWrite 8 | pub trait Encoder { 9 | /// The type of encoding errors. 10 | /// 11 | /// [`FramedWrite`] requires `Encoder`s errors to implement `From` 12 | /// in the interest letting it return `Error`s directly. 13 | /// 14 | /// [`FramedWrite`]: crate::codec::FramedWrite 15 | type Error: From; 16 | 17 | /// Encodes a frame into the buffer provided. 18 | /// 19 | /// This method will encode `item` into the byte buffer provided by `dst`. 20 | /// The `dst` provided is an internal buffer of the [`FramedWrite`] instance and 21 | /// will be written out when possible. 22 | /// 23 | /// [`FramedWrite`]: crate::codec::FramedWrite 24 | fn encode(&mut self, item: Item, dst: &mut BytesMut) -> Result<(), Self::Error>; 25 | } 26 | -------------------------------------------------------------------------------- /tokio/src/fs/write.rs: -------------------------------------------------------------------------------- 1 | use crate::fs::asyncify; 2 | 3 | use std::{io, path::Path}; 4 | 5 | /// Creates a future that will open a file for writing and write the entire 6 | /// contents of `contents` to it. 7 | /// 8 | /// This is the async equivalent of [`std::fs::write`][std]. 9 | /// 10 | /// This operation is implemented by running the equivalent blocking operation 11 | /// on a separate thread pool using [`spawn_blocking`]. 12 | /// 13 | /// [`spawn_blocking`]: crate::task::spawn_blocking 14 | /// [std]: fn@std::fs::write 15 | /// 16 | /// # Examples 17 | /// 18 | /// ```no_run 19 | /// use tokio::fs; 20 | /// 21 | /// # async fn dox() -> std::io::Result<()> { 22 | /// fs::write("foo.txt", b"Hello world!").await?; 23 | /// # Ok(()) 24 | /// # } 25 | /// ``` 26 | pub async fn write(path: impl AsRef, contents: impl AsRef<[u8]>) -> io::Result<()> { 27 | let path = path.as_ref().to_owned(); 28 | let contents = contents.as_ref().to_owned(); 29 | 30 | asyncify(move || std::fs::write(path, contents)).await 31 | } 32 | -------------------------------------------------------------------------------- /tokio/tests/io_fill_buf.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", not(target_os = "wasi")))] // Wasi does not support file operations 3 | 4 | use tempfile::NamedTempFile; 5 | use tokio::fs::File; 6 | use tokio::io::{AsyncBufReadExt, BufReader}; 7 | use tokio_test::assert_ok; 8 | 9 | #[tokio::test] 10 | async fn fill_buf_file() { 11 | let file = NamedTempFile::new().unwrap(); 12 | 13 | assert_ok!(std::fs::write(file.path(), b"hello")); 14 | 15 | let file = assert_ok!(File::open(file.path()).await); 16 | let mut file = BufReader::new(file); 17 | 18 | let mut contents = Vec::new(); 19 | 20 | loop { 21 | let consumed = { 22 | let buffer = assert_ok!(file.fill_buf().await); 23 | if buffer.is_empty() { 24 | break; 25 | } 26 | contents.extend_from_slice(buffer); 27 | buffer.len() 28 | }; 29 | 30 | file.consume(consumed); 31 | } 32 | 33 | assert_eq!(contents, b"hello"); 34 | } 35 | -------------------------------------------------------------------------------- /tokio/tests/process_smoke.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", not(target_os = "wasi")))] // Wasi cannot run system commands 3 | 4 | use tokio::process::Command; 5 | use tokio_test::assert_ok; 6 | 7 | #[tokio::test] 8 | async fn simple() { 9 | let mut cmd; 10 | 11 | if cfg!(windows) { 12 | cmd = Command::new("cmd"); 13 | cmd.arg("/c"); 14 | } else { 15 | cmd = Command::new("sh"); 16 | cmd.arg("-c"); 17 | } 18 | 19 | let mut child = cmd.arg("exit 2").spawn().unwrap(); 20 | 21 | let id = child.id().expect("missing id"); 22 | assert!(id > 0); 23 | 24 | let status = assert_ok!(child.wait().await); 25 | assert_eq!(status.code(), Some(2)); 26 | 27 | // test that the `.wait()` method is fused just like the stdlib 28 | let status = assert_ok!(child.wait().await); 29 | assert_eq!(status.code(), Some(2)); 30 | 31 | // Can't get id after process has exited 32 | assert_eq!(child.id(), None); 33 | drop(child.kill()); 34 | } 35 | -------------------------------------------------------------------------------- /tokio-test/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tokio-test" 3 | # When releasing to crates.io: 4 | # - Remove path dependencies 5 | # - Update CHANGELOG.md. 6 | # - Create "tokio-test-0.4.x" git tag. 7 | version = "0.4.3" 8 | edition = "2021" 9 | rust-version = "1.63" 10 | authors = ["Tokio Contributors "] 11 | license = "MIT" 12 | repository = "https://github.com/tokio-rs/tokio" 13 | homepage = "https://tokio.rs" 14 | description = """ 15 | Testing utilities for Tokio- and futures-based code 16 | """ 17 | categories = ["asynchronous", "development-tools::testing"] 18 | 19 | [dependencies] 20 | tokio = { version = "1.2.0", path = "../tokio", features = ["rt", "sync", "time", "test-util"] } 21 | tokio-stream = { version = "0.1.1", path = "../tokio-stream" } 22 | async-stream = "0.3.3" 23 | 24 | bytes = "1.0.0" 25 | futures-core = "0.3.0" 26 | 27 | [dev-dependencies] 28 | tokio = { version = "1.2.0", path = "../tokio", features = ["full"] } 29 | futures-util = "0.3.0" 30 | 31 | [package.metadata.docs.rs] 32 | all-features = true 33 | -------------------------------------------------------------------------------- /tokio-test/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![warn( 2 | missing_debug_implementations, 3 | missing_docs, 4 | rust_2018_idioms, 5 | unreachable_pub 6 | )] 7 | #![doc(test( 8 | no_crate_inject, 9 | attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables)) 10 | ))] 11 | 12 | //! Tokio and Futures based testing utilities 13 | 14 | pub mod io; 15 | pub mod stream_mock; 16 | 17 | mod macros; 18 | pub mod task; 19 | 20 | /// Runs the provided future, blocking the current thread until the 21 | /// future completes. 22 | /// 23 | /// For more information, see the documentation for 24 | /// [`tokio::runtime::Runtime::block_on`][runtime-block-on]. 25 | /// 26 | /// [runtime-block-on]: https://docs.rs/tokio/1.3.0/tokio/runtime/struct.Runtime.html#method.block_on 27 | pub fn block_on(future: F) -> F::Output { 28 | use tokio::runtime; 29 | 30 | let rt = runtime::Builder::new_current_thread() 31 | .enable_all() 32 | .build() 33 | .unwrap(); 34 | 35 | rt.block_on(future) 36 | } 37 | -------------------------------------------------------------------------------- /tokio-util/src/time/wheel/stack.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Borrow; 2 | use std::cmp::Eq; 3 | use std::hash::Hash; 4 | 5 | /// Abstracts the stack operations needed to track timeouts. 6 | pub(crate) trait Stack: Default { 7 | /// Type of the item stored in the stack 8 | type Owned: Borrow; 9 | 10 | /// Borrowed item 11 | type Borrowed: Eq + Hash; 12 | 13 | /// Item storage, this allows a slab to be used instead of just the heap 14 | type Store; 15 | 16 | /// Returns `true` if the stack is empty 17 | fn is_empty(&self) -> bool; 18 | 19 | /// Push an item onto the stack 20 | fn push(&mut self, item: Self::Owned, store: &mut Self::Store); 21 | 22 | /// Pop an item from the stack 23 | fn pop(&mut self, store: &mut Self::Store) -> Option; 24 | 25 | /// Peek into the stack. 26 | fn peek(&self) -> Option; 27 | 28 | fn remove(&mut self, item: &Self::Borrowed, store: &mut Self::Store); 29 | 30 | fn when(item: &Self::Borrowed, store: &Self::Store) -> u64; 31 | } 32 | -------------------------------------------------------------------------------- /tokio/src/fs/read_to_string.rs: -------------------------------------------------------------------------------- 1 | use crate::fs::asyncify; 2 | 3 | use std::{io, path::Path}; 4 | 5 | /// Creates a future which will open a file for reading and read the entire 6 | /// contents into a string and return said string. 7 | /// 8 | /// This is the async equivalent of [`std::fs::read_to_string`][std]. 9 | /// 10 | /// This operation is implemented by running the equivalent blocking operation 11 | /// on a separate thread pool using [`spawn_blocking`]. 12 | /// 13 | /// [`spawn_blocking`]: crate::task::spawn_blocking 14 | /// [std]: fn@std::fs::read_to_string 15 | /// 16 | /// # Examples 17 | /// 18 | /// ```no_run 19 | /// use tokio::fs; 20 | /// 21 | /// # async fn dox() -> std::io::Result<()> { 22 | /// let contents = fs::read_to_string("foo.txt").await?; 23 | /// println!("foo.txt contains {} bytes", contents.len()); 24 | /// # Ok(()) 25 | /// # } 26 | /// ``` 27 | pub async fn read_to_string(path: impl AsRef) -> io::Result { 28 | let path = path.as_ref().to_owned(); 29 | asyncify(move || std::fs::read_to_string(path)).await 30 | } 31 | -------------------------------------------------------------------------------- /tests-integration/tests/macros_select.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "macros")] 2 | 3 | use futures::channel::oneshot; 4 | use futures::executor::block_on; 5 | use std::thread; 6 | 7 | #[cfg_attr(target_os = "wasi", ignore = "WASI: std::thread::spawn not supported")] 8 | #[test] 9 | fn join_with_select() { 10 | block_on(async { 11 | let (tx1, mut rx1) = oneshot::channel::(); 12 | let (tx2, mut rx2) = oneshot::channel::(); 13 | 14 | thread::spawn(move || { 15 | tx1.send(123).unwrap(); 16 | tx2.send(456).unwrap(); 17 | }); 18 | 19 | let mut a = None; 20 | let mut b = None; 21 | 22 | while a.is_none() || b.is_none() { 23 | tokio::select! { 24 | v1 = (&mut rx1), if a.is_none() => a = Some(v1.unwrap()), 25 | v2 = (&mut rx2), if b.is_none() => b = Some(v2.unwrap()), 26 | } 27 | } 28 | 29 | let (a, b) = (a.unwrap(), b.unwrap()); 30 | 31 | assert_eq!(a, 123); 32 | assert_eq!(b, 456); 33 | }); 34 | } 35 | -------------------------------------------------------------------------------- /tokio/tests/fs_remove_dir_all.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", not(target_os = "wasi")))] // WASI does not support all fs operations 3 | 4 | use tempfile::tempdir; 5 | use tokio::fs; 6 | 7 | #[tokio::test] 8 | async fn remove_dir_all() { 9 | let temp_dir = tempdir().unwrap(); 10 | 11 | let test_dir = temp_dir.path().join("test"); 12 | fs::create_dir(&test_dir).await.unwrap(); 13 | 14 | let file_path = test_dir.as_path().join("a.txt"); 15 | 16 | fs::write(&file_path, b"Hello File!").await.unwrap(); 17 | 18 | fs::remove_dir_all(test_dir.as_path()).await.unwrap(); 19 | 20 | // test dir should no longer exist 21 | match fs::try_exists(test_dir).await { 22 | Ok(exists) => assert!(!exists), 23 | Err(_) => println!("ignored try_exists error after remove_dir_all"), 24 | }; 25 | 26 | // contents should no longer exist 27 | match fs::try_exists(file_path).await { 28 | Ok(exists) => assert!(!exists), 29 | Err(_) => println!("ignored try_exists error after remove_dir_all"), 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /tokio/src/net/unix/mod.rs: -------------------------------------------------------------------------------- 1 | //! Unix specific network types. 2 | // This module does not currently provide any public API, but it was 3 | // unintentionally defined as a public module. Hide it from the documentation 4 | // instead of changing it to a private module to avoid breakage. 5 | #[doc(hidden)] 6 | pub mod datagram; 7 | 8 | pub(crate) mod listener; 9 | 10 | pub(crate) mod socket; 11 | 12 | mod split; 13 | pub use split::{ReadHalf, WriteHalf}; 14 | 15 | mod split_owned; 16 | pub use split_owned::{OwnedReadHalf, OwnedWriteHalf, ReuniteError}; 17 | 18 | mod socketaddr; 19 | pub use socketaddr::SocketAddr; 20 | 21 | pub(crate) mod stream; 22 | pub(crate) use stream::UnixStream; 23 | 24 | mod ucred; 25 | pub use ucred::UCred; 26 | 27 | pub mod pipe; 28 | 29 | /// A type representing process and process group IDs. 30 | #[allow(non_camel_case_types)] 31 | pub type uid_t = u32; 32 | 33 | /// A type representing user ID. 34 | #[allow(non_camel_case_types)] 35 | pub type gid_t = u32; 36 | 37 | /// A type representing group ID. 38 | #[allow(non_camel_case_types)] 39 | pub type pid_t = i32; 40 | -------------------------------------------------------------------------------- /tokio/src/loom/std/mutex.rs: -------------------------------------------------------------------------------- 1 | use std::sync::{self, MutexGuard, TryLockError}; 2 | 3 | /// Adapter for `std::Mutex` that removes the poisoning aspects 4 | /// from its api. 5 | #[derive(Debug)] 6 | pub(crate) struct Mutex(sync::Mutex); 7 | 8 | #[allow(dead_code)] 9 | impl Mutex { 10 | #[inline] 11 | pub(crate) fn new(t: T) -> Mutex { 12 | Mutex(sync::Mutex::new(t)) 13 | } 14 | 15 | #[inline] 16 | pub(crate) const fn const_new(t: T) -> Mutex { 17 | Mutex(sync::Mutex::new(t)) 18 | } 19 | 20 | #[inline] 21 | pub(crate) fn lock(&self) -> MutexGuard<'_, T> { 22 | match self.0.lock() { 23 | Ok(guard) => guard, 24 | Err(p_err) => p_err.into_inner(), 25 | } 26 | } 27 | 28 | #[inline] 29 | pub(crate) fn try_lock(&self) -> Option> { 30 | match self.0.try_lock() { 31 | Ok(guard) => Some(guard), 32 | Err(TryLockError::Poisoned(p_err)) => Some(p_err.into_inner()), 33 | Err(TryLockError::WouldBlock) => None, 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tokio-util/tests/io_stream_reader.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | 3 | use bytes::Bytes; 4 | use tokio::io::AsyncReadExt; 5 | use tokio_stream::iter; 6 | use tokio_util::io::StreamReader; 7 | 8 | #[tokio::test] 9 | async fn test_stream_reader() -> std::io::Result<()> { 10 | let stream = iter(vec![ 11 | std::io::Result::Ok(Bytes::from_static(&[])), 12 | Ok(Bytes::from_static(&[0, 1, 2, 3])), 13 | Ok(Bytes::from_static(&[])), 14 | Ok(Bytes::from_static(&[4, 5, 6, 7])), 15 | Ok(Bytes::from_static(&[])), 16 | Ok(Bytes::from_static(&[8, 9, 10, 11])), 17 | Ok(Bytes::from_static(&[])), 18 | ]); 19 | 20 | let mut read = StreamReader::new(stream); 21 | 22 | let mut buf = [0; 5]; 23 | read.read_exact(&mut buf).await?; 24 | assert_eq!(buf, [0, 1, 2, 3, 4]); 25 | 26 | assert_eq!(read.read(&mut buf).await?, 3); 27 | assert_eq!(&buf[..3], [5, 6, 7]); 28 | 29 | assert_eq!(read.read(&mut buf).await?, 4); 30 | assert_eq!(&buf[..4], [8, 9, 10, 11]); 31 | 32 | assert_eq!(read.read(&mut buf).await?, 0); 33 | 34 | Ok(()) 35 | } 36 | -------------------------------------------------------------------------------- /tokio/tests/io_write_int.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | 4 | use tokio::io::{AsyncWrite, AsyncWriteExt}; 5 | 6 | use std::io; 7 | use std::pin::Pin; 8 | use std::task::{Context, Poll}; 9 | 10 | #[tokio::test] 11 | async fn write_int_should_err_if_write_count_0() { 12 | struct Wr {} 13 | 14 | impl AsyncWrite for Wr { 15 | fn poll_write( 16 | self: Pin<&mut Self>, 17 | _cx: &mut Context<'_>, 18 | _buf: &[u8], 19 | ) -> Poll> { 20 | Ok(0).into() 21 | } 22 | 23 | fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { 24 | Ok(()).into() 25 | } 26 | 27 | fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { 28 | Ok(()).into() 29 | } 30 | } 31 | 32 | let mut wr = Wr {}; 33 | 34 | // should be ok just to test these 2, other cases actually expanded by same macro. 35 | assert!(wr.write_i8(0).await.is_err()); 36 | assert!(wr.write_i32(12).await.is_err()); 37 | } 38 | -------------------------------------------------------------------------------- /tokio-util/src/io/mod.rs: -------------------------------------------------------------------------------- 1 | //! Helpers for IO related tasks. 2 | //! 3 | //! The stream types are often used in combination with hyper or reqwest, as they 4 | //! allow converting between a hyper [`Body`] and [`AsyncRead`]. 5 | //! 6 | //! The [`SyncIoBridge`] type converts from the world of async I/O 7 | //! to synchronous I/O; this may often come up when using synchronous APIs 8 | //! inside [`tokio::task::spawn_blocking`]. 9 | //! 10 | //! [`Body`]: https://docs.rs/hyper/0.13/hyper/struct.Body.html 11 | //! [`AsyncRead`]: tokio::io::AsyncRead 12 | 13 | mod copy_to_bytes; 14 | mod inspect; 15 | mod read_buf; 16 | mod reader_stream; 17 | mod sink_writer; 18 | mod stream_reader; 19 | 20 | cfg_io_util! { 21 | mod sync_bridge; 22 | pub use self::sync_bridge::SyncIoBridge; 23 | } 24 | 25 | pub use self::copy_to_bytes::CopyToBytes; 26 | pub use self::inspect::{InspectReader, InspectWriter}; 27 | pub use self::read_buf::read_buf; 28 | pub use self::reader_stream::ReaderStream; 29 | pub use self::sink_writer::SinkWriter; 30 | pub use self::stream_reader::StreamReader; 31 | pub use crate::util::{poll_read_buf, poll_write_buf}; 32 | -------------------------------------------------------------------------------- /tokio/src/runtime/tests/loom_oneshot.rs: -------------------------------------------------------------------------------- 1 | use crate::loom::sync::{Arc, Mutex}; 2 | use loom::sync::Notify; 3 | 4 | pub(crate) fn channel() -> (Sender, Receiver) { 5 | let inner = Arc::new(Inner { 6 | notify: Notify::new(), 7 | value: Mutex::new(None), 8 | }); 9 | 10 | let tx = Sender { 11 | inner: inner.clone(), 12 | }; 13 | let rx = Receiver { inner }; 14 | 15 | (tx, rx) 16 | } 17 | 18 | pub(crate) struct Sender { 19 | inner: Arc>, 20 | } 21 | 22 | pub(crate) struct Receiver { 23 | inner: Arc>, 24 | } 25 | 26 | struct Inner { 27 | notify: Notify, 28 | value: Mutex>, 29 | } 30 | 31 | impl Sender { 32 | pub(crate) fn send(self, value: T) { 33 | *self.inner.value.lock() = Some(value); 34 | self.inner.notify.notify(); 35 | } 36 | } 37 | 38 | impl Receiver { 39 | pub(crate) fn recv(self) -> T { 40 | loop { 41 | if let Some(v) = self.inner.value.lock().take() { 42 | return v; 43 | } 44 | 45 | self.inner.notify.wait(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 Tokio Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tokio/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 Tokio Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /examples/custom-executor-tokio-context.rs: -------------------------------------------------------------------------------- 1 | // This example shows how to use the tokio runtime with any other executor 2 | // 3 | //It takes advantage from RuntimeExt which provides the extension to customize your 4 | //runtime. 5 | 6 | use tokio::net::TcpListener; 7 | use tokio::runtime::Builder; 8 | use tokio::sync::oneshot; 9 | use tokio_util::context::RuntimeExt; 10 | 11 | fn main() { 12 | let (tx, rx) = oneshot::channel(); 13 | let rt1 = Builder::new_multi_thread() 14 | .worker_threads(1) 15 | // no timer! 16 | .build() 17 | .unwrap(); 18 | let rt2 = Builder::new_multi_thread() 19 | .worker_threads(1) 20 | .enable_all() 21 | .build() 22 | .unwrap(); 23 | 24 | // Without the `HandleExt.wrap()` there would be a panic because there is 25 | // no timer running, since it would be referencing runtime r1. 26 | let _ = rt1.block_on(rt2.wrap(async move { 27 | let listener = TcpListener::bind("0.0.0.0:0").await.unwrap(); 28 | println!("addr: {:?}", listener.local_addr()); 29 | tx.send(()).unwrap(); 30 | })); 31 | futures::executor::block_on(rx).unwrap(); 32 | } 33 | -------------------------------------------------------------------------------- /tokio-stream/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 Tokio Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tokio-test/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 Tokio Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tokio-util/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 Tokio Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tokio/tests/io_sink.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | 4 | use tokio::io::AsyncWriteExt; 5 | 6 | #[tokio::test] 7 | async fn sink_poll_write_is_cooperative() { 8 | tokio::select! { 9 | biased; 10 | _ = async { 11 | loop { 12 | let buf = vec![1, 2, 3]; 13 | tokio::io::sink().write_all(&buf).await.unwrap(); 14 | } 15 | } => {}, 16 | _ = tokio::task::yield_now() => {} 17 | } 18 | } 19 | 20 | #[tokio::test] 21 | async fn sink_poll_flush_is_cooperative() { 22 | tokio::select! { 23 | biased; 24 | _ = async { 25 | loop { 26 | tokio::io::sink().flush().await.unwrap(); 27 | } 28 | } => {}, 29 | _ = tokio::task::yield_now() => {} 30 | } 31 | } 32 | 33 | #[tokio::test] 34 | async fn sink_poll_shutdown_is_cooperative() { 35 | tokio::select! { 36 | biased; 37 | _ = async { 38 | loop { 39 | tokio::io::sink().shutdown().await.unwrap(); 40 | } 41 | } => {}, 42 | _ = tokio::task::yield_now() => {} 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tokio/src/runtime/scheduler/inject/synced.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr( 2 | any(not(all(tokio_unstable, feature = "full")), target_family = "wasm"), 3 | allow(dead_code) 4 | )] 5 | 6 | use crate::runtime::task; 7 | 8 | pub(crate) struct Synced { 9 | /// True if the queue is closed. 10 | pub(super) is_closed: bool, 11 | 12 | /// Linked-list head. 13 | pub(super) head: Option, 14 | 15 | /// Linked-list tail. 16 | pub(super) tail: Option, 17 | } 18 | 19 | unsafe impl Send for Synced {} 20 | unsafe impl Sync for Synced {} 21 | 22 | impl Synced { 23 | pub(super) fn pop(&mut self) -> Option> { 24 | let task = self.head?; 25 | 26 | self.head = unsafe { task.get_queue_next() }; 27 | 28 | if self.head.is_none() { 29 | self.tail = None; 30 | } 31 | 32 | unsafe { task.set_queue_next(None) }; 33 | 34 | // safety: a `Notified` is pushed into the queue and now it is popped! 35 | Some(unsafe { task::Notified::from_raw(task) }) 36 | } 37 | 38 | pub(crate) fn is_empty(&self) -> bool { 39 | self.head.is_none() 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tokio/src/runtime/context/runtime_mt.rs: -------------------------------------------------------------------------------- 1 | use super::{EnterRuntime, CONTEXT}; 2 | 3 | /// Returns true if in a runtime context. 4 | pub(crate) fn current_enter_context() -> EnterRuntime { 5 | CONTEXT.with(|c| c.runtime.get()) 6 | } 7 | 8 | /// Forces the current "entered" state to be cleared while the closure 9 | /// is executed. 10 | pub(crate) fn exit_runtime R, R>(f: F) -> R { 11 | // Reset in case the closure panics 12 | struct Reset(EnterRuntime); 13 | 14 | impl Drop for Reset { 15 | fn drop(&mut self) { 16 | CONTEXT.with(|c| { 17 | assert!( 18 | !c.runtime.get().is_entered(), 19 | "closure claimed permanent executor" 20 | ); 21 | c.runtime.set(self.0); 22 | }); 23 | } 24 | } 25 | 26 | let was = CONTEXT.with(|c| { 27 | let e = c.runtime.get(); 28 | assert!(e.is_entered(), "asked to exit when not entered"); 29 | c.runtime.set(EnterRuntime::NotEntered); 30 | e 31 | }); 32 | 33 | let _reset = Reset(was); 34 | // dropping _reset after f() will reset ENTERED 35 | f() 36 | } 37 | -------------------------------------------------------------------------------- /tokio/src/net/lookup_host.rs: -------------------------------------------------------------------------------- 1 | cfg_net! { 2 | use crate::net::addr::{self, ToSocketAddrs}; 3 | 4 | use std::io; 5 | use std::net::SocketAddr; 6 | 7 | /// Performs a DNS resolution. 8 | /// 9 | /// The returned iterator may not actually yield any values depending on the 10 | /// outcome of any resolution performed. 11 | /// 12 | /// This API is not intended to cover all DNS use cases. Anything beyond the 13 | /// basic use case should be done with a specialized library. 14 | /// 15 | /// # Examples 16 | /// 17 | /// To resolve a DNS entry: 18 | /// 19 | /// ```no_run 20 | /// use tokio::net; 21 | /// use std::io; 22 | /// 23 | /// #[tokio::main] 24 | /// async fn main() -> io::Result<()> { 25 | /// for addr in net::lookup_host("localhost:3000").await? { 26 | /// println!("socket address is {}", addr); 27 | /// } 28 | /// 29 | /// Ok(()) 30 | /// } 31 | /// ``` 32 | pub async fn lookup_host(host: T) -> io::Result> 33 | where 34 | T: ToSocketAddrs 35 | { 36 | addr::to_socket_addrs(host).await 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tokio/tests/process_change_of_runtime.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "process")] 2 | #![warn(rust_2018_idioms)] 3 | // This tests test the behavior of `process::Command::spawn` when it is used 4 | // outside runtime, and when `process::Child::wait ` is used in a different 5 | // runtime from which `process::Command::spawn` is used. 6 | #![cfg(all(unix, not(target_os = "freebsd")))] 7 | 8 | use std::process::Stdio; 9 | use tokio::{process::Command, runtime::Runtime}; 10 | 11 | #[test] 12 | fn process_spawned_and_wait_in_different_runtime() { 13 | let mut child = Runtime::new().unwrap().block_on(async { 14 | Command::new("true") 15 | .stdin(Stdio::piped()) 16 | .stdout(Stdio::null()) 17 | .spawn() 18 | .unwrap() 19 | }); 20 | Runtime::new().unwrap().block_on(async { 21 | let _ = child.wait().await.unwrap(); 22 | }); 23 | } 24 | 25 | #[test] 26 | #[should_panic( 27 | expected = "there is no reactor running, must be called from the context of a Tokio 1.x runtime" 28 | )] 29 | fn process_spawned_outside_runtime() { 30 | let _ = Command::new("true") 31 | .stdin(Stdio::piped()) 32 | .stdout(Stdio::null()) 33 | .spawn(); 34 | } 35 | -------------------------------------------------------------------------------- /tokio/tests/signal_drop_rt.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(unix)] 4 | 5 | mod support { 6 | pub mod signal; 7 | } 8 | use support::signal::send_signal; 9 | 10 | use tokio::runtime::Runtime; 11 | use tokio::signal::unix::{signal, SignalKind}; 12 | 13 | #[test] 14 | fn dropping_loops_does_not_cause_starvation() { 15 | let kind = SignalKind::user_defined1(); 16 | 17 | let first_rt = rt(); 18 | let mut first_signal = 19 | first_rt.block_on(async { signal(kind).expect("failed to register first signal") }); 20 | 21 | let second_rt = rt(); 22 | let mut second_signal = 23 | second_rt.block_on(async { signal(kind).expect("failed to register second signal") }); 24 | 25 | send_signal(libc::SIGUSR1); 26 | 27 | first_rt 28 | .block_on(first_signal.recv()) 29 | .expect("failed to await first signal"); 30 | 31 | drop(first_rt); 32 | drop(first_signal); 33 | 34 | send_signal(libc::SIGUSR1); 35 | 36 | second_rt.block_on(second_signal.recv()); 37 | } 38 | 39 | fn rt() -> Runtime { 40 | tokio::runtime::Builder::new_current_thread() 41 | .enable_all() 42 | .build() 43 | .unwrap() 44 | } 45 | -------------------------------------------------------------------------------- /tokio/src/runtime/tests/loom_current_thread/yield_now.rs: -------------------------------------------------------------------------------- 1 | use crate::runtime::park; 2 | use crate::runtime::tests::loom_oneshot as oneshot; 3 | use crate::runtime::{self, Runtime}; 4 | 5 | #[test] 6 | fn yield_calls_park_before_scheduling_again() { 7 | // Don't need to check all permutations 8 | let mut loom = loom::model::Builder::default(); 9 | loom.max_permutations = Some(1); 10 | loom.check(|| { 11 | let rt = mk_runtime(2); 12 | let (tx, rx) = oneshot::channel::<()>(); 13 | 14 | rt.spawn(async { 15 | let tid = loom::thread::current().id(); 16 | let park_count = park::current_thread_park_count(); 17 | 18 | crate::task::yield_now().await; 19 | 20 | if tid == loom::thread::current().id() { 21 | let new_park_count = park::current_thread_park_count(); 22 | assert_eq!(park_count + 1, new_park_count); 23 | } 24 | 25 | tx.send(()); 26 | }); 27 | 28 | rx.recv(); 29 | }); 30 | } 31 | 32 | fn mk_runtime(num_threads: usize) -> Runtime { 33 | runtime::Builder::new_multi_thread() 34 | .worker_threads(num_threads) 35 | .build() 36 | .unwrap() 37 | } 38 | -------------------------------------------------------------------------------- /tokio/src/runtime/tests/loom_multi_thread/yield_now.rs: -------------------------------------------------------------------------------- 1 | use crate::runtime::park; 2 | use crate::runtime::tests::loom_oneshot as oneshot; 3 | use crate::runtime::{self, Runtime}; 4 | 5 | #[test] 6 | fn yield_calls_park_before_scheduling_again() { 7 | // Don't need to check all permutations 8 | let mut loom = loom::model::Builder::default(); 9 | loom.max_permutations = Some(1); 10 | loom.check(|| { 11 | let rt = mk_runtime(2); 12 | let (tx, rx) = oneshot::channel::<()>(); 13 | 14 | rt.spawn(async { 15 | let tid = loom::thread::current().id(); 16 | let park_count = park::current_thread_park_count(); 17 | 18 | crate::task::yield_now().await; 19 | 20 | if tid == loom::thread::current().id() { 21 | let new_park_count = park::current_thread_park_count(); 22 | assert_eq!(park_count + 1, new_park_count); 23 | } 24 | 25 | tx.send(()); 26 | }); 27 | 28 | rx.recv(); 29 | }); 30 | } 31 | 32 | fn mk_runtime(num_threads: usize) -> Runtime { 33 | runtime::Builder::new_multi_thread() 34 | .worker_threads(num_threads) 35 | .build() 36 | .unwrap() 37 | } 38 | -------------------------------------------------------------------------------- /tokio/src/runtime/tests/loom_multi_thread_alt/yield_now.rs: -------------------------------------------------------------------------------- 1 | use crate::runtime::park; 2 | use crate::runtime::tests::loom_oneshot as oneshot; 3 | use crate::runtime::{self, Runtime}; 4 | 5 | #[test] 6 | fn yield_calls_park_before_scheduling_again() { 7 | // Don't need to check all permutations 8 | let mut loom = loom::model::Builder::default(); 9 | loom.max_permutations = Some(1); 10 | loom.check(|| { 11 | let rt = mk_runtime(2); 12 | let (tx, rx) = oneshot::channel::<()>(); 13 | 14 | rt.spawn(async { 15 | let tid = loom::thread::current().id(); 16 | let park_count = park::current_thread_park_count(); 17 | 18 | crate::task::yield_now().await; 19 | 20 | if tid == loom::thread::current().id() { 21 | let new_park_count = park::current_thread_park_count(); 22 | assert_eq!(park_count + 1, new_park_count); 23 | } 24 | 25 | tx.send(()); 26 | }); 27 | 28 | rx.recv(); 29 | }); 30 | } 31 | 32 | fn mk_runtime(num_threads: usize) -> Runtime { 33 | runtime::Builder::new_multi_thread() 34 | .worker_threads(num_threads) 35 | .build() 36 | .unwrap() 37 | } 38 | -------------------------------------------------------------------------------- /tokio-util/tests/framed_stream.rs: -------------------------------------------------------------------------------- 1 | use futures_core::stream::Stream; 2 | use std::{io, pin::Pin}; 3 | use tokio_test::{assert_ready, io::Builder, task}; 4 | use tokio_util::codec::{BytesCodec, FramedRead}; 5 | 6 | macro_rules! pin { 7 | ($id:ident) => { 8 | Pin::new(&mut $id) 9 | }; 10 | } 11 | 12 | macro_rules! assert_read { 13 | ($e:expr, $n:expr) => {{ 14 | let val = assert_ready!($e); 15 | assert_eq!(val.unwrap().unwrap(), $n); 16 | }}; 17 | } 18 | 19 | #[tokio::test] 20 | async fn return_none_after_error() { 21 | let mut io = FramedRead::new( 22 | Builder::new() 23 | .read(b"abcdef") 24 | .read_error(io::Error::new(io::ErrorKind::Other, "Resource errored out")) 25 | .read(b"more data") 26 | .build(), 27 | BytesCodec::new(), 28 | ); 29 | 30 | let mut task = task::spawn(()); 31 | 32 | task.enter(|cx, _| { 33 | assert_read!(pin!(io).poll_next(cx), b"abcdef".to_vec()); 34 | assert!(assert_ready!(pin!(io).poll_next(cx)).unwrap().is_err()); 35 | assert!(assert_ready!(pin!(io).poll_next(cx)).is_none()); 36 | assert_read!(pin!(io).poll_next(cx), b"more data".to_vec()); 37 | }) 38 | } 39 | -------------------------------------------------------------------------------- /tokio/src/runtime/scheduler/defer.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | use std::task::Waker; 3 | 4 | pub(crate) struct Defer { 5 | deferred: RefCell>, 6 | } 7 | 8 | impl Defer { 9 | pub(crate) fn new() -> Defer { 10 | Defer { 11 | deferred: RefCell::default(), 12 | } 13 | } 14 | 15 | pub(crate) fn defer(&self, waker: &Waker) { 16 | let mut deferred = self.deferred.borrow_mut(); 17 | 18 | // If the same task adds itself a bunch of times, then only add it once. 19 | if let Some(last) = deferred.last() { 20 | if last.will_wake(waker) { 21 | return; 22 | } 23 | } 24 | 25 | deferred.push(waker.clone()); 26 | } 27 | 28 | pub(crate) fn is_empty(&self) -> bool { 29 | self.deferred.borrow().is_empty() 30 | } 31 | 32 | pub(crate) fn wake(&self) { 33 | while let Some(waker) = self.deferred.borrow_mut().pop() { 34 | waker.wake(); 35 | } 36 | } 37 | 38 | #[cfg(tokio_taskdump)] 39 | pub(crate) fn take_deferred(&self) -> Vec { 40 | let mut deferred = self.deferred.borrow_mut(); 41 | std::mem::take(&mut *deferred) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tokio/tests/support/panic.rs: -------------------------------------------------------------------------------- 1 | use std::panic; 2 | use std::sync::{Arc, Mutex}; 3 | 4 | pub fn test_panic(func: Func) -> Option { 5 | static PANIC_MUTEX: Mutex<()> = Mutex::new(()); 6 | 7 | { 8 | let _guard = PANIC_MUTEX.lock(); 9 | let panic_file: Arc>> = Arc::new(Mutex::new(None)); 10 | 11 | let prev_hook = panic::take_hook(); 12 | { 13 | let panic_file = panic_file.clone(); 14 | panic::set_hook(Box::new(move |panic_info| { 15 | let panic_location = panic_info.location().unwrap(); 16 | panic_file 17 | .lock() 18 | .unwrap() 19 | .clone_from(&Some(panic_location.file().to_string())); 20 | })); 21 | } 22 | 23 | let result = panic::catch_unwind(func); 24 | // Return to the previously set panic hook (maybe default) so that we get nice error 25 | // messages in the tests. 26 | panic::set_hook(prev_hook); 27 | 28 | if result.is_err() { 29 | panic_file.lock().unwrap().clone() 30 | } else { 31 | None 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tokio-util/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::needless_doctest_main)] 2 | #![warn( 3 | missing_debug_implementations, 4 | missing_docs, 5 | rust_2018_idioms, 6 | unreachable_pub 7 | )] 8 | #![doc(test( 9 | no_crate_inject, 10 | attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables)) 11 | ))] 12 | #![cfg_attr(docsrs, feature(doc_cfg))] 13 | 14 | //! Utilities for working with Tokio. 15 | //! 16 | //! This crate is not versioned in lockstep with the core 17 | //! [`tokio`] crate. However, `tokio-util` _will_ respect Rust's 18 | //! semantic versioning policy, especially with regard to breaking changes. 19 | //! 20 | //! [`tokio`]: https://docs.rs/tokio 21 | 22 | #[macro_use] 23 | mod cfg; 24 | 25 | mod loom; 26 | 27 | cfg_codec! { 28 | pub mod codec; 29 | } 30 | 31 | cfg_net! { 32 | #[cfg(not(target_arch = "wasm32"))] 33 | pub mod udp; 34 | pub mod net; 35 | } 36 | 37 | cfg_compat! { 38 | pub mod compat; 39 | } 40 | 41 | cfg_io! { 42 | pub mod io; 43 | } 44 | 45 | cfg_rt! { 46 | pub mod context; 47 | pub mod task; 48 | } 49 | 50 | cfg_time! { 51 | pub mod time; 52 | } 53 | 54 | pub mod sync; 55 | 56 | pub mod either; 57 | 58 | pub use bytes; 59 | 60 | mod util; 61 | -------------------------------------------------------------------------------- /tokio/src/fs/try_exists.rs: -------------------------------------------------------------------------------- 1 | use crate::fs::asyncify; 2 | 3 | use std::io; 4 | use std::path::Path; 5 | 6 | /// Returns `Ok(true)` if the path points at an existing entity. 7 | /// 8 | /// This function will traverse symbolic links to query information about the 9 | /// destination file. In case of broken symbolic links this will return `Ok(false)`. 10 | /// 11 | /// This is the async equivalent of [`std::path::Path::try_exists`][std]. 12 | /// 13 | /// [std]: fn@std::path::Path::try_exists 14 | /// 15 | /// # Examples 16 | /// 17 | /// ```no_run 18 | /// use tokio::fs; 19 | /// 20 | /// # async fn dox() -> std::io::Result<()> { 21 | /// fs::try_exists("foo.txt").await?; 22 | /// # Ok(()) 23 | /// # } 24 | /// ``` 25 | pub async fn try_exists(path: impl AsRef) -> io::Result { 26 | let path = path.as_ref().to_owned(); 27 | // std's Path::try_exists is not available for current Rust min supported version. 28 | // Current implementation is based on its internal implementation instead. 29 | match asyncify(move || std::fs::metadata(path)).await { 30 | Ok(_) => Ok(true), 31 | Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(false), 32 | Err(error) => Err(error), 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tokio-stream/src/wrappers/signal_unix.rs: -------------------------------------------------------------------------------- 1 | use crate::Stream; 2 | use std::pin::Pin; 3 | use std::task::{Context, Poll}; 4 | use tokio::signal::unix::Signal; 5 | 6 | /// A wrapper around [`Signal`] that implements [`Stream`]. 7 | /// 8 | /// [`Signal`]: struct@tokio::signal::unix::Signal 9 | /// [`Stream`]: trait@crate::Stream 10 | #[derive(Debug)] 11 | #[cfg_attr(docsrs, doc(cfg(all(unix, feature = "signal"))))] 12 | pub struct SignalStream { 13 | inner: Signal, 14 | } 15 | 16 | impl SignalStream { 17 | /// Create a new `SignalStream`. 18 | pub fn new(interval: Signal) -> Self { 19 | Self { inner: interval } 20 | } 21 | 22 | /// Get back the inner `Signal`. 23 | pub fn into_inner(self) -> Signal { 24 | self.inner 25 | } 26 | } 27 | 28 | impl Stream for SignalStream { 29 | type Item = (); 30 | 31 | fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 32 | self.inner.poll_recv(cx) 33 | } 34 | } 35 | 36 | impl AsRef for SignalStream { 37 | fn as_ref(&self) -> &Signal { 38 | &self.inner 39 | } 40 | } 41 | 42 | impl AsMut for SignalStream { 43 | fn as_mut(&mut self) -> &mut Signal { 44 | &mut self.inner 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tokio/src/runtime/time/source.rs: -------------------------------------------------------------------------------- 1 | use super::MAX_SAFE_MILLIS_DURATION; 2 | use crate::time::{Clock, Duration, Instant}; 3 | 4 | /// A structure which handles conversion from Instants to u64 timestamps. 5 | #[derive(Debug)] 6 | pub(crate) struct TimeSource { 7 | start_time: Instant, 8 | } 9 | 10 | impl TimeSource { 11 | pub(crate) fn new(clock: &Clock) -> Self { 12 | Self { 13 | start_time: clock.now(), 14 | } 15 | } 16 | 17 | pub(crate) fn deadline_to_tick(&self, t: Instant) -> u64 { 18 | // Round up to the end of a ms 19 | self.instant_to_tick(t + Duration::from_nanos(999_999)) 20 | } 21 | 22 | pub(crate) fn instant_to_tick(&self, t: Instant) -> u64 { 23 | // round up 24 | let dur: Duration = t 25 | .checked_duration_since(self.start_time) 26 | .unwrap_or_else(|| Duration::from_secs(0)); 27 | let ms = dur.as_millis(); 28 | 29 | ms.try_into().unwrap_or(MAX_SAFE_MILLIS_DURATION) 30 | } 31 | 32 | pub(crate) fn tick_to_duration(&self, t: u64) -> Duration { 33 | Duration::from_millis(t) 34 | } 35 | 36 | pub(crate) fn now(&self, clock: &Clock) -> u64 { 37 | self.instant_to_tick(clock.now()) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tokio-stream/src/stream_ext/chain.rs: -------------------------------------------------------------------------------- 1 | use crate::stream_ext::Fuse; 2 | use crate::Stream; 3 | 4 | use core::pin::Pin; 5 | use core::task::{Context, Poll}; 6 | use pin_project_lite::pin_project; 7 | 8 | pin_project! { 9 | /// Stream returned by the [`chain`](super::StreamExt::chain) method. 10 | pub struct Chain { 11 | #[pin] 12 | a: Fuse, 13 | #[pin] 14 | b: U, 15 | } 16 | } 17 | 18 | impl Chain { 19 | pub(super) fn new(a: T, b: U) -> Chain 20 | where 21 | T: Stream, 22 | U: Stream, 23 | { 24 | Chain { a: Fuse::new(a), b } 25 | } 26 | } 27 | 28 | impl Stream for Chain 29 | where 30 | T: Stream, 31 | U: Stream, 32 | { 33 | type Item = T::Item; 34 | 35 | fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 36 | use Poll::Ready; 37 | 38 | let me = self.project(); 39 | 40 | if let Some(v) = ready!(me.a.poll_next(cx)) { 41 | return Ready(Some(v)); 42 | } 43 | 44 | me.b.poll_next(cx) 45 | } 46 | 47 | fn size_hint(&self) -> (usize, Option) { 48 | super::merge_size_hints(self.a.size_hint(), self.b.size_hint()) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /tokio-test/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.4.3 (August 23, 2023) 2 | 3 | - deps: fix minimum required version of `async-stream` ([#5347]) 4 | - deps: fix minimum required version of `tokio-stream` ([#4376]) 5 | - docs: improve `tokio_test::task` docs ([#5132]) 6 | - io: fetch actions from mock handle before write ([#5814]) 7 | - io: fix wait operation on mock ([#5554]) 8 | 9 | [#4376]: https://github.com/tokio-rs/tokio/pull/4376 10 | [#5132]: https://github.com/tokio-rs/tokio/pull/5132 11 | [#5347]: https://github.com/tokio-rs/tokio/pull/5347 12 | [#5554]: https://github.com/tokio-rs/tokio/pull/5554 13 | [#5814]: https://github.com/tokio-rs/tokio/pull/5814 14 | 15 | # 0.4.2 (May 14, 2021) 16 | 17 | - test: add `assert_elapsed!` macro ([#3728]) 18 | 19 | [#3728]: https://github.com/tokio-rs/tokio/pull/3728 20 | 21 | # 0.4.1 (March 10, 2021) 22 | 23 | - Fix `io::Mock` to be `Send` and `Sync` ([#3594]) 24 | 25 | [#3594]: https://github.com/tokio-rs/tokio/pull/3594 26 | 27 | # 0.4.0 (December 23, 2020) 28 | 29 | - Track `tokio` 1.0 release. 30 | 31 | # 0.3.0 (October 15, 2020) 32 | 33 | - Track `tokio` 0.3 release. 34 | 35 | # 0.2.1 (April 17, 2020) 36 | 37 | - Add `Future` and `Stream` implementations for `task::Spawn`. 38 | 39 | # 0.2.0 (November 25, 2019) 40 | 41 | - Initial release 42 | -------------------------------------------------------------------------------- /tokio/src/runtime/metrics/mod.rs: -------------------------------------------------------------------------------- 1 | //! This module contains information need to view information about how the 2 | //! runtime is performing. 3 | //! 4 | //! **Note**: This is an [unstable API][unstable]. The public API of types in 5 | //! this module may break in 1.x releases. See [the documentation on unstable 6 | //! features][unstable] for details. 7 | //! 8 | //! [unstable]: crate#unstable-features 9 | #![allow(clippy::module_inception)] 10 | 11 | cfg_metrics! { 12 | mod batch; 13 | pub(crate) use batch::MetricsBatch; 14 | 15 | mod histogram; 16 | pub(crate) use histogram::{Histogram, HistogramBatch, HistogramBuilder}; 17 | #[allow(unreachable_pub)] // rust-lang/rust#57411 18 | pub use histogram::HistogramScale; 19 | 20 | mod runtime; 21 | #[allow(unreachable_pub)] // rust-lang/rust#57411 22 | pub use runtime::RuntimeMetrics; 23 | 24 | mod scheduler; 25 | pub(crate) use scheduler::SchedulerMetrics; 26 | 27 | mod worker; 28 | pub(crate) use worker::WorkerMetrics; 29 | 30 | cfg_net! { 31 | mod io; 32 | pub(crate) use io::IoDriverMetrics; 33 | } 34 | } 35 | 36 | cfg_not_metrics! { 37 | mod mock; 38 | 39 | pub(crate) use mock::{SchedulerMetrics, WorkerMetrics, MetricsBatch, HistogramBuilder}; 40 | } 41 | -------------------------------------------------------------------------------- /tokio/tests/process_kill_on_drop.rs: -------------------------------------------------------------------------------- 1 | #![cfg(all(unix, feature = "process"))] 2 | #![warn(rust_2018_idioms)] 3 | 4 | use std::io::ErrorKind; 5 | use std::process::Stdio; 6 | use std::time::Duration; 7 | use tokio::io::AsyncReadExt; 8 | use tokio::process::Command; 9 | use tokio::time::sleep; 10 | use tokio_test::assert_ok; 11 | 12 | #[tokio::test] 13 | async fn kill_on_drop() { 14 | let mut cmd = Command::new("bash"); 15 | cmd.args([ 16 | "-c", 17 | " 18 | # Fork another child that won't get killed 19 | sh -c 'sleep 1; echo child ran' & 20 | disown -a 21 | 22 | # Await our death 23 | sleep 5 24 | echo hello from beyond the grave 25 | ", 26 | ]); 27 | 28 | let e = cmd.kill_on_drop(true).stdout(Stdio::piped()).spawn(); 29 | if e.is_err() && e.as_ref().unwrap_err().kind() == ErrorKind::NotFound { 30 | println!("bash not available; skipping test"); 31 | return; 32 | } 33 | let mut child = e.unwrap(); 34 | 35 | sleep(Duration::from_secs(2)).await; 36 | 37 | let mut out = child.stdout.take().unwrap(); 38 | drop(child); 39 | 40 | let mut msg = String::new(); 41 | assert_ok!(out.read_to_string(&mut msg).await); 42 | 43 | assert_eq!("child ran\n", msg); 44 | } 45 | -------------------------------------------------------------------------------- /tokio/tests/net_lookup_host.rs: -------------------------------------------------------------------------------- 1 | #![cfg(all(feature = "full", not(target_os = "wasi")))] // Wasi does not support direct socket operations 2 | 3 | use tokio::net; 4 | use tokio_test::assert_ok; 5 | 6 | use std::io; 7 | use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; 8 | 9 | #[tokio::test] 10 | async fn lookup_socket_addr() { 11 | let addr: SocketAddr = "127.0.0.1:8000".parse().unwrap(); 12 | 13 | let actual = assert_ok!(net::lookup_host(addr).await).collect::>(); 14 | assert_eq!(vec![addr], actual); 15 | } 16 | 17 | #[tokio::test] 18 | async fn lookup_str_socket_addr() { 19 | let addr: SocketAddr = "127.0.0.1:8000".parse().unwrap(); 20 | 21 | let actual = assert_ok!(net::lookup_host("127.0.0.1:8000").await).collect::>(); 22 | assert_eq!(vec![addr], actual); 23 | } 24 | 25 | #[tokio::test] 26 | async fn resolve_dns() -> io::Result<()> { 27 | let mut hosts = net::lookup_host("localhost:3000").await?; 28 | let host = hosts.next().unwrap(); 29 | 30 | let expected = if host.is_ipv4() { 31 | SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 3000) 32 | } else { 33 | SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), 3000) 34 | }; 35 | assert_eq!(host, expected); 36 | 37 | Ok(()) 38 | } 39 | -------------------------------------------------------------------------------- /tokio/src/sync/tests/loom_list.rs: -------------------------------------------------------------------------------- 1 | use crate::sync::mpsc::list; 2 | 3 | use loom::thread; 4 | use std::sync::Arc; 5 | 6 | #[test] 7 | fn smoke() { 8 | use crate::sync::mpsc::block::Read; 9 | 10 | const NUM_TX: usize = 2; 11 | const NUM_MSG: usize = 2; 12 | 13 | loom::model(|| { 14 | let (tx, mut rx) = list::channel(); 15 | let tx = Arc::new(tx); 16 | 17 | for th in 0..NUM_TX { 18 | let tx = tx.clone(); 19 | 20 | thread::spawn(move || { 21 | for i in 0..NUM_MSG { 22 | tx.push((th, i)); 23 | } 24 | }); 25 | } 26 | 27 | let mut next = vec![0; NUM_TX]; 28 | 29 | loop { 30 | match rx.pop(&tx) { 31 | Some(Read::Value((th, v))) => { 32 | assert_eq!(v, next[th]); 33 | next[th] += 1; 34 | 35 | if next.iter().all(|&i| i == NUM_MSG) { 36 | break; 37 | } 38 | } 39 | Some(Read::Closed) => { 40 | panic!(); 41 | } 42 | None => { 43 | thread::yield_now(); 44 | } 45 | } 46 | } 47 | }); 48 | } 49 | -------------------------------------------------------------------------------- /tokio/tests/support/mpsc_stream.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use std::pin::Pin; 4 | use std::task::{Context, Poll}; 5 | use tokio::sync::mpsc::{self, Receiver, Sender, UnboundedReceiver, UnboundedSender}; 6 | use tokio_stream::Stream; 7 | 8 | struct UnboundedStream { 9 | recv: UnboundedReceiver, 10 | } 11 | impl Stream for UnboundedStream { 12 | type Item = T; 13 | fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 14 | Pin::into_inner(self).recv.poll_recv(cx) 15 | } 16 | } 17 | 18 | pub fn unbounded_channel_stream() -> (UnboundedSender, impl Stream) { 19 | let (tx, rx) = mpsc::unbounded_channel(); 20 | 21 | let stream = UnboundedStream { recv: rx }; 22 | 23 | (tx, stream) 24 | } 25 | 26 | struct BoundedStream { 27 | recv: Receiver, 28 | } 29 | impl Stream for BoundedStream { 30 | type Item = T; 31 | fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 32 | Pin::into_inner(self).recv.poll_recv(cx) 33 | } 34 | } 35 | 36 | pub fn channel_stream(size: usize) -> (Sender, impl Stream) { 37 | let (tx, rx) = mpsc::channel(size); 38 | 39 | let stream = BoundedStream { recv: rx }; 40 | 41 | (tx, stream) 42 | } 43 | -------------------------------------------------------------------------------- /tokio/tests/unwindsafe.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", not(target_os = "wasi")))] // Wasi does not support panic recovery 3 | 4 | use std::panic::{RefUnwindSafe, UnwindSafe}; 5 | 6 | #[test] 7 | fn notify_is_unwind_safe() { 8 | is_unwind_safe::(); 9 | } 10 | 11 | #[test] 12 | fn join_handle_is_unwind_safe() { 13 | is_unwind_safe::>(); 14 | } 15 | 16 | #[test] 17 | fn net_types_are_unwind_safe() { 18 | is_unwind_safe::(); 19 | is_unwind_safe::(); 20 | is_unwind_safe::(); 21 | is_unwind_safe::(); 22 | } 23 | 24 | #[test] 25 | #[cfg(unix)] 26 | fn unix_net_types_are_unwind_safe() { 27 | is_unwind_safe::(); 28 | is_unwind_safe::(); 29 | is_unwind_safe::(); 30 | } 31 | 32 | #[test] 33 | #[cfg(windows)] 34 | fn windows_net_types_are_unwind_safe() { 35 | use tokio::net::windows::named_pipe::NamedPipeClient; 36 | use tokio::net::windows::named_pipe::NamedPipeServer; 37 | 38 | is_unwind_safe::(); 39 | is_unwind_safe::(); 40 | } 41 | 42 | fn is_unwind_safe() {} 43 | -------------------------------------------------------------------------------- /tests-build/tests/fail/macros_invalid_input.rs: -------------------------------------------------------------------------------- 1 | #![deny(duplicate_macro_attributes)] 2 | 3 | use tests_build::tokio; 4 | 5 | #[tokio::main] 6 | fn main_is_not_async() {} 7 | 8 | #[tokio::main(foo)] 9 | async fn main_attr_has_unknown_args() {} 10 | 11 | #[tokio::main(threadpool::bar)] 12 | async fn main_attr_has_path_args() {} 13 | 14 | #[tokio::test] 15 | fn test_is_not_async() {} 16 | 17 | #[tokio::test(foo)] 18 | async fn test_attr_has_args() {} 19 | 20 | #[tokio::test(foo = 123)] 21 | async fn test_unexpected_attr() {} 22 | 23 | #[tokio::test(flavor = 123)] 24 | async fn test_flavor_not_string() {} 25 | 26 | #[tokio::test(flavor = "foo")] 27 | async fn test_unknown_flavor() {} 28 | 29 | #[tokio::test(flavor = "multi_thread", start_paused = false)] 30 | async fn test_multi_thread_with_start_paused() {} 31 | 32 | #[tokio::test(flavor = "multi_thread", worker_threads = "foo")] 33 | async fn test_worker_threads_not_int() {} 34 | 35 | #[tokio::test(flavor = "current_thread", worker_threads = 4)] 36 | async fn test_worker_threads_and_current_thread() {} 37 | 38 | #[tokio::test(crate = 456)] 39 | async fn test_crate_not_path_int() {} 40 | 41 | #[tokio::test(crate = "456")] 42 | async fn test_crate_not_path_invalid() {} 43 | 44 | #[tokio::test] 45 | #[test] 46 | async fn test_has_second_test_attr() {} 47 | 48 | fn main() {} 49 | -------------------------------------------------------------------------------- /tokio-stream/src/wrappers/read_dir.rs: -------------------------------------------------------------------------------- 1 | use crate::Stream; 2 | use std::io; 3 | use std::pin::Pin; 4 | use std::task::{Context, Poll}; 5 | use tokio::fs::{DirEntry, ReadDir}; 6 | 7 | /// A wrapper around [`tokio::fs::ReadDir`] that implements [`Stream`]. 8 | /// 9 | /// [`tokio::fs::ReadDir`]: struct@tokio::fs::ReadDir 10 | /// [`Stream`]: trait@crate::Stream 11 | #[derive(Debug)] 12 | #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] 13 | pub struct ReadDirStream { 14 | inner: ReadDir, 15 | } 16 | 17 | impl ReadDirStream { 18 | /// Create a new `ReadDirStream`. 19 | pub fn new(read_dir: ReadDir) -> Self { 20 | Self { inner: read_dir } 21 | } 22 | 23 | /// Get back the inner `ReadDir`. 24 | pub fn into_inner(self) -> ReadDir { 25 | self.inner 26 | } 27 | } 28 | 29 | impl Stream for ReadDirStream { 30 | type Item = io::Result; 31 | 32 | fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 33 | self.inner.poll_next_entry(cx).map(Result::transpose) 34 | } 35 | } 36 | 37 | impl AsRef for ReadDirStream { 38 | fn as_ref(&self) -> &ReadDir { 39 | &self.inner 40 | } 41 | } 42 | 43 | impl AsMut for ReadDirStream { 44 | fn as_mut(&mut self) -> &mut ReadDir { 45 | &mut self.inner 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tokio/src/runtime/scheduler/multi_thread/handle/metrics.rs: -------------------------------------------------------------------------------- 1 | use super::Handle; 2 | 3 | use crate::runtime::{SchedulerMetrics, WorkerMetrics}; 4 | 5 | impl Handle { 6 | pub(crate) fn num_workers(&self) -> usize { 7 | self.shared.worker_metrics.len() 8 | } 9 | 10 | pub(crate) fn num_blocking_threads(&self) -> usize { 11 | self.blocking_spawner.num_threads() 12 | } 13 | 14 | pub(crate) fn num_idle_blocking_threads(&self) -> usize { 15 | self.blocking_spawner.num_idle_threads() 16 | } 17 | 18 | pub(crate) fn active_tasks_count(&self) -> usize { 19 | self.shared.owned.active_tasks_count() 20 | } 21 | 22 | pub(crate) fn scheduler_metrics(&self) -> &SchedulerMetrics { 23 | &self.shared.scheduler_metrics 24 | } 25 | 26 | pub(crate) fn worker_metrics(&self, worker: usize) -> &WorkerMetrics { 27 | &self.shared.worker_metrics[worker] 28 | } 29 | 30 | pub(crate) fn injection_queue_depth(&self) -> usize { 31 | self.shared.injection_queue_depth() 32 | } 33 | 34 | pub(crate) fn worker_local_queue_depth(&self, worker: usize) -> usize { 35 | self.shared.worker_local_queue_depth(worker) 36 | } 37 | 38 | pub(crate) fn blocking_queue_depth(&self) -> usize { 39 | self.blocking_spawner.queue_depth() 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tokio/src/runtime/scheduler/multi_thread_alt/handle/metrics.rs: -------------------------------------------------------------------------------- 1 | use super::Handle; 2 | 3 | use crate::runtime::{SchedulerMetrics, WorkerMetrics}; 4 | 5 | impl Handle { 6 | pub(crate) fn num_workers(&self) -> usize { 7 | self.shared.worker_metrics.len() 8 | } 9 | 10 | pub(crate) fn num_blocking_threads(&self) -> usize { 11 | self.blocking_spawner.num_threads() 12 | } 13 | 14 | pub(crate) fn num_idle_blocking_threads(&self) -> usize { 15 | self.blocking_spawner.num_idle_threads() 16 | } 17 | 18 | pub(crate) fn active_tasks_count(&self) -> usize { 19 | self.shared.owned.active_tasks_count() 20 | } 21 | 22 | pub(crate) fn scheduler_metrics(&self) -> &SchedulerMetrics { 23 | &self.shared.scheduler_metrics 24 | } 25 | 26 | pub(crate) fn worker_metrics(&self, worker: usize) -> &WorkerMetrics { 27 | &self.shared.worker_metrics[worker] 28 | } 29 | 30 | pub(crate) fn injection_queue_depth(&self) -> usize { 31 | self.shared.injection_queue_depth() 32 | } 33 | 34 | pub(crate) fn worker_local_queue_depth(&self, worker: usize) -> usize { 35 | self.shared.worker_local_queue_depth(worker) 36 | } 37 | 38 | pub(crate) fn blocking_queue_depth(&self) -> usize { 39 | self.blocking_spawner.queue_depth() 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tokio/src/runtime/metrics/scheduler.rs: -------------------------------------------------------------------------------- 1 | use crate::loom::sync::atomic::{AtomicU64, Ordering::Relaxed}; 2 | 3 | /// Retrieves metrics from the Tokio runtime. 4 | /// 5 | /// **Note**: This is an [unstable API][unstable]. The public API of this type 6 | /// may break in 1.x releases. See [the documentation on unstable 7 | /// features][unstable] for details. 8 | /// 9 | /// [unstable]: crate#unstable-features 10 | #[derive(Debug)] 11 | pub(crate) struct SchedulerMetrics { 12 | /// Number of tasks that are scheduled from outside the runtime. 13 | pub(super) remote_schedule_count: AtomicU64, 14 | pub(super) budget_forced_yield_count: AtomicU64, 15 | } 16 | 17 | impl SchedulerMetrics { 18 | pub(crate) fn new() -> SchedulerMetrics { 19 | SchedulerMetrics { 20 | remote_schedule_count: AtomicU64::new(0), 21 | budget_forced_yield_count: AtomicU64::new(0), 22 | } 23 | } 24 | 25 | /// Increment the number of tasks scheduled externally 26 | pub(crate) fn inc_remote_schedule_count(&self) { 27 | self.remote_schedule_count.fetch_add(1, Relaxed); 28 | } 29 | 30 | /// Increment the number of tasks forced to yield due to budget exhaustion 31 | pub(crate) fn inc_budget_forced_yield_count(&self) { 32 | self.budget_forced_yield_count.fetch_add(1, Relaxed); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tokio/src/runtime/scheduler/inject/pop.rs: -------------------------------------------------------------------------------- 1 | use super::Synced; 2 | 3 | use crate::runtime::task; 4 | 5 | use std::marker::PhantomData; 6 | 7 | pub(crate) struct Pop<'a, T: 'static> { 8 | len: usize, 9 | synced: &'a mut Synced, 10 | _p: PhantomData, 11 | } 12 | 13 | impl<'a, T: 'static> Pop<'a, T> { 14 | pub(super) fn new(len: usize, synced: &'a mut Synced) -> Pop<'a, T> { 15 | Pop { 16 | len, 17 | synced, 18 | _p: PhantomData, 19 | } 20 | } 21 | } 22 | 23 | impl<'a, T: 'static> Iterator for Pop<'a, T> { 24 | type Item = task::Notified; 25 | 26 | fn next(&mut self) -> Option { 27 | if self.len == 0 { 28 | return None; 29 | } 30 | 31 | let ret = self.synced.pop(); 32 | 33 | // Should be `Some` when `len > 0` 34 | debug_assert!(ret.is_some()); 35 | 36 | self.len -= 1; 37 | ret 38 | } 39 | 40 | fn size_hint(&self) -> (usize, Option) { 41 | (self.len, Some(self.len)) 42 | } 43 | } 44 | 45 | impl<'a, T: 'static> ExactSizeIterator for Pop<'a, T> { 46 | fn len(&self) -> usize { 47 | self.len 48 | } 49 | } 50 | 51 | impl<'a, T: 'static> Drop for Pop<'a, T> { 52 | fn drop(&mut self) { 53 | for _ in self.by_ref() {} 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /tokio/tests/fs_copy.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", not(target_os = "wasi")))] // WASI does not support all fs operations 3 | 4 | use tempfile::tempdir; 5 | use tokio::fs; 6 | 7 | #[tokio::test] 8 | async fn copy() { 9 | let dir = tempdir().unwrap(); 10 | 11 | let source_path = dir.path().join("foo.txt"); 12 | let dest_path = dir.path().join("bar.txt"); 13 | 14 | fs::write(&source_path, b"Hello File!").await.unwrap(); 15 | fs::copy(&source_path, &dest_path).await.unwrap(); 16 | 17 | let from = fs::read(&source_path).await.unwrap(); 18 | let to = fs::read(&dest_path).await.unwrap(); 19 | 20 | assert_eq!(from, to); 21 | } 22 | 23 | #[tokio::test] 24 | async fn copy_permissions() { 25 | let dir = tempdir().unwrap(); 26 | let from_path = dir.path().join("foo.txt"); 27 | let to_path = dir.path().join("bar.txt"); 28 | 29 | let from = tokio::fs::File::create(&from_path).await.unwrap(); 30 | let mut from_perms = from.metadata().await.unwrap().permissions(); 31 | from_perms.set_readonly(true); 32 | from.set_permissions(from_perms.clone()).await.unwrap(); 33 | 34 | tokio::fs::copy(from_path, &to_path).await.unwrap(); 35 | 36 | let to_perms = tokio::fs::metadata(to_path).await.unwrap().permissions(); 37 | 38 | assert_eq!(from_perms, to_perms); 39 | } 40 | -------------------------------------------------------------------------------- /tokio/src/loom/mocked.rs: -------------------------------------------------------------------------------- 1 | pub(crate) use loom::*; 2 | 3 | pub(crate) mod sync { 4 | 5 | pub(crate) use loom::sync::MutexGuard; 6 | 7 | #[derive(Debug)] 8 | pub(crate) struct Mutex(loom::sync::Mutex); 9 | 10 | #[allow(dead_code)] 11 | impl Mutex { 12 | #[inline] 13 | pub(crate) fn new(t: T) -> Mutex { 14 | Mutex(loom::sync::Mutex::new(t)) 15 | } 16 | 17 | #[inline] 18 | #[track_caller] 19 | pub(crate) fn lock(&self) -> MutexGuard<'_, T> { 20 | self.0.lock().unwrap() 21 | } 22 | 23 | #[inline] 24 | pub(crate) fn try_lock(&self) -> Option> { 25 | self.0.try_lock().ok() 26 | } 27 | } 28 | pub(crate) use loom::sync::*; 29 | 30 | pub(crate) mod atomic { 31 | pub(crate) use loom::sync::atomic::*; 32 | 33 | // TODO: implement a loom version 34 | pub(crate) type StaticAtomicU64 = std::sync::atomic::AtomicU64; 35 | } 36 | } 37 | 38 | pub(crate) mod rand { 39 | pub(crate) fn seed() -> u64 { 40 | 1 41 | } 42 | } 43 | 44 | pub(crate) mod sys { 45 | pub(crate) fn num_cpus() -> usize { 46 | 2 47 | } 48 | } 49 | 50 | pub(crate) mod thread { 51 | pub use loom::lazy_static::AccessError; 52 | pub use loom::thread::*; 53 | } 54 | -------------------------------------------------------------------------------- /tokio-stream/src/stream_ext/map.rs: -------------------------------------------------------------------------------- 1 | use crate::Stream; 2 | 3 | use core::fmt; 4 | use core::pin::Pin; 5 | use core::task::{Context, Poll}; 6 | use pin_project_lite::pin_project; 7 | 8 | pin_project! { 9 | /// Stream for the [`map`](super::StreamExt::map) method. 10 | #[must_use = "streams do nothing unless polled"] 11 | pub struct Map { 12 | #[pin] 13 | stream: St, 14 | f: F, 15 | } 16 | } 17 | 18 | impl fmt::Debug for Map 19 | where 20 | St: fmt::Debug, 21 | { 22 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 23 | f.debug_struct("Map").field("stream", &self.stream).finish() 24 | } 25 | } 26 | 27 | impl Map { 28 | pub(super) fn new(stream: St, f: F) -> Self { 29 | Map { stream, f } 30 | } 31 | } 32 | 33 | impl Stream for Map 34 | where 35 | St: Stream, 36 | F: FnMut(St::Item) -> T, 37 | { 38 | type Item = T; 39 | 40 | fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 41 | self.as_mut() 42 | .project() 43 | .stream 44 | .poll_next(cx) 45 | .map(|opt| opt.map(|x| (self.as_mut().project().f)(x))) 46 | } 47 | 48 | fn size_hint(&self) -> (usize, Option) { 49 | self.stream.size_hint() 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tokio-stream/src/empty.rs: -------------------------------------------------------------------------------- 1 | use crate::Stream; 2 | 3 | use core::marker::PhantomData; 4 | use core::pin::Pin; 5 | use core::task::{Context, Poll}; 6 | 7 | /// Stream for the [`empty`](fn@empty) function. 8 | #[derive(Debug)] 9 | #[must_use = "streams do nothing unless polled"] 10 | pub struct Empty(PhantomData); 11 | 12 | impl Unpin for Empty {} 13 | unsafe impl Send for Empty {} 14 | unsafe impl Sync for Empty {} 15 | 16 | /// Creates a stream that yields nothing. 17 | /// 18 | /// The returned stream is immediately ready and returns `None`. Use 19 | /// [`stream::pending()`](super::pending()) to obtain a stream that is never 20 | /// ready. 21 | /// 22 | /// # Examples 23 | /// 24 | /// Basic usage: 25 | /// 26 | /// ``` 27 | /// use tokio_stream::{self as stream, StreamExt}; 28 | /// 29 | /// #[tokio::main] 30 | /// async fn main() { 31 | /// let mut none = stream::empty::(); 32 | /// 33 | /// assert_eq!(None, none.next().await); 34 | /// } 35 | /// ``` 36 | pub const fn empty() -> Empty { 37 | Empty(PhantomData) 38 | } 39 | 40 | impl Stream for Empty { 41 | type Item = T; 42 | 43 | fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { 44 | Poll::Ready(None) 45 | } 46 | 47 | fn size_hint(&self) -> (usize, Option) { 48 | (0, Some(0)) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /tokio/tests/tcp_echo.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", not(target_os = "wasi")))] // Wasi doesn't support bind 3 | 4 | use tokio::io::{self, AsyncReadExt, AsyncWriteExt}; 5 | use tokio::net::{TcpListener, TcpStream}; 6 | use tokio::sync::oneshot; 7 | use tokio_test::assert_ok; 8 | 9 | #[tokio::test] 10 | async fn echo_server() { 11 | const ITER: usize = 1024; 12 | 13 | let (tx, rx) = oneshot::channel(); 14 | 15 | let srv = assert_ok!(TcpListener::bind("127.0.0.1:0").await); 16 | let addr = assert_ok!(srv.local_addr()); 17 | 18 | let msg = "foo bar baz"; 19 | tokio::spawn(async move { 20 | let mut stream = assert_ok!(TcpStream::connect(&addr).await); 21 | 22 | for _ in 0..ITER { 23 | // write 24 | assert_ok!(stream.write_all(msg.as_bytes()).await); 25 | 26 | // read 27 | let mut buf = [0; 11]; 28 | assert_ok!(stream.read_exact(&mut buf).await); 29 | assert_eq!(&buf[..], msg.as_bytes()); 30 | } 31 | 32 | assert_ok!(tx.send(())); 33 | }); 34 | 35 | let (mut stream, _) = assert_ok!(srv.accept().await); 36 | let (mut rd, mut wr) = stream.split(); 37 | 38 | let n = assert_ok!(io::copy(&mut rd, &mut wr).await); 39 | assert_eq!(n, (ITER * msg.len()) as u64); 40 | 41 | assert_ok!(rx.await); 42 | } 43 | -------------------------------------------------------------------------------- /tokio/tests/no_rt.rs: -------------------------------------------------------------------------------- 1 | #![cfg(all(feature = "full", not(target_os = "wasi")))] // Wasi does not support panic recovery 2 | 3 | use tokio::net::TcpStream; 4 | use tokio::sync::oneshot; 5 | use tokio::time::{timeout, Duration}; 6 | 7 | use futures::executor::block_on; 8 | 9 | use std::net::TcpListener; 10 | 11 | #[test] 12 | #[should_panic( 13 | expected = "there is no reactor running, must be called from the context of a Tokio 1.x runtime" 14 | )] 15 | fn timeout_panics_when_no_tokio_context() { 16 | block_on(timeout_value()); 17 | } 18 | 19 | #[test] 20 | #[should_panic( 21 | expected = "there is no reactor running, must be called from the context of a Tokio 1.x runtime" 22 | )] 23 | fn panics_when_no_reactor() { 24 | let srv = TcpListener::bind("127.0.0.1:0").unwrap(); 25 | let addr = srv.local_addr().unwrap(); 26 | block_on(TcpStream::connect(&addr)).unwrap(); 27 | } 28 | 29 | async fn timeout_value() { 30 | let (_tx, rx) = oneshot::channel::<()>(); 31 | let dur = Duration::from_millis(10); 32 | let _ = timeout(dur, rx).await; 33 | } 34 | 35 | #[test] 36 | #[should_panic( 37 | expected = "there is no reactor running, must be called from the context of a Tokio 1.x runtime" 38 | )] 39 | fn io_panics_when_no_tokio_context() { 40 | let _ = tokio::net::TcpListener::from_std(std::net::TcpListener::bind("127.0.0.1:0").unwrap()); 41 | } 42 | -------------------------------------------------------------------------------- /tokio-stream/src/stream_ext/next.rs: -------------------------------------------------------------------------------- 1 | use crate::Stream; 2 | 3 | use core::future::Future; 4 | use core::marker::PhantomPinned; 5 | use core::pin::Pin; 6 | use core::task::{Context, Poll}; 7 | use pin_project_lite::pin_project; 8 | 9 | pin_project! { 10 | /// Future for the [`next`](super::StreamExt::next) method. 11 | /// 12 | /// # Cancel safety 13 | /// 14 | /// This method is cancel safe. It only 15 | /// holds onto a reference to the underlying stream, 16 | /// so dropping it will never lose a value. 17 | /// 18 | #[derive(Debug)] 19 | #[must_use = "futures do nothing unless you `.await` or poll them"] 20 | pub struct Next<'a, St: ?Sized> { 21 | stream: &'a mut St, 22 | // Make this future `!Unpin` for compatibility with async trait methods. 23 | #[pin] 24 | _pin: PhantomPinned, 25 | } 26 | } 27 | 28 | impl<'a, St: ?Sized> Next<'a, St> { 29 | pub(super) fn new(stream: &'a mut St) -> Self { 30 | Next { 31 | stream, 32 | _pin: PhantomPinned, 33 | } 34 | } 35 | } 36 | 37 | impl Future for Next<'_, St> { 38 | type Output = Option; 39 | 40 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 41 | let me = self.project(); 42 | Pin::new(me.stream).poll_next(cx) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tokio/src/io/util/flush.rs: -------------------------------------------------------------------------------- 1 | use crate::io::AsyncWrite; 2 | 3 | use pin_project_lite::pin_project; 4 | use std::future::Future; 5 | use std::io; 6 | use std::marker::PhantomPinned; 7 | use std::pin::Pin; 8 | use std::task::{Context, Poll}; 9 | 10 | pin_project! { 11 | /// A future used to fully flush an I/O object. 12 | /// 13 | /// Created by the [`AsyncWriteExt::flush`][flush] function. 14 | /// 15 | /// [flush]: crate::io::AsyncWriteExt::flush 16 | #[derive(Debug)] 17 | #[must_use = "futures do nothing unless you `.await` or poll them"] 18 | pub struct Flush<'a, A: ?Sized> { 19 | a: &'a mut A, 20 | // Make this future `!Unpin` for compatibility with async trait methods. 21 | #[pin] 22 | _pin: PhantomPinned, 23 | } 24 | } 25 | 26 | /// Creates a future which will entirely flush an I/O object. 27 | pub(super) fn flush(a: &mut A) -> Flush<'_, A> 28 | where 29 | A: AsyncWrite + Unpin + ?Sized, 30 | { 31 | Flush { 32 | a, 33 | _pin: PhantomPinned, 34 | } 35 | } 36 | 37 | impl Future for Flush<'_, A> 38 | where 39 | A: AsyncWrite + Unpin + ?Sized, 40 | { 41 | type Output = io::Result<()>; 42 | 43 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 44 | let me = self.project(); 45 | Pin::new(&mut *me.a).poll_flush(cx) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tokio/src/io/util/shutdown.rs: -------------------------------------------------------------------------------- 1 | use crate::io::AsyncWrite; 2 | 3 | use pin_project_lite::pin_project; 4 | use std::future::Future; 5 | use std::io; 6 | use std::marker::PhantomPinned; 7 | use std::pin::Pin; 8 | use std::task::{Context, Poll}; 9 | 10 | pin_project! { 11 | /// A future used to shutdown an I/O object. 12 | /// 13 | /// Created by the [`AsyncWriteExt::shutdown`][shutdown] function. 14 | /// [shutdown]: crate::io::AsyncWriteExt::shutdown 15 | #[must_use = "futures do nothing unless you `.await` or poll them"] 16 | #[derive(Debug)] 17 | pub struct Shutdown<'a, A: ?Sized> { 18 | a: &'a mut A, 19 | // Make this future `!Unpin` for compatibility with async trait methods. 20 | #[pin] 21 | _pin: PhantomPinned, 22 | } 23 | } 24 | 25 | /// Creates a future which will shutdown an I/O object. 26 | pub(super) fn shutdown(a: &mut A) -> Shutdown<'_, A> 27 | where 28 | A: AsyncWrite + Unpin + ?Sized, 29 | { 30 | Shutdown { 31 | a, 32 | _pin: PhantomPinned, 33 | } 34 | } 35 | 36 | impl Future for Shutdown<'_, A> 37 | where 38 | A: AsyncWrite + Unpin + ?Sized, 39 | { 40 | type Output = io::Result<()>; 41 | 42 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 43 | let me = self.project(); 44 | Pin::new(me.a).poll_shutdown(cx) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tokio/src/util/atomic_cell.rs: -------------------------------------------------------------------------------- 1 | use crate::loom::sync::atomic::AtomicPtr; 2 | 3 | use std::ptr; 4 | use std::sync::atomic::Ordering::AcqRel; 5 | 6 | pub(crate) struct AtomicCell { 7 | data: AtomicPtr, 8 | } 9 | 10 | unsafe impl Send for AtomicCell {} 11 | unsafe impl Sync for AtomicCell {} 12 | 13 | impl AtomicCell { 14 | pub(crate) fn new(data: Option>) -> AtomicCell { 15 | AtomicCell { 16 | data: AtomicPtr::new(to_raw(data)), 17 | } 18 | } 19 | 20 | pub(crate) fn swap(&self, val: Option>) -> Option> { 21 | let old = self.data.swap(to_raw(val), AcqRel); 22 | from_raw(old) 23 | } 24 | 25 | pub(crate) fn set(&self, val: Box) { 26 | let _ = self.swap(Some(val)); 27 | } 28 | 29 | pub(crate) fn take(&self) -> Option> { 30 | self.swap(None) 31 | } 32 | } 33 | 34 | fn to_raw(data: Option>) -> *mut T { 35 | data.map_or(ptr::null_mut(), Box::into_raw) 36 | } 37 | 38 | fn from_raw(val: *mut T) -> Option> { 39 | if val.is_null() { 40 | None 41 | } else { 42 | Some(unsafe { Box::from_raw(val) }) 43 | } 44 | } 45 | 46 | impl Drop for AtomicCell { 47 | fn drop(&mut self) { 48 | // Free any data still held by the cell 49 | let _ = self.take(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tokio-stream/src/wrappers/interval.rs: -------------------------------------------------------------------------------- 1 | use crate::Stream; 2 | use std::pin::Pin; 3 | use std::task::{Context, Poll}; 4 | use tokio::time::{Instant, Interval}; 5 | 6 | /// A wrapper around [`Interval`] that implements [`Stream`]. 7 | /// 8 | /// [`Interval`]: struct@tokio::time::Interval 9 | /// [`Stream`]: trait@crate::Stream 10 | #[derive(Debug)] 11 | #[cfg_attr(docsrs, doc(cfg(feature = "time")))] 12 | pub struct IntervalStream { 13 | inner: Interval, 14 | } 15 | 16 | impl IntervalStream { 17 | /// Create a new `IntervalStream`. 18 | pub fn new(interval: Interval) -> Self { 19 | Self { inner: interval } 20 | } 21 | 22 | /// Get back the inner `Interval`. 23 | pub fn into_inner(self) -> Interval { 24 | self.inner 25 | } 26 | } 27 | 28 | impl Stream for IntervalStream { 29 | type Item = Instant; 30 | 31 | fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 32 | self.inner.poll_tick(cx).map(Some) 33 | } 34 | 35 | fn size_hint(&self) -> (usize, Option) { 36 | (std::usize::MAX, None) 37 | } 38 | } 39 | 40 | impl AsRef for IntervalStream { 41 | fn as_ref(&self) -> &Interval { 42 | &self.inner 43 | } 44 | } 45 | 46 | impl AsMut for IntervalStream { 47 | fn as_mut(&mut self) -> &mut Interval { 48 | &mut self.inner 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /tokio-stream/src/stream_ext/fuse.rs: -------------------------------------------------------------------------------- 1 | use crate::Stream; 2 | 3 | use pin_project_lite::pin_project; 4 | use std::pin::Pin; 5 | use std::task::{Context, Poll}; 6 | 7 | pin_project! { 8 | /// Stream returned by [`fuse()`][super::StreamExt::fuse]. 9 | #[derive(Debug)] 10 | pub struct Fuse { 11 | #[pin] 12 | stream: Option, 13 | } 14 | } 15 | 16 | impl Fuse 17 | where 18 | T: Stream, 19 | { 20 | pub(crate) fn new(stream: T) -> Fuse { 21 | Fuse { 22 | stream: Some(stream), 23 | } 24 | } 25 | } 26 | 27 | impl Stream for Fuse 28 | where 29 | T: Stream, 30 | { 31 | type Item = T::Item; 32 | 33 | fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 34 | let res = match Option::as_pin_mut(self.as_mut().project().stream) { 35 | Some(stream) => ready!(stream.poll_next(cx)), 36 | None => return Poll::Ready(None), 37 | }; 38 | 39 | if res.is_none() { 40 | // Do not poll the stream anymore 41 | self.as_mut().project().stream.set(None); 42 | } 43 | 44 | Poll::Ready(res) 45 | } 46 | 47 | fn size_hint(&self) -> (usize, Option) { 48 | match self.stream { 49 | Some(ref stream) => stream.size_hint(), 50 | None => (0, Some(0)), 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /tokio/src/io/util/write.rs: -------------------------------------------------------------------------------- 1 | use crate::io::AsyncWrite; 2 | 3 | use pin_project_lite::pin_project; 4 | use std::future::Future; 5 | use std::io; 6 | use std::marker::PhantomPinned; 7 | use std::pin::Pin; 8 | use std::task::{Context, Poll}; 9 | 10 | pin_project! { 11 | /// A future to write some of the buffer to an `AsyncWrite`. 12 | #[derive(Debug)] 13 | #[must_use = "futures do nothing unless you `.await` or poll them"] 14 | pub struct Write<'a, W: ?Sized> { 15 | writer: &'a mut W, 16 | buf: &'a [u8], 17 | // Make this future `!Unpin` for compatibility with async trait methods. 18 | #[pin] 19 | _pin: PhantomPinned, 20 | } 21 | } 22 | 23 | /// Tries to write some bytes from the given `buf` to the writer in an 24 | /// asynchronous manner, returning a future. 25 | pub(crate) fn write<'a, W>(writer: &'a mut W, buf: &'a [u8]) -> Write<'a, W> 26 | where 27 | W: AsyncWrite + Unpin + ?Sized, 28 | { 29 | Write { 30 | writer, 31 | buf, 32 | _pin: PhantomPinned, 33 | } 34 | } 35 | 36 | impl Future for Write<'_, W> 37 | where 38 | W: AsyncWrite + Unpin + ?Sized, 39 | { 40 | type Output = io::Result; 41 | 42 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 43 | let me = self.project(); 44 | Pin::new(&mut *me.writer).poll_write(cx, me.buf) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tokio/src/runtime/process.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "rt"), allow(dead_code))] 2 | 3 | //! Process driver. 4 | 5 | use crate::process::unix::GlobalOrphanQueue; 6 | use crate::runtime::driver; 7 | use crate::runtime::signal::{Driver as SignalDriver, Handle as SignalHandle}; 8 | 9 | use std::time::Duration; 10 | 11 | /// Responsible for cleaning up orphaned child processes on Unix platforms. 12 | #[derive(Debug)] 13 | pub(crate) struct Driver { 14 | park: SignalDriver, 15 | signal_handle: SignalHandle, 16 | } 17 | 18 | // ===== impl Driver ===== 19 | 20 | impl Driver { 21 | /// Creates a new signal `Driver` instance that delegates wakeups to `park`. 22 | pub(crate) fn new(park: SignalDriver) -> Self { 23 | let signal_handle = park.handle(); 24 | 25 | Self { 26 | park, 27 | signal_handle, 28 | } 29 | } 30 | 31 | pub(crate) fn park(&mut self, handle: &driver::Handle) { 32 | self.park.park(handle); 33 | GlobalOrphanQueue::reap_orphans(&self.signal_handle); 34 | } 35 | 36 | pub(crate) fn park_timeout(&mut self, handle: &driver::Handle, duration: Duration) { 37 | self.park.park_timeout(handle, duration); 38 | GlobalOrphanQueue::reap_orphans(&self.signal_handle); 39 | } 40 | 41 | pub(crate) fn shutdown(&mut self, handle: &driver::Handle) { 42 | self.park.shutdown(handle); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tokio/src/io/util/write_vectored.rs: -------------------------------------------------------------------------------- 1 | use crate::io::AsyncWrite; 2 | 3 | use pin_project_lite::pin_project; 4 | use std::io; 5 | use std::marker::PhantomPinned; 6 | use std::pin::Pin; 7 | use std::task::{Context, Poll}; 8 | use std::{future::Future, io::IoSlice}; 9 | 10 | pin_project! { 11 | /// A future to write a slice of buffers to an `AsyncWrite`. 12 | #[derive(Debug)] 13 | #[must_use = "futures do nothing unless you `.await` or poll them"] 14 | pub struct WriteVectored<'a, 'b, W: ?Sized> { 15 | writer: &'a mut W, 16 | bufs: &'a [IoSlice<'b>], 17 | // Make this future `!Unpin` for compatibility with async trait methods. 18 | #[pin] 19 | _pin: PhantomPinned, 20 | } 21 | } 22 | 23 | pub(crate) fn write_vectored<'a, 'b, W>( 24 | writer: &'a mut W, 25 | bufs: &'a [IoSlice<'b>], 26 | ) -> WriteVectored<'a, 'b, W> 27 | where 28 | W: AsyncWrite + Unpin + ?Sized, 29 | { 30 | WriteVectored { 31 | writer, 32 | bufs, 33 | _pin: PhantomPinned, 34 | } 35 | } 36 | 37 | impl Future for WriteVectored<'_, '_, W> 38 | where 39 | W: AsyncWrite + Unpin + ?Sized, 40 | { 41 | type Output = io::Result; 42 | 43 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 44 | let me = self.project(); 45 | Pin::new(&mut *me.writer).poll_write_vectored(cx, me.bufs) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tokio-stream/src/once.rs: -------------------------------------------------------------------------------- 1 | use crate::{Iter, Stream}; 2 | 3 | use core::option; 4 | use core::pin::Pin; 5 | use core::task::{Context, Poll}; 6 | 7 | /// Stream for the [`once`](fn@once) function. 8 | #[derive(Debug)] 9 | #[must_use = "streams do nothing unless polled"] 10 | pub struct Once { 11 | iter: Iter>, 12 | } 13 | 14 | impl Unpin for Once {} 15 | 16 | /// Creates a stream that emits an element exactly once. 17 | /// 18 | /// The returned stream is immediately ready and emits the provided value once. 19 | /// 20 | /// # Examples 21 | /// 22 | /// ``` 23 | /// use tokio_stream::{self as stream, StreamExt}; 24 | /// 25 | /// #[tokio::main] 26 | /// async fn main() { 27 | /// // one is the loneliest number 28 | /// let mut one = stream::once(1); 29 | /// 30 | /// assert_eq!(Some(1), one.next().await); 31 | /// 32 | /// // just one, that's all we get 33 | /// assert_eq!(None, one.next().await); 34 | /// } 35 | /// ``` 36 | pub fn once(value: T) -> Once { 37 | Once { 38 | iter: crate::iter(Some(value)), 39 | } 40 | } 41 | 42 | impl Stream for Once { 43 | type Item = T; 44 | 45 | fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 46 | Pin::new(&mut self.iter).poll_next(cx) 47 | } 48 | 49 | fn size_hint(&self) -> (usize, Option) { 50 | self.iter.size_hint() 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tokio-stream/src/stream_ext/peekable.rs: -------------------------------------------------------------------------------- 1 | use std::pin::Pin; 2 | use std::task::{Context, Poll}; 3 | 4 | use futures_core::Stream; 5 | use pin_project_lite::pin_project; 6 | 7 | use crate::stream_ext::Fuse; 8 | use crate::StreamExt; 9 | 10 | pin_project! { 11 | /// Stream returned by the [`chain`](super::StreamExt::peekable) method. 12 | pub struct Peekable { 13 | peek: Option, 14 | #[pin] 15 | stream: Fuse, 16 | } 17 | } 18 | 19 | impl Peekable { 20 | pub(crate) fn new(stream: T) -> Self { 21 | let stream = stream.fuse(); 22 | Self { peek: None, stream } 23 | } 24 | 25 | /// Peek at the next item in the stream. 26 | pub async fn peek(&mut self) -> Option<&T::Item> 27 | where 28 | T: Unpin, 29 | { 30 | if let Some(ref it) = self.peek { 31 | Some(it) 32 | } else { 33 | self.peek = self.next().await; 34 | self.peek.as_ref() 35 | } 36 | } 37 | } 38 | 39 | impl Stream for Peekable { 40 | type Item = T::Item; 41 | 42 | fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 43 | let this = self.project(); 44 | if let Some(it) = this.peek.take() { 45 | Poll::Ready(Some(it)) 46 | } else { 47 | this.stream.poll_next(cx) 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /tokio/tests/io_write_all.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | 4 | use tokio::io::{AsyncWrite, AsyncWriteExt}; 5 | use tokio_test::assert_ok; 6 | 7 | use bytes::BytesMut; 8 | use std::cmp; 9 | use std::io; 10 | use std::pin::Pin; 11 | use std::task::{Context, Poll}; 12 | 13 | #[tokio::test] 14 | async fn write_all() { 15 | struct Wr { 16 | buf: BytesMut, 17 | cnt: usize, 18 | } 19 | 20 | impl AsyncWrite for Wr { 21 | fn poll_write( 22 | mut self: Pin<&mut Self>, 23 | _cx: &mut Context<'_>, 24 | buf: &[u8], 25 | ) -> Poll> { 26 | let n = cmp::min(4, buf.len()); 27 | let buf = &buf[0..n]; 28 | 29 | self.cnt += 1; 30 | self.buf.extend(buf); 31 | Ok(buf.len()).into() 32 | } 33 | 34 | fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { 35 | Ok(()).into() 36 | } 37 | 38 | fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { 39 | Ok(()).into() 40 | } 41 | } 42 | 43 | let mut wr = Wr { 44 | buf: BytesMut::with_capacity(64), 45 | cnt: 0, 46 | }; 47 | 48 | assert_ok!(wr.write_all(b"hello world").await); 49 | assert_eq!(wr.buf, b"hello world"[..]); 50 | assert_eq!(wr.cnt, 3); 51 | } 52 | -------------------------------------------------------------------------------- /tokio-stream/src/stream_ext/map_while.rs: -------------------------------------------------------------------------------- 1 | use crate::Stream; 2 | 3 | use core::fmt; 4 | use core::pin::Pin; 5 | use core::task::{Context, Poll}; 6 | use pin_project_lite::pin_project; 7 | 8 | pin_project! { 9 | /// Stream for the [`map_while`](super::StreamExt::map_while) method. 10 | #[must_use = "streams do nothing unless polled"] 11 | pub struct MapWhile { 12 | #[pin] 13 | stream: St, 14 | f: F, 15 | } 16 | } 17 | 18 | impl fmt::Debug for MapWhile 19 | where 20 | St: fmt::Debug, 21 | { 22 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 23 | f.debug_struct("MapWhile") 24 | .field("stream", &self.stream) 25 | .finish() 26 | } 27 | } 28 | 29 | impl MapWhile { 30 | pub(super) fn new(stream: St, f: F) -> Self { 31 | MapWhile { stream, f } 32 | } 33 | } 34 | 35 | impl Stream for MapWhile 36 | where 37 | St: Stream, 38 | F: FnMut(St::Item) -> Option, 39 | { 40 | type Item = T; 41 | 42 | fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 43 | let me = self.project(); 44 | let f = me.f; 45 | me.stream.poll_next(cx).map(|opt| opt.and_then(f)) 46 | } 47 | 48 | fn size_hint(&self) -> (usize, Option) { 49 | let (_, upper) = self.stream.size_hint(); 50 | (0, upper) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tokio-stream/src/wrappers.rs: -------------------------------------------------------------------------------- 1 | //! Wrappers for Tokio types that implement `Stream`. 2 | 3 | /// Error types for the wrappers. 4 | pub mod errors { 5 | cfg_sync! { 6 | pub use crate::wrappers::broadcast::BroadcastStreamRecvError; 7 | } 8 | } 9 | 10 | mod mpsc_bounded; 11 | pub use mpsc_bounded::ReceiverStream; 12 | 13 | mod mpsc_unbounded; 14 | pub use mpsc_unbounded::UnboundedReceiverStream; 15 | 16 | cfg_sync! { 17 | mod broadcast; 18 | pub use broadcast::BroadcastStream; 19 | 20 | mod watch; 21 | pub use watch::WatchStream; 22 | } 23 | 24 | cfg_signal! { 25 | #[cfg(unix)] 26 | mod signal_unix; 27 | #[cfg(unix)] 28 | pub use signal_unix::SignalStream; 29 | 30 | #[cfg(any(windows, docsrs))] 31 | mod signal_windows; 32 | #[cfg(any(windows, docsrs))] 33 | pub use signal_windows::{CtrlCStream, CtrlBreakStream}; 34 | } 35 | 36 | cfg_time! { 37 | mod interval; 38 | pub use interval::IntervalStream; 39 | } 40 | 41 | cfg_net! { 42 | mod tcp_listener; 43 | pub use tcp_listener::TcpListenerStream; 44 | 45 | #[cfg(unix)] 46 | mod unix_listener; 47 | #[cfg(unix)] 48 | pub use unix_listener::UnixListenerStream; 49 | } 50 | 51 | cfg_io_util! { 52 | mod split; 53 | pub use split::SplitStream; 54 | 55 | mod lines; 56 | pub use lines::LinesStream; 57 | } 58 | 59 | cfg_fs! { 60 | mod read_dir; 61 | pub use read_dir::ReadDirStream; 62 | } 63 | -------------------------------------------------------------------------------- /tokio/tests/io_driver_drop.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", not(target_os = "wasi")))] // Wasi does not support bind 3 | 4 | use tokio::net::TcpListener; 5 | use tokio::runtime; 6 | use tokio_test::{assert_err, assert_pending, assert_ready, task}; 7 | 8 | #[test] 9 | fn tcp_doesnt_block() { 10 | let rt = rt(); 11 | 12 | let listener = { 13 | let _enter = rt.enter(); 14 | let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap(); 15 | TcpListener::from_std(listener).unwrap() 16 | }; 17 | 18 | drop(rt); 19 | 20 | let mut task = task::spawn(async move { 21 | assert_err!(listener.accept().await); 22 | }); 23 | 24 | assert_ready!(task.poll()); 25 | } 26 | 27 | #[test] 28 | fn drop_wakes() { 29 | let rt = rt(); 30 | 31 | let listener = { 32 | let _enter = rt.enter(); 33 | let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap(); 34 | TcpListener::from_std(listener).unwrap() 35 | }; 36 | 37 | let mut task = task::spawn(async move { 38 | assert_err!(listener.accept().await); 39 | }); 40 | 41 | assert_pending!(task.poll()); 42 | 43 | drop(rt); 44 | 45 | assert!(task.is_woken()); 46 | assert_ready!(task.poll()); 47 | } 48 | 49 | fn rt() -> runtime::Runtime { 50 | runtime::Builder::new_current_thread() 51 | .enable_all() 52 | .build() 53 | .unwrap() 54 | } 55 | -------------------------------------------------------------------------------- /tokio/tests/process_issue_42.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(unix)] 4 | 5 | use futures::future::join_all; 6 | use std::process::Stdio; 7 | use tokio::process::Command; 8 | use tokio::task; 9 | 10 | #[tokio::test] 11 | async fn issue_42() { 12 | // We spawn a many batches of processes which should exit at roughly the 13 | // same time (modulo OS scheduling delays), to make sure that consuming 14 | // a readiness event for one process doesn't inadvertently starve another. 15 | // We then do this many times (in parallel) in an effort to stress test the 16 | // implementation to ensure there are no race conditions. 17 | // See alexcrichton/tokio-process#42 for background 18 | let join_handles = (0..10usize).map(|_| { 19 | task::spawn(async { 20 | let processes = (0..10usize).map(|i| { 21 | let mut child = Command::new("echo") 22 | .arg(format!("I am spawned process #{}", i)) 23 | .stdin(Stdio::null()) 24 | .stdout(Stdio::null()) 25 | .stderr(Stdio::null()) 26 | .kill_on_drop(true) 27 | .spawn() 28 | .unwrap(); 29 | 30 | async move { child.wait().await } 31 | }); 32 | 33 | join_all(processes).await; 34 | }) 35 | }); 36 | 37 | join_all(join_handles).await; 38 | } 39 | -------------------------------------------------------------------------------- /tokio/src/runtime/context/scoped.rs: -------------------------------------------------------------------------------- 1 | use std::cell::Cell; 2 | use std::ptr; 3 | 4 | /// Scoped thread-local storage 5 | pub(super) struct Scoped { 6 | pub(super) inner: Cell<*const T>, 7 | } 8 | 9 | impl Scoped { 10 | pub(super) const fn new() -> Scoped { 11 | Scoped { 12 | inner: Cell::new(ptr::null()), 13 | } 14 | } 15 | 16 | /// Inserts a value into the scoped cell for the duration of the closure 17 | pub(super) fn set(&self, t: &T, f: F) -> R 18 | where 19 | F: FnOnce() -> R, 20 | { 21 | struct Reset<'a, T> { 22 | cell: &'a Cell<*const T>, 23 | prev: *const T, 24 | } 25 | 26 | impl Drop for Reset<'_, T> { 27 | fn drop(&mut self) { 28 | self.cell.set(self.prev); 29 | } 30 | } 31 | 32 | let prev = self.inner.get(); 33 | self.inner.set(t as *const _); 34 | 35 | let _reset = Reset { 36 | cell: &self.inner, 37 | prev, 38 | }; 39 | 40 | f() 41 | } 42 | 43 | /// Gets the value out of the scoped cell; 44 | pub(super) fn with(&self, f: F) -> R 45 | where 46 | F: FnOnce(Option<&T>) -> R, 47 | { 48 | let val = self.inner.get(); 49 | 50 | if val.is_null() { 51 | f(None) 52 | } else { 53 | unsafe { f(Some(&*val)) } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tokio/tests/uds_split.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(unix)] 4 | 5 | use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; 6 | use tokio::net::UnixStream; 7 | 8 | /// Checks that `UnixStream` can be split into a read half and a write half using 9 | /// `UnixStream::split` and `UnixStream::split_mut`. 10 | /// 11 | /// Verifies that the implementation of `AsyncWrite::poll_shutdown` shutdowns the stream for 12 | /// writing by reading to the end of stream on the other side of the connection. 13 | #[tokio::test] 14 | async fn split() -> std::io::Result<()> { 15 | let (mut a, mut b) = UnixStream::pair()?; 16 | 17 | let (mut a_read, mut a_write) = a.split(); 18 | let (mut b_read, mut b_write) = b.split(); 19 | 20 | let (a_response, b_response) = futures::future::try_join( 21 | send_recv_all(&mut a_read, &mut a_write, b"A"), 22 | send_recv_all(&mut b_read, &mut b_write, b"B"), 23 | ) 24 | .await?; 25 | 26 | assert_eq!(a_response, b"B"); 27 | assert_eq!(b_response, b"A"); 28 | 29 | Ok(()) 30 | } 31 | 32 | async fn send_recv_all( 33 | read: &mut (dyn AsyncRead + Unpin), 34 | write: &mut (dyn AsyncWrite + Unpin), 35 | input: &[u8], 36 | ) -> std::io::Result> { 37 | write.write_all(input).await?; 38 | write.shutdown().await?; 39 | 40 | let mut output = Vec::new(); 41 | read.read_to_end(&mut output).await?; 42 | Ok(output) 43 | } 44 | -------------------------------------------------------------------------------- /.github/workflows/stress-test.yml: -------------------------------------------------------------------------------- 1 | name: Stress Test 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - master 7 | 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} 10 | cancel-in-progress: true 11 | 12 | env: 13 | RUSTFLAGS: -Dwarnings 14 | RUST_BACKTRACE: 1 15 | # Change to specific Rust release to pin 16 | rust_stable: stable 17 | 18 | permissions: 19 | contents: read 20 | 21 | jobs: 22 | stress-test: 23 | name: Stress Test 24 | runs-on: ubuntu-latest 25 | strategy: 26 | matrix: 27 | stress-test: 28 | - simple_echo_tcp 29 | steps: 30 | - uses: actions/checkout@v4 31 | - name: Install Rust ${{ env.rust_stable }} 32 | uses: dtolnay/rust-toolchain@master 33 | with: 34 | toolchain: ${{ env.rust_stable }} 35 | - name: Install Valgrind 36 | uses: taiki-e/install-action@valgrind 37 | 38 | - uses: Swatinem/rust-cache@v2 39 | # Compiles each of the stress test examples. 40 | - name: Compile stress test examples 41 | run: cargo build -p stress-test --release --example ${{ matrix.stress-test }} 42 | 43 | # Runs each of the examples using Valgrind. Detects leaks and displays them. 44 | - name: Run valgrind 45 | run: valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all --fair-sched=yes ./target/release/examples/${{ matrix.stress-test }} 46 | -------------------------------------------------------------------------------- /tokio/tests/duplex_stream.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | 4 | use std::io::IoSlice; 5 | use tokio::io::{AsyncReadExt, AsyncWriteExt}; 6 | 7 | const HELLO: &[u8] = b"hello world..."; 8 | 9 | #[tokio::test] 10 | async fn write_vectored() { 11 | let (mut client, mut server) = tokio::io::duplex(64); 12 | 13 | let ret = client 14 | .write_vectored(&[IoSlice::new(HELLO), IoSlice::new(HELLO)]) 15 | .await 16 | .unwrap(); 17 | assert_eq!(ret, HELLO.len() * 2); 18 | 19 | client.flush().await.unwrap(); 20 | drop(client); 21 | 22 | let mut buf = Vec::with_capacity(HELLO.len() * 2); 23 | let bytes_read = server.read_to_end(&mut buf).await.unwrap(); 24 | 25 | assert_eq!(bytes_read, HELLO.len() * 2); 26 | assert_eq!(buf, [HELLO, HELLO].concat()); 27 | } 28 | 29 | #[tokio::test] 30 | async fn write_vectored_and_shutdown() { 31 | let (mut client, mut server) = tokio::io::duplex(64); 32 | 33 | let ret = client 34 | .write_vectored(&[IoSlice::new(HELLO), IoSlice::new(HELLO)]) 35 | .await 36 | .unwrap(); 37 | assert_eq!(ret, HELLO.len() * 2); 38 | 39 | client.shutdown().await.unwrap(); 40 | drop(client); 41 | 42 | let mut buf = Vec::with_capacity(HELLO.len() * 2); 43 | let bytes_read = server.read_to_end(&mut buf).await.unwrap(); 44 | 45 | assert_eq!(bytes_read, HELLO.len() * 2); 46 | assert_eq!(buf, [HELLO, HELLO].concat()); 47 | } 48 | -------------------------------------------------------------------------------- /tokio/tests/support/io_vec.rs: -------------------------------------------------------------------------------- 1 | use std::io::IoSlice; 2 | use std::ops::Deref; 3 | use std::slice; 4 | 5 | pub struct IoBufs<'a, 'b>(&'b mut [IoSlice<'a>]); 6 | 7 | impl<'a, 'b> IoBufs<'a, 'b> { 8 | pub fn new(slices: &'b mut [IoSlice<'a>]) -> Self { 9 | IoBufs(slices) 10 | } 11 | 12 | pub fn is_empty(&self) -> bool { 13 | self.0.is_empty() 14 | } 15 | 16 | pub fn advance(mut self, n: usize) -> IoBufs<'a, 'b> { 17 | let mut to_remove = 0; 18 | let mut remaining_len = n; 19 | for slice in self.0.iter() { 20 | if remaining_len < slice.len() { 21 | break; 22 | } else { 23 | remaining_len -= slice.len(); 24 | to_remove += 1; 25 | } 26 | } 27 | self.0 = self.0.split_at_mut(to_remove).1; 28 | if let Some(slice) = self.0.first_mut() { 29 | let tail = &slice[remaining_len..]; 30 | // Safety: recasts slice to the original lifetime 31 | let tail = unsafe { slice::from_raw_parts(tail.as_ptr(), tail.len()) }; 32 | *slice = IoSlice::new(tail); 33 | } else if remaining_len != 0 { 34 | panic!("advance past the end of the slice vector"); 35 | } 36 | self 37 | } 38 | } 39 | 40 | impl<'a, 'b> Deref for IoBufs<'a, 'b> { 41 | type Target = [IoSlice<'a>]; 42 | fn deref(&self) -> &[IoSlice<'a>] { 43 | self.0 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tokio-util/tests/compat.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "compat")] 2 | #![cfg(not(target_os = "wasi"))] // WASI does not support all fs operations 3 | #![warn(rust_2018_idioms)] 4 | 5 | use futures_io::SeekFrom; 6 | use futures_util::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt}; 7 | use tempfile::NamedTempFile; 8 | use tokio::fs::OpenOptions; 9 | use tokio_util::compat::TokioAsyncWriteCompatExt; 10 | 11 | #[tokio::test] 12 | async fn compat_file_seek() -> futures_util::io::Result<()> { 13 | let temp_file = NamedTempFile::new()?; 14 | let mut file = OpenOptions::new() 15 | .read(true) 16 | .write(true) 17 | .create(true) 18 | .open(temp_file) 19 | .await? 20 | .compat_write(); 21 | 22 | file.write_all(&[0, 1, 2, 3, 4, 5]).await?; 23 | file.write_all(&[6, 7]).await?; 24 | 25 | assert_eq!(file.stream_position().await?, 8); 26 | 27 | // Modify elements at position 2. 28 | assert_eq!(file.seek(SeekFrom::Start(2)).await?, 2); 29 | file.write_all(&[8, 9]).await?; 30 | 31 | file.flush().await?; 32 | 33 | // Verify we still have 8 elements. 34 | assert_eq!(file.seek(SeekFrom::End(0)).await?, 8); 35 | // Seek back to the start of the file to read and verify contents. 36 | file.seek(SeekFrom::Start(0)).await?; 37 | 38 | let mut buf = Vec::new(); 39 | let num_bytes = file.read_to_end(&mut buf).await?; 40 | assert_eq!(&buf[..num_bytes], &[0, 1, 8, 9, 4, 5, 6, 7]); 41 | 42 | Ok(()) 43 | } 44 | -------------------------------------------------------------------------------- /tokio/tests/tcp_split.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", not(target_os = "wasi")))] // Wasi doesn't support bind 3 | 4 | use std::io::Result; 5 | use std::io::{Read, Write}; 6 | use std::{net, thread}; 7 | 8 | use tokio::io::{AsyncReadExt, AsyncWriteExt}; 9 | use tokio::net::TcpStream; 10 | 11 | #[tokio::test] 12 | async fn split() -> Result<()> { 13 | const MSG: &[u8] = b"split"; 14 | 15 | let listener = net::TcpListener::bind("127.0.0.1:0")?; 16 | let addr = listener.local_addr()?; 17 | 18 | let handle = thread::spawn(move || { 19 | let (mut stream, _) = listener.accept().unwrap(); 20 | stream.write_all(MSG).unwrap(); 21 | 22 | let mut read_buf = [0u8; 32]; 23 | let read_len = stream.read(&mut read_buf).unwrap(); 24 | assert_eq!(&read_buf[..read_len], MSG); 25 | }); 26 | 27 | let mut stream = TcpStream::connect(&addr).await?; 28 | let (mut read_half, mut write_half) = stream.split(); 29 | 30 | let mut read_buf = [0u8; 32]; 31 | let peek_len1 = read_half.peek(&mut read_buf[..]).await?; 32 | let peek_len2 = read_half.peek(&mut read_buf[..]).await?; 33 | assert_eq!(peek_len1, peek_len2); 34 | 35 | let read_len = read_half.read(&mut read_buf[..]).await?; 36 | assert_eq!(peek_len1, read_len); 37 | assert_eq!(&read_buf[..read_len], MSG); 38 | 39 | assert_eq!(write_half.write(MSG).await?, MSG.len()); 40 | handle.join().unwrap(); 41 | Ok(()) 42 | } 43 | -------------------------------------------------------------------------------- /tokio/src/fs/hard_link.rs: -------------------------------------------------------------------------------- 1 | use crate::fs::asyncify; 2 | 3 | use std::io; 4 | use std::path::Path; 5 | 6 | /// Creates a new hard link on the filesystem. 7 | /// 8 | /// This is an async version of [`std::fs::hard_link`]. 9 | /// 10 | /// The `dst` path will be a link pointing to the `src` path. Note that systems 11 | /// often require these two paths to both be located on the same filesystem. 12 | /// 13 | /// # Platform-specific behavior 14 | /// 15 | /// This function currently corresponds to the `link` function on Unix 16 | /// and the `CreateHardLink` function on Windows. 17 | /// Note that, this [may change in the future][changes]. 18 | /// 19 | /// [changes]: https://doc.rust-lang.org/std/io/index.html#platform-specific-behavior 20 | /// 21 | /// # Errors 22 | /// 23 | /// This function will return an error in the following situations, but is not 24 | /// limited to just these cases: 25 | /// 26 | /// * The `src` path is not a file or doesn't exist. 27 | /// 28 | /// # Examples 29 | /// 30 | /// ```no_run 31 | /// use tokio::fs; 32 | /// 33 | /// #[tokio::main] 34 | /// async fn main() -> std::io::Result<()> { 35 | /// fs::hard_link("a.txt", "b.txt").await?; // Hard link a.txt to b.txt 36 | /// Ok(()) 37 | /// } 38 | /// ``` 39 | pub async fn hard_link(src: impl AsRef, dst: impl AsRef) -> io::Result<()> { 40 | let src = src.as_ref().to_owned(); 41 | let dst = dst.as_ref().to_owned(); 42 | 43 | asyncify(move || std::fs::hard_link(src, dst)).await 44 | } 45 | -------------------------------------------------------------------------------- /tokio/src/doc/mod.rs: -------------------------------------------------------------------------------- 1 | //! Types which are documented locally in the Tokio crate, but does not actually 2 | //! live here. 3 | //! 4 | //! **Note** this module is only visible on docs.rs, you cannot use it directly 5 | //! in your own code. 6 | 7 | /// The name of a type which is not defined here. 8 | /// 9 | /// This is typically used as an alias for another type, like so: 10 | /// 11 | /// ```rust,ignore 12 | /// /// See [some::other::location](https://example.com). 13 | /// type DEFINED_ELSEWHERE = crate::doc::NotDefinedHere; 14 | /// ``` 15 | /// 16 | /// This type is uninhabitable like the [`never` type] to ensure that no one 17 | /// will ever accidentally use it. 18 | /// 19 | /// [`never` type]: https://doc.rust-lang.org/std/primitive.never.html 20 | #[derive(Debug)] 21 | pub enum NotDefinedHere {} 22 | 23 | #[cfg(feature = "net")] 24 | impl mio::event::Source for NotDefinedHere { 25 | fn register( 26 | &mut self, 27 | registry: &mio::Registry, 28 | token: mio::Token, 29 | interests: mio::Interest, 30 | ) -> std::io::Result<()> { 31 | Ok(()) 32 | } 33 | fn reregister( 34 | &mut self, 35 | registry: &mio::Registry, 36 | token: mio::Token, 37 | interests: mio::Interest, 38 | ) -> std::io::Result<()> { 39 | Ok(()) 40 | } 41 | fn deregister(&mut self, registry: &mio::Registry) -> std::io::Result<()> { 42 | Ok(()) 43 | } 44 | } 45 | 46 | #[cfg(feature = "net")] 47 | pub mod os; 48 | -------------------------------------------------------------------------------- /tokio/src/loom/std/atomic_u16.rs: -------------------------------------------------------------------------------- 1 | use std::cell::UnsafeCell; 2 | use std::fmt; 3 | use std::ops::Deref; 4 | 5 | /// `AtomicU16` providing an additional `unsync_load` function. 6 | pub(crate) struct AtomicU16 { 7 | inner: UnsafeCell, 8 | } 9 | 10 | unsafe impl Send for AtomicU16 {} 11 | unsafe impl Sync for AtomicU16 {} 12 | 13 | impl AtomicU16 { 14 | pub(crate) const fn new(val: u16) -> AtomicU16 { 15 | let inner = UnsafeCell::new(std::sync::atomic::AtomicU16::new(val)); 16 | AtomicU16 { inner } 17 | } 18 | 19 | /// Performs an unsynchronized load. 20 | /// 21 | /// # Safety 22 | /// 23 | /// All mutations must have happened before the unsynchronized load. 24 | /// Additionally, there must be no concurrent mutations. 25 | pub(crate) unsafe fn unsync_load(&self) -> u16 { 26 | // See 27 | self.load(std::sync::atomic::Ordering::Relaxed) 28 | } 29 | } 30 | 31 | impl Deref for AtomicU16 { 32 | type Target = std::sync::atomic::AtomicU16; 33 | 34 | fn deref(&self) -> &Self::Target { 35 | // safety: it is always safe to access `&self` fns on the inner value as 36 | // we never perform unsafe mutations. 37 | unsafe { &*self.inner.get() } 38 | } 39 | } 40 | 41 | impl fmt::Debug for AtomicU16 { 42 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 43 | self.deref().fmt(fmt) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tokio/src/loom/std/atomic_u32.rs: -------------------------------------------------------------------------------- 1 | use std::cell::UnsafeCell; 2 | use std::fmt; 3 | use std::ops::Deref; 4 | 5 | /// `AtomicU32` providing an additional `unsync_load` function. 6 | pub(crate) struct AtomicU32 { 7 | inner: UnsafeCell, 8 | } 9 | 10 | unsafe impl Send for AtomicU32 {} 11 | unsafe impl Sync for AtomicU32 {} 12 | 13 | impl AtomicU32 { 14 | pub(crate) const fn new(val: u32) -> AtomicU32 { 15 | let inner = UnsafeCell::new(std::sync::atomic::AtomicU32::new(val)); 16 | AtomicU32 { inner } 17 | } 18 | 19 | /// Performs an unsynchronized load. 20 | /// 21 | /// # Safety 22 | /// 23 | /// All mutations must have happened before the unsynchronized load. 24 | /// Additionally, there must be no concurrent mutations. 25 | pub(crate) unsafe fn unsync_load(&self) -> u32 { 26 | // See 27 | self.load(std::sync::atomic::Ordering::Relaxed) 28 | } 29 | } 30 | 31 | impl Deref for AtomicU32 { 32 | type Target = std::sync::atomic::AtomicU32; 33 | 34 | fn deref(&self) -> &Self::Target { 35 | // safety: it is always safe to access `&self` fns on the inner value as 36 | // we never perform unsafe mutations. 37 | unsafe { &*self.inner.get() } 38 | } 39 | } 40 | 41 | impl fmt::Debug for AtomicU32 { 42 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 43 | self.deref().fmt(fmt) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tokio-stream/src/stream_ext/try_next.rs: -------------------------------------------------------------------------------- 1 | use crate::stream_ext::Next; 2 | use crate::Stream; 3 | 4 | use core::future::Future; 5 | use core::marker::PhantomPinned; 6 | use core::pin::Pin; 7 | use core::task::{Context, Poll}; 8 | use pin_project_lite::pin_project; 9 | 10 | pin_project! { 11 | /// Future for the [`try_next`](super::StreamExt::try_next) method. 12 | /// 13 | /// # Cancel safety 14 | /// 15 | /// This method is cancel safe. It only 16 | /// holds onto a reference to the underlying stream, 17 | /// so dropping it will never lose a value. 18 | #[derive(Debug)] 19 | #[must_use = "futures do nothing unless you `.await` or poll them"] 20 | pub struct TryNext<'a, St: ?Sized> { 21 | #[pin] 22 | inner: Next<'a, St>, 23 | // Make this future `!Unpin` for compatibility with async trait methods. 24 | #[pin] 25 | _pin: PhantomPinned, 26 | } 27 | } 28 | 29 | impl<'a, St: ?Sized> TryNext<'a, St> { 30 | pub(super) fn new(stream: &'a mut St) -> Self { 31 | Self { 32 | inner: Next::new(stream), 33 | _pin: PhantomPinned, 34 | } 35 | } 36 | } 37 | 38 | impl> + Unpin> Future for TryNext<'_, St> { 39 | type Output = Result, E>; 40 | 41 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 42 | let me = self.project(); 43 | me.inner.poll(cx).map(Option::transpose) 44 | } 45 | } 46 | --------------------------------------------------------------------------------