├── .cirrus.yml ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md ├── buildomat │ ├── README.md │ └── config.toml ├── labeler.yml └── workflows │ ├── audit.yml │ ├── ci.yml │ ├── labeler.yml │ ├── loom.yml │ ├── pr-audit.yml │ └── stress-test.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Cargo.toml ├── Cross.toml ├── LICENSE ├── README.md ├── SECURITY.md ├── benches ├── Cargo.toml ├── copy.rs ├── fs.rs ├── rt_current_thread.rs ├── rt_multi_threaded.rs ├── signal.rs ├── spawn.rs ├── sync_broadcast.rs ├── sync_mpsc.rs ├── sync_mpsc_oneshot.rs ├── sync_notify.rs ├── sync_rwlock.rs ├── sync_semaphore.rs ├── sync_watch.rs ├── time_now.rs └── time_timeout.rs ├── deny.toml ├── examples ├── Cargo.toml ├── README.md ├── chat.rs ├── connect-tcp.rs ├── connect-udp.rs ├── custom-executor-tokio-context.rs ├── custom-executor.rs ├── dump.rs ├── echo-tcp.rs ├── echo-udp.rs ├── hello_world.rs ├── named-pipe-multi-client.rs ├── named-pipe-ready.rs ├── named-pipe.rs ├── print_each_packet.rs ├── proxy.rs ├── tinydb.rs ├── tinyhttp.rs ├── udp-client.rs └── udp-codec.rs ├── netlify.toml ├── spellcheck.dic ├── spellcheck.toml ├── stress-test ├── Cargo.toml └── examples │ └── simple_echo_tcp.rs ├── target-specs ├── README.md └── i686-unknown-linux-gnu.json ├── tests-build ├── Cargo.toml ├── README.md ├── src │ └── lib.rs └── tests │ ├── fail │ ├── macros_core_no_default.rs │ ├── macros_core_no_default.stderr │ ├── macros_dead_code.rs │ ├── macros_dead_code.stderr │ ├── macros_invalid_input.rs │ ├── macros_invalid_input.stderr │ ├── macros_type_mismatch.rs │ └── macros_type_mismatch.stderr │ ├── macros.rs │ ├── macros_clippy.rs │ └── pass │ ├── forward_args_and_output.rs │ ├── macros_main_loop.rs │ └── macros_main_return.rs ├── tests-integration ├── Cargo.toml ├── README.md ├── src │ ├── bin │ │ ├── test-cat.rs │ │ ├── test-mem.rs │ │ └── test-process-signal.rs │ └── lib.rs └── tests │ ├── macros_main.rs │ ├── macros_pin.rs │ ├── macros_select.rs │ ├── process_stdio.rs │ └── rt_yield.rs ├── tokio-macros ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md └── src │ ├── entry.rs │ ├── lib.rs │ └── select.rs ├── tokio-stream ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── fuzz │ ├── .gitignore │ ├── Cargo.toml │ └── fuzz_targets │ │ └── fuzz_stream_map.rs ├── src │ ├── empty.rs │ ├── iter.rs │ ├── lib.rs │ ├── macros.rs │ ├── once.rs │ ├── pending.rs │ ├── stream_close.rs │ ├── stream_ext.rs │ ├── stream_ext │ │ ├── all.rs │ │ ├── any.rs │ │ ├── chain.rs │ │ ├── chunks_timeout.rs │ │ ├── collect.rs │ │ ├── filter.rs │ │ ├── filter_map.rs │ │ ├── fold.rs │ │ ├── fuse.rs │ │ ├── map.rs │ │ ├── map_while.rs │ │ ├── merge.rs │ │ ├── next.rs │ │ ├── peekable.rs │ │ ├── skip.rs │ │ ├── skip_while.rs │ │ ├── take.rs │ │ ├── take_while.rs │ │ ├── then.rs │ │ ├── throttle.rs │ │ ├── timeout.rs │ │ ├── timeout_repeating.rs │ │ └── try_next.rs │ ├── stream_map.rs │ ├── wrappers.rs │ └── wrappers │ │ ├── broadcast.rs │ │ ├── interval.rs │ │ ├── lines.rs │ │ ├── mpsc_bounded.rs │ │ ├── mpsc_unbounded.rs │ │ ├── read_dir.rs │ │ ├── signal_unix.rs │ │ ├── signal_windows.rs │ │ ├── split.rs │ │ ├── tcp_listener.rs │ │ ├── unix_listener.rs │ │ └── watch.rs └── tests │ ├── async_send_sync.rs │ ├── chunks_timeout.rs │ ├── stream_chain.rs │ ├── stream_close.rs │ ├── stream_collect.rs │ ├── stream_empty.rs │ ├── stream_fuse.rs │ ├── stream_iter.rs │ ├── stream_merge.rs │ ├── stream_once.rs │ ├── stream_panic.rs │ ├── stream_pending.rs │ ├── stream_stream_map.rs │ ├── stream_timeout.rs │ ├── support │ └── mpsc.rs │ ├── time_throttle.rs │ └── watch.rs ├── tokio-test ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── src │ ├── io.rs │ ├── lib.rs │ ├── macros.rs │ ├── stream_mock.rs │ └── task.rs └── tests │ ├── block_on.rs │ ├── io.rs │ ├── macros.rs │ ├── stream_mock.rs │ └── task.rs ├── tokio-util ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── src │ ├── cfg.rs │ ├── codec │ │ ├── any_delimiter_codec.rs │ │ ├── bytes_codec.rs │ │ ├── decoder.rs │ │ ├── encoder.rs │ │ ├── framed.rs │ │ ├── framed_impl.rs │ │ ├── framed_read.rs │ │ ├── framed_write.rs │ │ ├── length_delimited.rs │ │ ├── lines_codec.rs │ │ └── mod.rs │ ├── compat.rs │ ├── context.rs │ ├── either.rs │ ├── io │ │ ├── copy_to_bytes.rs │ │ ├── inspect.rs │ │ ├── mod.rs │ │ ├── read_arc.rs │ │ ├── read_buf.rs │ │ ├── reader_stream.rs │ │ ├── sink_writer.rs │ │ ├── stream_reader.rs │ │ └── sync_bridge.rs │ ├── lib.rs │ ├── loom.rs │ ├── net │ │ ├── mod.rs │ │ └── unix │ │ │ └── mod.rs │ ├── sync │ │ ├── cancellation_token.rs │ │ ├── cancellation_token │ │ │ ├── guard.rs │ │ │ └── tree_node.rs │ │ ├── mod.rs │ │ ├── mpsc.rs │ │ ├── poll_semaphore.rs │ │ ├── reusable_box.rs │ │ └── tests │ │ │ ├── loom_cancellation_token.rs │ │ │ └── mod.rs │ ├── task │ │ ├── abort_on_drop.rs │ │ ├── join_map.rs │ │ ├── mod.rs │ │ ├── spawn_pinned.rs │ │ └── task_tracker.rs │ ├── time │ │ ├── delay_queue.rs │ │ ├── mod.rs │ │ └── wheel │ │ │ ├── level.rs │ │ │ ├── mod.rs │ │ │ └── stack.rs │ ├── tracing.rs │ ├── udp │ │ ├── frame.rs │ │ └── mod.rs │ └── util │ │ ├── maybe_dangling.rs │ │ ├── mod.rs │ │ └── poll_buf.rs └── tests │ ├── _require_full.rs │ ├── abort_on_drop.rs │ ├── codecs.rs │ ├── compat.rs │ ├── context.rs │ ├── framed.rs │ ├── framed_read.rs │ ├── framed_stream.rs │ ├── framed_write.rs │ ├── io_inspect.rs │ ├── io_reader_stream.rs │ ├── io_sink_writer.rs │ ├── io_stream_reader.rs │ ├── io_sync_bridge.rs │ ├── length_delimited.rs │ ├── mpsc.rs │ ├── panic.rs │ ├── poll_semaphore.rs │ ├── reusable_box.rs │ ├── spawn_pinned.rs │ ├── sync_cancellation_token.rs │ ├── task_join_map.rs │ ├── task_tracker.rs │ ├── time_delay_queue.rs │ └── udp.rs └── tokio ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── docs └── reactor-refactor.md ├── fuzz ├── .gitignore ├── Cargo.toml └── fuzz_targets │ └── fuzz_linked_list.rs ├── src ├── blocking.rs ├── doc │ ├── mod.rs │ └── os.rs ├── fs │ ├── canonicalize.rs │ ├── copy.rs │ ├── create_dir.rs │ ├── create_dir_all.rs │ ├── dir_builder.rs │ ├── file.rs │ ├── file │ │ └── tests.rs │ ├── hard_link.rs │ ├── metadata.rs │ ├── mocks.rs │ ├── mod.rs │ ├── open_options.rs │ ├── open_options │ │ └── mock_open_options.rs │ ├── read.rs │ ├── read_dir.rs │ ├── read_link.rs │ ├── read_to_string.rs │ ├── remove_dir.rs │ ├── remove_dir_all.rs │ ├── remove_file.rs │ ├── rename.rs │ ├── set_permissions.rs │ ├── symlink.rs │ ├── symlink_dir.rs │ ├── symlink_file.rs │ ├── symlink_metadata.rs │ ├── try_exists.rs │ └── write.rs ├── future │ ├── block_on.rs │ ├── maybe_done.rs │ ├── mod.rs │ ├── trace.rs │ └── try_join.rs ├── fuzz.rs ├── io │ ├── async_buf_read.rs │ ├── async_fd.rs │ ├── async_read.rs │ ├── async_seek.rs │ ├── async_write.rs │ ├── blocking.rs │ ├── bsd │ │ └── poll_aio.rs │ ├── interest.rs │ ├── join.rs │ ├── mod.rs │ ├── poll_evented.rs │ ├── read_buf.rs │ ├── ready.rs │ ├── seek.rs │ ├── split.rs │ ├── stderr.rs │ ├── stdin.rs │ ├── stdio_common.rs │ ├── stdout.rs │ └── util │ │ ├── async_buf_read_ext.rs │ │ ├── async_read_ext.rs │ │ ├── async_seek_ext.rs │ │ ├── async_write_ext.rs │ │ ├── buf_reader.rs │ │ ├── buf_stream.rs │ │ ├── buf_writer.rs │ │ ├── chain.rs │ │ ├── copy.rs │ │ ├── copy_bidirectional.rs │ │ ├── copy_buf.rs │ │ ├── empty.rs │ │ ├── fill_buf.rs │ │ ├── flush.rs │ │ ├── lines.rs │ │ ├── mem.rs │ │ ├── mod.rs │ │ ├── read.rs │ │ ├── read_buf.rs │ │ ├── read_exact.rs │ │ ├── read_int.rs │ │ ├── read_line.rs │ │ ├── read_to_end.rs │ │ ├── read_to_string.rs │ │ ├── read_until.rs │ │ ├── repeat.rs │ │ ├── shutdown.rs │ │ ├── sink.rs │ │ ├── split.rs │ │ ├── take.rs │ │ ├── vec_with_initialized.rs │ │ ├── write.rs │ │ ├── write_all.rs │ │ ├── write_all_buf.rs │ │ ├── write_buf.rs │ │ ├── write_int.rs │ │ └── write_vectored.rs ├── lib.rs ├── loom │ ├── mocked.rs │ ├── mod.rs │ └── std │ │ ├── atomic_u16.rs │ │ ├── atomic_u32.rs │ │ ├── atomic_u64.rs │ │ ├── atomic_u64_as_mutex.rs │ │ ├── atomic_u64_native.rs │ │ ├── atomic_u64_static_const_new.rs │ │ ├── atomic_u64_static_once_cell.rs │ │ ├── atomic_usize.rs │ │ ├── barrier.rs │ │ ├── mod.rs │ │ ├── mutex.rs │ │ ├── parking_lot.rs │ │ ├── rwlock.rs │ │ └── unsafe_cell.rs ├── macros │ ├── addr_of.rs │ ├── cfg.rs │ ├── join.rs │ ├── loom.rs │ ├── mod.rs │ ├── pin.rs │ ├── select.rs │ ├── support.rs │ ├── thread_local.rs │ ├── trace.rs │ └── try_join.rs ├── net │ ├── addr.rs │ ├── lookup_host.rs │ ├── mod.rs │ ├── tcp │ │ ├── listener.rs │ │ ├── mod.rs │ │ ├── socket.rs │ │ ├── split.rs │ │ ├── split_owned.rs │ │ └── stream.rs │ ├── udp.rs │ ├── unix │ │ ├── datagram │ │ │ ├── mod.rs │ │ │ └── socket.rs │ │ ├── listener.rs │ │ ├── mod.rs │ │ ├── pipe.rs │ │ ├── socket.rs │ │ ├── socketaddr.rs │ │ ├── split.rs │ │ ├── split_owned.rs │ │ ├── stream.rs │ │ └── ucred.rs │ └── windows │ │ ├── mod.rs │ │ └── named_pipe.rs ├── process │ ├── kill.rs │ ├── mod.rs │ ├── unix │ │ ├── mod.rs │ │ ├── orphan.rs │ │ ├── pidfd_reaper.rs │ │ └── reap.rs │ └── windows.rs ├── runtime │ ├── blocking │ │ ├── mod.rs │ │ ├── pool.rs │ │ ├── schedule.rs │ │ ├── shutdown.rs │ │ └── task.rs │ ├── builder.rs │ ├── config.rs │ ├── context.rs │ ├── context │ │ ├── blocking.rs │ │ ├── current.rs │ │ ├── runtime.rs │ │ ├── runtime_mt.rs │ │ └── scoped.rs │ ├── driver.rs │ ├── driver │ │ └── op.rs │ ├── dump.rs │ ├── handle.rs │ ├── id.rs │ ├── io │ │ ├── driver.rs │ │ ├── driver │ │ │ ├── signal.rs │ │ │ └── uring.rs │ │ ├── metrics.rs │ │ ├── mod.rs │ │ ├── registration.rs │ │ ├── registration_set.rs │ │ └── scheduled_io.rs │ ├── local_runtime │ │ ├── mod.rs │ │ ├── options.rs │ │ └── runtime.rs │ ├── metrics │ │ ├── batch.rs │ │ ├── histogram.rs │ │ ├── histogram │ │ │ └── h2_histogram.rs │ │ ├── io.rs │ │ ├── mock.rs │ │ ├── mod.rs │ │ ├── runtime.rs │ │ ├── scheduler.rs │ │ └── worker.rs │ ├── mod.rs │ ├── park.rs │ ├── process.rs │ ├── runtime.rs │ ├── scheduler │ │ ├── block_in_place.rs │ │ ├── current_thread │ │ │ └── mod.rs │ │ ├── defer.rs │ │ ├── inject.rs │ │ ├── inject │ │ │ ├── metrics.rs │ │ │ ├── pop.rs │ │ │ ├── rt_multi_thread.rs │ │ │ ├── shared.rs │ │ │ └── synced.rs │ │ ├── lock.rs │ │ ├── mod.rs │ │ └── multi_thread │ │ │ ├── counters.rs │ │ │ ├── handle.rs │ │ │ ├── handle │ │ │ ├── metrics.rs │ │ │ └── taskdump.rs │ │ │ ├── idle.rs │ │ │ ├── mod.rs │ │ │ ├── overflow.rs │ │ │ ├── park.rs │ │ │ ├── queue.rs │ │ │ ├── stats.rs │ │ │ ├── trace.rs │ │ │ ├── trace_mock.rs │ │ │ ├── worker.rs │ │ │ └── worker │ │ │ ├── metrics.rs │ │ │ ├── taskdump.rs │ │ │ └── taskdump_mock.rs │ ├── signal │ │ └── mod.rs │ ├── task │ │ ├── abort.rs │ │ ├── core.rs │ │ ├── error.rs │ │ ├── harness.rs │ │ ├── id.rs │ │ ├── join.rs │ │ ├── list.rs │ │ ├── mod.rs │ │ ├── raw.rs │ │ ├── state.rs │ │ ├── trace │ │ │ ├── mod.rs │ │ │ ├── symbol.rs │ │ │ └── tree.rs │ │ └── waker.rs │ ├── task_hooks.rs │ ├── tests │ │ ├── inject.rs │ │ ├── loom_blocking.rs │ │ ├── loom_current_thread.rs │ │ ├── loom_current_thread │ │ │ └── yield_now.rs │ │ ├── loom_join_set.rs │ │ ├── loom_local.rs │ │ ├── loom_multi_thread.rs │ │ ├── loom_multi_thread │ │ │ ├── queue.rs │ │ │ ├── shutdown.rs │ │ │ └── yield_now.rs │ │ ├── loom_oneshot.rs │ │ ├── mod.rs │ │ ├── queue.rs │ │ ├── task.rs │ │ └── task_combinations.rs │ ├── thread_id.rs │ └── time │ │ ├── entry.rs │ │ ├── handle.rs │ │ ├── mod.rs │ │ ├── source.rs │ │ ├── tests │ │ └── mod.rs │ │ └── wheel │ │ ├── level.rs │ │ └── mod.rs ├── signal │ ├── ctrl_c.rs │ ├── mod.rs │ ├── registry.rs │ ├── reusable_box.rs │ ├── unix.rs │ ├── windows.rs │ └── windows │ │ ├── stub.rs │ │ └── sys.rs ├── sync │ ├── barrier.rs │ ├── batch_semaphore.rs │ ├── broadcast.rs │ ├── mod.rs │ ├── mpsc │ │ ├── block.rs │ │ ├── bounded.rs │ │ ├── chan.rs │ │ ├── error.rs │ │ ├── list.rs │ │ ├── mod.rs │ │ └── unbounded.rs │ ├── mutex.rs │ ├── notify.rs │ ├── once_cell.rs │ ├── oneshot.rs │ ├── rwlock.rs │ ├── rwlock │ │ ├── owned_read_guard.rs │ │ ├── owned_write_guard.rs │ │ ├── owned_write_guard_mapped.rs │ │ ├── read_guard.rs │ │ ├── write_guard.rs │ │ └── write_guard_mapped.rs │ ├── semaphore.rs │ ├── task │ │ ├── atomic_waker.rs │ │ └── mod.rs │ ├── tests │ │ ├── atomic_waker.rs │ │ ├── loom_atomic_waker.rs │ │ ├── loom_broadcast.rs │ │ ├── loom_list.rs │ │ ├── loom_mpsc.rs │ │ ├── loom_notify.rs │ │ ├── loom_oneshot.rs │ │ ├── loom_rwlock.rs │ │ ├── loom_semaphore_batch.rs │ │ ├── loom_watch.rs │ │ ├── mod.rs │ │ ├── notify.rs │ │ └── semaphore_batch.rs │ └── watch.rs ├── task │ ├── blocking.rs │ ├── builder.rs │ ├── coop │ │ ├── consume_budget.rs │ │ ├── mod.rs │ │ └── unconstrained.rs │ ├── join_set.rs │ ├── local.rs │ ├── mod.rs │ ├── spawn.rs │ ├── task_local.rs │ └── yield_now.rs ├── time │ ├── clock.rs │ ├── error.rs │ ├── instant.rs │ ├── interval.rs │ ├── mod.rs │ ├── sleep.rs │ └── timeout.rs └── util │ ├── as_ref.rs │ ├── atomic_cell.rs │ ├── bit.rs │ ├── blocking_check.rs │ ├── cacheline.rs │ ├── error.rs │ ├── idle_notified_set.rs │ ├── linked_list.rs │ ├── markers.rs │ ├── memchr.rs │ ├── metric_atomics.rs │ ├── mod.rs │ ├── ptr_expose.rs │ ├── rand.rs │ ├── rand │ ├── rt.rs │ └── rt_unstable.rs │ ├── rc_cell.rs │ ├── sharded_list.rs │ ├── sync_wrapper.rs │ ├── trace.rs │ ├── try_lock.rs │ ├── typeid.rs │ ├── wake.rs │ └── wake_list.rs └── tests ├── _require_full.rs ├── async_send_sync.rs ├── buffered.rs ├── coop_budget.rs ├── dump.rs ├── duplex_stream.rs ├── fs.rs ├── fs_canonicalize_dir.rs ├── fs_copy.rs ├── fs_dir.rs ├── fs_file.rs ├── fs_link.rs ├── fs_open_options.rs ├── fs_open_options_windows.rs ├── fs_remove_dir_all.rs ├── fs_remove_file.rs ├── fs_rename.rs ├── fs_symlink_dir_windows.rs ├── fs_symlink_file_windows.rs ├── fs_try_exists.rs ├── io_async_fd.rs ├── io_async_read.rs ├── io_buf_reader.rs ├── io_buf_writer.rs ├── io_chain.rs ├── io_copy.rs ├── io_copy_bidirectional.rs ├── io_driver.rs ├── io_driver_drop.rs ├── io_fill_buf.rs ├── io_join.rs ├── io_lines.rs ├── io_mem_stream.rs ├── io_panic.rs ├── io_poll_aio.rs ├── io_read.rs ├── io_read_buf.rs ├── io_read_exact.rs ├── io_read_line.rs ├── io_read_to_end.rs ├── io_read_to_string.rs ├── io_read_until.rs ├── io_repeat.rs ├── io_sink.rs ├── io_split.rs ├── io_take.rs ├── io_util_empty.rs ├── io_write.rs ├── io_write_all.rs ├── io_write_all_buf.rs ├── io_write_buf.rs ├── io_write_int.rs ├── join_handle_panic.rs ├── macros_join.rs ├── macros_pin.rs ├── macros_rename_test.rs ├── macros_select.rs ├── macros_test.rs ├── macros_try_join.rs ├── net_bind_resource.rs ├── net_lookup_host.rs ├── net_named_pipe.rs ├── net_panic.rs ├── net_unix_pipe.rs ├── no_rt.rs ├── process_arg0.rs ├── process_change_of_runtime.rs ├── process_issue_2174.rs ├── process_issue_42.rs ├── process_kill_after_wait.rs ├── process_kill_on_drop.rs ├── process_raw_handle.rs ├── process_smoke.rs ├── rt_basic.rs ├── rt_common.rs ├── rt_handle.rs ├── rt_handle_block_on.rs ├── rt_local.rs ├── rt_metrics.rs ├── rt_panic.rs ├── rt_poll_callbacks.rs ├── rt_threaded.rs ├── rt_time_start_paused.rs ├── rt_unstable_metrics.rs ├── signal_ctrl_c.rs ├── signal_drop_recv.rs ├── signal_drop_rt.rs ├── signal_drop_signal.rs ├── signal_info.rs ├── signal_multi_rt.rs ├── signal_no_rt.rs ├── signal_notify_both.rs ├── signal_panic.rs ├── signal_realtime.rs ├── signal_twice.rs ├── signal_usr1.rs ├── support ├── io_vec.rs ├── leaked_buffers.rs ├── mpsc_stream.rs ├── panic.rs └── signal.rs ├── sync_barrier.rs ├── sync_broadcast.rs ├── sync_broadcast_weak.rs ├── sync_errors.rs ├── sync_mpsc.rs ├── sync_mpsc_weak.rs ├── sync_mutex.rs ├── sync_mutex_owned.rs ├── sync_notify.rs ├── sync_once_cell.rs ├── sync_oneshot.rs ├── sync_panic.rs ├── sync_rwlock.rs ├── sync_semaphore.rs ├── sync_semaphore_owned.rs ├── sync_watch.rs ├── task_abort.rs ├── task_blocking.rs ├── task_builder.rs ├── task_hooks.rs ├── task_id.rs ├── task_join_set.rs ├── task_local.rs ├── task_local_set.rs ├── task_panic.rs ├── task_trace_self.rs ├── task_yield_now.rs ├── tcp_accept.rs ├── tcp_connect.rs ├── tcp_echo.rs ├── tcp_into_split.rs ├── tcp_into_std.rs ├── tcp_peek.rs ├── tcp_shutdown.rs ├── tcp_socket.rs ├── tcp_split.rs ├── tcp_stream.rs ├── test_clock.rs ├── time_interval.rs ├── time_panic.rs ├── time_pause.rs ├── time_rt.rs ├── time_sleep.rs ├── time_timeout.rs ├── tracing_sync.rs ├── tracing_task.rs ├── tracing_time.rs ├── udp.rs ├── uds_cred.rs ├── uds_datagram.rs ├── uds_socket.rs ├── uds_split.rs ├── uds_stream.rs └── unwindsafe.rs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [tokio-rs] 4 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 12 | 13 | ## Motivation 14 | 15 | 20 | 21 | ## Solution 22 | 23 | 27 | -------------------------------------------------------------------------------- /.github/buildomat/README.md: -------------------------------------------------------------------------------- 1 | # Buildomat illumos CI 2 | 3 | This directory contains CI configurations for the [illumos] operating system. 4 | Tokio's illumos CI jobs are run using [Buildomat], a CI system developed by 5 | Oxide Computer, which supports illumos. See [the Buildomat README] for more 6 | details. 7 | 8 | ## illumos-Specific CI Failures 9 | 10 | If your pull request's CI build fails on illumos, and you aren't able to easily 11 | reproduce the failure on other operating systems, don't worry! The 12 | [tokio-rs/illumos] team is responsible for maintaining Tokio's illumos support, 13 | and can be called on to assist contributors with illumos-specific issues. Please 14 | feel free to tag @tokio-rs/illumos to ask for help resolving build failures on 15 | illumos. 16 | 17 | [illumos]: https://www.illumos.org/ 18 | [Buildomat]: https://github.com/oxidecomputer/buildomat 19 | [the Buildomat README]: https://github.com/oxidecomputer/buildomat 20 | [tokio-rs/illumos]: https://github.com/orgs/tokio-rs/teams/illumos 21 | -------------------------------------------------------------------------------- /.github/buildomat/config.toml: -------------------------------------------------------------------------------- 1 | # Repository-level Buildomat configuration. 2 | # See: https://github.com/oxidecomputer/buildomat#per-repository-configuration 3 | 4 | # Enable buildomat. This one should be self-explanatory. 5 | enable = true 6 | # Allow CI runs for PRs from users outside the `tokio-rs` organization. Our 7 | # buildomat jobs don't touch any secrets/keys, so this should be fine. 8 | org_only = false 9 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | cargo-deny: 17 | permissions: 18 | checks: write 19 | contents: read 20 | issues: write 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: actions/checkout@v4 24 | - uses: EmbarkStudios/cargo-deny-action@v2 25 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | cargo-deny: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v4 23 | - uses: EmbarkStudios/cargo-deny-action@v2 24 | -------------------------------------------------------------------------------- /.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: 1.82 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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | 4 | .cargo/config.toml 5 | .cargo/config 6 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | 18 | [workspace.metadata.spellcheck] 19 | config = "spellcheck.toml" 20 | 21 | [workspace.lints.rust] 22 | unexpected_cfgs = { level = "warn", check-cfg = [ 23 | 'cfg(fuzzing)', 24 | 'cfg(loom)', 25 | 'cfg(mio_unsupported_force_poll_poll)', 26 | 'cfg(tokio_allow_from_blocking_fd)', 27 | 'cfg(tokio_internal_mt_counters)', 28 | 'cfg(tokio_no_parking_lot)', 29 | 'cfg(tokio_no_tuning_tests)', 30 | 'cfg(tokio_taskdump)', 31 | 'cfg(tokio_unstable)', 32 | 'cfg(tokio_uring)', 33 | ] } 34 | -------------------------------------------------------------------------------- /Cross.toml: -------------------------------------------------------------------------------- 1 | [build.env] 2 | passthrough = [ 3 | "RUSTFLAGS", 4 | "RUST_BACKTRACE", 5 | ] 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Tokio Contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | ## Report a security issue 2 | 3 | The Tokio project team welcomes security reports and is committed to providing prompt attention to security issues. Security issues should be reported privately via [security@tokio.rs](mailto:security@tokio.rs). Security issues should not be reported via the public GitHub Issue tracker. 4 | 5 | ## Vulnerability coordination 6 | 7 | Remediation of security vulnerabilities is prioritized by the project team. The project team coordinates remediation with third-party project stakeholders via [GitHub Security Advisories](https://help.github.com/en/github/managing-security-vulnerabilities/about-github-security-advisories). Third-party stakeholders may include the reporter of the issue, affected direct or indirect users of Tokio, and maintainers of upstream dependencies if applicable. 8 | 9 | Downstream project maintainers and Tokio users can request participation in coordination of applicable security issues by sending your contact email address, GitHub username(s) and any other salient information to [security@tokio.rs](mailto:security@tokio.rs). Participation in security issue coordination processes is at the discretion of the Tokio team. 10 | 11 | ## Security advisories 12 | 13 | The project team is committed to transparency in the security issue disclosure process. The Tokio team announces security issues via [project GitHub Release notes](https://github.com/tokio-rs/tokio/releases) and the [RustSec advisory database](https://github.com/RustSec/advisory-db) (i.e. `cargo-audit`). 14 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /deny.toml: -------------------------------------------------------------------------------- 1 | # https://embarkstudios.github.io/cargo-deny/cli/init.html 2 | 3 | [graph] 4 | all-features = true 5 | 6 | [licenses] 7 | allow = [ 8 | "MIT", 9 | "Apache-2.0", 10 | ] 11 | exceptions = [ 12 | { allow = ["Unicode-3.0", "Unicode-DFS-2016"], crate = "unicode-ident" }, 13 | ] 14 | 15 | [bans] 16 | multiple-versions = "allow" 17 | wildcards = "deny" 18 | 19 | [sources] 20 | unknown-registry = "deny" 21 | unknown-git = "deny" 22 | -------------------------------------------------------------------------------- /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-tcp`](echo-tcp.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 | -------------------------------------------------------------------------------- /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 | 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /spellcheck.toml: -------------------------------------------------------------------------------- 1 | dev_comments = false 2 | skip_readme = false 3 | 4 | [Hunspell] 5 | lang = "en_US" 6 | search_dirs = ["."] 7 | extra_dictionaries = ["spellcheck.dic"] 8 | skip_os_lookups = true 9 | use_builtin = true 10 | 11 | [Hunspell.quirks] 12 | allow_concatenation = true 13 | 14 | -------------------------------------------------------------------------------- /stress-test/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stress-test" 3 | version = "0.1.0" 4 | authors = ["Tokio Contributors "] 5 | edition = "2021" 6 | license = "MIT" 7 | publish = false 8 | 9 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 10 | 11 | [dependencies] 12 | tokio = { version = "1.0.0", path = "../tokio/", features = ["full"] } 13 | 14 | [dev-dependencies] 15 | rand = "0.9" 16 | 17 | [lints] 18 | workspace = true 19 | -------------------------------------------------------------------------------- /target-specs/README.md: -------------------------------------------------------------------------------- 1 | This is used for the `no-atomic-u64-test` ci check that verifies that Tokio 2 | works even if the `AtomicU64` type is missing. 3 | 4 | When increasing the nightly compiler version, you may need to regenerate this 5 | target using the following command: 6 | ``` 7 | rustc +nightly -Z unstable-options --print target-spec-json --target i686-unknown-linux-gnu | grep -v 'is-builtin' | sed 's/"max-atomic-width": 64/"max-atomic-width": 32/' > target-specs/i686-unknown-linux-gnu.json 8 | ``` 9 | 10 | -------------------------------------------------------------------------------- /target-specs/i686-unknown-linux-gnu.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "x86", 3 | "cpu": "pentium4", 4 | "crt-objects-fallback": "false", 5 | "crt-static-respected": true, 6 | "data-layout": "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128", 7 | "dynamic-linking": true, 8 | "env": "gnu", 9 | "has-rpath": true, 10 | "has-thread-local": true, 11 | "linker-flavor": "gnu-cc", 12 | "llvm-target": "i686-unknown-linux-gnu", 13 | "max-atomic-width": 32, 14 | "metadata": { 15 | "description": null, 16 | "host_tools": null, 17 | "std": null, 18 | "tier": null 19 | }, 20 | "os": "linux", 21 | "position-independent-executables": true, 22 | "pre-link-args": { 23 | "gnu-cc": [ 24 | "-m32" 25 | ], 26 | "gnu-lld-cc": [ 27 | "-m32" 28 | ] 29 | }, 30 | "relro-level": "full", 31 | "stack-probes": { 32 | "kind": "inline" 33 | }, 34 | "supported-sanitizers": [ 35 | "address" 36 | ], 37 | "supported-split-debuginfo": [ 38 | "packed", 39 | "unpacked", 40 | "off" 41 | ], 42 | "target-family": [ 43 | "unix" 44 | ], 45 | "target-pointer-width": "32" 46 | } 47 | -------------------------------------------------------------------------------- /tests-build/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tests-build" 3 | version = "0.1.0" 4 | authors = ["Tokio Contributors "] 5 | edition = "2021" 6 | license = "MIT" 7 | publish = false 8 | 9 | [features] 10 | full = ["tokio/full"] 11 | rt = ["tokio/rt", "tokio/macros"] 12 | 13 | [dependencies] 14 | tokio = { version = "1.0.0", path = "../tokio", optional = true } 15 | 16 | [dev-dependencies] 17 | trybuild = "1.0" 18 | 19 | [lints] 20 | workspace = true 21 | -------------------------------------------------------------------------------- /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 any 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 | -------------------------------------------------------------------------------- /tests-build/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "tokio")] 2 | pub use tokio; 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /tests-build/tests/macros.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | #[cfg_attr(miri, ignore)] 3 | fn compile_fail_full() { 4 | let t = trybuild::TestCases::new(); 5 | 6 | #[cfg(feature = "full")] 7 | t.pass("tests/pass/forward_args_and_output.rs"); 8 | 9 | #[cfg(feature = "full")] 10 | t.pass("tests/pass/macros_main_return.rs"); 11 | 12 | #[cfg(feature = "full")] 13 | t.pass("tests/pass/macros_main_loop.rs"); 14 | 15 | #[cfg(feature = "full")] 16 | t.compile_fail("tests/fail/macros_invalid_input.rs"); 17 | 18 | #[cfg(feature = "full")] 19 | t.compile_fail("tests/fail/macros_dead_code.rs"); 20 | 21 | #[cfg(feature = "full")] 22 | t.compile_fail("tests/fail/macros_type_mismatch.rs"); 23 | 24 | #[cfg(all(feature = "rt", not(feature = "full")))] 25 | t.compile_fail("tests/fail/macros_core_no_default.rs"); 26 | 27 | drop(t); 28 | } 29 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /tests-integration/README.md: -------------------------------------------------------------------------------- 1 | Tests that require additional components than just the `tokio` crate. 2 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /tests-integration/src/bin/test-mem.rs: -------------------------------------------------------------------------------- 1 | use std::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 | -------------------------------------------------------------------------------- /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-integration/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "full")] 2 | doc_comment::doc_comment!(include_str!("../../README.md")); 3 | -------------------------------------------------------------------------------- /tests-integration/tests/macros_main.rs: -------------------------------------------------------------------------------- 1 | #![cfg(all(feature = "macros", feature = "rt-multi-thread"))] 2 | 3 | #[tokio::main] 4 | async fn basic_main() -> usize { 5 | 1 6 | } 7 | 8 | #[tokio::main] 9 | async fn generic_fun() -> T { 10 | T::default() 11 | } 12 | 13 | #[tokio::main] 14 | async fn spawning() -> usize { 15 | let join = tokio::spawn(async { 1 }); 16 | join.await.unwrap() 17 | } 18 | 19 | #[test] 20 | fn main_with_spawn() { 21 | assert_eq!(1, spawning()); 22 | } 23 | 24 | #[test] 25 | fn shell() { 26 | assert_eq!(1, basic_main()); 27 | assert_eq!(bool::default(), generic_fun::()) 28 | } 29 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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( 8 | not(feature = "rt-multi-thread"), 9 | ignore = "WASI: std::thread::spawn not supported" 10 | )] 11 | #[test] 12 | fn join_with_select() { 13 | block_on(async { 14 | let (tx1, mut rx1) = oneshot::channel::(); 15 | let (tx2, mut rx2) = oneshot::channel::(); 16 | 17 | thread::spawn(move || { 18 | tx1.send(123).unwrap(); 19 | tx2.send(456).unwrap(); 20 | }); 21 | 22 | let mut a = None; 23 | let mut b = None; 24 | 25 | while a.is_none() || b.is_none() { 26 | tokio::select! { 27 | v1 = (&mut rx1), if a.is_none() => a = Some(v1.unwrap()), 28 | v2 = (&mut rx2), if b.is_none() => b = Some(v2.unwrap()), 29 | } 30 | } 31 | 32 | let (a, b) = (a.unwrap(), b.unwrap()); 33 | 34 | assert_eq!(a, 123); 35 | assert_eq!(b, 456); 36 | }); 37 | } 38 | -------------------------------------------------------------------------------- /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-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.5.0" 8 | edition = "2021" 9 | rust-version = "1.70" 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 | 35 | [lints] 36 | workspace = true 37 | -------------------------------------------------------------------------------- /tokio-macros/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Yoshua Wuyts 4 | Copyright (c) Tokio Contributors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /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-stream/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Tokio Contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tokio-stream/README.md: -------------------------------------------------------------------------------- 1 | # tokio-stream 2 | 3 | Utilities to work with `Stream` and `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-stream/fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | corpus 3 | artifacts 4 | coverage 5 | -------------------------------------------------------------------------------- /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-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-stream/src/macros.rs: -------------------------------------------------------------------------------- 1 | macro_rules! cfg_fs { 2 | ($($item:item)*) => { 3 | $( 4 | #[cfg(feature = "fs")] 5 | #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] 6 | $item 7 | )* 8 | } 9 | } 10 | 11 | macro_rules! cfg_io_util { 12 | ($($item:item)*) => { 13 | $( 14 | #[cfg(feature = "io-util")] 15 | #[cfg_attr(docsrs, doc(cfg(feature = "io-util")))] 16 | $item 17 | )* 18 | } 19 | } 20 | 21 | macro_rules! cfg_net { 22 | ($($item:item)*) => { 23 | $( 24 | #[cfg(feature = "net")] 25 | #[cfg_attr(docsrs, doc(cfg(feature = "net")))] 26 | $item 27 | )* 28 | } 29 | } 30 | 31 | macro_rules! cfg_time { 32 | ($($item:item)*) => { 33 | $( 34 | #[cfg(feature = "time")] 35 | #[cfg_attr(docsrs, doc(cfg(feature = "time")))] 36 | $item 37 | )* 38 | } 39 | } 40 | 41 | macro_rules! cfg_sync { 42 | ($($item:item)*) => { 43 | $( 44 | #[cfg(feature = "sync")] 45 | #[cfg_attr(docsrs, doc(cfg(feature = "sync")))] 46 | $item 47 | )* 48 | } 49 | } 50 | 51 | macro_rules! cfg_signal { 52 | ($($item:item)*) => { 53 | $( 54 | #[cfg(feature = "signal")] 55 | #[cfg_attr(docsrs, doc(cfg(feature = "signal")))] 56 | $item 57 | )* 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /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/pending.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 [`pending`](fn@pending) function. 8 | #[derive(Debug)] 9 | #[must_use = "streams do nothing unless polled"] 10 | pub struct Pending(PhantomData); 11 | 12 | impl Unpin for Pending {} 13 | unsafe impl Send for Pending {} 14 | unsafe impl Sync for Pending {} 15 | 16 | /// Creates a stream that is never ready 17 | /// 18 | /// The returned stream is never ready. Attempting to call 19 | /// [`next()`](crate::StreamExt::next) will never complete. Use 20 | /// [`stream::empty()`](super::empty()) to obtain a stream that is 21 | /// immediately empty but returns no values. 22 | /// 23 | /// # Examples 24 | /// 25 | /// Basic usage: 26 | /// 27 | /// ```no_run 28 | /// use tokio_stream::{self as stream, StreamExt}; 29 | /// 30 | /// #[tokio::main] 31 | /// async fn main() { 32 | /// let mut never = stream::pending::(); 33 | /// 34 | /// // This will never complete 35 | /// never.next().await; 36 | /// 37 | /// unreachable!(); 38 | /// } 39 | /// ``` 40 | pub const fn pending() -> Pending { 41 | Pending(PhantomData) 42 | } 43 | 44 | impl Stream for Pending { 45 | type Item = T; 46 | 47 | fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { 48 | Poll::Pending 49 | } 50 | 51 | fn size_hint(&self) -> (usize, Option) { 52 | (0, None) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /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::{ready, 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-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::{ready, 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-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/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/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-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 [`peekable`](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-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 | -------------------------------------------------------------------------------- /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-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-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-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-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-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-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-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-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.4" 8 | edition = "2021" 9 | rust-version = "1.70" 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 | futures-core = "0.3.0" 23 | 24 | [dev-dependencies] 25 | tokio = { version = "1.2.0", path = "../tokio", features = ["full"] } 26 | futures-util = "0.3.0" 27 | 28 | [package.metadata.docs.rs] 29 | all-features = true 30 | 31 | [lints] 32 | workspace = true 33 | -------------------------------------------------------------------------------- /tokio-test/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Tokio Contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /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-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-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-test/tests/task.rs: -------------------------------------------------------------------------------- 1 | use std::pin::Pin; 2 | use std::task::{Context, Poll}; 3 | use tokio_stream::Stream; 4 | use tokio_test::task; 5 | 6 | /// A [`Stream`] that has a stub size hint. 7 | struct SizedStream; 8 | 9 | impl Stream for SizedStream { 10 | type Item = (); 11 | 12 | fn poll_next(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { 13 | Poll::Pending 14 | } 15 | 16 | fn size_hint(&self) -> (usize, Option) { 17 | (100, Some(200)) 18 | } 19 | } 20 | 21 | #[test] 22 | fn test_spawn_stream_size_hint() { 23 | let spawn = task::spawn(SizedStream); 24 | assert_eq!(spawn.size_hint(), (100, Some(200))); 25 | } 26 | -------------------------------------------------------------------------------- /tokio-util/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Tokio Contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /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-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 of 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-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 read_arc; 22 | pub use self::read_arc::read_exact_arc; 23 | 24 | mod sync_bridge; 25 | pub use self::sync_bridge::SyncIoBridge; 26 | } 27 | 28 | pub use self::copy_to_bytes::CopyToBytes; 29 | pub use self::inspect::{InspectReader, InspectWriter}; 30 | pub use self::read_buf::read_buf; 31 | pub use self::reader_stream::ReaderStream; 32 | pub use self::sink_writer::SinkWriter; 33 | pub use self::stream_reader::StreamReader; 34 | pub use crate::util::{poll_read_buf, poll_write_buf}; 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 | #[macro_use] 21 | mod cfg; 22 | 23 | mod loom; 24 | 25 | cfg_codec! { 26 | #[macro_use] 27 | mod tracing; 28 | 29 | pub mod codec; 30 | } 31 | 32 | cfg_net! { 33 | #[cfg(not(target_arch = "wasm32"))] 34 | pub mod udp; 35 | pub mod net; 36 | } 37 | 38 | cfg_compat! { 39 | pub mod compat; 40 | } 41 | 42 | cfg_io! { 43 | pub mod io; 44 | } 45 | 46 | cfg_rt! { 47 | pub mod context; 48 | pub mod task; 49 | } 50 | 51 | cfg_time! { 52 | pub mod time; 53 | } 54 | 55 | pub mod sync; 56 | 57 | pub mod either; 58 | 59 | pub use bytes; 60 | 61 | mod util; 62 | -------------------------------------------------------------------------------- /tokio-util/src/loom.rs: -------------------------------------------------------------------------------- 1 | pub(crate) use std::sync; 2 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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-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 | -------------------------------------------------------------------------------- /tokio-util/src/sync/tests/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tokio-util/src/task/mod.rs: -------------------------------------------------------------------------------- 1 | //! Extra utilities for spawning tasks 2 | 3 | #[cfg(tokio_unstable)] 4 | mod join_map; 5 | mod spawn_pinned; 6 | pub use spawn_pinned::LocalPoolHandle; 7 | 8 | #[cfg(tokio_unstable)] 9 | #[cfg_attr(docsrs, doc(cfg(all(tokio_unstable, feature = "rt"))))] 10 | pub use join_map::{JoinMap, JoinMapKeys}; 11 | 12 | pub mod task_tracker; 13 | pub use task_tracker::TaskTracker; 14 | 15 | mod abort_on_drop; 16 | pub use abort_on_drop::AbortOnDropHandle; 17 | -------------------------------------------------------------------------------- /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-util/src/tracing.rs: -------------------------------------------------------------------------------- 1 | macro_rules! trace { 2 | ($($arg:tt)*) => { 3 | #[cfg(feature = "tracing")] 4 | tracing::trace!($($arg)*); 5 | }; 6 | } 7 | -------------------------------------------------------------------------------- /tokio-util/src/udp/mod.rs: -------------------------------------------------------------------------------- 1 | //! UDP framing 2 | 3 | mod frame; 4 | pub use frame::UdpFramed; 5 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /tokio-util/tests/_require_full.rs: -------------------------------------------------------------------------------- 1 | #![cfg(not(feature = "full"))] 2 | compile_error!("run tokio-util tests with `--features full`"); 3 | -------------------------------------------------------------------------------- /tokio-util/tests/abort_on_drop.rs: -------------------------------------------------------------------------------- 1 | use tokio::sync::oneshot; 2 | use tokio_util::task::AbortOnDropHandle; 3 | 4 | #[tokio::test] 5 | async fn aborts_task_on_drop() { 6 | let (mut tx, rx) = oneshot::channel::(); 7 | let handle = tokio::spawn(async move { 8 | let _ = rx.await; 9 | }); 10 | let handle = AbortOnDropHandle::new(handle); 11 | drop(handle); 12 | tx.closed().await; 13 | assert!(tx.is_closed()); 14 | } 15 | 16 | #[tokio::test] 17 | async fn aborts_task_directly() { 18 | let (mut tx, rx) = oneshot::channel::(); 19 | let handle = tokio::spawn(async move { 20 | let _ = rx.await; 21 | }); 22 | let handle = AbortOnDropHandle::new(handle); 23 | handle.abort(); 24 | tx.closed().await; 25 | assert!(tx.is_closed()); 26 | assert!(handle.is_finished()); 27 | } 28 | -------------------------------------------------------------------------------- /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 | .truncate(true) 19 | .open(temp_file) 20 | .await? 21 | .compat_write(); 22 | 23 | file.write_all(&[0, 1, 2, 3, 4, 5]).await?; 24 | file.write_all(&[6, 7]).await?; 25 | 26 | assert_eq!(file.stream_position().await?, 8); 27 | 28 | // Modify elements at position 2. 29 | assert_eq!(file.seek(SeekFrom::Start(2)).await?, 2); 30 | file.write_all(&[8, 9]).await?; 31 | 32 | file.flush().await?; 33 | 34 | // Verify we still have 8 elements. 35 | assert_eq!(file.seek(SeekFrom::End(0)).await?, 8); 36 | // Seek back to the start of the file to read and verify contents. 37 | file.seek(SeekFrom::Start(0)).await?; 38 | 39 | let mut buf = Vec::new(); 40 | let num_bytes = file.read_to_end(&mut buf).await?; 41 | assert_eq!(&buf[..num_bytes], &[0, 1, 8, 9, 4, 5, 6, 7]); 42 | 43 | Ok(()) 44 | } 45 | -------------------------------------------------------------------------------- /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-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-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/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Tokio Contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tokio/fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | corpus 3 | artifacts 4 | coverage 5 | -------------------------------------------------------------------------------- /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/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/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(any(feature = "net", feature = "fs"))] 47 | pub mod os; 48 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 `link` path will be a link pointing to the `original` 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 `original` 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(original: impl AsRef, link: impl AsRef) -> io::Result<()> { 40 | let original = original.as_ref().to_owned(); 41 | let link = link.as_ref().to_owned(); 42 | 43 | asyncify(move || std::fs::hard_link(original, link)).await 44 | } 45 | -------------------------------------------------------------------------------- /tokio/src/fs/metadata.rs: -------------------------------------------------------------------------------- 1 | use crate::fs::asyncify; 2 | 3 | use std::fs::Metadata; 4 | use std::io; 5 | use std::path::Path; 6 | 7 | /// Given a path, queries the file system to get information about a file, 8 | /// directory, etc. 9 | /// 10 | /// This is an async version of [`std::fs::metadata`]. 11 | /// 12 | /// This function will traverse symbolic links to query information about the 13 | /// destination file. 14 | /// 15 | /// # Platform-specific behavior 16 | /// 17 | /// This function currently corresponds to the `stat` function on Unix and the 18 | /// `GetFileAttributesEx` function on Windows. Note that, this [may change in 19 | /// the future][changes]. 20 | /// 21 | /// [changes]: https://doc.rust-lang.org/std/io/index.html#platform-specific-behavior 22 | /// 23 | /// # Errors 24 | /// 25 | /// This function will return an error in the following situations, but is not 26 | /// limited to just these cases: 27 | /// 28 | /// * The user lacks permissions to perform `metadata` call on `path`. 29 | /// * `path` does not exist. 30 | /// 31 | /// # Examples 32 | /// 33 | /// ```rust,no_run 34 | /// use tokio::fs; 35 | /// 36 | /// #[tokio::main] 37 | /// async fn main() -> std::io::Result<()> { 38 | /// let attr = fs::metadata("/some/file/path.txt").await?; 39 | /// // inspect attr ... 40 | /// Ok(()) 41 | /// } 42 | /// ``` 43 | pub async fn metadata(path: impl AsRef) -> io::Result { 44 | let path = path.as_ref().to_owned(); 45 | asyncify(|| std::fs::metadata(path)).await 46 | } 47 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/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/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 `link` path will be a symbolic link pointing to the `original` path. 9 | /// 10 | /// This is an async version of [`std::os::unix::fs::symlink`]. 11 | pub async fn symlink(original: impl AsRef, link: impl AsRef) -> io::Result<()> { 12 | let original = original.as_ref().to_owned(); 13 | let link = link.as_ref().to_owned(); 14 | 15 | asyncify(move || std::os::unix::fs::symlink(original, link)).await 16 | } 17 | -------------------------------------------------------------------------------- /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 `link` path will be a directory symbolic link pointing to the `original` 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(original: impl AsRef, link: impl AsRef) -> io::Result<()> { 15 | let original = original.as_ref().to_owned(); 16 | let link = link.as_ref().to_owned(); 17 | 18 | asyncify(move || std::os::windows::fs::symlink_dir(original, link)).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 `link` path will be a file symbolic link pointing to the `original` 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(original: impl AsRef, link: impl AsRef) -> io::Result<()> { 15 | let original = original.as_ref().to_owned(); 16 | let link = link.as_ref().to_owned(); 17 | 18 | asyncify(move || std::os::windows::fs::symlink_file(original, link)).await 19 | } 20 | -------------------------------------------------------------------------------- /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/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 | asyncify(move || path.try_exists()).await 28 | } 29 | -------------------------------------------------------------------------------- /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 = crate::util::as_ref::upgrade(contents); 29 | 30 | asyncify(move || std::fs::write(path, contents)).await 31 | } 32 | -------------------------------------------------------------------------------- /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/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 | cfg_process! { 9 | mod try_join; 10 | pub(crate) use try_join::try_join3; 11 | } 12 | 13 | cfg_sync! { 14 | mod block_on; 15 | pub(crate) use block_on::block_on; 16 | } 17 | 18 | cfg_trace! { 19 | mod trace; 20 | #[allow(unused_imports)] 21 | pub(crate) use trace::InstrumentedFuture as Future; 22 | } 23 | 24 | cfg_not_trace! { 25 | cfg_rt! { 26 | pub(crate) use std::future::Future; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /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/fuzz.rs: -------------------------------------------------------------------------------- 1 | pub use crate::util::linked_list::tests::fuzz_linked_list; 2 | -------------------------------------------------------------------------------- /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/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/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/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/loom/std/atomic_u16.rs: -------------------------------------------------------------------------------- 1 | use std::cell::UnsafeCell; 2 | use std::fmt; 3 | use std::ops::Deref; 4 | use std::panic; 5 | 6 | /// `AtomicU16` providing an additional `unsync_load` function. 7 | pub(crate) struct AtomicU16 { 8 | inner: UnsafeCell, 9 | } 10 | 11 | unsafe impl Send for AtomicU16 {} 12 | unsafe impl Sync for AtomicU16 {} 13 | impl panic::RefUnwindSafe for AtomicU16 {} 14 | impl panic::UnwindSafe for AtomicU16 {} 15 | 16 | impl AtomicU16 { 17 | pub(crate) const fn new(val: u16) -> AtomicU16 { 18 | let inner = UnsafeCell::new(std::sync::atomic::AtomicU16::new(val)); 19 | AtomicU16 { inner } 20 | } 21 | 22 | /// Performs an unsynchronized load. 23 | /// 24 | /// # Safety 25 | /// 26 | /// All mutations must have happened before the unsynchronized load. 27 | /// Additionally, there must be no concurrent mutations. 28 | pub(crate) unsafe fn unsync_load(&self) -> u16 { 29 | core::ptr::read(self.inner.get() as *const u16) 30 | } 31 | } 32 | 33 | impl Deref for AtomicU16 { 34 | type Target = std::sync::atomic::AtomicU16; 35 | 36 | fn deref(&self) -> &Self::Target { 37 | // safety: it is always safe to access `&self` fns on the inner value as 38 | // we never perform unsafe mutations. 39 | unsafe { &*self.inner.get() } 40 | } 41 | } 42 | 43 | impl fmt::Debug for AtomicU16 { 44 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 45 | self.deref().fmt(fmt) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tokio/src/loom/std/atomic_u32.rs: -------------------------------------------------------------------------------- 1 | use std::cell::UnsafeCell; 2 | use std::fmt; 3 | use std::ops::Deref; 4 | use std::panic; 5 | 6 | /// `AtomicU32` providing an additional `unsync_load` function. 7 | pub(crate) struct AtomicU32 { 8 | inner: UnsafeCell, 9 | } 10 | 11 | unsafe impl Send for AtomicU32 {} 12 | unsafe impl Sync for AtomicU32 {} 13 | impl panic::RefUnwindSafe for AtomicU32 {} 14 | impl panic::UnwindSafe for AtomicU32 {} 15 | 16 | impl AtomicU32 { 17 | pub(crate) const fn new(val: u32) -> AtomicU32 { 18 | let inner = UnsafeCell::new(std::sync::atomic::AtomicU32::new(val)); 19 | AtomicU32 { inner } 20 | } 21 | 22 | /// Performs an unsynchronized load. 23 | /// 24 | /// # Safety 25 | /// 26 | /// All mutations must have happened before the unsynchronized load. 27 | /// Additionally, there must be no concurrent mutations. 28 | pub(crate) unsafe fn unsync_load(&self) -> u32 { 29 | core::ptr::read(self.inner.get() as *const u32) 30 | } 31 | } 32 | 33 | impl Deref for AtomicU32 { 34 | type Target = std::sync::atomic::AtomicU32; 35 | 36 | fn deref(&self) -> &Self::Target { 37 | // safety: it is always safe to access `&self` fns on the inner value as 38 | // we never perform unsafe mutations. 39 | unsafe { &*self.inner.get() } 40 | } 41 | } 42 | 43 | impl fmt::Debug for AtomicU32 { 44 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 45 | self.deref().fmt(fmt) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/src/loom/std/atomic_u64_static_once_cell.rs: -------------------------------------------------------------------------------- 1 | use super::AtomicU64; 2 | use crate::loom::sync::{atomic::Ordering, Mutex}; 3 | use std::sync::OnceLock; 4 | 5 | pub(crate) struct StaticAtomicU64 { 6 | init: u64, 7 | cell: OnceLock>, 8 | } 9 | 10 | impl AtomicU64 { 11 | pub(crate) fn new(val: u64) -> Self { 12 | Self { 13 | inner: Mutex::new(val), 14 | } 15 | } 16 | } 17 | 18 | impl StaticAtomicU64 { 19 | pub(crate) const fn new(val: u64) -> StaticAtomicU64 { 20 | StaticAtomicU64 { 21 | init: val, 22 | cell: OnceLock::new(), 23 | } 24 | } 25 | 26 | pub(crate) fn load(&self, order: Ordering) -> u64 { 27 | *self.inner().lock() 28 | } 29 | 30 | pub(crate) fn fetch_add(&self, val: u64, order: Ordering) -> u64 { 31 | let mut lock = self.inner().lock(); 32 | let prev = *lock; 33 | *lock = prev + val; 34 | prev 35 | } 36 | 37 | pub(crate) fn compare_exchange_weak( 38 | &self, 39 | current: u64, 40 | new: u64, 41 | _success: Ordering, 42 | _failure: Ordering, 43 | ) -> Result { 44 | let mut lock = self.inner().lock(); 45 | 46 | if *lock == current { 47 | *lock = new; 48 | Ok(current) 49 | } else { 50 | Err(*lock) 51 | } 52 | } 53 | 54 | fn inner(&self) -> &Mutex { 55 | self.cell.get_or_init(|| Mutex::new(self.init)) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /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/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/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/src/macros/loom.rs: -------------------------------------------------------------------------------- 1 | macro_rules! if_loom { 2 | ($($t:tt)*) => {{ 3 | #[cfg(loom)] 4 | { 5 | $($t)* 6 | } 7 | }} 8 | } 9 | -------------------------------------------------------------------------------- /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 thread_local; 14 | 15 | #[macro_use] 16 | mod addr_of; 17 | 18 | cfg_trace! { 19 | #[macro_use] 20 | mod trace; 21 | } 22 | 23 | cfg_macros! { 24 | #[macro_use] 25 | mod select; 26 | 27 | #[macro_use] 28 | mod join; 29 | 30 | #[macro_use] 31 | mod try_join; 32 | } 33 | 34 | // Includes re-exports needed to implement macros 35 | #[doc(hidden)] 36 | pub mod support; 37 | -------------------------------------------------------------------------------- /tokio/src/macros/support.rs: -------------------------------------------------------------------------------- 1 | cfg_macros! { 2 | pub use crate::future::maybe_done::maybe_done; 3 | 4 | pub use std::future::poll_fn; 5 | 6 | #[doc(hidden)] 7 | pub fn thread_rng_n(n: u32) -> u32 { 8 | crate::runtime::context::thread_rng_n(n) 9 | } 10 | 11 | cfg_coop! { 12 | #[doc(hidden)] 13 | #[inline] 14 | pub fn poll_budget_available(cx: &mut Context<'_>) -> Poll<()> { 15 | crate::task::coop::poll_budget_available(cx) 16 | } 17 | } 18 | 19 | cfg_not_coop! { 20 | #[doc(hidden)] 21 | #[inline] 22 | pub fn poll_budget_available(_: &mut Context<'_>) -> Poll<()> { 23 | Poll::Ready(()) 24 | } 25 | } 26 | } 27 | 28 | pub use std::future::{Future, IntoFuture}; 29 | pub use std::pin::Pin; 30 | pub use std::task::{Context, Poll}; 31 | -------------------------------------------------------------------------------- /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/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/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/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/src/net/unix/datagram/mod.rs: -------------------------------------------------------------------------------- 1 | //! Unix datagram types. 2 | 3 | pub(crate) mod socket; 4 | -------------------------------------------------------------------------------- /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 user ID. 30 | #[allow(non_camel_case_types)] 31 | pub type uid_t = u32; 32 | 33 | /// A type representing group ID. 34 | #[allow(non_camel_case_types)] 35 | pub type gid_t = u32; 36 | 37 | /// A type representing process and process group IDs. 38 | #[allow(non_camel_case_types)] 39 | pub type pid_t = i32; 40 | -------------------------------------------------------------------------------- /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 | /// 6 | /// This type is a thin wrapper around [`std::os::unix::net::SocketAddr`]. You 7 | /// can convert to and from the standard library `SocketAddr` type using the 8 | /// [`From`] trait. 9 | pub struct SocketAddr(pub(super) std::os::unix::net::SocketAddr); 10 | 11 | impl SocketAddr { 12 | /// Returns `true` if the address is unnamed. 13 | /// 14 | /// Documentation reflected in [`SocketAddr`] 15 | /// 16 | /// [`SocketAddr`]: std::os::unix::net::SocketAddr 17 | pub fn is_unnamed(&self) -> bool { 18 | self.0.is_unnamed() 19 | } 20 | 21 | /// Returns the contents of this address if it is a `pathname` address. 22 | /// 23 | /// Documentation reflected in [`SocketAddr`] 24 | /// 25 | /// [`SocketAddr`]: std::os::unix::net::SocketAddr 26 | pub fn as_pathname(&self) -> Option<&Path> { 27 | self.0.as_pathname() 28 | } 29 | } 30 | 31 | impl fmt::Debug for SocketAddr { 32 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 33 | self.0.fmt(fmt) 34 | } 35 | } 36 | 37 | impl From for SocketAddr { 38 | fn from(value: std::os::unix::net::SocketAddr) -> Self { 39 | SocketAddr(value) 40 | } 41 | } 42 | 43 | impl From for std::os::unix::net::SocketAddr { 44 | fn from(value: SocketAddr) -> Self { 45 | value.0 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tokio/src/net/windows/mod.rs: -------------------------------------------------------------------------------- 1 | //! Windows specific network types. 2 | 3 | pub mod named_pipe; 4 | -------------------------------------------------------------------------------- /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/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/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/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/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/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_unstable_metrics! { 21 | pub(crate) use crate::runtime::IoDriverMetrics; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tokio/src/runtime/io/mod.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr( 2 | not(all(feature = "rt", feature = "net", tokio_uring)), 3 | allow(dead_code) 4 | )] 5 | mod driver; 6 | use driver::{Direction, Tick}; 7 | pub(crate) use driver::{Driver, Handle, ReadyEvent}; 8 | 9 | mod registration; 10 | pub(crate) use registration::Registration; 11 | 12 | mod registration_set; 13 | use registration_set::RegistrationSet; 14 | 15 | mod scheduled_io; 16 | use scheduled_io::ScheduledIo; 17 | 18 | mod metrics; 19 | use metrics::IoDriverMetrics; 20 | 21 | use crate::util::ptr_expose::PtrExposeDomain; 22 | static EXPOSE_IO: PtrExposeDomain = PtrExposeDomain::new(); 23 | -------------------------------------------------------------------------------- /tokio/src/runtime/local_runtime/mod.rs: -------------------------------------------------------------------------------- 1 | mod runtime; 2 | 3 | mod options; 4 | 5 | pub use options::LocalOptions; 6 | pub use runtime::LocalRuntime; 7 | pub(super) use runtime::LocalRuntimeScheduler; 8 | -------------------------------------------------------------------------------- /tokio/src/runtime/local_runtime/options.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | 3 | /// [`LocalRuntime`]-only config options 4 | /// 5 | /// Currently, there are no such options, but in the future, things like `!Send + !Sync` hooks may 6 | /// be added. 7 | /// 8 | /// Use `LocalOptions::default()` to create the default set of options. This type is used with 9 | /// [`Builder::build_local`]. 10 | /// 11 | /// [`Builder::build_local`]: crate::runtime::Builder::build_local 12 | /// [`LocalRuntime`]: crate::runtime::LocalRuntime 13 | #[derive(Default, Debug)] 14 | #[non_exhaustive] 15 | pub struct LocalOptions { 16 | /// Marker used to make this !Send and !Sync. 17 | _phantom: PhantomData<*mut u8>, 18 | } 19 | -------------------------------------------------------------------------------- /tokio/src/runtime/metrics/io.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "net"), allow(dead_code))] 2 | 3 | use crate::util::metric_atomics::MetricAtomicU64; 4 | use std::sync::atomic::Ordering::Relaxed; 5 | 6 | #[derive(Default)] 7 | pub(crate) struct IoDriverMetrics { 8 | pub(super) fd_registered_count: MetricAtomicU64, 9 | pub(super) fd_deregistered_count: MetricAtomicU64, 10 | pub(super) ready_count: MetricAtomicU64, 11 | } 12 | 13 | impl IoDriverMetrics { 14 | pub(crate) fn incr_fd_count(&self) { 15 | self.fd_registered_count.add(1, Relaxed); 16 | } 17 | 18 | pub(crate) fn dec_fd_count(&self) { 19 | self.fd_deregistered_count.add(1, Relaxed); 20 | } 21 | 22 | pub(crate) fn incr_ready_count_by(&self, amt: u64) { 23 | self.ready_count.add(amt, Relaxed); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tokio/src/runtime/metrics/mock.rs: -------------------------------------------------------------------------------- 1 | //! This file contains mocks of the types in src/runtime/metrics 2 | 3 | pub(crate) struct SchedulerMetrics {} 4 | 5 | #[derive(Clone, Default)] 6 | pub(crate) struct HistogramBuilder {} 7 | 8 | impl SchedulerMetrics { 9 | pub(crate) fn new() -> Self { 10 | Self {} 11 | } 12 | 13 | /// Increment the number of tasks scheduled externally 14 | pub(crate) fn inc_remote_schedule_count(&self) {} 15 | } 16 | -------------------------------------------------------------------------------- /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 | mod runtime; 12 | pub use runtime::RuntimeMetrics; 13 | 14 | mod batch; 15 | pub(crate) use batch::MetricsBatch; 16 | 17 | mod worker; 18 | pub(crate) use worker::WorkerMetrics; 19 | 20 | cfg_unstable_metrics! { 21 | 22 | mod histogram; 23 | pub(crate) use histogram::{Histogram, HistogramBatch, HistogramBuilder}; 24 | 25 | #[allow(unreachable_pub)] // rust-lang/rust#57411 26 | pub use histogram::{HistogramScale, HistogramConfiguration, LogHistogram, LogHistogramBuilder, InvalidHistogramConfiguration}; 27 | 28 | mod scheduler; 29 | pub(crate) use scheduler::SchedulerMetrics; 30 | 31 | cfg_net! { 32 | mod io; 33 | pub(crate) use io::IoDriverMetrics; 34 | } 35 | } 36 | 37 | cfg_not_unstable_metrics! { 38 | mod mock; 39 | pub(crate) use mock::{SchedulerMetrics, HistogramBuilder}; 40 | } 41 | -------------------------------------------------------------------------------- /tokio/src/runtime/metrics/scheduler.rs: -------------------------------------------------------------------------------- 1 | use crate::loom::sync::atomic::Ordering::Relaxed; 2 | use crate::util::metric_atomics::MetricAtomicU64; 3 | 4 | /// Retrieves metrics from the Tokio runtime. 5 | /// 6 | /// **Note**: This is an [unstable API][unstable]. The public API of this type 7 | /// may break in 1.x releases. See [the documentation on unstable 8 | /// features][unstable] for details. 9 | /// 10 | /// [unstable]: crate#unstable-features 11 | #[derive(Debug)] 12 | pub(crate) struct SchedulerMetrics { 13 | /// Number of tasks that are scheduled from outside the runtime. 14 | pub(super) remote_schedule_count: MetricAtomicU64, 15 | pub(super) budget_forced_yield_count: MetricAtomicU64, 16 | } 17 | 18 | impl SchedulerMetrics { 19 | pub(crate) fn new() -> SchedulerMetrics { 20 | SchedulerMetrics { 21 | remote_schedule_count: MetricAtomicU64::new(0), 22 | budget_forced_yield_count: MetricAtomicU64::new(0), 23 | } 24 | } 25 | 26 | /// Increment the number of tasks scheduled externally 27 | pub(crate) fn inc_remote_schedule_count(&self) { 28 | self.remote_schedule_count.add(1, Relaxed); 29 | } 30 | 31 | /// Increment the number of tasks forced to yield due to budget exhaustion 32 | pub(crate) fn inc_budget_forced_yield_count(&self) { 33 | self.budget_forced_yield_count.add(1, Relaxed); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /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/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 | scheduler::multi_thread::block_in_place(f) 9 | } 10 | -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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/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 | 9 | cfg_unstable_metrics! { 10 | impl Shared { 11 | pub(crate) fn worker_local_queue_depth(&self, worker: usize) -> usize { 12 | self.remotes[worker].steal.len() 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /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/tests/loom_current_thread/yield_now.rs: -------------------------------------------------------------------------------- 1 | use crate::runtime::park; 2 | use crate::runtime::{self, Runtime}; 3 | 4 | #[test] 5 | fn yield_calls_park_before_scheduling_again() { 6 | // Don't need to check all permutations 7 | let mut loom = loom::model::Builder::default(); 8 | loom.max_permutations = Some(1); 9 | loom.check(|| { 10 | let rt = mk_runtime(); 11 | 12 | let jh = rt.spawn(async { 13 | let tid = loom::thread::current().id(); 14 | let park_count = park::current_thread_park_count(); 15 | 16 | crate::task::yield_now().await; 17 | 18 | if tid == loom::thread::current().id() { 19 | let new_park_count = park::current_thread_park_count(); 20 | assert_eq!(park_count + 1, new_park_count); 21 | } 22 | }); 23 | 24 | rt.block_on(jh).unwrap(); 25 | }); 26 | } 27 | 28 | fn mk_runtime() -> Runtime { 29 | runtime::Builder::new_current_thread().build().unwrap() 30 | } 31 | -------------------------------------------------------------------------------- /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/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_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 | -------------------------------------------------------------------------------- /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/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.saturating_duration_since(self.start_time); 25 | let ms = dur 26 | .as_millis() 27 | .try_into() 28 | .unwrap_or(MAX_SAFE_MILLIS_DURATION); 29 | ms.min(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 | #[cfg(test)] 41 | #[allow(dead_code)] 42 | pub(super) fn start_time(&self) -> Instant { 43 | self.start_time 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /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/sync/task/mod.rs: -------------------------------------------------------------------------------- 1 | //! Thread-safe task notification primitives. 2 | 3 | mod atomic_waker; 4 | pub(crate) use self::atomic_waker::AtomicWaker; 5 | -------------------------------------------------------------------------------- /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/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/src/task/coop/consume_budget.rs: -------------------------------------------------------------------------------- 1 | /// Consumes a unit of budget and returns the execution back to the Tokio 2 | /// runtime *if* the task's coop budget was exhausted. 3 | /// 4 | /// The task will only yield if its entire coop budget has been exhausted. 5 | /// This function can be used in order to insert optional yield points into long 6 | /// computations that do not use Tokio resources like sockets or semaphores, 7 | /// without redundantly yielding to the runtime each time. 8 | /// 9 | /// # Examples 10 | /// 11 | /// Make sure that a function which returns a sum of (potentially lots of) 12 | /// iterated values is cooperative. 13 | /// 14 | /// ``` 15 | /// async fn sum_iterator(input: &mut impl std::iter::Iterator) -> i64 { 16 | /// let mut sum: i64 = 0; 17 | /// while let Some(i) = input.next() { 18 | /// sum += i; 19 | /// tokio::task::consume_budget().await 20 | /// } 21 | /// sum 22 | /// } 23 | /// ``` 24 | #[cfg_attr(docsrs, doc(cfg(feature = "rt")))] 25 | pub async fn consume_budget() { 26 | let mut status = std::task::Poll::Pending; 27 | 28 | std::future::poll_fn(move |cx| { 29 | std::task::ready!(crate::trace::trace_leaf(cx)); 30 | if status.is_ready() { 31 | return status; 32 | } 33 | status = crate::task::coop::poll_proceed(cx).map(|restore| { 34 | restore.made_progress(); 35 | }); 36 | status 37 | }) 38 | .await 39 | } 40 | -------------------------------------------------------------------------------- /tokio/src/util/as_ref.rs: -------------------------------------------------------------------------------- 1 | use super::typeid; 2 | 3 | #[derive(Debug)] 4 | pub(crate) enum OwnedBuf { 5 | Vec(Vec), 6 | #[cfg(feature = "io-util")] 7 | Bytes(bytes::Bytes), 8 | } 9 | 10 | impl AsRef<[u8]> for OwnedBuf { 11 | fn as_ref(&self) -> &[u8] { 12 | match self { 13 | Self::Vec(vec) => vec, 14 | #[cfg(feature = "io-util")] 15 | Self::Bytes(bytes) => bytes, 16 | } 17 | } 18 | } 19 | 20 | pub(crate) fn upgrade>(buf: B) -> OwnedBuf { 21 | let buf = match unsafe { typeid::try_transmute::>(buf) } { 22 | Ok(vec) => return OwnedBuf::Vec(vec), 23 | Err(original_buf) => original_buf, 24 | }; 25 | 26 | let buf = match unsafe { typeid::try_transmute::(buf) } { 27 | Ok(string) => return OwnedBuf::Vec(string.into_bytes()), 28 | Err(original_buf) => original_buf, 29 | }; 30 | 31 | #[cfg(feature = "io-util")] 32 | let buf = match unsafe { typeid::try_transmute::(buf) } { 33 | Ok(bytes) => return OwnedBuf::Bytes(bytes), 34 | Err(original_buf) => original_buf, 35 | }; 36 | 37 | OwnedBuf::Vec(buf.as_ref().to_owned()) 38 | } 39 | -------------------------------------------------------------------------------- /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/src/util/blocking_check.rs: -------------------------------------------------------------------------------- 1 | #[cfg(unix)] 2 | use std::os::fd::AsFd; 3 | 4 | #[cfg(unix)] 5 | #[allow(unused_variables)] 6 | #[track_caller] 7 | pub(crate) fn check_socket_for_blocking(s: &S) -> crate::io::Result<()> { 8 | #[cfg(not(tokio_allow_from_blocking_fd))] 9 | { 10 | let sock = socket2::SockRef::from(s); 11 | 12 | debug_assert!( 13 | sock.nonblocking()?, 14 | "Registering a blocking socket with the tokio runtime is unsupported. \ 15 | If you wish to do anyways, please add `--cfg tokio_allow_from_blocking_fd` to your \ 16 | RUSTFLAGS. See github.com/tokio-rs/tokio/issues/7172 for details." 17 | ); 18 | } 19 | 20 | Ok(()) 21 | } 22 | 23 | #[cfg(not(unix))] 24 | #[allow(unused_variables)] 25 | pub(crate) fn check_socket_for_blocking(s: &S) -> crate::io::Result<()> { 26 | // we cannot retrieve the nonblocking status on windows 27 | // and i dont know how to support wasi yet 28 | Ok(()) 29 | } 30 | -------------------------------------------------------------------------------- /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/util/markers.rs: -------------------------------------------------------------------------------- 1 | /// Marker for types that are `Sync` but not `Send` 2 | #[allow(dead_code)] 3 | pub(crate) struct SyncNotSend(#[allow(dead_code)] *mut ()); 4 | 5 | unsafe impl Sync for SyncNotSend {} 6 | 7 | cfg_rt! { 8 | pub(crate) struct NotSendOrSync(#[allow(dead_code)] *mut ()); 9 | } 10 | -------------------------------------------------------------------------------- /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/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 | use std::any::Any; 7 | 8 | pub(crate) struct SyncWrapper { 9 | value: T, 10 | } 11 | 12 | // safety: The SyncWrapper being send allows you to send the inner value across 13 | // thread boundaries. 14 | unsafe impl Send for SyncWrapper {} 15 | 16 | // safety: An immutable reference to a SyncWrapper is useless, so moving such an 17 | // immutable reference across threads is safe. 18 | unsafe impl Sync for SyncWrapper {} 19 | 20 | impl SyncWrapper { 21 | pub(crate) fn new(value: T) -> Self { 22 | Self { value } 23 | } 24 | 25 | pub(crate) fn into_inner(self) -> T { 26 | self.value 27 | } 28 | } 29 | 30 | impl SyncWrapper> { 31 | /// Attempt to downcast using `Any::downcast_ref()` to a type that is known to be `Sync`. 32 | pub(crate) fn downcast_ref_sync(&self) -> Option<&T> { 33 | // SAFETY: if the downcast fails, the inner value is not touched, 34 | // so no thread-safety violation can occur. 35 | self.value.downcast_ref() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tokio/src/util/typeid.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | any::TypeId, 3 | marker::PhantomData, 4 | mem::{self, ManuallyDrop}, 5 | }; 6 | 7 | // SAFETY: this function does not compare lifetimes. Values returned as `Ok` 8 | // may have their lifetimes extended. 9 | pub(super) unsafe fn try_transmute(x: Src) -> Result { 10 | if nonstatic_typeid::() == TypeId::of::() { 11 | let x = ManuallyDrop::new(x); 12 | Ok(mem::transmute_copy::(&x)) 13 | } else { 14 | Err(x) 15 | } 16 | } 17 | 18 | // https://github.com/dtolnay/typeid/blob/b06a3c08a0eaccc7df6091ade1ae4e3fb53609d5/src/lib.rs#L197-L222 19 | #[inline(always)] 20 | fn nonstatic_typeid() -> TypeId 21 | where 22 | T: ?Sized, 23 | { 24 | trait NonStaticAny { 25 | fn get_type_id(&self) -> TypeId 26 | where 27 | Self: 'static; 28 | } 29 | 30 | impl NonStaticAny for PhantomData { 31 | #[inline(always)] 32 | fn get_type_id(&self) -> TypeId 33 | where 34 | Self: 'static, 35 | { 36 | TypeId::of::() 37 | } 38 | } 39 | 40 | let phantom_data = PhantomData::; 41 | NonStaticAny::get_type_id(unsafe { 42 | mem::transmute::<&dyn NonStaticAny, &(dyn NonStaticAny + 'static)>(&phantom_data) 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /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/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/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/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/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 | #[cfg_attr(miri, ignore)] // No `fchmod` in miri. 9 | async fn copy() { 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::copy(&source_path, &dest_path).await.unwrap(); 17 | 18 | let from = fs::read(&source_path).await.unwrap(); 19 | let to = fs::read(&dest_path).await.unwrap(); 20 | 21 | assert_eq!(from, to); 22 | } 23 | 24 | #[tokio::test] 25 | #[cfg_attr(miri, ignore)] // No `fchmod` in miri. 26 | async fn copy_permissions() { 27 | let dir = tempdir().unwrap(); 28 | let from_path = dir.path().join("foo.txt"); 29 | let to_path = dir.path().join("bar.txt"); 30 | 31 | let from = tokio::fs::File::create(&from_path).await.unwrap(); 32 | let mut from_perms = from.metadata().await.unwrap().permissions(); 33 | from_perms.set_readonly(true); 34 | from.set_permissions(from_perms.clone()).await.unwrap(); 35 | 36 | tokio::fs::copy(from_path, &to_path).await.unwrap(); 37 | 38 | let to_perms = tokio::fs::metadata(to_path).await.unwrap().permissions(); 39 | 40 | assert_eq!(from_perms, to_perms); 41 | } 42 | -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/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/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_repeat.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", not(miri)))] 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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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 | #[cfg_attr(miri, ignore)] // No `socket` in miri. 11 | fn no_runtime_panics_binding_net_tcp_listener() { 12 | let listener = net::TcpListener::bind("127.0.0.1:0").expect("failed to bind listener"); 13 | let _ = TcpListener::try_from(listener); 14 | } 15 | -------------------------------------------------------------------------------- /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 | #[cfg_attr(miri, ignore)] // No `getaddrinfo` in miri. 27 | async fn resolve_dns() -> io::Result<()> { 28 | let mut hosts = net::lookup_host("localhost:3000").await?; 29 | let host = hosts.next().unwrap(); 30 | 31 | let expected = if host.is_ipv4() { 32 | SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 3000) 33 | } else { 34 | SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), 3000) 35 | }; 36 | assert_eq!(host, expected); 37 | 38 | Ok(()) 39 | } 40 | -------------------------------------------------------------------------------- /tokio/tests/process_arg0.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", unix, not(miri)))] 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/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"), not(miri)))] 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/process_issue_42.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(unix)] 4 | #![cfg(not(miri))] 5 | 6 | use futures::future::join_all; 7 | use std::process::Stdio; 8 | use tokio::process::Command; 9 | use tokio::task; 10 | 11 | #[tokio::test] 12 | async fn issue_42() { 13 | // We spawn a many batches of processes which should exit at roughly the 14 | // same time (modulo OS scheduling delays), to make sure that consuming 15 | // a readiness event for one process doesn't inadvertently starve another. 16 | // We then do this many times (in parallel) in an effort to stress test the 17 | // implementation to ensure there are no race conditions. 18 | // See alexcrichton/tokio-process#42 for background 19 | let join_handles = (0..10usize).map(|_| { 20 | task::spawn(async { 21 | let processes = (0..10usize).map(|i| { 22 | let mut child = Command::new("echo") 23 | .arg(format!("I am spawned process #{i}")) 24 | .stdin(Stdio::null()) 25 | .stdout(Stdio::null()) 26 | .stderr(Stdio::null()) 27 | .kill_on_drop(true) 28 | .spawn() 29 | .unwrap(); 30 | 31 | async move { child.wait().await } 32 | }); 33 | 34 | join_all(processes).await; 35 | }) 36 | }); 37 | 38 | join_all(join_handles).await; 39 | } 40 | -------------------------------------------------------------------------------- /tokio/tests/process_kill_after_wait.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", not(target_os = "wasi"), not(miri)))] // Wasi cannot run system commands 3 | 4 | use tokio::process::Command; 5 | 6 | #[tokio::test] 7 | async fn kill_after_wait() { 8 | let mut cmd; 9 | 10 | if cfg!(windows) { 11 | cmd = Command::new("cmd"); 12 | cmd.arg("/c"); 13 | } else { 14 | cmd = Command::new("sh"); 15 | cmd.arg("-c"); 16 | } 17 | 18 | let mut child = cmd.arg("exit 2").spawn().unwrap(); 19 | 20 | child.start_kill().unwrap(); 21 | 22 | child.wait().await.unwrap(); 23 | 24 | // Kill after `wait` is fine. 25 | child.start_kill().unwrap(); 26 | child.kill().await.unwrap(); 27 | } 28 | -------------------------------------------------------------------------------- /tokio/tests/process_kill_on_drop.rs: -------------------------------------------------------------------------------- 1 | #![cfg(all(unix, feature = "process", not(miri)))] 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/process_raw_handle.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(windows)] 4 | #![cfg(not(miri))] 5 | 6 | use tokio::process::Command; 7 | use windows_sys::Win32::System::Threading::GetProcessId; 8 | 9 | #[tokio::test] 10 | async fn obtain_raw_handle() { 11 | let mut cmd = Command::new("cmd"); 12 | cmd.kill_on_drop(true); 13 | cmd.arg("/c"); 14 | cmd.arg("pause"); 15 | 16 | let child = cmd.spawn().unwrap(); 17 | 18 | let orig_id = child.id().expect("missing id"); 19 | assert!(orig_id > 0); 20 | 21 | let handle = child.raw_handle().expect("process stopped"); 22 | let handled_id = unsafe { GetProcessId(handle as _) }; 23 | assert_eq!(handled_id, orig_id); 24 | } 25 | -------------------------------------------------------------------------------- /tokio/tests/process_smoke.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", not(target_os = "wasi"), not(miri)))] // 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/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/tests/signal_ctrl_c.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(unix)] 4 | #![cfg(not(miri))] // No `sigaction` on Miri 5 | 6 | mod support { 7 | pub mod signal; 8 | } 9 | use support::signal::send_signal; 10 | 11 | use tokio::signal; 12 | use tokio_test::assert_ok; 13 | 14 | #[tokio::test] 15 | async fn ctrl_c() { 16 | let ctrl_c = signal::ctrl_c(); 17 | 18 | tokio::spawn(async { 19 | send_signal(libc::SIGINT); 20 | }); 21 | 22 | assert_ok!(ctrl_c.await); 23 | } 24 | -------------------------------------------------------------------------------- /tokio/tests/signal_drop_recv.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(unix)] 4 | #![cfg(not(miri))] // No `sigaction` in Miri. 5 | 6 | mod support { 7 | pub mod signal; 8 | } 9 | use support::signal::send_signal; 10 | 11 | use tokio::signal::unix::{signal, SignalKind}; 12 | 13 | #[tokio::test] 14 | async fn drop_then_get_a_signal() { 15 | let kind = SignalKind::user_defined1(); 16 | let sig = signal(kind).expect("failed to create first signal"); 17 | drop(sig); 18 | 19 | send_signal(libc::SIGUSR1); 20 | let mut sig = signal(kind).expect("failed to create second signal"); 21 | 22 | let _ = sig.recv().await; 23 | } 24 | -------------------------------------------------------------------------------- /tokio/tests/signal_drop_rt.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(unix)] 4 | #![cfg(not(miri))] // No `sigaction` in miri. 5 | 6 | mod support { 7 | pub mod signal; 8 | } 9 | use support::signal::send_signal; 10 | 11 | use tokio::runtime::Runtime; 12 | use tokio::signal::unix::{signal, SignalKind}; 13 | 14 | #[test] 15 | fn dropping_loops_does_not_cause_starvation() { 16 | let kind = SignalKind::user_defined1(); 17 | 18 | let first_rt = rt(); 19 | let mut first_signal = 20 | first_rt.block_on(async { signal(kind).expect("failed to register first signal") }); 21 | 22 | let second_rt = rt(); 23 | let mut second_signal = 24 | second_rt.block_on(async { signal(kind).expect("failed to register second signal") }); 25 | 26 | send_signal(libc::SIGUSR1); 27 | 28 | first_rt 29 | .block_on(first_signal.recv()) 30 | .expect("failed to await first signal"); 31 | 32 | drop(first_rt); 33 | drop(first_signal); 34 | 35 | send_signal(libc::SIGUSR1); 36 | 37 | second_rt.block_on(second_signal.recv()); 38 | } 39 | 40 | fn rt() -> Runtime { 41 | tokio::runtime::Builder::new_current_thread() 42 | .enable_all() 43 | .build() 44 | .unwrap() 45 | } 46 | -------------------------------------------------------------------------------- /tokio/tests/signal_drop_signal.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(unix)] 4 | #![cfg(not(miri))] // No `sigaction` in miri. 5 | 6 | mod support { 7 | pub mod signal; 8 | } 9 | use support::signal::send_signal; 10 | 11 | use tokio::signal::unix::{signal, SignalKind}; 12 | 13 | #[tokio::test] 14 | async fn dropping_signal_does_not_deregister_any_other_instances() { 15 | let kind = SignalKind::user_defined1(); 16 | 17 | // Signals should not starve based on ordering 18 | let first_duplicate_signal = signal(kind).expect("failed to register first duplicate signal"); 19 | let mut sig = signal(kind).expect("failed to register signal"); 20 | let second_duplicate_signal = signal(kind).expect("failed to register second duplicate signal"); 21 | 22 | drop(first_duplicate_signal); 23 | drop(second_duplicate_signal); 24 | 25 | send_signal(libc::SIGUSR1); 26 | let _ = sig.recv().await; 27 | } 28 | -------------------------------------------------------------------------------- /tokio/tests/signal_info.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(any( 4 | target_os = "dragonfly", 5 | target_os = "freebsd", 6 | target_os = "macos", 7 | target_os = "netbsd", 8 | target_os = "openbsd", 9 | target_os = "illumos" 10 | ))] 11 | #![cfg(not(miri))] // No `sigaction` on Miri 12 | 13 | mod support { 14 | pub mod signal; 15 | } 16 | use support::signal::send_signal; 17 | 18 | use tokio::signal; 19 | use tokio::signal::unix::SignalKind; 20 | use tokio::time::{timeout, Duration}; 21 | 22 | #[tokio::test] 23 | async fn siginfo() { 24 | let mut sig = signal::unix::signal(SignalKind::info()).expect("installed signal handler"); 25 | 26 | tokio::spawn(async { 27 | send_signal(libc::SIGINFO); 28 | }); 29 | 30 | // Add a timeout to ensure the test doesn't hang. 31 | timeout(Duration::from_secs(5), sig.recv()) 32 | .await 33 | .expect("received SIGINFO signal in time") 34 | .expect("received SIGINFO signal"); 35 | } 36 | -------------------------------------------------------------------------------- /tokio/tests/signal_no_rt.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(unix)] 4 | #![cfg(not(miri))] // No `sigaction` on Miri. 5 | 6 | use tokio::signal::unix::{signal, SignalKind}; 7 | 8 | #[cfg_attr(target_os = "wasi", ignore = "Wasi does not support panic recovery")] 9 | #[test] 10 | #[should_panic] 11 | fn no_runtime_panics_creating_signals() { 12 | let _ = signal(SignalKind::hangup()); 13 | } 14 | -------------------------------------------------------------------------------- /tokio/tests/signal_notify_both.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(unix)] 4 | #![cfg(not(miri))] // No `sigaction` on Miri. 5 | 6 | mod support { 7 | pub mod signal; 8 | } 9 | use support::signal::send_signal; 10 | 11 | use tokio::signal::unix::{signal, SignalKind}; 12 | 13 | #[tokio::test] 14 | async fn notify_both() { 15 | let kind = SignalKind::user_defined2(); 16 | 17 | let mut signal1 = signal(kind).expect("failed to create signal1"); 18 | let mut signal2 = signal(kind).expect("failed to create signal2"); 19 | 20 | send_signal(libc::SIGUSR2); 21 | 22 | signal1.recv().await; 23 | signal2.recv().await; 24 | } 25 | -------------------------------------------------------------------------------- /tokio/tests/signal_panic.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(unix)] 4 | #![cfg(panic = "unwind")] 5 | #![cfg(not(miri))] // No `sigaction` on Miri. 6 | 7 | use std::error::Error; 8 | use tokio::runtime::Builder; 9 | use tokio::signal::unix::{signal, SignalKind}; 10 | 11 | mod support { 12 | pub mod panic; 13 | } 14 | use support::panic::test_panic; 15 | 16 | #[test] 17 | fn signal_panic_caller() -> Result<(), Box> { 18 | let panic_location_file = test_panic(|| { 19 | let rt = Builder::new_current_thread().build().unwrap(); 20 | 21 | rt.block_on(async { 22 | let kind = SignalKind::from_raw(-1); 23 | let _ = signal(kind); 24 | }); 25 | }); 26 | 27 | // The panic location should be in this file 28 | assert_eq!(&panic_location_file.unwrap(), file!()); 29 | 30 | Ok(()) 31 | } 32 | -------------------------------------------------------------------------------- /tokio/tests/signal_twice.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(unix)] 4 | #![cfg(not(miri))] // No `sigaction` on Miri. 5 | 6 | mod support { 7 | pub mod signal; 8 | } 9 | use support::signal::send_signal; 10 | 11 | use tokio::signal::unix::{signal, SignalKind}; 12 | 13 | #[tokio::test] 14 | async fn twice() { 15 | let kind = SignalKind::user_defined1(); 16 | let mut sig = signal(kind).expect("failed to get signal"); 17 | 18 | for _ in 0..2 { 19 | send_signal(libc::SIGUSR1); 20 | 21 | assert!(sig.recv().await.is_some()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tokio/tests/signal_usr1.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(unix)] 4 | #![cfg(not(miri))] // No `sigaction` in Miri. 5 | 6 | mod support { 7 | pub mod signal; 8 | } 9 | use support::signal::send_signal; 10 | 11 | use tokio::signal::unix::{signal, SignalKind}; 12 | use tokio_test::assert_ok; 13 | 14 | #[tokio::test] 15 | async fn signal_usr1() { 16 | let mut signal = assert_ok!( 17 | signal(SignalKind::user_defined1()), 18 | "failed to create signal" 19 | ); 20 | 21 | send_signal(libc::SIGUSR1); 22 | 23 | signal.recv().await; 24 | } 25 | -------------------------------------------------------------------------------- /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/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/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/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/tests/support/signal.rs: -------------------------------------------------------------------------------- 1 | pub fn send_signal(signal: libc::c_int) { 2 | use libc::{getpid, kill}; 3 | 4 | unsafe { 5 | let pid = getpid(); 6 | assert_eq!( 7 | kill(pid, signal), 8 | 0, 9 | "kill(pid = {}, {}) failed with error: {}", 10 | pid, 11 | signal, 12 | std::io::Error::last_os_error(), 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /tokio/tests/task_yield_now.rs: -------------------------------------------------------------------------------- 1 | #![cfg(all(feature = "full", not(target_os = "wasi"), 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 | 18 | #[tokio::test(flavor = "multi_thread")] 19 | async fn yield_now_external_executor_and_block_in_place() { 20 | let j = tokio::spawn(async { 21 | task::block_in_place(|| futures::executor::block_on(task::yield_now())); 22 | }); 23 | j.await.unwrap(); 24 | } 25 | -------------------------------------------------------------------------------- /tokio/tests/tcp_echo.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", not(target_os = "wasi"), not(miri)))] // Wasi doesn't support bind 3 | // No socket on miri. 4 | 5 | use tokio::io::{self, AsyncReadExt, AsyncWriteExt}; 6 | use tokio::net::{TcpListener, TcpStream}; 7 | use tokio::sync::oneshot; 8 | use tokio_test::assert_ok; 9 | 10 | #[tokio::test] 11 | async fn echo_server() { 12 | const ITER: usize = 1024; 13 | 14 | let (tx, rx) = oneshot::channel(); 15 | 16 | let srv = assert_ok!(TcpListener::bind("127.0.0.1:0").await); 17 | let addr = assert_ok!(srv.local_addr()); 18 | 19 | let msg = "foo bar baz"; 20 | tokio::spawn(async move { 21 | let mut stream = assert_ok!(TcpStream::connect(&addr).await); 22 | 23 | for _ in 0..ITER { 24 | // write 25 | assert_ok!(stream.write_all(msg.as_bytes()).await); 26 | 27 | // read 28 | let mut buf = [0; 11]; 29 | assert_ok!(stream.read_exact(&mut buf).await); 30 | assert_eq!(&buf[..], msg.as_bytes()); 31 | } 32 | 33 | assert_ok!(tx.send(())); 34 | }); 35 | 36 | let (mut stream, _) = assert_ok!(srv.accept().await); 37 | let (mut rd, mut wr) = stream.split(); 38 | 39 | let n = assert_ok!(io::copy(&mut rd, &mut wr).await); 40 | assert_eq!(n, (ITER * msg.len()) as u64); 41 | 42 | assert_ok!(rx.await); 43 | } 44 | -------------------------------------------------------------------------------- /tokio/tests/tcp_peek.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(all(feature = "full", not(target_os = "wasi"), not(miri)))] // Wasi doesn't support bind 3 | // No `socket` on miri. 4 | 5 | use tokio::io::AsyncReadExt; 6 | use tokio::net::TcpStream; 7 | 8 | use tokio_test::assert_ok; 9 | 10 | use std::thread; 11 | use std::{io::Write, net}; 12 | 13 | #[tokio::test] 14 | async fn peek() { 15 | let listener = net::TcpListener::bind("127.0.0.1:0").unwrap(); 16 | 17 | let addr = listener.local_addr().unwrap(); 18 | let t = thread::spawn(move || assert_ok!(listener.accept()).0); 19 | 20 | let left = net::TcpStream::connect(addr).unwrap(); 21 | 22 | left.set_nonblocking(true).unwrap(); 23 | 24 | let mut right = t.join().unwrap(); 25 | 26 | right.set_nonblocking(true).unwrap(); 27 | 28 | let _ = right.write(&[1, 2, 3, 4]).unwrap(); 29 | 30 | let mut left: TcpStream = left.try_into().unwrap(); 31 | let mut buf = [0u8; 16]; 32 | let n = assert_ok!(left.peek(&mut buf).await); 33 | assert_eq!([1, 2, 3, 4], buf[..n]); 34 | 35 | let n = assert_ok!(left.read(&mut buf).await); 36 | assert_eq!([1, 2, 3, 4], buf[..n]); 37 | } 38 | -------------------------------------------------------------------------------- /tokio/tests/uds_cred.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(all(unix, not(target_os = "dragonfly"), not(miri)))] // No `getsockopt` on miri. 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/tests/uds_split.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | #![cfg(unix)] 4 | #![cfg(not(miri))] // No `socket` in miri. 5 | 6 | use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; 7 | use tokio::net::UnixStream; 8 | 9 | /// Checks that `UnixStream` can be split into a read half and a write half using 10 | /// `UnixStream::split` and `UnixStream::split_mut`. 11 | /// 12 | /// Verifies that the implementation of `AsyncWrite::poll_shutdown` shutdowns the stream for 13 | /// writing by reading to the end of stream on the other side of the connection. 14 | #[tokio::test] 15 | async fn split() -> std::io::Result<()> { 16 | let (mut a, mut b) = UnixStream::pair()?; 17 | 18 | let (mut a_read, mut a_write) = a.split(); 19 | let (mut b_read, mut b_write) = b.split(); 20 | 21 | let (a_response, b_response) = futures::future::try_join( 22 | send_recv_all(&mut a_read, &mut a_write, b"A"), 23 | send_recv_all(&mut b_read, &mut b_write, b"B"), 24 | ) 25 | .await?; 26 | 27 | assert_eq!(a_response, b"B"); 28 | assert_eq!(b_response, b"A"); 29 | 30 | Ok(()) 31 | } 32 | 33 | async fn send_recv_all( 34 | read: &mut (dyn AsyncRead + Unpin), 35 | write: &mut (dyn AsyncWrite + Unpin), 36 | input: &[u8], 37 | ) -> std::io::Result> { 38 | write.write_all(input).await?; 39 | write.shutdown().await?; 40 | 41 | let mut output = Vec::new(); 42 | read.read_to_end(&mut output).await?; 43 | Ok(output) 44 | } 45 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------