From 6e63b18c624965a11766c812b6878b9aa04f555e Mon Sep 17 00:00:00 2001 From: hu-kai45 Date: Wed, 7 Jun 2023 11:07:46 +0800 Subject: [PATCH] =?UTF-8?q?tokio=20=E7=89=88=E6=9C=AC=E5=8D=87=E7=BA=A7?= =?UTF-8?q?=E5=88=B0=201.25.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: hu-kai45 --- .circleci/config.yml | 2 +- .cirrus.yml | 7 +- .github/ISSUE_TEMPLATE/config.yml | 4 + .github/ISSUE_TEMPLATE/question.md | 16 - .github/workflows/audit.yml | 10 +- .github/workflows/ci.yml | 287 +++++++--- .github/workflows/labeler.yml | 7 + .github/workflows/loom.yml | 11 +- .github/workflows/pr-audit.yml | 16 +- .github/workflows/stress-test.yml | 16 +- CONTRIBUTING.md | 14 +- Cargo.toml | 1 - Cross.toml | 1 + LICENSE | 2 +- README.OpenSource | 2 +- README.md | 26 +- SECURITY.md | 8 +- benches/Cargo.toml | 7 + benches/copy.rs | 238 ++++++++ benches/sync_rwlock.rs | 10 +- examples/Cargo.toml | 5 +- examples/hello_world.rs | 6 +- examples/named-pipe-multi-client.rs | 4 +- target-specs/i686-unknown-linux-gnu.json | 40 ++ tests-build/README.md | 8 + .../tests/fail/macros_core_no_default.stderr | 2 +- .../tests/fail/macros_dead_code.stderr | 2 +- tests-integration/Cargo.toml | 3 +- tests-integration/src/bin/test-cat.rs | 24 +- tests-integration/tests/macros_main.rs | 6 +- tests-integration/tests/macros_select.rs | 1 + tests-integration/tests/process_stdio.rs | 67 ++- tokio-macros/CHANGELOG.md | 18 + tokio-macros/Cargo.toml | 4 +- tokio-macros/LICENSE | 2 +- tokio-macros/src/entry.rs | 53 +- tokio-macros/src/select.rs | 4 +- tokio-stream/CHANGELOG.md | 14 + tokio-stream/Cargo.toml | 3 +- tokio-stream/LICENSE | 2 +- tokio-stream/src/stream_ext.rs | 2 + tokio-stream/src/stream_ext/chunks_timeout.rs | 12 +- tokio-stream/src/stream_ext/collect.rs | 6 +- tokio-stream/src/stream_ext/then.rs | 2 +- tokio-stream/src/stream_ext/throttle.rs | 4 +- tokio-stream/src/stream_ext/timeout.rs | 2 +- tokio-stream/src/wrappers/broadcast.rs | 2 +- tokio-stream/tests/stream_panic.rs | 2 +- tokio-stream/tests/stream_stream_map.rs | 1 + tokio-test/Cargo.toml | 2 +- tokio-test/LICENSE | 2 +- tokio-test/src/macros.rs | 2 +- tokio-test/src/task.rs | 45 +- tokio-util/CHANGELOG.md | 22 + tokio-util/Cargo.toml | 4 +- tokio-util/LICENSE | 2 +- tokio-util/src/codec/framed.rs | 15 +- tokio-util/src/codec/framed_impl.rs | 12 +- tokio-util/src/codec/framed_write.rs | 10 + tokio-util/src/codec/length_delimited.rs | 10 +- tokio-util/src/io/copy_to_bytes.rs | 68 +++ tokio-util/src/io/inspect.rs | 134 +++++ tokio-util/src/io/mod.rs | 7 + tokio-util/src/io/sink_writer.rs | 124 +++++ tokio-util/src/io/stream_reader.rs | 231 ++++++-- tokio-util/src/io/sync_bridge.rs | 43 +- tokio-util/src/lib.rs | 1 + tokio-util/src/sync/cancellation_token.rs | 97 ++++ .../src/sync/cancellation_token/tree_node.rs | 4 +- tokio-util/src/sync/mod.rs | 4 +- tokio-util/src/sync/poll_semaphore.rs | 53 +- .../src/sync/tests/loom_cancellation_token.rs | 23 +- tokio-util/src/task/join_map.rs | 12 +- tokio-util/src/task/mod.rs | 2 + tokio-util/src/time/delay_queue.rs | 41 +- tokio-util/tests/context.rs | 3 +- tokio-util/tests/framed_write.rs | 19 +- tokio-util/tests/io_inspect.rs | 194 +++++++ tokio-util/tests/io_sink_writer.rs | 72 +++ tokio-util/tests/io_sync_bridge.rs | 23 +- tokio-util/tests/panic.rs | 2 +- tokio-util/tests/poll_semaphore.rs | 48 ++ tokio-util/tests/spawn_pinned.rs | 9 +- tokio-util/tests/sync_cancellation_token.rs | 67 ++- tokio-util/tests/time_delay_queue.rs | 4 +- tokio-util/tests/udp.rs | 1 + tokio/CHANGELOG.md | 390 ++++++++++++- tokio/Cargo.toml | 65 +-- tokio/LICENSE | 2 +- tokio/README.md | 26 +- tokio/build.rs | 128 +++++ tokio/docs/reactor-refactor.md | 8 +- tokio/external-types.toml | 11 + tokio/src/doc/mod.rs | 1 - tokio/src/doc/winapi.rs | 66 --- tokio/src/fs/file.rs | 39 +- tokio/src/fs/file/tests.rs | 29 +- tokio/src/fs/mocks.rs | 2 +- tokio/src/fs/open_options.rs | 6 +- .../src/fs/open_options/mock_open_options.rs | 1 + tokio/src/fs/read_dir.rs | 91 +++- tokio/src/future/block_on.rs | 9 +- tokio/src/future/poll_fn.rs | 28 +- tokio/src/io/async_fd.rs | 9 +- tokio/src/io/blocking.rs | 5 +- tokio/src/io/bsd/poll_aio.rs | 6 +- tokio/src/io/{driver => }/interest.rs | 4 +- tokio/src/io/mod.rs | 16 +- tokio/src/io/poll_evented.rs | 83 ++- tokio/src/io/{driver => }/ready.rs | 2 +- tokio/src/io/split.rs | 5 +- tokio/src/io/stdio_common.rs | 3 +- tokio/src/io/util/async_seek_ext.rs | 2 +- tokio/src/io/util/async_write_ext.rs | 10 +- tokio/src/io/util/copy.rs | 62 ++- tokio/src/io/util/empty.rs | 2 +- tokio/src/io/util/mem.rs | 4 +- tokio/src/io/util/read.rs | 2 +- tokio/src/lib.rs | 131 +++-- tokio/src/loom/mocked.rs | 12 + tokio/src/loom/std/atomic_ptr.rs | 34 -- tokio/src/loom/std/atomic_u16.rs | 4 +- tokio/src/loom/std/atomic_u32.rs | 12 +- tokio/src/loom/std/atomic_u64.rs | 79 +-- tokio/src/loom/std/atomic_u64_as_mutex.rs | 76 +++ tokio/src/loom/std/atomic_u64_native.rs | 4 + .../loom/std/atomic_u64_static_const_new.rs | 12 + .../loom/std/atomic_u64_static_once_cell.rs | 57 ++ tokio/src/loom/std/atomic_u8.rs | 34 -- tokio/src/loom/std/atomic_usize.rs | 4 +- tokio/src/loom/std/mod.rs | 34 +- tokio/src/loom/std/mutex.rs | 6 + tokio/src/loom/std/parking_lot.rs | 2 +- tokio/src/macros/addr_of.rs | 53 ++ tokio/src/macros/cfg.rs | 102 +++- tokio/src/macros/join.rs | 12 +- tokio/src/macros/mod.rs | 3 + tokio/src/macros/scoped_tls.rs | 2 +- tokio/src/macros/select.rs | 12 +- tokio/src/macros/support.rs | 6 +- tokio/src/macros/thread_local.rs | 10 +- tokio/src/macros/try_join.rs | 12 +- tokio/src/net/addr.rs | 2 +- tokio/src/net/mod.rs | 14 +- tokio/src/net/tcp/listener.rs | 169 +++--- tokio/src/net/tcp/mod.rs | 4 +- tokio/src/net/tcp/socket.rs | 94 +++- tokio/src/net/tcp/split.rs | 20 +- tokio/src/net/tcp/split_owned.rs | 24 +- tokio/src/net/tcp/stream.rs | 308 ++++++----- tokio/src/net/udp.rs | 119 +++- tokio/src/net/unix/datagram/socket.rs | 50 +- tokio/src/net/unix/listener.rs | 54 +- tokio/src/net/unix/mod.rs | 13 +- tokio/src/net/unix/split.rs | 14 +- tokio/src/net/unix/split_owned.rs | 24 +- tokio/src/net/unix/stream.rs | 58 +- tokio/src/net/unix/ucred.rs | 52 +- tokio/src/net/windows/named_pipe.rs | 398 ++++++++++---- tokio/src/park/either.rs | 74 --- tokio/src/park/mod.rs | 117 ---- tokio/src/process/mod.rs | 66 ++- tokio/src/process/unix/mod.rs | 104 +++- tokio/src/process/unix/orphan.rs | 28 +- tokio/src/process/windows.rs | 127 ++++- tokio/src/runtime/blocking/mod.rs | 7 +- tokio/src/runtime/blocking/pool.rs | 253 +++++++-- tokio/src/runtime/blocking/schedule.rs | 49 +- tokio/src/runtime/blocking/shutdown.rs | 4 +- tokio/src/runtime/blocking/task.rs | 2 +- tokio/src/runtime/builder.rs | 241 +++++--- tokio/src/runtime/config.rs | 34 ++ tokio/src/runtime/context.rs | 478 +++++++++++++--- tokio/src/{ => runtime}/coop.rs | 54 +- tokio/src/runtime/defer.rs | 27 + tokio/src/runtime/driver.rs | 338 ++++++++---- tokio/src/runtime/enter.rs | 206 ------- tokio/src/runtime/handle.rs | 219 ++------ .../src/{io/driver => runtime/io}/metrics.rs | 0 tokio/src/{io/driver => runtime/io}/mod.rs | 298 +++++----- .../src/{io/driver => runtime/io}/platform.rs | 0 .../{io/driver => runtime/io}/registration.rs | 54 +- .../{io/driver => runtime/io}/scheduled_io.rs | 75 ++- tokio/src/runtime/metrics/batch.rs | 13 +- tokio/src/runtime/metrics/mock.rs | 1 + tokio/src/runtime/metrics/runtime.rs | 164 +++++- tokio/src/runtime/metrics/worker.rs | 6 +- tokio/src/runtime/mod.rs | 453 ++-------------- tokio/src/{park/thread.rs => runtime/park.rs} | 101 ++-- .../unix/driver.rs => runtime/process.rs} | 30 +- tokio/src/runtime/runtime.rs | 423 +++++++++++++++ .../current_thread.rs} | 306 +++++------ tokio/src/runtime/scheduler/mod.rs | 194 +++++++ .../runtime/scheduler/multi_thread/handle.rs | 98 ++++ .../multi_thread}/idle.rs | 0 .../src/runtime/scheduler/multi_thread/mod.rs | 84 +++ .../multi_thread}/park.rs | 90 ++- .../multi_thread}/queue.rs | 88 +-- .../multi_thread}/worker.rs | 312 +++++------ tokio/src/runtime/signal/mod.rs | 142 +++++ tokio/src/runtime/spawner.rs | 92 ---- tokio/src/runtime/task/abort.rs | 47 +- tokio/src/runtime/task/core.rs | 145 ++++- tokio/src/runtime/task/error.rs | 2 +- tokio/src/runtime/task/harness.rs | 318 ++++++----- tokio/src/runtime/task/id.rs | 87 +++ tokio/src/runtime/task/join.rs | 85 ++- tokio/src/runtime/task/list.rs | 4 +- tokio/src/runtime/task/mod.rs | 131 ++--- tokio/src/runtime/task/raw.rs | 176 ++++-- tokio/src/runtime/task/state.rs | 8 +- tokio/src/runtime/task/waker.rs | 84 +-- tokio/src/runtime/tests/loom_blocking.rs | 21 + ...er.rs => loom_current_thread_scheduler.rs} | 0 tokio/src/runtime/tests/loom_join_set.rs | 1 - tokio/src/runtime/tests/loom_queue.rs | 4 +- tokio/src/runtime/tests/loom_yield.rs | 37 ++ tokio/src/runtime/tests/mod.rs | 27 +- tokio/src/runtime/tests/queue.rs | 4 +- tokio/src/runtime/tests/task.rs | 2 +- tokio/src/runtime/tests/task_combinations.rs | 13 +- tokio/src/runtime/thread_id.rs | 31 ++ tokio/src/runtime/thread_pool/mod.rs | 157 ------ .../{time/driver => runtime/time}/entry.rs | 120 +++- tokio/src/runtime/time/handle.rs | 62 +++ .../src/{time/driver => runtime/time}/mod.rs | 304 ++++------- tokio/src/runtime/time/source.rs | 42 ++ .../driver => runtime/time}/tests/mod.rs | 175 +++--- .../driver => runtime/time}/wheel/level.rs | 4 +- .../driver => runtime/time}/wheel/mod.rs | 2 +- tokio/src/signal/mod.rs | 2 +- tokio/src/signal/registry.rs | 26 +- tokio/src/signal/unix.rs | 41 +- tokio/src/signal/unix/driver.rs | 209 ------- tokio/src/signal/windows.rs | 302 ++++++++++- tokio/src/signal/windows/stub.rs | 14 +- tokio/src/signal/windows/sys.rs | 121 ++++- tokio/src/sync/batch_semaphore.rs | 24 +- tokio/src/sync/broadcast.rs | 237 +++++--- tokio/src/sync/mod.rs | 8 + tokio/src/sync/mpsc/block.rs | 143 +++-- tokio/src/sync/mpsc/bounded.rs | 129 ++++- tokio/src/sync/mpsc/chan.rs | 62 ++- tokio/src/sync/mpsc/list.rs | 2 +- tokio/src/sync/mpsc/mod.rs | 12 +- tokio/src/sync/mpsc/unbounded.rs | 77 ++- tokio/src/sync/mutex.rs | 63 ++- tokio/src/sync/notify.rs | 15 +- tokio/src/sync/once_cell.rs | 4 +- tokio/src/sync/oneshot.rs | 14 +- tokio/src/sync/rwlock/read_guard.rs | 1 + tokio/src/sync/rwlock/write_guard.rs | 1 + tokio/src/sync/semaphore.rs | 49 +- tokio/src/sync/tests/atomic_waker.rs | 6 +- tokio/src/sync/tests/notify.rs | 4 +- tokio/src/sync/tests/semaphore_batch.rs | 4 +- tokio/src/sync/watch.rs | 76 ++- tokio/src/task/blocking.rs | 22 +- tokio/src/task/builder.rs | 42 +- tokio/src/task/consume_budget.rs | 4 +- tokio/src/task/join_set.rs | 136 +++-- tokio/src/task/local.rs | 460 ++++++++++++++-- tokio/src/task/mod.rs | 25 +- tokio/src/task/spawn.rs | 44 +- tokio/src/task/task_local.rs | 6 +- tokio/src/task/unconstrained.rs | 2 +- tokio/src/task/yield_now.rs | 14 +- tokio/src/time/clock.rs | 27 +- tokio/src/time/driver/handle.rs | 96 ---- tokio/src/time/error.rs | 5 +- tokio/src/time/interval.rs | 3 +- tokio/src/time/mod.rs | 13 +- tokio/src/time/{driver => }/sleep.rs | 33 +- tokio/src/time/tests/mod.rs | 22 - tokio/src/time/tests/test_sleep.rs | 443 --------------- tokio/src/time/timeout.rs | 26 +- tokio/src/util/error.rs | 7 +- tokio/src/util/idle_notified_set.rs | 19 +- tokio/src/util/linked_list.rs | 5 +- tokio/src/util/mod.rs | 37 +- tokio/src/util/once_cell.rs | 70 +++ tokio/src/util/rand.rs | 140 ++++- tokio/src/util/rc_cell.rs | 57 ++ tokio/src/util/vec_deque_cell.rs | 53 -- tokio/tests/_require_full.rs | 8 +- tokio/tests/async_send_sync.rs | 197 ++++--- tokio/tests/buffered.rs | 6 +- tokio/tests/fs.rs | 2 +- tokio/tests/fs_copy.rs | 2 +- tokio/tests/fs_dir.rs | 2 +- tokio/tests/fs_file.rs | 4 +- tokio/tests/fs_link.rs | 2 +- tokio/tests/io_buf_writer.rs | 36 +- tokio/tests/io_copy_bidirectional.rs | 38 +- tokio/tests/io_driver.rs | 5 +- tokio/tests/io_driver_drop.rs | 2 +- tokio/tests/io_fill_buf.rs | 2 +- tokio/tests/io_mem_stream.rs | 2 +- tokio/tests/io_panic.rs | 2 +- tokio/tests/io_read.rs | 2 +- tokio/tests/io_split.rs | 2 +- tokio/tests/io_take.rs | 2 +- tokio/tests/join_handle_panic.rs | 2 +- tokio/tests/macros_join.rs | 16 +- tokio/tests/macros_pin.rs | 4 +- tokio/tests/macros_rename_test.rs | 2 +- tokio/tests/macros_select.rs | 76 ++- tokio/tests/macros_test.rs | 18 +- tokio/tests/macros_try_join.rs | 13 +- tokio/tests/net_bind_resource.rs | 2 +- tokio/tests/net_lookup_host.rs | 2 +- .../{named_pipe.rs => net_named_pipe.rs} | 42 +- tokio/tests/net_panic.rs | 188 +++++++ tokio/tests/no_rt.rs | 2 +- tokio/tests/process_raw_handle.rs | 2 +- tokio/tests/process_smoke.rs | 2 +- tokio/tests/rt_basic.rs | 64 ++- tokio/tests/rt_common.rs | 202 +++++-- tokio/tests/rt_handle_block_on.rs | 24 +- tokio/tests/rt_metrics.rs | 108 +++- tokio/tests/rt_panic.rs | 5 +- tokio/tests/rt_threaded.rs | 62 ++- tokio/tests/signal_no_rt.rs | 1 + tokio/tests/support/leaked_buffers.rs | 6 +- tokio/tests/support/panic.rs | 8 +- tokio/tests/sync_barrier.rs | 2 +- tokio/tests/sync_broadcast.rs | 80 ++- tokio/tests/sync_errors.rs | 2 +- tokio/tests/sync_mpsc.rs | 60 +- tokio/tests/sync_mpsc_weak.rs | 513 ++++++++++++++++++ tokio/tests/sync_mutex.rs | 16 +- tokio/tests/sync_mutex_owned.rs | 6 +- tokio/tests/sync_notify.rs | 2 +- tokio/tests/sync_once_cell.rs | 355 ++++++------ tokio/tests/sync_oneshot.rs | 8 +- tokio/tests/sync_panic.rs | 56 +- tokio/tests/sync_rwlock.rs | 18 +- tokio/tests/sync_semaphore.rs | 62 ++- tokio/tests/sync_semaphore_owned.rs | 29 +- tokio/tests/sync_watch.rs | 5 +- tokio/tests/task_abort.rs | 12 +- tokio/tests/task_blocking.rs | 91 +++- tokio/tests/task_builder.rs | 20 +- tokio/tests/task_id.rs | 303 +++++++++++ tokio/tests/task_join_set.rs | 97 ++-- tokio/tests/task_local.rs | 3 +- tokio/tests/task_local_set.rs | 183 ++++++- tokio/tests/task_panic.rs | 123 +++++ tokio/tests/tcp_accept.rs | 2 +- tokio/tests/tcp_connect.rs | 3 +- tokio/tests/tcp_echo.rs | 2 +- tokio/tests/tcp_into_split.rs | 2 +- tokio/tests/tcp_into_std.rs | 2 +- tokio/tests/tcp_peek.rs | 4 +- tokio/tests/tcp_shutdown.rs | 2 +- tokio/tests/tcp_socket.rs | 3 +- tokio/tests/tcp_split.rs | 4 +- tokio/tests/tcp_stream.rs | 51 +- tokio/tests/time_panic.rs | 8 +- tokio/tests/time_pause.rs | 7 +- tokio/tests/time_rt.rs | 3 +- tokio/tests/time_sleep.rs | 20 +- tokio/tests/time_timeout.rs | 1 + tokio/tests/udp.rs | 4 +- tokio/tests/uds_datagram.rs | 10 +- tokio/tests/unwindsafe.rs | 7 +- 366 files changed, 13743 insertions(+), 6252 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/config.yml delete mode 100644 .github/ISSUE_TEMPLATE/question.md create mode 100644 benches/copy.rs create mode 100644 target-specs/i686-unknown-linux-gnu.json create mode 100644 tokio-util/src/io/copy_to_bytes.rs create mode 100644 tokio-util/src/io/inspect.rs create mode 100644 tokio-util/src/io/sink_writer.rs create mode 100644 tokio-util/tests/io_inspect.rs create mode 100644 tokio-util/tests/io_sink_writer.rs create mode 100644 tokio/external-types.toml delete mode 100644 tokio/src/doc/winapi.rs rename tokio/src/io/{driver => }/interest.rs (98%) rename tokio/src/io/{driver => }/ready.rs (99%) delete mode 100644 tokio/src/loom/std/atomic_ptr.rs create mode 100644 tokio/src/loom/std/atomic_u64_as_mutex.rs create mode 100644 tokio/src/loom/std/atomic_u64_native.rs create mode 100644 tokio/src/loom/std/atomic_u64_static_const_new.rs create mode 100644 tokio/src/loom/std/atomic_u64_static_once_cell.rs delete mode 100644 tokio/src/loom/std/atomic_u8.rs create mode 100644 tokio/src/macros/addr_of.rs delete mode 100644 tokio/src/park/either.rs delete mode 100644 tokio/src/park/mod.rs create mode 100644 tokio/src/runtime/config.rs rename tokio/src/{ => runtime}/coop.rs (86%) create mode 100644 tokio/src/runtime/defer.rs delete mode 100644 tokio/src/runtime/enter.rs rename tokio/src/{io/driver => runtime/io}/metrics.rs (100%) rename tokio/src/{io/driver => runtime/io}/mod.rs (62%) rename tokio/src/{io/driver => runtime/io}/platform.rs (100%) rename tokio/src/{io/driver => runtime/io}/registration.rs (85%) rename tokio/src/{io/driver => runtime/io}/scheduled_io.rs (88%) rename tokio/src/{park/thread.rs => runtime/park.rs} (83%) rename tokio/src/{process/unix/driver.rs => runtime/process.rs} (55%) create mode 100644 tokio/src/runtime/runtime.rs rename tokio/src/runtime/{basic_scheduler.rs => scheduler/current_thread.rs} (68%) create mode 100644 tokio/src/runtime/scheduler/mod.rs create mode 100644 tokio/src/runtime/scheduler/multi_thread/handle.rs rename tokio/src/runtime/{thread_pool => scheduler/multi_thread}/idle.rs (100%) create mode 100644 tokio/src/runtime/scheduler/multi_thread/mod.rs rename tokio/src/runtime/{thread_pool => scheduler/multi_thread}/park.rs (86%) rename tokio/src/runtime/{thread_pool => scheduler/multi_thread}/queue.rs (85%) rename tokio/src/runtime/{thread_pool => scheduler/multi_thread}/worker.rs (77%) create mode 100644 tokio/src/runtime/signal/mod.rs delete mode 100644 tokio/src/runtime/spawner.rs create mode 100644 tokio/src/runtime/task/id.rs rename tokio/src/runtime/tests/{loom_basic_scheduler.rs => loom_current_thread_scheduler.rs} (100%) create mode 100644 tokio/src/runtime/tests/loom_yield.rs create mode 100644 tokio/src/runtime/thread_id.rs delete mode 100644 tokio/src/runtime/thread_pool/mod.rs rename tokio/src/{time/driver => runtime/time}/entry.rs (84%) create mode 100644 tokio/src/runtime/time/handle.rs rename tokio/src/{time/driver => runtime/time}/mod.rs (67%) create mode 100644 tokio/src/runtime/time/source.rs rename tokio/src/{time/driver => runtime/time}/tests/mod.rs (54%) rename tokio/src/{time/driver => runtime/time}/wheel/level.rs (98%) rename tokio/src/{time/driver => runtime/time}/wheel/mod.rs (99%) delete mode 100644 tokio/src/signal/unix/driver.rs delete mode 100644 tokio/src/time/driver/handle.rs rename tokio/src/time/{driver => }/sleep.rs (95%) delete mode 100644 tokio/src/time/tests/mod.rs delete mode 100644 tokio/src/time/tests/test_sleep.rs create mode 100644 tokio/src/util/once_cell.rs create mode 100644 tokio/src/util/rc_cell.rs delete mode 100644 tokio/src/util/vec_deque_cell.rs rename tokio/tests/{named_pipe.rs => net_named_pipe.rs} (89%) create mode 100644 tokio/tests/net_panic.rs create mode 100644 tokio/tests/sync_mpsc_weak.rs create mode 100644 tokio/tests/task_id.rs create mode 100644 tokio/tests/task_panic.rs diff --git a/.circleci/config.yml b/.circleci/config.yml index d8d8ca67..6f901a95 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -22,4 +22,4 @@ jobs: workflows: ci: jobs: - - test-arm \ No newline at end of file + - test-arm diff --git a/.cirrus.yml b/.cirrus.yml index 1adc492a..bdc44e0c 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,8 +1,8 @@ freebsd_instance: - image: freebsd-12-3-release-amd64 + image: freebsd-12-4-release-amd64 env: RUST_STABLE: stable - RUST_NIGHTLY: nightly-2022-03-21 + RUST_NIGHTLY: nightly-2022-10-25 RUSTFLAGS: -D warnings # Test FreeBSD in a full VM on cirrus-ci.com. Test the i686 target too, in the @@ -11,6 +11,7 @@ env: # the system's binaries, so the environment shouldn't matter. task: name: FreeBSD 64-bit + auto_cancellation: $CIRRUS_BRANCH != 'master' && $CIRRUS_BRANCH !=~ 'tokio-.*' setup_script: - pkg install -y bash curl - curl https://sh.rustup.rs -sSf --output rustup.sh @@ -25,6 +26,7 @@ task: task: name: FreeBSD docs + auto_cancellation: $CIRRUS_BRANCH != 'master' && $CIRRUS_BRANCH !=~ 'tokio-.*' env: RUSTFLAGS: --cfg docsrs --cfg tokio_unstable RUSTDOCFLAGS: --cfg docsrs --cfg tokio_unstable -Dwarnings @@ -42,6 +44,7 @@ task: task: name: FreeBSD 32-bit + auto_cancellation: $CIRRUS_BRANCH != 'master' && $CIRRUS_BRANCH !=~ 'tokio-.*' setup_script: - pkg install -y bash curl - curl https://sh.rustup.rs -sSf --output rustup.sh diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..2d7079c6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,4 @@ +contact_links: + - name: Question + url: https://github.com/tokio-rs/tokio/discussions + about: Questions about Tokio should be posted as a GitHub discussion. diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md deleted file mode 100644 index 03112f55..00000000 --- a/.github/ISSUE_TEMPLATE/question.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: Question -about: Please use the discussions tab for questions -title: '' -labels: '' -assignees: '' - ---- - -Please post your question as a discussion here: -https://github.com/tokio-rs/tokio/discussions - - -You may also be able to find help here: -https://discord.gg/tokio -https://users.rust-lang.org/ diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 9c9ce69d..cb124aab 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -9,14 +9,22 @@ on: schedule: - cron: '0 2 * * *' # run at 2 AM UTC +permissions: + contents: read + jobs: security-audit: + permissions: + checks: write # for rustsec/audit-check to create check + contents: read # for actions/checkout to fetch code + issues: write # for rustsec/audit-check to create issues runs-on: ubuntu-latest if: "!contains(github.event.head_commit.message, 'ci skip')" steps: - uses: actions/checkout@v3 - name: Audit Check - uses: actions-rs/audit-check@v1 + # https://github.com/rustsec/audit-check/issues/2 + uses: rustsec/audit-check@master with: token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 78bdfbc7..2813ede8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,8 +11,8 @@ env: RUST_BACKTRACE: 1 # Change to specific Rust release to pin rust_stable: stable - rust_nightly: nightly-2022-04-18 - rust_clippy: 1.52.0 + rust_nightly: nightly-2022-11-03 + rust_clippy: 1.65.0 # When updating this, also update: # - README.md # - tokio/README.md @@ -27,6 +27,9 @@ defaults: run: shell: bash +permissions: + contents: read + jobs: # Depends on all action sthat are required for a "successful" CI run. tests-pass: @@ -34,21 +37,27 @@ jobs: runs-on: ubuntu-latest needs: - test - - test-unstable - test-parking_lot + - valgrind + - test-unstable - miri - - cross + - asan + - cross-check + - cross-test + - no-atomic-u64 - features - minrust + - minimal-versions - fmt - clippy - docs - - valgrind - loom-compile - check-readme - test-hyper + - x86_64-fortanix-unknown-sgx - wasm32-unknown-unknown - wasm32-wasi + - check-external-types steps: - run: exit 0 @@ -64,15 +73,14 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install Rust ${{ env.rust_stable }} - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.rust_stable }} - override: true - name: Install Rust run: rustup update stable - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: Install cargo-hack - run: cargo install cargo-hack + uses: taiki-e/install-action@cargo-hack # Run `tokio` with `full` features. This excludes testing utilities which # can alter the runtime behavior of Tokio. @@ -114,11 +122,10 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install Rust ${{ env.rust_stable }} - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.rust_stable }} - override: true - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: Enable parking_lot send_guard feature # Inserts the line "plsend = ["parking_lot/send_guard"]" right after [features] run: sed -i '/\[features\]/a plsend = ["parking_lot/send_guard"]' tokio/Cargo.toml @@ -131,16 +138,13 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install Rust ${{ env.rust_stable }} - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.rust_stable }} - override: true - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: Install Valgrind - run: | - sudo apt-get update -y - sudo apt-get install -y valgrind + uses: taiki-e/install-action@valgrind # Compile tests - name: cargo build test-mem @@ -172,11 +176,10 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install Rust ${{ env.rust_stable }} - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.rust_stable }} - override: true - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 # Run `tokio` with "unstable" cfg flag. - name: test tokio full --cfg unstable run: cargo test --all-features @@ -193,19 +196,18 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install Rust ${{ env.rust_nightly }} - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: - toolchain: nightly-2022-07-10 + toolchain: ${{ env.rust_nightly }} components: miri - override: true - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: miri # Many of tests in tokio/tests and doctests use #[tokio::test] or # #[tokio::main] that calls epoll_create1 that Miri does not support. run: cargo miri test --features full --lib --no-fail-fast working-directory: tokio env: - MIRIFLAGS: -Zmiri-disable-isolation -Zmiri-tag-raw-pointers + MIRIFLAGS: -Zmiri-disable-isolation -Zmiri-strict-provenance -Zmiri-retag-fields PROPTEST_CASES: 10 asan: @@ -217,11 +219,10 @@ jobs: # Required to resolve symbols in sanitizer output run: sudo apt-get install -y llvm - name: Install Rust ${{ env.rust_nightly }} - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.rust_nightly }} - override: true - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: asan run: cargo test --workspace --all-features --target x86_64-unknown-linux-gnu --tests -- --test-threads 1 env: @@ -229,13 +230,12 @@ jobs: # Ignore `trybuild` errors as they are irrelevant and flaky on nightly TRYBUILD: overwrite - cross: - name: cross + cross-check: + name: cross-check runs-on: ubuntu-latest strategy: matrix: target: - - i686-unknown-linux-gnu - powerpc-unknown-linux-gnu - powerpc64-unknown-linux-gnu - mips-unknown-linux-gnu @@ -244,43 +244,98 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install Rust ${{ env.rust_stable }} - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.rust_stable }} target: ${{ matrix.target }} - override: true - - uses: actions-rs/cargo@v1 - with: - use-cross: true - command: check - args: --workspace --all-features --target ${{ matrix.target }} - - uses: actions-rs/cargo@v1 - with: - use-cross: true - command: check - args: --workspace --all-features --target ${{ matrix.target }} + - name: Install cross + uses: taiki-e/install-action@cross + - run: cross check --workspace --all-features --target ${{ matrix.target }} env: RUSTFLAGS: --cfg tokio_unstable -Dwarnings + cross-test: + name: cross-test + runs-on: ubuntu-latest + strategy: + matrix: + include: + - target: i686-unknown-linux-gnu + - target: arm-unknown-linux-gnueabihf + - target: armv7-unknown-linux-gnueabihf + - target: aarch64-unknown-linux-gnu + + # Run a platform without AtomicU64 and no const Mutex::new + - target: arm-unknown-linux-gnueabihf + rustflags: --cfg tokio_no_const_mutex_new + steps: + - uses: actions/checkout@v3 + - name: Install Rust stable + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.rust_stable }} + target: ${{ matrix.target }} + - name: Install cross + uses: taiki-e/install-action@cross + # First run with all features (including parking_lot) + - run: cross test -p tokio --all-features --target ${{ matrix.target }} --tests + env: + RUSTFLAGS: --cfg tokio_unstable -Dwarnings --cfg tokio_no_ipv6 ${{ matrix.rustflags }} + # Now run without parking_lot + - name: Remove `parking_lot` from `full` feature + run: sed -i '0,/parking_lot/{/parking_lot/d;}' tokio/Cargo.toml + # The `tokio_no_parking_lot` cfg is here to ensure the `sed` above does not silently break. + - run: cross test -p tokio --features full,test-util --target ${{ matrix.target }} --tests + env: + RUSTFLAGS: --cfg tokio_unstable -Dwarnings --cfg tokio_no_ipv6 --cfg tokio_no_parking_lot ${{ matrix.rustflags }} + + # See https://github.com/tokio-rs/tokio/issues/5187 + no-atomic-u64: + name: Test i686-unknown-linux-gnu without AtomicU64 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install Rust ${{ env.rust_nightly }} + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.rust_nightly }} + components: rust-src + - name: Install cargo-hack + uses: taiki-e/install-action@cargo-hack + # Install linker and libraries for i686-unknown-linux-gnu + - uses: taiki-e/setup-cross-toolchain-action@v1 + with: + target: i686-unknown-linux-gnu + - run: cargo test -Zbuild-std --target target-specs/i686-unknown-linux-gnu.json -p tokio --all-features + env: + RUSTFLAGS: --cfg tokio_unstable -Dwarnings --cfg tokio_no_atomic_u64 + # https://github.com/tokio-rs/tokio/pull/5356 + # https://github.com/tokio-rs/tokio/issues/5373 + - run: cargo hack build -p tokio --feature-powerset --depth 2 -Z avoid-dev-deps --keep-going + env: + RUSTFLAGS: --cfg tokio_unstable -Dwarnings --cfg tokio_no_atomic_u64 --cfg tokio_no_const_mutex_new + - run: cargo hack build -p tokio --feature-powerset --depth 2 -Z avoid-dev-deps --keep-going + env: + RUSTFLAGS: --cfg tokio_unstable -Dwarnings --cfg tokio_no_atomic_u64 + features: name: features runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install Rust ${{ env.rust_nightly }} - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.rust_nightly }} target: ${{ matrix.target }} - override: true - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: Install cargo-hack - run: cargo install cargo-hack - - name: check --each-feature - run: cargo hack check --all --each-feature -Z avoid-dev-deps + uses: taiki-e/install-action@cargo-hack + - name: check --feature-powerset + run: cargo hack check --all --feature-powerset --depth 2 -Z avoid-dev-deps --keep-going # Try with unstable feature flags - - name: check --each-feature --unstable - run: cargo hack check --all --each-feature -Z avoid-dev-deps + - name: check --feature-powerset --unstable + run: cargo hack check --all --feature-powerset --depth 2 -Z avoid-dev-deps --keep-going env: RUSTFLAGS: --cfg tokio_unstable -Dwarnings @@ -290,13 +345,27 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install Rust ${{ env.rust_min }} - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.rust_min }} - override: true - - uses: Swatinem/rust-cache@v1 - - name: "test --workspace --all-features" + - uses: Swatinem/rust-cache@v2 + # First compile just the main tokio crate with minrust and newest version + # of all dependencies, then pin once_cell and compile the rest of the + # crates with the pinned once_cell version. + # + # This is necessary because tokio-util transitively depends on once_cell, + # which is not compatible with the current minrust after the 1.15.0 + # release. + - name: "check -p tokio --all-features" + run: cargo check -p tokio --all-features + env: + RUSTFLAGS: "" # remove -Dwarnings + - name: "pin once_cell version" + run: cargo update -p once_cell --precise 1.14.0 + - name: "check --workspace --all-features" run: cargo check --workspace --all-features + env: + RUSTFLAGS: "" # remove -Dwarnings minimal-versions: name: minimal-versions @@ -304,13 +373,12 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install Rust ${{ env.rust_nightly }} - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.rust_nightly }} - override: true - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: Install cargo-hack - run: cargo install cargo-hack + uses: taiki-e/install-action@cargo-hack - name: "check --all-features -Z minimal-versions" run: | # Remove dev-dependencies from Cargo.toml to prevent the next `cargo update` @@ -336,12 +404,11 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install Rust ${{ env.rust_stable }} - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.rust_stable }} - override: true components: rustfmt - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 # Check fmt - name: "rustfmt --check" # Workaround for rust-lang/cargo#7732 @@ -357,12 +424,11 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install Rust ${{ env.rust_clippy }} - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.rust_clippy }} - override: true components: clippy - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 # Run clippy - name: "clippy --all" run: cargo clippy --all --tests --all-features @@ -373,11 +439,10 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install Rust ${{ env.rust_nightly }} - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.rust_nightly }} - override: true - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: "doc --lib --all-features" run: cargo doc --lib --no-deps --all-features --document-private-items env: @@ -390,11 +455,10 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install Rust ${{ env.rust_stable }} - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.rust_stable }} - override: true - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: build --cfg loom run: cargo test --no-run --lib --features full working-directory: tokio @@ -425,11 +489,10 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install Rust ${{ env.rust_stable }} - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.rust_stable }} - override: true - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: Test hyper run: | set -x @@ -447,17 +510,32 @@ jobs: git diff cargo test --features full + x86_64-fortanix-unknown-sgx: + name: build tokio for x86_64-fortanix-unknown-sgx + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install Rust ${{ env.rust_nightly }} + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.rust_nightly }} + target: x86_64-fortanix-unknown-sgx + - uses: Swatinem/rust-cache@v2 + # NOTE: Currently the only test we can run is to build tokio with rt and sync features. + - name: build tokio + run: cargo build --target x86_64-fortanix-unknown-sgx --features rt,sync + working-directory: tokio + wasm32-unknown-unknown: name: test tokio for wasm32-unknown-unknown runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install Rust ${{ env.rust_stable }} - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.rust_stable }} - override: true - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: Install wasm-pack run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - name: test tokio @@ -470,30 +548,67 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install Rust ${{ env.rust_stable }} - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.rust_stable }} - override: true - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 # Install dependencies - name: Install cargo-hack - run: cargo install cargo-hack + uses: taiki-e/install-action@cargo-hack - name: Install wasm32-wasi target run: rustup target add wasm32-wasi - name: Install wasmtime - run: cargo install wasmtime-cli + uses: taiki-e/install-action@wasmtime - name: Install cargo-wasi run: cargo install cargo-wasi - # TODO: Expand this when full WASI support lands. - # Currently, this is a bare bones regression test - # for features that work today with wasi. + - name: WASI test tokio full + run: cargo test -p tokio --target wasm32-wasi --features full + env: + CARGO_TARGET_WASM32_WASI_RUNNER: "wasmtime run --" + RUSTFLAGS: --cfg tokio_unstable -Dwarnings + + - name: WASI test tokio-util full + run: cargo test -p tokio-util --target wasm32-wasi --features full + env: + CARGO_TARGET_WASM32_WASI_RUNNER: "wasmtime run --" + RUSTFLAGS: --cfg tokio_unstable -Dwarnings + + - name: WASI test tokio-stream + run: cargo test -p tokio-stream --target wasm32-wasi --features time,net,io-util,sync + env: + CARGO_TARGET_WASM32_WASI_RUNNER: "wasmtime run --" + RUSTFLAGS: --cfg tokio_unstable -Dwarnings - name: test tests-integration --features wasi-rt # TODO: this should become: `cargo hack wasi test --each-feature` run: cargo wasi test --test rt_yield --features wasi-rt working-directory: tests-integration + + check-external-types: + name: check-external-types + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: + - windows-latest + - ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install Rust nightly-2022-11-16 + uses: dtolnay/rust-toolchain@master + with: + # `check-external-types` requires a specific Rust nightly version. See + # the README for details: https://github.com/awslabs/cargo-check-external-types + toolchain: nightly-2022-11-16 + - uses: Swatinem/rust-cache@v2 + - name: check-external-types + run: | + set -x + cargo install cargo-check-external-types --locked --version 0.1.6 + cargo check-external-types --all-features --config external-types.toml + working-directory: tokio diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 6d5dd6fb..28824cff 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -4,9 +4,16 @@ on: # See .github/labeler.yml file +permissions: + contents: read + jobs: triage: + permissions: + contents: read # for actions/labeler to determine modified files + pull-requests: write # for actions/labeler to add labels to PRs runs-on: ubuntu-latest + if: github.repository_owner == 'tokio-rs' steps: - uses: actions/labeler@v3 with: diff --git a/.github/workflows/loom.yml b/.github/workflows/loom.yml index 760b6347..0c18e0c3 100644 --- a/.github/workflows/loom.yml +++ b/.github/workflows/loom.yml @@ -13,11 +13,14 @@ env: # Change to specific Rust release to pin rust_stable: stable +permissions: + contents: read + jobs: loom: name: loom # base_ref is null when it's not a pull request - if: contains(github.event.pull_request.labels.*.name, 'R-loom') || (github.base_ref == null) + if: github.repository_owner == 'tokio-rs' && (contains(github.event.pull_request.labels.*.name, 'R-loom') || (github.base_ref == null)) runs-on: ubuntu-latest strategy: matrix: @@ -31,15 +34,15 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install Rust ${{ env.rust_stable }} - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.rust_stable }} - override: true - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: loom ${{ matrix.scope }} run: cargo test --lib --release --features full -- --nocapture $SCOPE working-directory: tokio env: RUSTFLAGS: --cfg loom --cfg tokio_unstable -Dwarnings LOOM_MAX_PREEMPTIONS: 2 + LOOM_MAX_BRANCHES: 10000 SCOPE: ${{ matrix.scope }} diff --git a/.github/workflows/pr-audit.yml b/.github/workflows/pr-audit.yml index 8081a91b..d6f79829 100644 --- a/.github/workflows/pr-audit.yml +++ b/.github/workflows/pr-audit.yml @@ -8,6 +8,9 @@ on: paths: - '**/Cargo.toml' +permissions: + contents: read + jobs: security-audit: runs-on: ubuntu-latest @@ -16,17 +19,10 @@ jobs: - uses: actions/checkout@v3 - name: Install cargo-audit - uses: actions-rs/cargo@v1 - with: - command: install - args: cargo-audit + run: cargo install cargo-audit - name: Generate lockfile - uses: actions-rs/cargo@v1 - with: - command: generate-lockfile + run: cargo generate-lockfile - name: Audit dependencies - uses: actions-rs/cargo@v1 - with: - command: audit + run: cargo audit diff --git a/.github/workflows/stress-test.yml b/.github/workflows/stress-test.yml index bcbede18..f33cc181 100644 --- a/.github/workflows/stress-test.yml +++ b/.github/workflows/stress-test.yml @@ -11,8 +11,11 @@ env: # Change to specific Rust release to pin rust_stable: stable +permissions: + contents: read + jobs: - stess-test: + stress-test: name: Stress Test runs-on: ubuntu-latest strategy: @@ -22,15 +25,12 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install Rust ${{ env.rust_stable }} - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.rust_stable }} - override: true - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: Install Valgrind - run: | - sudo apt-get update -y - sudo apt-get install -y valgrind + uses: taiki-e/install-action@valgrind # Compiles each of the stress test examples. - name: Compile stress test examples @@ -38,4 +38,4 @@ jobs: # Runs each of the examples using Valgrind. Detects leaks and displays them. - name: Run valgrind - run: valgrind --leak-check=full --show-leak-kinds=all ./target/release/examples/${{ matrix.stress-test }} + run: valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./target/release/examples/${{ matrix.stress-test }} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f7e75857..a3c1c910 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -146,7 +146,7 @@ When updating this, also update: --> ``` -cargo +1.49.0 clippy --all-features +cargo +1.49.0 clippy --all --tests --all-features ``` When building documentation normally, the markers that list the features @@ -154,7 +154,7 @@ required for various parts of Tokio are missing. To build the documentation correctly, use this command: ``` -RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features +RUSTDOCFLAGS="--cfg docsrs" RUSTFLAGS="--cfg docsrs" cargo +nightly doc --all-features ``` To build documentation including Tokio's unstable features, it is necessary to @@ -162,15 +162,9 @@ pass `--cfg tokio_unstable` to both RustDoc *and* rustc. To build the documentation for unstable features, use this command: ``` -RUSTDOCFLAGS="--cfg docsrs --cfg tokio_unstable" RUSTFLAGS="--cfg tokio_unstable" cargo +nightly doc --all-features +RUSTDOCFLAGS="--cfg docsrs --cfg tokio_unstable" RUSTFLAGS="--cfg docsrs --cfg tokio_unstable" cargo +nightly doc --all-features ``` -There is currently a [bug in cargo] that means documentation cannot be built -from the root of the workspace. If you `cd` into the `tokio` subdirectory the -command shown above will work. - -[bug in cargo]: https://github.com/rust-lang/cargo/issues/9274 - The `cargo fmt` command does not work on the Tokio codebase. You can use the command below instead: @@ -562,7 +556,7 @@ Tokio ≥1.0.0 comes with LTS guarantees: The goal of these guarantees is to provide stability to the ecosystem. -## Mininum Supported Rust Version (MSRV) +## Minimum Supported Rust Version (MSRV) * All Tokio ≥1.0.0 releases will support at least a 6-month old Rust compiler release. diff --git a/Cargo.toml b/Cargo.toml index 4560bbbe..bc01f186 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,6 @@ members = [ "tokio-test", "tokio-stream", "tokio-util", - "ylong_runtime", # Internal "benches", diff --git a/Cross.toml b/Cross.toml index 050f2bdb..0720116e 100644 --- a/Cross.toml +++ b/Cross.toml @@ -1,4 +1,5 @@ [build.env] passthrough = [ "RUSTFLAGS", + "RUST_BACKTRACE", ] diff --git a/LICENSE b/LICENSE index 8af5baf0..8bdf6bd6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2022 Tokio Contributors +Copyright (c) 2023 Tokio Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/README.OpenSource b/README.OpenSource index 8c934a3f..3f93f3a4 100644 --- a/README.OpenSource +++ b/README.OpenSource @@ -3,7 +3,7 @@ "Name": "tokio", "License": "MIT", "License File": "LICENSE", - "Version Number": "1.20.1", + "Version Number": "1.25.0", "Owner": "xuelei3@huawei.com", "Upstream URL": "https://github.com/tokio-rs/tokio", "Description": "An event-driven, non-blocking I/O platform for writing asynchronous I/O backed applications." diff --git a/README.md b/README.md index 6b16d64b..462e6e8b 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ Make sure you activated the full features of the tokio crate on Cargo.toml: ```toml [dependencies] -tokio = { version = "1.20.1", features = ["full"] } +tokio = { version = "1.25.0", features = ["full"] } ``` Then, on your main.rs: @@ -161,6 +161,16 @@ several other libraries, including: [`mio`]: https://github.com/tokio-rs/mio [`bytes`]: https://github.com/tokio-rs/bytes +## Changelog + +The Tokio repository contains multiple crates. Each crate has its own changelog. + + * `tokio` - [view changelog](https://github.com/tokio-rs/tokio/blob/master/tokio/CHANGELOG.md) + * `tokio-util` - [view changelog](https://github.com/tokio-rs/tokio/blob/master/tokio-util/CHANGELOG.md) + * `tokio-stream` - [view changelog](https://github.com/tokio-rs/tokio/blob/master/tokio-stream/CHANGELOG.md) + * `tokio-macros` - [view changelog](https://github.com/tokio-rs/tokio/blob/master/tokio-macros/CHANGELOG.md) + * `tokio-test` - [view changelog](https://github.com/tokio-rs/tokio/blob/master/tokio-test/CHANGELOG.md) + ## Supported Rust Versions tests/fail/macros_core_no_default.rs:3:1 + --> $DIR/macros_core_no_default.rs:3:1 | 3 | #[tokio::main] | ^^^^^^^^^^^^^^ diff --git a/tests-build/tests/fail/macros_dead_code.stderr b/tests-build/tests/fail/macros_dead_code.stderr index 816c294b..a46538a8 100644 --- a/tests-build/tests/fail/macros_dead_code.stderr +++ b/tests-build/tests/fail/macros_dead_code.stderr @@ -1,4 +1,4 @@ -error: function is never used: `f` +error: function `f` is never used --> $DIR/macros_dead_code.rs:6:10 | 6 | async fn f() {} diff --git a/tests-integration/Cargo.toml b/tests-integration/Cargo.toml index d2dd5c9c..5daeed08 100644 --- a/tests-integration/Cargo.toml +++ b/tests-integration/Cargo.toml @@ -7,7 +7,6 @@ publish = false [[bin]] name = "test-cat" -required-features = ["rt-process-io-util"] [[bin]] name = "test-mem" @@ -31,7 +30,6 @@ name = "rt_yield" required-features = ["rt", "macros", "sync"] [features] -rt-process-io-util = ["tokio/rt", "tokio/macros", "tokio/process", "tokio/io-util", "tokio/io-std"] # For mem check rt-net = ["tokio/rt", "tokio/rt-multi-thread", "tokio/net"] # For test-process-signal @@ -60,3 +58,4 @@ tokio = { path = "../tokio" } tokio-test = { path = "../tokio-test", optional = true } doc-comment = "0.3.1" futures = { version = "0.3.0", features = ["async-await"] } +bytes = "1.0.0" diff --git a/tests-integration/src/bin/test-cat.rs b/tests-integration/src/bin/test-cat.rs index 1e40c9d9..3b30bf18 100644 --- a/tests-integration/src/bin/test-cat.rs +++ b/tests-integration/src/bin/test-cat.rs @@ -1,14 +1,20 @@ //! A cat-like utility that can be used as a subprocess to test I/O //! stream communication. -use tokio::io::AsyncWriteExt; +use std::io; +use std::io::Write; -#[tokio::main(flavor = "current_thread")] -async fn main() { - let mut stdin = tokio::io::stdin(); - let mut stdout = tokio::io::stdout(); - - tokio::io::copy(&mut stdin, &mut stdout).await.unwrap(); - - stdout.flush().await.unwrap(); +fn main() { + let stdin = io::stdin(); + let mut stdout = io::stdout(); + let mut line = String::new(); + loop { + line.clear(); + stdin.read_line(&mut line).unwrap(); + if line.is_empty() { + break; + } + stdout.write_all(line.as_bytes()).unwrap(); + } + stdout.flush().unwrap(); } diff --git a/tests-integration/tests/macros_main.rs b/tests-integration/tests/macros_main.rs index 31442805..e34387e5 100644 --- a/tests-integration/tests/macros_main.rs +++ b/tests-integration/tests/macros_main.rs @@ -1,4 +1,8 @@ -#![cfg(all(feature = "macros", feature = "rt-multi-thread"))] +#![cfg(all( + feature = "macros", + feature = "rt-multi-thread", + not(target_os = "wasi") +))] #[tokio::main] async fn basic_main() -> usize { diff --git a/tests-integration/tests/macros_select.rs b/tests-integration/tests/macros_select.rs index 4c4fef7c..a1a242c0 100644 --- a/tests-integration/tests/macros_select.rs +++ b/tests-integration/tests/macros_select.rs @@ -4,6 +4,7 @@ use futures::channel::oneshot; use futures::executor::block_on; use std::thread; +#[cfg_attr(target_os = "wasi", ignore = "WASI: std::thread::spawn not supported")] #[test] fn join_with_select() { block_on(async { diff --git a/tests-integration/tests/process_stdio.rs b/tests-integration/tests/process_stdio.rs index 94861635..3ccb6900 100644 --- a/tests-integration/tests/process_stdio.rs +++ b/tests-integration/tests/process_stdio.rs @@ -1,5 +1,5 @@ #![warn(rust_2018_idioms)] -#![cfg(feature = "full")] +#![cfg(all(feature = "full", not(target_os = "wasi")))] use tokio::io::{AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader}; use tokio::join; @@ -8,22 +8,12 @@ use tokio_test::assert_ok; use futures::future::{self, FutureExt}; use std::convert::TryInto; +use std::env; use std::io; use std::process::{ExitStatus, Stdio}; -// so, we need to change this back as a test, but for now this doesn't work because of: -// https://github.com/rust-lang/rust/pull/95469 -// -// undo when this is closed: https://github.com/tokio-rs/tokio/issues/4802 - -// fn cat() -> Command { -// let mut cmd = Command::new(std::env!("CARGO_BIN_EXE_test-cat")); -// cmd.stdin(Stdio::piped()).stdout(Stdio::piped()); -// cmd -// } - fn cat() -> Command { - let mut cmd = Command::new("cat"); + let mut cmd = Command::new(env!("CARGO_BIN_EXE_test-cat")); cmd.stdin(Stdio::piped()).stdout(Stdio::piped()); cmd } @@ -200,3 +190,54 @@ async fn pipe_from_one_command_to_another() { assert!(second_status.expect("second status").success()); assert!(third_status.expect("third status").success()); } + +#[tokio::test] +async fn vectored_writes() { + use bytes::{Buf, Bytes}; + use std::{io::IoSlice, pin::Pin}; + use tokio::io::AsyncWrite; + + let mut cat = cat().spawn().unwrap(); + let mut stdin = cat.stdin.take().unwrap(); + let are_writes_vectored = stdin.is_write_vectored(); + let mut stdout = cat.stdout.take().unwrap(); + + let write = async { + let mut input = Bytes::from_static(b"hello\n").chain(Bytes::from_static(b"world!\n")); + let mut writes_completed = 0; + + futures::future::poll_fn(|cx| loop { + let mut slices = [IoSlice::new(&[]); 2]; + let vectored = input.chunks_vectored(&mut slices); + if vectored == 0 { + return std::task::Poll::Ready(std::io::Result::Ok(())); + } + let n = futures::ready!(Pin::new(&mut stdin).poll_write_vectored(cx, &slices))?; + writes_completed += 1; + input.advance(n); + }) + .await?; + + drop(stdin); + + std::io::Result::Ok(writes_completed) + }; + + let read = async { + let mut buffer = Vec::with_capacity(6 + 7); + stdout.read_to_end(&mut buffer).await?; + std::io::Result::Ok(buffer) + }; + + let (write, read, status) = future::join3(write, read, cat.wait()).await; + + assert!(status.unwrap().success()); + + let writes_completed = write.unwrap(); + // on unix our small payload should always fit in whatever default sized pipe with a single + // syscall. if multiple are used, then the forwarding does not work, or we are on a platform + // for which the `std` does not support vectored writes. + assert_eq!(writes_completed == 1, are_writes_vectored); + + assert_eq!(&read.unwrap(), b"hello\nworld!\n"); +} diff --git a/tokio-macros/CHANGELOG.md b/tokio-macros/CHANGELOG.md index 2189faa9..93d52e73 100644 --- a/tokio-macros/CHANGELOG.md +++ b/tokio-macros/CHANGELOG.md @@ -1,3 +1,21 @@ +# 1.8.2 (November 30th, 2022) + +- fix a regression introduced in 1.8.1 ([#5244]) + +[#5244]: https://github.com/tokio-rs/tokio/pull/5244 + +# 1.8.1 (November 29th, 2022) + +(yanked) + +- macros: Pin Futures in `#[tokio::test]` to stack ([#5205]) +- macros: Reduce usage of last statement spans in proc-macros ([#5092]) +- macros: Improve the documentation for `#[tokio::test]` ([#4761]) + +[#5205]: https://github.com/tokio-rs/tokio/pull/5205 +[#5092]: https://github.com/tokio-rs/tokio/pull/5092 +[#4761]: https://github.com/tokio-rs/tokio/pull/4761 + # 1.8.0 (June 4th, 2022) - macros: always emit return statement ([#4636]) diff --git a/tokio-macros/Cargo.toml b/tokio-macros/Cargo.toml index 2b704a58..ea536a8d 100644 --- a/tokio-macros/Cargo.toml +++ b/tokio-macros/Cargo.toml @@ -3,8 +3,8 @@ name = "tokio-macros" # When releasing to crates.io: # - Remove path dependencies # - Update CHANGELOG.md. -# - Create "tokio-macros-1.0.x" git tag. -version = "1.8.0" +# - Create "tokio-macros-1.x.y" git tag. +version = "1.8.2" edition = "2018" rust-version = "1.49" authors = ["Tokio Contributors "] diff --git a/tokio-macros/LICENSE b/tokio-macros/LICENSE index a3753c03..12d1037f 100644 --- a/tokio-macros/LICENSE +++ b/tokio-macros/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2022 Tokio Contributors +Copyright (c) 2023 Tokio Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index 68eb8291..6460e70a 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -383,17 +383,50 @@ fn parse_knobs(mut input: syn::ItemFn, is_test: bool, config: FinalConfig) -> To let body = &input.block; let brace_token = input.block.brace_token; - input.block = syn::parse2(quote_spanned! {last_stmt_end_span=> + let body_ident = quote! { body }; + let block_expr = quote_spanned! {last_stmt_end_span=> + #[allow(clippy::expect_used, clippy::diverging_sub_expression)] { + return #rt + .enable_all() + .build() + .expect("Failed building the Runtime") + .block_on(#body_ident); + } + }; + + // For test functions pin the body to the stack and use `Pin<&mut dyn + // Future>` to reduce the amount of `Runtime::block_on` (and related + // functions) copies we generate during compilation due to the generic + // parameter `F` (the future to block on). This could have an impact on + // performance, but because it's only for testing it's unlikely to be very + // large. + // + // We don't do this for the main function as it should only be used once so + // there will be no benefit. + let body = if is_test { + let output_type = match &input.sig.output { + // For functions with no return value syn doesn't print anything, + // but that doesn't work as `Output` for our boxed `Future`, so + // default to `()` (the same type as the function output). + syn::ReturnType::Default => quote! { () }, + syn::ReturnType::Type(_, ret_type) => quote! { #ret_type }, + }; + quote! { let body = async #body; - #[allow(clippy::expect_used, clippy::diverging_sub_expression)] - { - return #rt - .enable_all() - .build() - .expect("Failed building the Runtime") - .block_on(body); - } + #crate_ident::pin!(body); + let body: ::std::pin::Pin<&mut dyn ::std::future::Future> = body; + } + } else { + quote! { + let body = async #body; + } + }; + + input.block = syn::parse2(quote! { + { + #body + #block_expr } }) .expect("Parsing failure"); @@ -447,7 +480,7 @@ pub(crate) fn test(args: TokenStream, item: TokenStream, rt_multi_thread: bool) }; let config = if let Some(attr) = input.attrs.iter().find(|attr| attr.path.is_ident("test")) { let msg = "second test attribute is supplied"; - Err(syn::Error::new_spanned(&attr, msg)) + Err(syn::Error::new_spanned(attr, msg)) } else { AttributeArgs::parse_terminated .parse(args) diff --git a/tokio-macros/src/select.rs b/tokio-macros/src/select.rs index 23e280a1..8c5ae306 100644 --- a/tokio-macros/src/select.rs +++ b/tokio-macros/src/select.rs @@ -100,10 +100,10 @@ fn clean_pattern(pat: &mut syn::Pat) { } syn::Pat::Reference(reference) => { reference.mutability = None; - clean_pattern(&mut *reference.pat); + clean_pattern(&mut reference.pat); } syn::Pat::Type(type_pat) => { - clean_pattern(&mut *type_pat.pat); + clean_pattern(&mut type_pat.pat); } _ => {} } diff --git a/tokio-stream/CHANGELOG.md b/tokio-stream/CHANGELOG.md index ce6d340a..05c2b188 100644 --- a/tokio-stream/CHANGELOG.md +++ b/tokio-stream/CHANGELOG.md @@ -1,3 +1,17 @@ +# 0.1.11 (October 11, 2022) + +- time: allow `StreamExt::chunks_timeout` outside of a runtime ([#5036]) + +[#5036]: https://github.com/tokio-rs/tokio/pull/5036 + +# 0.1.10 (Sept 18, 2022) + +- time: add `StreamExt::chunks_timeout` ([#4695]) +- stream: add track_caller to public APIs ([#4786]) + +[#4695]: https://github.com/tokio-rs/tokio/pull/4695 +[#4786]: https://github.com/tokio-rs/tokio/pull/4786 + # 0.1.9 (June 4, 2022) - deps: upgrade `tokio-util` dependency to `0.7.x` ([#3762]) diff --git a/tokio-stream/Cargo.toml b/tokio-stream/Cargo.toml index a84c924b..6dfa9784 100644 --- a/tokio-stream/Cargo.toml +++ b/tokio-stream/Cargo.toml @@ -4,7 +4,7 @@ name = "tokio-stream" # - Remove path dependencies # - Update CHANGELOG.md. # - Create "tokio-stream-0.1.x" git tag. -version = "0.1.9" +version = "0.1.11" edition = "2018" rust-version = "1.49" authors = ["Tokio Contributors "] @@ -38,6 +38,7 @@ parking_lot = "0.12.0" tokio-test = { path = "../tokio-test" } futures = { version = "0.3", default-features = false } +[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] proptest = "1" [package.metadata.docs.rs] diff --git a/tokio-stream/LICENSE b/tokio-stream/LICENSE index 8af5baf0..8bdf6bd6 100644 --- a/tokio-stream/LICENSE +++ b/tokio-stream/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2022 Tokio Contributors +Copyright (c) 2023 Tokio Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/tokio-stream/src/stream_ext.rs b/tokio-stream/src/stream_ext.rs index 6cea7b55..52d32024 100644 --- a/tokio-stream/src/stream_ext.rs +++ b/tokio-stream/src/stream_ext.rs @@ -982,6 +982,8 @@ pub trait StreamExt: Stream { /// Slows down a stream by enforcing a delay between items. /// + /// The underlying timer behind this utility has a granularity of one millisecond. + /// /// # Example /// /// Create a throttled stream. diff --git a/tokio-stream/src/stream_ext/chunks_timeout.rs b/tokio-stream/src/stream_ext/chunks_timeout.rs index 10710131..48acd932 100644 --- a/tokio-stream/src/stream_ext/chunks_timeout.rs +++ b/tokio-stream/src/stream_ext/chunks_timeout.rs @@ -1,6 +1,6 @@ use crate::stream_ext::Fuse; use crate::Stream; -use tokio::time::{sleep, Instant, Sleep}; +use tokio::time::{sleep, Sleep}; use core::future::Future; use core::pin::Pin; @@ -16,7 +16,7 @@ pin_project! { #[pin] stream: Fuse, #[pin] - deadline: Sleep, + deadline: Option, duration: Duration, items: Vec, cap: usize, // https://github.com/rust-lang/futures-rs/issues/1475 @@ -27,7 +27,7 @@ impl ChunksTimeout { pub(super) fn new(stream: S, max_size: usize, duration: Duration) -> Self { ChunksTimeout { stream: Fuse::new(stream), - deadline: sleep(duration), + deadline: None, duration, items: Vec::with_capacity(max_size), cap: max_size, @@ -45,7 +45,7 @@ impl Stream for ChunksTimeout { Poll::Pending => break, Poll::Ready(Some(item)) => { if me.items.is_empty() { - me.deadline.as_mut().reset(Instant::now() + *me.duration); + me.deadline.set(Some(sleep(*me.duration))); me.items.reserve_exact(*me.cap); } me.items.push(item); @@ -67,7 +67,9 @@ impl Stream for ChunksTimeout { } if !me.items.is_empty() { - ready!(me.deadline.poll(cx)); + if let Some(deadline) = me.deadline.as_pin_mut() { + ready!(deadline.poll(cx)); + } return Poll::Ready(Some(std::mem::take(me.items))); } diff --git a/tokio-stream/src/stream_ext/collect.rs b/tokio-stream/src/stream_ext/collect.rs index 4b157a9a..8548b745 100644 --- a/tokio-stream/src/stream_ext/collect.rs +++ b/tokio-stream/src/stream_ext/collect.rs @@ -195,11 +195,7 @@ where } else { let res = mem::replace(collection, Ok(U::initialize(sealed::Internal, 0, Some(0)))); - if let Err(err) = res { - Err(err) - } else { - unreachable!(); - } + Err(res.map(drop).unwrap_err()) } } } diff --git a/tokio-stream/src/stream_ext/then.rs b/tokio-stream/src/stream_ext/then.rs index 7f6b5a23..cc7caa72 100644 --- a/tokio-stream/src/stream_ext/then.rs +++ b/tokio-stream/src/stream_ext/then.rs @@ -72,7 +72,7 @@ where } fn size_hint(&self) -> (usize, Option) { - let future_len = if self.future.is_some() { 1 } else { 0 }; + let future_len = usize::from(self.future.is_some()); let (lower, upper) = self.stream.size_hint(); let lower = lower.saturating_add(future_len); diff --git a/tokio-stream/src/stream_ext/throttle.rs b/tokio-stream/src/stream_ext/throttle.rs index f36c66a5..50001392 100644 --- a/tokio-stream/src/stream_ext/throttle.rs +++ b/tokio-stream/src/stream_ext/throttle.rs @@ -4,7 +4,6 @@ use crate::Stream; use tokio::time::{Duration, Instant, Sleep}; use std::future::Future; -use std::marker::Unpin; use std::pin::Pin; use std::task::{self, Poll}; @@ -41,8 +40,7 @@ pin_project! { } } -// XXX: are these safe if `T: !Unpin`? -impl Throttle { +impl Throttle { /// Acquires a reference to the underlying stream that this combinator is /// pulling from. pub fn get_ref(&self) -> &T { diff --git a/tokio-stream/src/stream_ext/timeout.rs b/tokio-stream/src/stream_ext/timeout.rs index 98d7cd5c..a440d203 100644 --- a/tokio-stream/src/stream_ext/timeout.rs +++ b/tokio-stream/src/stream_ext/timeout.rs @@ -24,7 +24,7 @@ pin_project! { } /// Error returned by `Timeout`. -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq)] pub struct Elapsed(()); impl Timeout { diff --git a/tokio-stream/src/wrappers/broadcast.rs b/tokio-stream/src/wrappers/broadcast.rs index 10184bf9..71106646 100644 --- a/tokio-stream/src/wrappers/broadcast.rs +++ b/tokio-stream/src/wrappers/broadcast.rs @@ -18,7 +18,7 @@ pub struct BroadcastStream { } /// An error returned from the inner stream of a [`BroadcastStream`]. -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone)] pub enum BroadcastStreamRecvError { /// The receiver lagged too far behind. Attempting to receive again will /// return the oldest message still retained by the channel. diff --git a/tokio-stream/tests/stream_panic.rs b/tokio-stream/tests/stream_panic.rs index c0a3a45a..22c1c208 100644 --- a/tokio-stream/tests/stream_panic.rs +++ b/tokio-stream/tests/stream_panic.rs @@ -1,5 +1,5 @@ #![warn(rust_2018_idioms)] -#![cfg(feature = "time")] +#![cfg(all(feature = "time", not(target_os = "wasi")))] // Wasi does not support panic recovery use parking_lot::{const_mutex, Mutex}; use std::error::Error; diff --git a/tokio-stream/tests/stream_stream_map.rs b/tokio-stream/tests/stream_stream_map.rs index 53f3d86c..ffc489b3 100644 --- a/tokio-stream/tests/stream_stream_map.rs +++ b/tokio-stream/tests/stream_stream_map.rs @@ -325,6 +325,7 @@ fn one_ready_many_none() { } } +#[cfg(not(target_os = "wasi"))] proptest::proptest! { #[test] fn fuzz_pending_complete_mix(kinds: Vec) { diff --git a/tokio-test/Cargo.toml b/tokio-test/Cargo.toml index e889dcec..30cacead 100644 --- a/tokio-test/Cargo.toml +++ b/tokio-test/Cargo.toml @@ -19,7 +19,7 @@ categories = ["asynchronous", "testing"] [dependencies] tokio = { version = "1.2.0", path = "../tokio", features = ["rt", "sync", "time", "test-util"] } tokio-stream = { version = "0.1.1", path = "../tokio-stream" } -async-stream = "0.3" +async-stream = "0.3.3" bytes = "1.0.0" futures-core = "0.3.0" diff --git a/tokio-test/LICENSE b/tokio-test/LICENSE index 8af5baf0..8bdf6bd6 100644 --- a/tokio-test/LICENSE +++ b/tokio-test/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2022 Tokio Contributors +Copyright (c) 2023 Tokio Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/tokio-test/src/macros.rs b/tokio-test/src/macros.rs index 7ca73451..4c029c9e 100644 --- a/tokio-test/src/macros.rs +++ b/tokio-test/src/macros.rs @@ -260,7 +260,7 @@ macro_rules! assert_err { }}; } -/// Asserts that an exact duration has elapsed since since the start instant ±1ms. +/// Asserts that an exact duration has elapsed since the start instant ±1ms. /// /// ```rust /// use tokio::time::{self, Instant}; diff --git a/tokio-test/src/task.rs b/tokio-test/src/task.rs index f84b4f4c..c1cfca16 100644 --- a/tokio-test/src/task.rs +++ b/tokio-test/src/task.rs @@ -1,4 +1,29 @@ -//! Futures task based helpers +//! Futures task based helpers to easily test futures and manually written futures. +//! +//! The [`Spawn`] type is used as a mock task harness that allows you to poll futures +//! without needing to setup pinning or context. Any future can be polled but if the +//! future requires the tokio async context you will need to ensure that you poll the +//! [`Spawn`] within a tokio context, this means that as long as you are inside the +//! runtime it will work and you can poll it via [`Spawn`]. +//! +//! [`Spawn`] also supports [`Stream`] to call `poll_next` without pinning +//! or context. +//! +//! In addition to circumventing the need for pinning and context, [`Spawn`] also tracks +//! the amount of times the future/task was woken. This can be useful to track if some +//! leaf future notified the root task correctly. +//! +//! # Example +//! +//! ``` +//! use tokio_test::task; +//! +//! let fut = async {}; +//! +//! let mut task = task::spawn(fut); +//! +//! assert!(task.poll().is_ready(), "Task was not ready!"); +//! ``` #![allow(clippy::mutex_atomic)] @@ -11,7 +36,11 @@ use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; use tokio_stream::Stream; -/// TODO: dox +/// Spawn a future into a [`Spawn`] which wraps the future in a mocked executor. +/// +/// This can be used to spawn a [`Future`] or a [`Stream`]. +/// +/// For more information, check the module docs. pub fn spawn(task: T) -> Spawn { Spawn { task: MockTask::new(), @@ -19,16 +48,14 @@ pub fn spawn(task: T) -> Spawn { } } -/// Future spawned on a mock task +/// Future spawned on a mock task that can be used to poll the future or stream +/// without needing pinning or context types. #[derive(Debug)] pub struct Spawn { task: MockTask, future: Pin>, } -/// Mock task -/// -/// A mock task is able to intercept and track wake notifications. #[derive(Debug, Clone)] struct MockTask { waker: Arc, @@ -91,7 +118,8 @@ impl ops::DerefMut for Spawn { } impl Spawn { - /// Polls a future + /// If `T` is a [`Future`] then poll it. This will handle pinning and the context + /// type for the future. pub fn poll(&mut self) -> Poll { let fut = self.future.as_mut(); self.task.enter(|cx| fut.poll(cx)) @@ -99,7 +127,8 @@ impl Spawn { } impl Spawn { - /// Polls a stream + /// If `T` is a [`Stream`] then poll_next it. This will handle pinning and the context + /// type for the stream. pub fn poll_next(&mut self) -> Poll> { let stream = self.future.as_mut(); self.task.enter(|cx| stream.poll_next(cx)) diff --git a/tokio-util/CHANGELOG.md b/tokio-util/CHANGELOG.md index ffa80e4b..ca378b1e 100644 --- a/tokio-util/CHANGELOG.md +++ b/tokio-util/CHANGELOG.md @@ -1,3 +1,25 @@ +# 0.7.4 (September 8, 2022) + +### Added + +- io: add `SyncIoBridge::shutdown()` ([#4938]) +- task: improve `LocalPoolHandle` ([#4680]) + +### Fixed + +- util: add `track_caller` to public APIs ([#4785]) + +### Unstable + +- task: fix compilation errors in `JoinMap` with Tokio v1.21.0 ([#4755]) +- task: remove the unstable, deprecated `JoinMap::join_one` ([#4920]) + +[#4680]: https://github.com/tokio-rs/tokio/pull/4680 +[#4755]: https://github.com/tokio-rs/tokio/pull/4755 +[#4785]: https://github.com/tokio-rs/tokio/pull/4785 +[#4920]: https://github.com/tokio-rs/tokio/pull/4920 +[#4938]: https://github.com/tokio-rs/tokio/pull/4938 + # 0.7.3 (June 4, 2022) ### Changed diff --git a/tokio-util/Cargo.toml b/tokio-util/Cargo.toml index 6406af63..d5a9f748 100644 --- a/tokio-util/Cargo.toml +++ b/tokio-util/Cargo.toml @@ -4,7 +4,7 @@ name = "tokio-util" # - Remove path dependencies # - Update CHANGELOG.md. # - Create "tokio-util-0.7.x" git tag. -version = "0.7.3" +version = "0.7.4" edition = "2018" rust-version = "1.49" authors = ["Tokio Contributors "] @@ -34,7 +34,7 @@ rt = ["tokio/rt", "tokio/sync", "futures-util", "hashbrown"] __docs_rs = ["futures-util"] [dependencies] -tokio = { version = "1.19.0", path = "../tokio", features = ["sync"] } +tokio = { version = "1.21.0", path = "../tokio", features = ["sync"] } bytes = "1.0.0" futures-core = "0.3.0" futures-sink = "0.3.0" diff --git a/tokio-util/LICENSE b/tokio-util/LICENSE index 8af5baf0..8bdf6bd6 100644 --- a/tokio-util/LICENSE +++ b/tokio-util/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2022 Tokio Contributors +Copyright (c) 2023 Tokio Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/tokio-util/src/codec/framed.rs b/tokio-util/src/codec/framed.rs index d89b8b6d..043b4384 100644 --- a/tokio-util/src/codec/framed.rs +++ b/tokio-util/src/codec/framed.rs @@ -253,6 +253,16 @@ impl Framed { &mut self.inner.state.write.buffer } + /// Returns backpressure boundary + pub fn backpressure_boundary(&self) -> usize { + self.inner.state.write.backpressure_boundary + } + + /// Updates backpressure boundary + pub fn set_backpressure_boundary(&mut self, boundary: usize) { + self.inner.state.write.backpressure_boundary = boundary; + } + /// Consumes the `Framed`, returning its underlying I/O stream. /// /// Note that care should be taken to not tamper with the underlying stream @@ -358,10 +368,7 @@ pub struct FramedParts { impl FramedParts { /// Create a new, default, `FramedParts` - pub fn new(io: T, codec: U) -> FramedParts - where - U: Encoder, - { + pub fn new(io: T, codec: U) -> FramedParts { FramedParts { io, codec, diff --git a/tokio-util/src/codec/framed_impl.rs b/tokio-util/src/codec/framed_impl.rs index ce1a6db8..8f3fa49b 100644 --- a/tokio-util/src/codec/framed_impl.rs +++ b/tokio-util/src/codec/framed_impl.rs @@ -25,7 +25,6 @@ pin_project! { } const INITIAL_CAPACITY: usize = 8 * 1024; -const BACKPRESSURE_BOUNDARY: usize = INITIAL_CAPACITY; #[derive(Debug)] pub(crate) struct ReadFrame { @@ -37,6 +36,7 @@ pub(crate) struct ReadFrame { pub(crate) struct WriteFrame { pub(crate) buffer: BytesMut, + pub(crate) backpressure_boundary: usize, } #[derive(Default)] @@ -60,6 +60,7 @@ impl Default for WriteFrame { fn default() -> Self { Self { buffer: BytesMut::with_capacity(INITIAL_CAPACITY), + backpressure_boundary: INITIAL_CAPACITY, } } } @@ -87,7 +88,10 @@ impl From for WriteFrame { buffer.reserve(INITIAL_CAPACITY - size); } - Self { buffer } + Self { + buffer, + backpressure_boundary: INITIAL_CAPACITY, + } } } @@ -256,7 +260,7 @@ where type Error = U::Error; fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - if self.state.borrow().buffer.len() >= BACKPRESSURE_BOUNDARY { + if self.state.borrow().buffer.len() >= self.state.borrow().backpressure_boundary { self.as_mut().poll_flush(cx) } else { Poll::Ready(Ok(())) @@ -277,7 +281,7 @@ where let mut pinned = self.project(); while !pinned.state.borrow_mut().buffer.is_empty() { - let WriteFrame { buffer } = pinned.state.borrow_mut(); + let WriteFrame { buffer, .. } = pinned.state.borrow_mut(); trace!(remaining = buffer.len(), "writing;"); let n = ready!(poll_write_buf(pinned.inner.as_mut(), cx, buffer))?; diff --git a/tokio-util/src/codec/framed_write.rs b/tokio-util/src/codec/framed_write.rs index aa4cec98..3f0a3408 100644 --- a/tokio-util/src/codec/framed_write.rs +++ b/tokio-util/src/codec/framed_write.rs @@ -123,6 +123,16 @@ impl FramedWrite { pub fn write_buffer_mut(&mut self) -> &mut BytesMut { &mut self.inner.state.buffer } + + /// Returns backpressure boundary + pub fn backpressure_boundary(&self) -> usize { + self.inner.state.backpressure_boundary + } + + /// Updates backpressure boundary + pub fn set_backpressure_boundary(&mut self, boundary: usize) { + self.inner.state.backpressure_boundary = boundary; + } } // This impl just defers to the underlying FramedImpl diff --git a/tokio-util/src/codec/length_delimited.rs b/tokio-util/src/codec/length_delimited.rs index 93d2f180..a182dcae 100644 --- a/tokio-util/src/codec/length_delimited.rs +++ b/tokio-util/src/codec/length_delimited.rs @@ -522,15 +522,11 @@ impl LengthDelimitedCodec { } }; - let num_skip = self.builder.get_num_skip(); - - if num_skip > 0 { - src.advance(num_skip); - } + src.advance(self.builder.get_num_skip()); // Ensure that the buffer has enough space to read the incoming // payload - src.reserve(n); + src.reserve(n.saturating_sub(src.len())); Ok(Some(n)) } @@ -568,7 +564,7 @@ impl Decoder for LengthDelimitedCodec { self.state = DecodeState::Head; // Make sure the buffer has enough space to read the next head - src.reserve(self.builder.num_head_bytes()); + src.reserve(self.builder.num_head_bytes().saturating_sub(src.len())); Ok(Some(data)) } diff --git a/tokio-util/src/io/copy_to_bytes.rs b/tokio-util/src/io/copy_to_bytes.rs new file mode 100644 index 00000000..9509e711 --- /dev/null +++ b/tokio-util/src/io/copy_to_bytes.rs @@ -0,0 +1,68 @@ +use bytes::Bytes; +use futures_sink::Sink; +use pin_project_lite::pin_project; +use std::pin::Pin; +use std::task::{Context, Poll}; + +pin_project! { + /// A helper that wraps a [`Sink`]`<`[`Bytes`]`>` and converts it into a + /// [`Sink`]`<&'a [u8]>` by copying each byte slice into an owned [`Bytes`]. + /// + /// See the documentation for [`SinkWriter`] for an example. + /// + /// [`Bytes`]: bytes::Bytes + /// [`SinkWriter`]: crate::io::SinkWriter + /// [`Sink`]: futures_sink::Sink + #[derive(Debug)] + pub struct CopyToBytes { + #[pin] + inner: S, + } +} + +impl CopyToBytes { + /// Creates a new [`CopyToBytes`]. + pub fn new(inner: S) -> Self { + Self { inner } + } + + /// Gets a reference to the underlying sink. + pub fn get_ref(&self) -> &S { + &self.inner + } + + /// Gets a mutable reference to the underlying sink. + pub fn get_mut(&mut self) -> &mut S { + &mut self.inner + } + + /// Consumes this [`CopyToBytes`], returning the underlying sink. + pub fn into_inner(self) -> S { + self.inner + } +} + +impl<'a, S> Sink<&'a [u8]> for CopyToBytes +where + S: Sink, +{ + type Error = S::Error; + + fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.project().inner.poll_ready(cx) + } + + fn start_send(self: Pin<&mut Self>, item: &'a [u8]) -> Result<(), Self::Error> { + self.project() + .inner + .start_send(Bytes::copy_from_slice(item)) + } + + fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.project().inner.poll_flush(cx) + } + + fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.project().inner.poll_close(cx) + } +} diff --git a/tokio-util/src/io/inspect.rs b/tokio-util/src/io/inspect.rs new file mode 100644 index 00000000..ec5bb97e --- /dev/null +++ b/tokio-util/src/io/inspect.rs @@ -0,0 +1,134 @@ +use futures_core::ready; +use pin_project_lite::pin_project; +use std::io::{IoSlice, Result}; +use std::pin::Pin; +use std::task::{Context, Poll}; + +use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; + +pin_project! { + /// An adapter that lets you inspect the data that's being read. + /// + /// This is useful for things like hashing data as it's read in. + pub struct InspectReader { + #[pin] + reader: R, + f: F, + } +} + +impl InspectReader { + /// Create a new InspectReader, wrapping `reader` and calling `f` for the + /// new data supplied by each read call. + /// + /// The closure will only be called with an empty slice if the inner reader + /// returns without reading data into the buffer. This happens at EOF, or if + /// `poll_read` is called with a zero-size buffer. + pub fn new(reader: R, f: F) -> InspectReader + where + R: AsyncRead, + F: FnMut(&[u8]), + { + InspectReader { reader, f } + } + + /// Consumes the `InspectReader`, returning the wrapped reader + pub fn into_inner(self) -> R { + self.reader + } +} + +impl AsyncRead for InspectReader { + fn poll_read( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut ReadBuf<'_>, + ) -> Poll> { + let me = self.project(); + let filled_length = buf.filled().len(); + ready!(me.reader.poll_read(cx, buf))?; + (me.f)(&buf.filled()[filled_length..]); + Poll::Ready(Ok(())) + } +} + +pin_project! { + /// An adapter that lets you inspect the data that's being written. + /// + /// This is useful for things like hashing data as it's written out. + pub struct InspectWriter { + #[pin] + writer: W, + f: F, + } +} + +impl InspectWriter { + /// Create a new InspectWriter, wrapping `write` and calling `f` for the + /// data successfully written by each write call. + /// + /// The closure `f` will never be called with an empty slice. A vectored + /// write can result in multiple calls to `f` - at most one call to `f` per + /// buffer supplied to `poll_write_vectored`. + pub fn new(writer: W, f: F) -> InspectWriter + where + W: AsyncWrite, + F: FnMut(&[u8]), + { + InspectWriter { writer, f } + } + + /// Consumes the `InspectWriter`, returning the wrapped writer + pub fn into_inner(self) -> W { + self.writer + } +} + +impl AsyncWrite for InspectWriter { + fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll> { + let me = self.project(); + let res = me.writer.poll_write(cx, buf); + if let Poll::Ready(Ok(count)) = res { + if count != 0 { + (me.f)(&buf[..count]); + } + } + res + } + + fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let me = self.project(); + me.writer.poll_flush(cx) + } + + fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let me = self.project(); + me.writer.poll_shutdown(cx) + } + + fn poll_write_vectored( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + bufs: &[IoSlice<'_>], + ) -> Poll> { + let me = self.project(); + let res = me.writer.poll_write_vectored(cx, bufs); + if let Poll::Ready(Ok(mut count)) = res { + for buf in bufs { + if count == 0 { + break; + } + let size = count.min(buf.len()); + if size != 0 { + (me.f)(&buf[..size]); + count -= size; + } + } + } + res + } + + fn is_write_vectored(&self) -> bool { + self.writer.is_write_vectored() + } +} diff --git a/tokio-util/src/io/mod.rs b/tokio-util/src/io/mod.rs index eb48a21f..6c40d739 100644 --- a/tokio-util/src/io/mod.rs +++ b/tokio-util/src/io/mod.rs @@ -10,15 +10,22 @@ //! [`Body`]: https://docs.rs/hyper/0.13/hyper/struct.Body.html //! [`AsyncRead`]: tokio::io::AsyncRead +mod copy_to_bytes; +mod inspect; mod read_buf; mod reader_stream; +mod sink_writer; mod stream_reader; + cfg_io_util! { mod sync_bridge; pub use self::sync_bridge::SyncIoBridge; } +pub use self::copy_to_bytes::CopyToBytes; +pub use self::inspect::{InspectReader, InspectWriter}; pub use self::read_buf::read_buf; pub use self::reader_stream::ReaderStream; +pub use self::sink_writer::SinkWriter; pub use self::stream_reader::StreamReader; pub use crate::util::{poll_read_buf, poll_write_buf}; diff --git a/tokio-util/src/io/sink_writer.rs b/tokio-util/src/io/sink_writer.rs new file mode 100644 index 00000000..5d1acc49 --- /dev/null +++ b/tokio-util/src/io/sink_writer.rs @@ -0,0 +1,124 @@ +use futures_sink::Sink; + +use pin_project_lite::pin_project; +use std::io; +use std::pin::Pin; +use std::task::{Context, Poll}; +use tokio::io::AsyncWrite; + +pin_project! { + /// Convert a [`Sink`] of byte chunks into an [`AsyncWrite`]. + /// + /// Whenever you write to this [`SinkWriter`], the supplied bytes are + /// forwarded to the inner [`Sink`]. When `shutdown` is called on this + /// [`SinkWriter`], the inner sink is closed. + /// + /// This adapter takes a `Sink<&[u8]>` and provides an [`AsyncWrite`] impl + /// for it. Because of the lifetime, this trait is relatively rarely + /// implemented. The main ways to get a `Sink<&[u8]>` that you can use with + /// this type are: + /// + /// * With the codec module by implementing the [`Encoder`]`<&[u8]>` trait. + /// * By wrapping a `Sink` in a [`CopyToBytes`]. + /// * Manually implementing `Sink<&[u8]>` directly. + /// + /// The opposite conversion of implementing `Sink<_>` for an [`AsyncWrite`] + /// is done using the [`codec`] module. + /// + /// # Example + /// + /// ``` + /// use bytes::Bytes; + /// use futures_util::SinkExt; + /// use std::io::{Error, ErrorKind}; + /// use tokio::io::AsyncWriteExt; + /// use tokio_util::io::{SinkWriter, CopyToBytes}; + /// use tokio_util::sync::PollSender; + /// + /// # #[tokio::main(flavor = "current_thread")] + /// # async fn main() -> Result<(), Error> { + /// // We use an mpsc channel as an example of a `Sink`. + /// let (tx, mut rx) = tokio::sync::mpsc::channel::(1); + /// let sink = PollSender::new(tx).sink_map_err(|_| Error::from(ErrorKind::BrokenPipe)); + /// + /// // Wrap it in `CopyToBytes` to get a `Sink<&[u8]>`. + /// let mut writer = SinkWriter::new(CopyToBytes::new(sink)); + /// + /// // Write data to our interface... + /// let data: [u8; 4] = [1, 2, 3, 4]; + /// let _ = writer.write(&data).await?; + /// + /// // ... and receive it. + /// assert_eq!(data.as_slice(), &*rx.recv().await.unwrap()); + /// # Ok(()) + /// # } + /// ``` + /// + /// [`AsyncWrite`]: tokio::io::AsyncWrite + /// [`CopyToBytes`]: crate::io::CopyToBytes + /// [`Encoder`]: crate::codec::Encoder + /// [`Sink`]: futures_sink::Sink + /// [`codec`]: tokio_util::codec + #[derive(Debug)] + pub struct SinkWriter { + #[pin] + inner: S, + } +} + +impl SinkWriter { + /// Creates a new [`SinkWriter`]. + pub fn new(sink: S) -> Self { + Self { inner: sink } + } + + /// Gets a reference to the underlying sink. + pub fn get_ref(&self) -> &S { + &self.inner + } + + /// Gets a mutable reference to the underlying sink. + pub fn get_mut(&mut self) -> &mut S { + &mut self.inner + } + + /// Consumes this [`SinkWriter`], returning the underlying sink. + pub fn into_inner(self) -> S { + self.inner + } +} +impl AsyncWrite for SinkWriter +where + for<'a> S: Sink<&'a [u8], Error = E>, + E: Into, +{ + fn poll_write( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + let mut this = self.project(); + match this.inner.as_mut().poll_ready(cx) { + Poll::Ready(Ok(())) => { + if let Err(e) = this.inner.as_mut().start_send(buf) { + Poll::Ready(Err(e.into())) + } else { + Poll::Ready(Ok(buf.len())) + } + } + Poll::Ready(Err(e)) => Poll::Ready(Err(e.into())), + Poll::Pending => { + cx.waker().wake_by_ref(); + Poll::Pending + } + } + } + + fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.project().inner.poll_flush(cx).map_err(Into::into) + } + + fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.project().inner.poll_close(cx).map_err(Into::into) + } +} diff --git a/tokio-util/src/io/stream_reader.rs b/tokio-util/src/io/stream_reader.rs index 6260f9e4..3353722c 100644 --- a/tokio-util/src/io/stream_reader.rs +++ b/tokio-util/src/io/stream_reader.rs @@ -1,64 +1,162 @@ use bytes::Buf; use futures_core::stream::Stream; -use pin_project_lite::pin_project; use std::io; use std::pin::Pin; use std::task::{Context, Poll}; use tokio::io::{AsyncBufRead, AsyncRead, ReadBuf}; -pin_project! { - /// Convert a [`Stream`] of byte chunks into an [`AsyncRead`]. - /// - /// This type performs the inverse operation of [`ReaderStream`]. - /// - /// # Example - /// - /// ``` - /// use bytes::Bytes; - /// use tokio::io::{AsyncReadExt, Result}; - /// use tokio_util::io::StreamReader; - /// # #[tokio::main] - /// # async fn main() -> std::io::Result<()> { - /// - /// // Create a stream from an iterator. - /// let stream = tokio_stream::iter(vec![ - /// Result::Ok(Bytes::from_static(&[0, 1, 2, 3])), - /// Result::Ok(Bytes::from_static(&[4, 5, 6, 7])), - /// Result::Ok(Bytes::from_static(&[8, 9, 10, 11])), - /// ]); - /// - /// // Convert it to an AsyncRead. - /// let mut read = StreamReader::new(stream); - /// - /// // Read five bytes from the stream. - /// let mut buf = [0; 5]; - /// read.read_exact(&mut buf).await?; - /// assert_eq!(buf, [0, 1, 2, 3, 4]); - /// - /// // Read the rest of the current chunk. - /// assert_eq!(read.read(&mut buf).await?, 3); - /// assert_eq!(&buf[..3], [5, 6, 7]); - /// - /// // Read the next chunk. - /// assert_eq!(read.read(&mut buf).await?, 4); - /// assert_eq!(&buf[..4], [8, 9, 10, 11]); - /// - /// // We have now reached the end. - /// assert_eq!(read.read(&mut buf).await?, 0); - /// - /// # Ok(()) - /// # } - /// ``` - /// - /// [`AsyncRead`]: tokio::io::AsyncRead - /// [`Stream`]: futures_core::Stream - /// [`ReaderStream`]: crate::io::ReaderStream - #[derive(Debug)] - pub struct StreamReader { - #[pin] - inner: S, - chunk: Option, - } +/// Convert a [`Stream`] of byte chunks into an [`AsyncRead`]. +/// +/// This type performs the inverse operation of [`ReaderStream`]. +/// +/// This type also implements the [`AsyncBufRead`] trait, so you can use it +/// to read a `Stream` of byte chunks line-by-line. See the examples below. +/// +/// # Example +/// +/// ``` +/// use bytes::Bytes; +/// use tokio::io::{AsyncReadExt, Result}; +/// use tokio_util::io::StreamReader; +/// # #[tokio::main(flavor = "current_thread")] +/// # async fn main() -> std::io::Result<()> { +/// +/// // Create a stream from an iterator. +/// let stream = tokio_stream::iter(vec![ +/// Result::Ok(Bytes::from_static(&[0, 1, 2, 3])), +/// Result::Ok(Bytes::from_static(&[4, 5, 6, 7])), +/// Result::Ok(Bytes::from_static(&[8, 9, 10, 11])), +/// ]); +/// +/// // Convert it to an AsyncRead. +/// let mut read = StreamReader::new(stream); +/// +/// // Read five bytes from the stream. +/// let mut buf = [0; 5]; +/// read.read_exact(&mut buf).await?; +/// assert_eq!(buf, [0, 1, 2, 3, 4]); +/// +/// // Read the rest of the current chunk. +/// assert_eq!(read.read(&mut buf).await?, 3); +/// assert_eq!(&buf[..3], [5, 6, 7]); +/// +/// // Read the next chunk. +/// assert_eq!(read.read(&mut buf).await?, 4); +/// assert_eq!(&buf[..4], [8, 9, 10, 11]); +/// +/// // We have now reached the end. +/// assert_eq!(read.read(&mut buf).await?, 0); +/// +/// # Ok(()) +/// # } +/// ``` +/// +/// If the stream produces errors which are not [`std::io::Error`], +/// the errors can be converted using [`StreamExt`] to map each +/// element. +/// +/// ``` +/// use bytes::Bytes; +/// use tokio::io::AsyncReadExt; +/// use tokio_util::io::StreamReader; +/// use tokio_stream::StreamExt; +/// # #[tokio::main(flavor = "current_thread")] +/// # async fn main() -> std::io::Result<()> { +/// +/// // Create a stream from an iterator, including an error. +/// let stream = tokio_stream::iter(vec![ +/// Result::Ok(Bytes::from_static(&[0, 1, 2, 3])), +/// Result::Ok(Bytes::from_static(&[4, 5, 6, 7])), +/// Result::Err("Something bad happened!") +/// ]); +/// +/// // Use StreamExt to map the stream and error to a std::io::Error +/// let stream = stream.map(|result| result.map_err(|err| { +/// std::io::Error::new(std::io::ErrorKind::Other, err) +/// })); +/// +/// // Convert it to an AsyncRead. +/// let mut read = StreamReader::new(stream); +/// +/// // Read five bytes from the stream. +/// let mut buf = [0; 5]; +/// read.read_exact(&mut buf).await?; +/// assert_eq!(buf, [0, 1, 2, 3, 4]); +/// +/// // Read the rest of the current chunk. +/// assert_eq!(read.read(&mut buf).await?, 3); +/// assert_eq!(&buf[..3], [5, 6, 7]); +/// +/// // Reading the next chunk will produce an error +/// let error = read.read(&mut buf).await.unwrap_err(); +/// assert_eq!(error.kind(), std::io::ErrorKind::Other); +/// assert_eq!(error.into_inner().unwrap().to_string(), "Something bad happened!"); +/// +/// // We have now reached the end. +/// assert_eq!(read.read(&mut buf).await?, 0); +/// +/// # Ok(()) +/// # } +/// ``` +/// +/// Using the [`AsyncBufRead`] impl, you can read a `Stream` of byte chunks +/// line-by-line. Note that you will usually also need to convert the error +/// type when doing this. See the second example for an explanation of how +/// to do this. +/// +/// ``` +/// use tokio::io::{Result, AsyncBufReadExt}; +/// use tokio_util::io::StreamReader; +/// # #[tokio::main(flavor = "current_thread")] +/// # async fn main() -> std::io::Result<()> { +/// +/// // Create a stream of byte chunks. +/// let stream = tokio_stream::iter(vec![ +/// Result::Ok(b"The first line.\n".as_slice()), +/// Result::Ok(b"The second line.".as_slice()), +/// Result::Ok(b"\nThe third".as_slice()), +/// Result::Ok(b" line.\nThe fourth line.\nThe fifth line.\n".as_slice()), +/// ]); +/// +/// // Convert it to an AsyncRead. +/// let mut read = StreamReader::new(stream); +/// +/// // Loop through the lines from the `StreamReader`. +/// let mut line = String::new(); +/// let mut lines = Vec::new(); +/// loop { +/// line.clear(); +/// let len = read.read_line(&mut line).await?; +/// if len == 0 { break; } +/// lines.push(line.clone()); +/// } +/// +/// // Verify that we got the lines we expected. +/// assert_eq!( +/// lines, +/// vec![ +/// "The first line.\n", +/// "The second line.\n", +/// "The third line.\n", +/// "The fourth line.\n", +/// "The fifth line.\n", +/// ] +/// ); +/// # Ok(()) +/// # } +/// ``` +/// +/// [`AsyncRead`]: tokio::io::AsyncRead +/// [`AsyncBufRead`]: tokio::io::AsyncBufRead +/// [`Stream`]: futures_core::Stream +/// [`ReaderStream`]: crate::io::ReaderStream +/// [`StreamExt`]: https://docs.rs/tokio-stream/latest/tokio_stream/trait.StreamExt.html +#[derive(Debug)] +pub struct StreamReader { + // This field is pinned. + inner: S, + // This field is not pinned. + chunk: Option, } impl StreamReader @@ -201,3 +299,28 @@ where } } } + +// The code below is a manual expansion of the code that pin-project-lite would +// generate. This is done because pin-project-lite fails by hitting the recusion +// limit on this struct. (Every line of documentation is handled recursively by +// the macro.) + +impl Unpin for StreamReader {} + +struct StreamReaderProject<'a, S, B> { + inner: Pin<&'a mut S>, + chunk: &'a mut Option, +} + +impl StreamReader { + #[inline] + fn project(self: Pin<&mut Self>) -> StreamReaderProject<'_, S, B> { + // SAFETY: We define that only `inner` should be pinned when `Self` is + // and have an appropriate `impl Unpin` for this. + let me = unsafe { Pin::into_inner_unchecked(self) }; + StreamReaderProject { + inner: unsafe { Pin::new_unchecked(&mut me.inner) }, + chunk: &mut me.chunk, + } + } +} diff --git a/tokio-util/src/io/sync_bridge.rs b/tokio-util/src/io/sync_bridge.rs index 5587175b..f87bfbb9 100644 --- a/tokio-util/src/io/sync_bridge.rs +++ b/tokio-util/src/io/sync_bridge.rs @@ -1,5 +1,7 @@ -use std::io::{Read, Write}; -use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; +use std::io::{BufRead, Read, Write}; +use tokio::io::{ + AsyncBufRead, AsyncBufReadExt, AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, +}; /// Use a [`tokio::io::AsyncRead`] synchronously as a [`std::io::Read`] or /// a [`tokio::io::AsyncWrite`] as a [`std::io::Write`]. @@ -9,6 +11,28 @@ pub struct SyncIoBridge { rt: tokio::runtime::Handle, } +impl BufRead for SyncIoBridge { + fn fill_buf(&mut self) -> std::io::Result<&[u8]> { + let src = &mut self.src; + self.rt.block_on(AsyncBufReadExt::fill_buf(src)) + } + + fn consume(&mut self, amt: usize) { + let src = &mut self.src; + AsyncBufReadExt::consume(src, amt) + } + + fn read_until(&mut self, byte: u8, buf: &mut Vec) -> std::io::Result { + let src = &mut self.src; + self.rt + .block_on(AsyncBufReadExt::read_until(src, byte, buf)) + } + fn read_line(&mut self, buf: &mut String) -> std::io::Result { + let src = &mut self.src; + self.rt.block_on(AsyncBufReadExt::read_line(src, buf)) + } +} + impl Read for SyncIoBridge { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { let src = &mut self.src; @@ -66,6 +90,21 @@ impl SyncIoBridge { } } +impl SyncIoBridge { + /// Shutdown this writer. This method provides a way to call the [`AsyncWriteExt::shutdown`] + /// function of the inner [`tokio::io::AsyncWrite`] instance. + /// + /// # Errors + /// + /// This method returns the same errors as [`AsyncWriteExt::shutdown`]. + /// + /// [`AsyncWriteExt::shutdown`]: tokio::io::AsyncWriteExt::shutdown + pub fn shutdown(&mut self) -> std::io::Result<()> { + let src = &mut self.src; + self.rt.block_on(src.shutdown()) + } +} + impl SyncIoBridge { /// Use a [`tokio::io::AsyncRead`] synchronously as a [`std::io::Read`] or /// a [`tokio::io::AsyncWrite`] as a [`std::io::Write`]. diff --git a/tokio-util/src/lib.rs b/tokio-util/src/lib.rs index e4876a58..524fc470 100644 --- a/tokio-util/src/lib.rs +++ b/tokio-util/src/lib.rs @@ -29,6 +29,7 @@ cfg_codec! { } cfg_net! { + #[cfg(not(target_arch = "wasm32"))] pub mod udp; pub mod net; } diff --git a/tokio-util/src/sync/cancellation_token.rs b/tokio-util/src/sync/cancellation_token.rs index 2a6ef392..fbceb2ee 100644 --- a/tokio-util/src/sync/cancellation_token.rs +++ b/tokio-util/src/sync/cancellation_token.rs @@ -66,6 +66,23 @@ pin_project! { } } +pin_project! { + /// A Future that is resolved once the corresponding [`CancellationToken`] + /// is cancelled. + /// + /// This is the counterpart to [`WaitForCancellationFuture`] that takes + /// [`CancellationToken`] by value instead of using a reference. + #[must_use = "futures do nothing unless polled"] + pub struct WaitForCancellationFutureOwned { + // Since `future` is the first field, it is dropped before the + // cancellation_token field. This ensures that the reference inside the + // `Notified` remains valid. + #[pin] + future: tokio::sync::futures::Notified<'static>, + cancellation_token: CancellationToken, + } +} + // ===== impl CancellationToken ===== impl core::fmt::Debug for CancellationToken { @@ -183,6 +200,21 @@ impl CancellationToken { } } + /// Returns a `Future` that gets fulfilled when cancellation is requested. + /// + /// The future will complete immediately if the token is already cancelled + /// when this method is called. + /// + /// The function takes self by value and returns a future that owns the + /// token. + /// + /// # Cancel safety + /// + /// This method is cancel safe. + pub fn cancelled_owned(self) -> WaitForCancellationFutureOwned { + WaitForCancellationFutureOwned::new(self) + } + /// Creates a `DropGuard` for this token. /// /// Returned guard will cancel this token (and all its children) on drop @@ -222,3 +254,68 @@ impl<'a> Future for WaitForCancellationFuture<'a> { } } } + +// ===== impl WaitForCancellationFutureOwned ===== + +impl core::fmt::Debug for WaitForCancellationFutureOwned { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("WaitForCancellationFutureOwned").finish() + } +} + +impl WaitForCancellationFutureOwned { + fn new(cancellation_token: CancellationToken) -> Self { + WaitForCancellationFutureOwned { + // cancellation_token holds a heap allocation and is guaranteed to have a + // stable deref, thus it would be ok to move the cancellation_token while + // the future holds a reference to it. + // + // # Safety + // + // cancellation_token is dropped after future due to the field ordering. + future: unsafe { Self::new_future(&cancellation_token) }, + cancellation_token, + } + } + + /// # Safety + /// The returned future must be destroyed before the cancellation token is + /// destroyed. + unsafe fn new_future( + cancellation_token: &CancellationToken, + ) -> tokio::sync::futures::Notified<'static> { + let inner_ptr = Arc::as_ptr(&cancellation_token.inner); + // SAFETY: The `Arc::as_ptr` method guarantees that `inner_ptr` remains + // valid until the strong count of the Arc drops to zero, and the caller + // guarantees that they will drop the future before that happens. + (*inner_ptr).notified() + } +} + +impl Future for WaitForCancellationFutureOwned { + type Output = (); + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + let mut this = self.project(); + + loop { + if this.cancellation_token.is_cancelled() { + return Poll::Ready(()); + } + + // No wakeups can be lost here because there is always a call to + // `is_cancelled` between the creation of the future and the call to + // `poll`, and the code that sets the cancelled flag does so before + // waking the `Notified`. + if this.future.as_mut().poll(cx).is_pending() { + return Poll::Pending; + } + + // # Safety + // + // cancellation_token is dropped after future due to the field ordering. + this.future + .set(unsafe { Self::new_future(this.cancellation_token) }); + } + } +} diff --git a/tokio-util/src/sync/cancellation_token/tree_node.rs b/tokio-util/src/sync/cancellation_token/tree_node.rs index b6cd698e..8f97dee8 100644 --- a/tokio-util/src/sync/cancellation_token/tree_node.rs +++ b/tokio-util/src/sync/cancellation_token/tree_node.rs @@ -200,7 +200,7 @@ where /// `parent` MUST have been a parent of the node when they both got locked, /// otherwise there is a potential for a deadlock as invariant #2 would be violated. /// -/// To aquire the locks for node and parent, use [with_locked_node_and_parent]. +/// To acquire the locks for node and parent, use [with_locked_node_and_parent]. fn move_children_to_parent(node: &mut Inner, parent: &mut Inner) { // Pre-allocate in the parent, for performance parent.children.reserve(node.children.len()); @@ -218,7 +218,7 @@ fn move_children_to_parent(node: &mut Inner, parent: &mut Inner) { /// Removes a child from the parent. /// /// `parent` MUST be the parent of `node`. -/// To aquire the locks for node and parent, use [with_locked_node_and_parent]. +/// To acquire the locks for node and parent, use [with_locked_node_and_parent]. fn remove_child(parent: &mut Inner, mut node: MutexGuard<'_, Inner>) { // Query the position from where to remove a node let pos = node.parent_idx; diff --git a/tokio-util/src/sync/mod.rs b/tokio-util/src/sync/mod.rs index de392f0b..1ae1b7ee 100644 --- a/tokio-util/src/sync/mod.rs +++ b/tokio-util/src/sync/mod.rs @@ -1,7 +1,9 @@ //! Synchronization primitives mod cancellation_token; -pub use cancellation_token::{guard::DropGuard, CancellationToken, WaitForCancellationFuture}; +pub use cancellation_token::{ + guard::DropGuard, CancellationToken, WaitForCancellationFuture, WaitForCancellationFutureOwned, +}; mod mpsc; pub use mpsc::{PollSendError, PollSender}; diff --git a/tokio-util/src/sync/poll_semaphore.rs b/tokio-util/src/sync/poll_semaphore.rs index d0b1dedc..6b44574a 100644 --- a/tokio-util/src/sync/poll_semaphore.rs +++ b/tokio-util/src/sync/poll_semaphore.rs @@ -12,7 +12,10 @@ use super::ReusableBoxFuture; /// [`Semaphore`]: tokio::sync::Semaphore pub struct PollSemaphore { semaphore: Arc, - permit_fut: Option>>, + permit_fut: Option<( + u32, // The number of permits requested. + ReusableBoxFuture<'static, Result>, + )>, } impl PollSemaphore { @@ -53,25 +56,57 @@ impl PollSemaphore { /// the `Waker` from the `Context` passed to the most recent call is /// scheduled to receive a wakeup. pub fn poll_acquire(&mut self, cx: &mut Context<'_>) -> Poll> { + self.poll_acquire_many(cx, 1) + } + + /// Poll to acquire many permits from the semaphore. + /// + /// This can return the following values: + /// + /// - `Poll::Pending` if a permit is not currently available. + /// - `Poll::Ready(Some(permit))` if a permit was acquired. + /// - `Poll::Ready(None)` if the semaphore has been closed. + /// + /// When this method returns `Poll::Pending`, the current task is scheduled + /// to receive a wakeup when the permits become available, or when the + /// semaphore is closed. Note that on multiple calls to `poll_acquire`, only + /// the `Waker` from the `Context` passed to the most recent call is + /// scheduled to receive a wakeup. + pub fn poll_acquire_many( + &mut self, + cx: &mut Context<'_>, + permits: u32, + ) -> Poll> { let permit_future = match self.permit_fut.as_mut() { - Some(fut) => fut, + Some((prev_permits, fut)) if *prev_permits == permits => fut, + Some((old_permits, fut_box)) => { + // We're requesting a different number of permits, so replace the future + // and record the new amount. + let fut = Arc::clone(&self.semaphore).acquire_many_owned(permits); + fut_box.set(fut); + *old_permits = permits; + fut_box + } None => { // avoid allocations completely if we can grab a permit immediately - match Arc::clone(&self.semaphore).try_acquire_owned() { + match Arc::clone(&self.semaphore).try_acquire_many_owned(permits) { Ok(permit) => return Poll::Ready(Some(permit)), Err(TryAcquireError::Closed) => return Poll::Ready(None), Err(TryAcquireError::NoPermits) => {} } - let next_fut = Arc::clone(&self.semaphore).acquire_owned(); - self.permit_fut - .get_or_insert(ReusableBoxFuture::new(next_fut)) + let next_fut = Arc::clone(&self.semaphore).acquire_many_owned(permits); + &mut self + .permit_fut + .get_or_insert((permits, ReusableBoxFuture::new(next_fut))) + .1 } }; let result = ready!(permit_future.poll(cx)); - let next_fut = Arc::clone(&self.semaphore).acquire_owned(); + // Assume we'll request the same amount of permits in a subsequent call. + let next_fut = Arc::clone(&self.semaphore).acquire_many_owned(permits); permit_future.set(next_fut); match result { @@ -95,7 +130,7 @@ impl PollSemaphore { /// Adds `n` new permits to the semaphore. /// - /// The maximum number of permits is `usize::MAX >> 3`, and this function + /// The maximum number of permits is [`Semaphore::MAX_PERMITS`], and this function /// will panic if the limit is exceeded. /// /// This is equivalent to the [`Semaphore::add_permits`] method on the @@ -131,6 +166,6 @@ impl fmt::Debug for PollSemaphore { impl AsRef for PollSemaphore { fn as_ref(&self) -> &Semaphore { - &*self.semaphore + &self.semaphore } } diff --git a/tokio-util/src/sync/tests/loom_cancellation_token.rs b/tokio-util/src/sync/tests/loom_cancellation_token.rs index e9c9f3dd..b57503dd 100644 --- a/tokio-util/src/sync/tests/loom_cancellation_token.rs +++ b/tokio-util/src/sync/tests/loom_cancellation_token.rs @@ -24,6 +24,27 @@ fn cancel_token() { }); } +#[test] +fn cancel_token_owned() { + loom::model(|| { + let token = CancellationToken::new(); + let token1 = token.clone(); + + let th1 = thread::spawn(move || { + block_on(async { + token1.cancelled_owned().await; + }); + }); + + let th2 = thread::spawn(move || { + token.cancel(); + }); + + assert_ok!(th1.join()); + assert_ok!(th2.join()); + }); +} + #[test] fn cancel_with_child() { loom::model(|| { @@ -80,7 +101,7 @@ fn drop_token_no_child() { } #[test] -fn drop_token_with_childs() { +fn drop_token_with_children() { loom::model(|| { let token1 = CancellationToken::new(); let child_token1 = token1.child_token(); diff --git a/tokio-util/src/task/join_map.rs b/tokio-util/src/task/join_map.rs index 5d4441b9..c6bf5bc2 100644 --- a/tokio-util/src/task/join_map.rs +++ b/tokio-util/src/task/join_map.rs @@ -363,10 +363,7 @@ where fn insert(&mut self, key: K, abort: AbortHandle) { let hash = self.hash(&key); let id = abort.id(); - let map_key = Key { - id: id.clone(), - key, - }; + let map_key = Key { id, key }; // Insert the new key into the map of tasks by keys. let entry = self @@ -416,7 +413,6 @@ where /// * `None` if the `JoinMap` is empty. /// /// [`tokio::select!`]: tokio::select - #[doc(alias = "join_one")] pub async fn join_next(&mut self) -> Option<(K, Result)> { let (res, id) = match self.tasks.join_next_with_id().await { Some(Ok((id, output))) => (Ok(output), id), @@ -430,12 +426,6 @@ where Some((key, res)) } - #[doc(hidden)] - #[deprecated(since = "0.7.4", note = "renamed to `JoinMap::join_next`.")] - pub async fn join_one(&mut self) -> Option<(K, Result)> { - self.join_next().await - } - /// Aborts all tasks and waits for them to finish shutting down. /// /// Calling this method is equivalent to calling [`abort_all`] and then calling [`join_next`] in diff --git a/tokio-util/src/task/mod.rs b/tokio-util/src/task/mod.rs index 7ba8ad9a..de41dd5d 100644 --- a/tokio-util/src/task/mod.rs +++ b/tokio-util/src/task/mod.rs @@ -2,7 +2,9 @@ #[cfg(tokio_unstable)] mod join_map; +#[cfg(not(target_os = "wasi"))] mod spawn_pinned; +#[cfg(not(target_os = "wasi"))] pub use spawn_pinned::LocalPoolHandle; #[cfg(tokio_unstable)] diff --git a/tokio-util/src/time/delay_queue.rs b/tokio-util/src/time/delay_queue.rs index 07082b97..ee66adba 100644 --- a/tokio-util/src/time/delay_queue.rs +++ b/tokio-util/src/time/delay_queue.rs @@ -190,7 +190,7 @@ impl SlabStorage { let key_contained = self.key_map.contains_key(&key.into()); if key_contained { - // It's possible that a `compact` call creates capacitiy in `self.inner` in + // It's possible that a `compact` call creates capacity in `self.inner` in // such a way that a `self.inner.insert` call creates a `key` which was // previously given out during an `insert` call prior to the `compact` call. // If `key` is contained in `self.key_map`, we have encountered this exact situation, @@ -275,7 +275,7 @@ impl SlabStorage { fn remap_key(&self, key: &Key) -> Option { let key_map = &self.key_map; if self.compact_called { - key_map.get(&*key).copied() + key_map.get(key).copied() } else { Some((*key).into()) } @@ -740,6 +740,43 @@ impl DelayQueue { } } + /// Attempts to remove the item associated with `key` from the queue. + /// + /// Removes the item associated with `key`, and returns it along with the + /// `Instant` at which it would have expired, if it exists. + /// + /// Returns `None` if `key` is not in the queue. + /// + /// # Examples + /// + /// Basic usage + /// + /// ```rust + /// use tokio_util::time::DelayQueue; + /// use std::time::Duration; + /// + /// # #[tokio::main(flavor = "current_thread")] + /// # async fn main() { + /// let mut delay_queue = DelayQueue::new(); + /// let key = delay_queue.insert("foo", Duration::from_secs(5)); + /// + /// // The item is in the queue, `try_remove` returns `Some(Expired("foo"))`. + /// let item = delay_queue.try_remove(&key); + /// assert_eq!(item.unwrap().into_inner(), "foo"); + /// + /// // The item is not in the queue anymore, `try_remove` returns `None`. + /// let item = delay_queue.try_remove(&key); + /// assert!(item.is_none()); + /// # } + /// ``` + pub fn try_remove(&mut self, key: &Key) -> Option> { + if self.slab.contains(key) { + Some(self.remove(key)) + } else { + None + } + } + /// Sets the delay of the item associated with `key` to expire at `when`. /// /// This function is identical to `reset` but takes an `Instant` instead of diff --git a/tokio-util/tests/context.rs b/tokio-util/tests/context.rs index 7510f36f..2ec8258d 100644 --- a/tokio-util/tests/context.rs +++ b/tokio-util/tests/context.rs @@ -1,4 +1,5 @@ #![cfg(feature = "rt")] +#![cfg(not(target_os = "wasi"))] // Wasi doesn't support threads #![warn(rust_2018_idioms)] use tokio::runtime::Builder; @@ -20,5 +21,5 @@ fn tokio_context_with_another_runtime() { // Without the `HandleExt.wrap()` there would be a panic because there is // no timer running, since it would be referencing runtime r1. - let _ = rt1.block_on(rt2.wrap(async move { sleep(Duration::from_millis(2)).await })); + rt1.block_on(rt2.wrap(async move { sleep(Duration::from_millis(2)).await })); } diff --git a/tokio-util/tests/framed_write.rs b/tokio-util/tests/framed_write.rs index 259d9b0c..39091c0b 100644 --- a/tokio-util/tests/framed_write.rs +++ b/tokio-util/tests/framed_write.rs @@ -109,12 +109,12 @@ fn write_hits_backpressure() { const ITER: usize = 2 * 1024; let mut mock = mock! { - // Block the `ITER`th write + // Block the `ITER*2`th write Err(io::Error::new(io::ErrorKind::WouldBlock, "not ready")), Ok(b"".to_vec()), }; - for i in 0..=ITER { + for i in 0..=ITER * 2 { let mut b = BytesMut::with_capacity(4); b.put_u32(i as u32); @@ -130,17 +130,18 @@ fn write_hits_backpressure() { _ => unreachable!(), } - // Push a new new chunk + // Push a new chunk mock.calls.push_back(Ok(b[..].to_vec())); } - // 1 'wouldblock', 4 * 2KB buffers, 1 b-byte buffer - assert_eq!(mock.calls.len(), 6); + // 1 'wouldblock', 8 * 2KB buffers, 1 b-byte buffer + assert_eq!(mock.calls.len(), 10); let mut task = task::spawn(()); let mut framed = FramedWrite::new(mock, U32Encoder); + framed.set_backpressure_boundary(ITER * 8); task.enter(|cx, _| { - // Send 8KB. This fills up FramedWrite2 buffer - for i in 0..ITER { + // Send 16KB. This fills up FramedWrite buffer + for i in 0..ITER * 2 { assert!(assert_ready!(pin!(framed).poll_ready(cx)).is_ok()); assert!(pin!(framed).start_send(i as u32).is_ok()); } @@ -150,11 +151,11 @@ fn write_hits_backpressure() { assert!(pin!(framed).poll_ready(cx).is_pending()); // We poll again, forcing another flush, which this time succeeds - // The whole 8KB buffer is flushed + // The whole 16KB buffer is flushed assert!(assert_ready!(pin!(framed).poll_ready(cx)).is_ok()); // Send more data. This matches the final message expected by the mock - assert!(pin!(framed).start_send(ITER as u32).is_ok()); + assert!(pin!(framed).start_send((ITER * 2) as u32).is_ok()); // Flush the rest of the buffer assert!(assert_ready!(pin!(framed).poll_flush(cx)).is_ok()); diff --git a/tokio-util/tests/io_inspect.rs b/tokio-util/tests/io_inspect.rs new file mode 100644 index 00000000..e6319afc --- /dev/null +++ b/tokio-util/tests/io_inspect.rs @@ -0,0 +1,194 @@ +use futures::future::poll_fn; +use std::{ + io::IoSlice, + pin::Pin, + task::{Context, Poll}, +}; +use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, ReadBuf}; +use tokio_util::io::{InspectReader, InspectWriter}; + +/// An AsyncRead implementation that works byte-by-byte, to catch out callers +/// who don't allow for `buf` being part-filled before the call +struct SmallReader { + contents: Vec, +} + +impl Unpin for SmallReader {} + +impl AsyncRead for SmallReader { + fn poll_read( + mut self: Pin<&mut Self>, + _cx: &mut Context<'_>, + buf: &mut ReadBuf<'_>, + ) -> Poll> { + if let Some(byte) = self.contents.pop() { + buf.put_slice(&[byte]) + } + Poll::Ready(Ok(())) + } +} + +#[tokio::test] +async fn read_tee() { + let contents = b"This could be really long, you know".to_vec(); + let reader = SmallReader { + contents: contents.clone(), + }; + let mut altout: Vec = Vec::new(); + let mut teeout = Vec::new(); + { + let mut tee = InspectReader::new(reader, |bytes| altout.extend(bytes)); + tee.read_to_end(&mut teeout).await.unwrap(); + } + assert_eq!(teeout, altout); + assert_eq!(altout.len(), contents.len()); +} + +/// An AsyncWrite implementation that works byte-by-byte for poll_write, and +/// that reads the whole of the first buffer plus one byte from the second in +/// poll_write_vectored. +/// +/// This is designed to catch bugs in handling partially written buffers +#[derive(Debug)] +struct SmallWriter { + contents: Vec, +} + +impl Unpin for SmallWriter {} + +impl AsyncWrite for SmallWriter { + fn poll_write( + mut self: Pin<&mut Self>, + _cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + // Just write one byte at a time + if buf.is_empty() { + return Poll::Ready(Ok(0)); + } + self.contents.push(buf[0]); + Poll::Ready(Ok(1)) + } + + fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn poll_shutdown( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + ) -> Poll> { + Poll::Ready(Ok(())) + } + + fn poll_write_vectored( + mut self: Pin<&mut Self>, + _cx: &mut Context<'_>, + bufs: &[IoSlice<'_>], + ) -> Poll> { + // Write all of the first buffer, then one byte from the second buffer + // This should trip up anything that doesn't correctly handle multiple + // buffers. + if bufs.is_empty() { + return Poll::Ready(Ok(0)); + } + let mut written_len = bufs[0].len(); + self.contents.extend_from_slice(&bufs[0]); + + if bufs.len() > 1 { + let buf = bufs[1]; + if !buf.is_empty() { + written_len += 1; + self.contents.push(buf[0]); + } + } + Poll::Ready(Ok(written_len)) + } + + fn is_write_vectored(&self) -> bool { + true + } +} + +#[tokio::test] +async fn write_tee() { + let mut altout: Vec = Vec::new(); + let mut writeout = SmallWriter { + contents: Vec::new(), + }; + { + let mut tee = InspectWriter::new(&mut writeout, |bytes| altout.extend(bytes)); + tee.write_all(b"A testing string, very testing") + .await + .unwrap(); + } + assert_eq!(altout, writeout.contents); +} + +// This is inefficient, but works well enough for test use. +// If you want something similar for real code, you'll want to avoid all the +// fun of manipulating `bufs` - ideally, by the time you read this, +// IoSlice::advance_slices will be stable, and you can use that. +async fn write_all_vectored( + mut writer: W, + mut bufs: Vec>, +) -> Result { + let mut res = 0; + while !bufs.is_empty() { + let mut written = poll_fn(|cx| { + let bufs: Vec = bufs.iter().map(|v| IoSlice::new(v)).collect(); + Pin::new(&mut writer).poll_write_vectored(cx, &bufs) + }) + .await?; + res += written; + while written > 0 { + let buf_len = bufs[0].len(); + if buf_len <= written { + bufs.remove(0); + written -= buf_len; + } else { + let buf = &mut bufs[0]; + let drain_len = written.min(buf.len()); + buf.drain(..drain_len); + written -= drain_len; + } + } + } + Ok(res) +} + +#[tokio::test] +async fn write_tee_vectored() { + let mut altout: Vec = Vec::new(); + let mut writeout = SmallWriter { + contents: Vec::new(), + }; + let original = b"A very long string split up"; + let bufs: Vec> = original + .split(|b| b.is_ascii_whitespace()) + .map(Vec::from) + .collect(); + assert!(bufs.len() > 1); + let expected: Vec = { + let mut out = Vec::new(); + for item in &bufs { + out.extend_from_slice(item) + } + out + }; + { + let mut bufcount = 0; + let tee = InspectWriter::new(&mut writeout, |bytes| { + bufcount += 1; + altout.extend(bytes) + }); + + assert!(tee.is_write_vectored()); + + write_all_vectored(tee, bufs.clone()).await.unwrap(); + + assert!(bufcount >= bufs.len()); + } + assert_eq!(altout, writeout.contents); + assert_eq!(writeout.contents, expected); +} diff --git a/tokio-util/tests/io_sink_writer.rs b/tokio-util/tests/io_sink_writer.rs new file mode 100644 index 00000000..e76870be --- /dev/null +++ b/tokio-util/tests/io_sink_writer.rs @@ -0,0 +1,72 @@ +#![warn(rust_2018_idioms)] + +use bytes::Bytes; +use futures_util::SinkExt; +use std::io::{self, Error, ErrorKind}; +use tokio::io::AsyncWriteExt; +use tokio_util::codec::{Encoder, FramedWrite}; +use tokio_util::io::{CopyToBytes, SinkWriter}; +use tokio_util::sync::PollSender; + +#[tokio::test] +async fn test_copied_sink_writer() -> Result<(), Error> { + // Construct a channel pair to send data across and wrap a pollable sink. + // Note that the sink must mimic a writable object, e.g. have `std::io::Error` + // as its error type. + // As `PollSender` requires an owned copy of the buffer, we wrap it additionally + // with a `CopyToBytes` helper. + let (tx, mut rx) = tokio::sync::mpsc::channel::(1); + let mut writer = SinkWriter::new(CopyToBytes::new( + PollSender::new(tx).sink_map_err(|_| io::Error::from(ErrorKind::BrokenPipe)), + )); + + // Write data to our interface... + let data: [u8; 4] = [1, 2, 3, 4]; + let _ = writer.write(&data).await; + + // ... and receive it. + assert_eq!(data.to_vec(), rx.recv().await.unwrap().to_vec()); + + Ok(()) +} + +/// A trivial encoder. +struct SliceEncoder; + +impl SliceEncoder { + fn new() -> Self { + Self {} + } +} + +impl<'a> Encoder<&'a [u8]> for SliceEncoder { + type Error = Error; + + fn encode(&mut self, item: &'a [u8], dst: &mut bytes::BytesMut) -> Result<(), Self::Error> { + // This is where we'd write packet headers, lengths, etc. in a real encoder. + // For simplicity and demonstration purposes, we just pack a copy of + // the slice at the end of a buffer. + dst.extend_from_slice(item); + Ok(()) + } +} + +#[tokio::test] +async fn test_direct_sink_writer() -> Result<(), Error> { + // We define a framed writer which accepts byte slices + // and 'reverse' this construction immediately. + let framed_byte_lc = FramedWrite::new(Vec::new(), SliceEncoder::new()); + let mut writer = SinkWriter::new(framed_byte_lc); + + // Write multiple slices to the sink... + let _ = writer.write(&[1, 2, 3]).await; + let _ = writer.write(&[4, 5, 6]).await; + + // ... and compare it with the buffer. + assert_eq!( + writer.into_inner().write_buffer().to_vec().as_slice(), + &[1, 2, 3, 4, 5, 6] + ); + + Ok(()) +} diff --git a/tokio-util/tests/io_sync_bridge.rs b/tokio-util/tests/io_sync_bridge.rs index 0d420857..76bbd0b4 100644 --- a/tokio-util/tests/io_sync_bridge.rs +++ b/tokio-util/tests/io_sync_bridge.rs @@ -1,8 +1,9 @@ #![cfg(feature = "io-util")] +#![cfg(not(target_os = "wasi"))] // Wasi doesn't support threads use std::error::Error; -use std::io::{Cursor, Read, Result as IoResult}; -use tokio::io::AsyncRead; +use std::io::{Cursor, Read, Result as IoResult, Write}; +use tokio::io::{AsyncRead, AsyncReadExt}; use tokio_util::io::SyncIoBridge; async fn test_reader_len( @@ -41,3 +42,21 @@ async fn test_async_write_to_sync() -> Result<(), Box> { assert_eq!(dest.as_slice(), src); Ok(()) } + +#[tokio::test] +async fn test_shutdown() -> Result<(), Box> { + let (s1, mut s2) = tokio::io::duplex(1024); + let (_rh, wh) = tokio::io::split(s1); + tokio::task::spawn_blocking(move || -> std::io::Result<_> { + let mut wh = SyncIoBridge::new(wh); + wh.write_all(b"hello")?; + wh.shutdown()?; + assert!(wh.write_all(b" world").is_err()); + Ok(()) + }) + .await??; + let mut buf = vec![]; + s2.read_to_end(&mut buf).await?; + assert_eq!(buf, b"hello"); + Ok(()) +} diff --git a/tokio-util/tests/panic.rs b/tokio-util/tests/panic.rs index fbaab5f2..e4fcb47e 100644 --- a/tokio-util/tests/panic.rs +++ b/tokio-util/tests/panic.rs @@ -1,5 +1,5 @@ #![warn(rust_2018_idioms)] -#![cfg(feature = "full")] +#![cfg(all(feature = "full", not(target_os = "wasi")))] // Wasi doesn't support panic recovery use parking_lot::{const_mutex, Mutex}; use std::error::Error; diff --git a/tokio-util/tests/poll_semaphore.rs b/tokio-util/tests/poll_semaphore.rs index 50f36dd8..28beca19 100644 --- a/tokio-util/tests/poll_semaphore.rs +++ b/tokio-util/tests/poll_semaphore.rs @@ -13,6 +13,14 @@ fn semaphore_poll( tokio_test::task::spawn(fut) } +fn semaphore_poll_many( + sem: &mut PollSemaphore, + permits: u32, +) -> tokio_test::task::Spawn + '_> { + let fut = futures::future::poll_fn(move |cx| sem.poll_acquire_many(cx, permits)); + tokio_test::task::spawn(fut) +} + #[tokio::test] async fn it_works() { let sem = Arc::new(Semaphore::new(1)); @@ -34,3 +42,43 @@ async fn it_works() { assert!(semaphore_poll(&mut poll_sem).await.is_none()); assert!(semaphore_poll(&mut poll_sem).await.is_none()); } + +#[tokio::test] +async fn can_acquire_many_permits() { + let sem = Arc::new(Semaphore::new(4)); + let mut poll_sem = PollSemaphore::new(sem.clone()); + + let permit1 = semaphore_poll(&mut poll_sem).poll(); + assert!(matches!(permit1, Poll::Ready(Some(_)))); + + let permit2 = semaphore_poll_many(&mut poll_sem, 2).poll(); + assert!(matches!(permit2, Poll::Ready(Some(_)))); + + assert_eq!(sem.available_permits(), 1); + + drop(permit2); + + let mut permit4 = semaphore_poll_many(&mut poll_sem, 4); + assert!(permit4.poll().is_pending()); + + drop(permit1); + + let permit4 = permit4.poll(); + assert!(matches!(permit4, Poll::Ready(Some(_)))); + assert_eq!(sem.available_permits(), 0); +} + +#[tokio::test] +async fn can_poll_different_amounts_of_permits() { + let sem = Arc::new(Semaphore::new(4)); + let mut poll_sem = PollSemaphore::new(sem.clone()); + assert!(semaphore_poll_many(&mut poll_sem, 5).poll().is_pending()); + assert!(semaphore_poll_many(&mut poll_sem, 4).poll().is_ready()); + + let permit = sem.acquire_many(4).await.unwrap(); + assert!(semaphore_poll_many(&mut poll_sem, 5).poll().is_pending()); + assert!(semaphore_poll_many(&mut poll_sem, 4).poll().is_pending()); + drop(permit); + assert!(semaphore_poll_many(&mut poll_sem, 5).poll().is_pending()); + assert!(semaphore_poll_many(&mut poll_sem, 4).poll().is_ready()); +} diff --git a/tokio-util/tests/spawn_pinned.rs b/tokio-util/tests/spawn_pinned.rs index ac68b7f3..9ea8cd27 100644 --- a/tokio-util/tests/spawn_pinned.rs +++ b/tokio-util/tests/spawn_pinned.rs @@ -1,4 +1,5 @@ #![warn(rust_2018_idioms)] +#![cfg(not(target_os = "wasi"))] // Wasi doesn't support threads use std::rc::Rc; use std::sync::Arc; @@ -81,8 +82,8 @@ async fn task_panic_propagates() { assert!(result.is_err()); let error = result.unwrap_err(); assert!(error.is_panic()); - let panic_str: &str = *error.into_panic().downcast().unwrap(); - assert_eq!(panic_str, "Test panic"); + let panic_str = error.into_panic().downcast::<&'static str>().unwrap(); + assert_eq!(*panic_str, "Test panic"); // Trying again with a "safe" task still works let join_handle = pool.spawn_pinned(|| async { "test" }); @@ -107,8 +108,8 @@ async fn callback_panic_does_not_kill_worker() { assert!(result.is_err()); let error = result.unwrap_err(); assert!(error.is_panic()); - let panic_str: &str = *error.into_panic().downcast().unwrap(); - assert_eq!(panic_str, "Test panic"); + let panic_str = error.into_panic().downcast::<&'static str>().unwrap(); + assert_eq!(*panic_str, "Test panic"); // Trying again with a "safe" callback works let join_handle = pool.spawn_pinned(|| async { "test" }); diff --git a/tokio-util/tests/sync_cancellation_token.rs b/tokio-util/tests/sync_cancellation_token.rs index 28ba284b..279d74fd 100644 --- a/tokio-util/tests/sync_cancellation_token.rs +++ b/tokio-util/tests/sync_cancellation_token.rs @@ -39,6 +39,56 @@ fn cancel_token() { ); } +#[test] +fn cancel_token_owned() { + let (waker, wake_counter) = new_count_waker(); + let token = CancellationToken::new(); + assert!(!token.is_cancelled()); + + let wait_fut = token.clone().cancelled_owned(); + pin!(wait_fut); + + assert_eq!( + Poll::Pending, + wait_fut.as_mut().poll(&mut Context::from_waker(&waker)) + ); + assert_eq!(wake_counter, 0); + + let wait_fut_2 = token.clone().cancelled_owned(); + pin!(wait_fut_2); + + token.cancel(); + assert_eq!(wake_counter, 1); + assert!(token.is_cancelled()); + + assert_eq!( + Poll::Ready(()), + wait_fut.as_mut().poll(&mut Context::from_waker(&waker)) + ); + assert_eq!( + Poll::Ready(()), + wait_fut_2.as_mut().poll(&mut Context::from_waker(&waker)) + ); +} + +#[test] +fn cancel_token_owned_drop_test() { + let (waker, wake_counter) = new_count_waker(); + let token = CancellationToken::new(); + + let future = token.cancelled_owned(); + pin!(future); + + assert_eq!( + Poll::Pending, + future.as_mut().poll(&mut Context::from_waker(&waker)) + ); + assert_eq!(wake_counter, 0); + + // let future be dropped while pinned and under pending state to + // find potential memory related bugs. +} + #[test] fn cancel_child_token_through_parent() { let (waker, wake_counter) = new_count_waker(); @@ -206,9 +256,6 @@ fn create_child_token_after_parent_was_cancelled() { parent_fut.as_mut().poll(&mut Context::from_waker(&waker)) ); assert_eq!(wake_counter, 0); - - drop(child_fut); - drop(parent_fut); } if drop_child_first { @@ -258,7 +305,7 @@ fn cancel_only_all_descendants() { let child2_token = token.child_token(); let grandchild_token = child1_token.child_token(); let grandchild2_token = child1_token.child_token(); - let grandgrandchild_token = grandchild_token.child_token(); + let great_grandchild_token = grandchild_token.child_token(); assert!(!parent_token.is_cancelled()); assert!(!token.is_cancelled()); @@ -267,7 +314,7 @@ fn cancel_only_all_descendants() { assert!(!child2_token.is_cancelled()); assert!(!grandchild_token.is_cancelled()); assert!(!grandchild2_token.is_cancelled()); - assert!(!grandgrandchild_token.is_cancelled()); + assert!(!great_grandchild_token.is_cancelled()); let parent_fut = parent_token.cancelled(); let fut = token.cancelled(); @@ -276,7 +323,7 @@ fn cancel_only_all_descendants() { let child2_fut = child2_token.cancelled(); let grandchild_fut = grandchild_token.cancelled(); let grandchild2_fut = grandchild2_token.cancelled(); - let grandgrandchild_fut = grandgrandchild_token.cancelled(); + let great_grandchild_fut = great_grandchild_token.cancelled(); pin!(parent_fut); pin!(fut); @@ -285,7 +332,7 @@ fn cancel_only_all_descendants() { pin!(child2_fut); pin!(grandchild_fut); pin!(grandchild2_fut); - pin!(grandgrandchild_fut); + pin!(great_grandchild_fut); assert_eq!( Poll::Pending, @@ -321,7 +368,7 @@ fn cancel_only_all_descendants() { ); assert_eq!( Poll::Pending, - grandgrandchild_fut + great_grandchild_fut .as_mut() .poll(&mut Context::from_waker(&waker)) ); @@ -339,7 +386,7 @@ fn cancel_only_all_descendants() { assert!(child2_token.is_cancelled()); assert!(grandchild_token.is_cancelled()); assert!(grandchild2_token.is_cancelled()); - assert!(grandgrandchild_token.is_cancelled()); + assert!(great_grandchild_token.is_cancelled()); assert_eq!( Poll::Ready(()), @@ -367,7 +414,7 @@ fn cancel_only_all_descendants() { ); assert_eq!( Poll::Ready(()), - grandgrandchild_fut + great_grandchild_fut .as_mut() .poll(&mut Context::from_waker(&waker)) ); diff --git a/tokio-util/tests/time_delay_queue.rs b/tokio-util/tests/time_delay_queue.rs index cb163adf..9ceae343 100644 --- a/tokio-util/tests/time_delay_queue.rs +++ b/tokio-util/tests/time_delay_queue.rs @@ -1,4 +1,4 @@ -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_names)] #![warn(rust_2018_idioms)] #![cfg(feature = "full")] @@ -778,6 +778,7 @@ async fn compact_change_deadline() { assert!(entry.is_none()); } +#[cfg_attr(target_os = "wasi", ignore = "FIXME: Does not seem to work with WASI")] #[tokio::test(start_paused = true)] async fn remove_after_compact() { let now = Instant::now(); @@ -794,6 +795,7 @@ async fn remove_after_compact() { assert!(panic.is_err()); } +#[cfg_attr(target_os = "wasi", ignore = "FIXME: Does not seem to work with WASI")] #[tokio::test(start_paused = true)] async fn remove_after_compact_poll() { let now = Instant::now(); diff --git a/tokio-util/tests/udp.rs b/tokio-util/tests/udp.rs index b9436a30..1b998063 100644 --- a/tokio-util/tests/udp.rs +++ b/tokio-util/tests/udp.rs @@ -1,4 +1,5 @@ #![warn(rust_2018_idioms)] +#![cfg(not(target_os = "wasi"))] // Wasi doesn't support UDP use tokio::net::UdpSocket; use tokio_stream::StreamExt; diff --git a/tokio/CHANGELOG.md b/tokio/CHANGELOG.md index 3758fc44..39a57fde 100644 --- a/tokio/CHANGELOG.md +++ b/tokio/CHANGELOG.md @@ -1,3 +1,367 @@ +# 1.25.0 (January 28, 2023) + +### Fixed + +- rt: fix runtime metrics reporting ([#5330]) + +### Added + +- sync: add `broadcast::Sender::len` ([#5343]) + +### Changed + +- fs: increase maximum read buffer size to 2MiB ([#5397]) + +[#5330]: https://github.com/tokio-rs/tokio/pull/5330 +[#5343]: https://github.com/tokio-rs/tokio/pull/5343 +[#5397]: https://github.com/tokio-rs/tokio/pull/5397 + +# 1.24.2 (January 17, 2023) + +Forward ports 1.18.5 changes. + +### Fixed + +- io: fix unsoundness in `ReadHalf::unsplit` ([#5375]) + +[#5375]: https://github.com/tokio-rs/tokio/pull/5375 + +# 1.24.1 (January 6, 2022) + +This release fixes a compilation failure on targets without `AtomicU64` when using rustc older than 1.63. ([#5356]) + +[#5356]: https://github.com/tokio-rs/tokio/pull/5356 + +# 1.24.0 (January 5, 2022) + +### Fixed + - rt: improve native `AtomicU64` support detection ([#5284]) + +### Added + - rt: add configuration option for max number of I/O events polled from the OS + per tick ([#5186]) + - rt: add an environment variable for configuring the default number of worker + threads per runtime instance ([#4250]) + +### Changed + - sync: reduce MPSC channel stack usage ([#5294]) + - io: reduce lock contention in I/O operations ([#5300]) + - fs: speed up `read_dir()` by chunking operations ([#5309]) + - rt: use internal `ThreadId` implementation ([#5329]) + - test: don't auto-advance time when a `spawn_blocking` task is running ([#5115]) + +[#5186]: https://github.com/tokio-rs/tokio/pull/5186 +[#5294]: https://github.com/tokio-rs/tokio/pull/5294 +[#5284]: https://github.com/tokio-rs/tokio/pull/5284 +[#4250]: https://github.com/tokio-rs/tokio/pull/4250 +[#5300]: https://github.com/tokio-rs/tokio/pull/5300 +[#5329]: https://github.com/tokio-rs/tokio/pull/5329 +[#5115]: https://github.com/tokio-rs/tokio/pull/5115 +[#5309]: https://github.com/tokio-rs/tokio/pull/5309 + +# 1.23.1 (January 4, 2022) + +This release forward ports changes from 1.18.4. + +### Fixed + +- net: fix Windows named pipe server builder to maintain option when toggling + pipe mode ([#5336]). + +[#5336]: https://github.com/tokio-rs/tokio/pull/5336 + +# 1.23.0 (December 5, 2022) + +### Fixed + + - net: fix Windows named pipe connect ([#5208]) + - io: support vectored writes for `ChildStdin` ([#5216]) + - io: fix `async fn ready()` false positive for OS-specific events ([#5231]) + + ### Changed + - runtime: `yield_now` defers task until after driver poll ([#5223]) + - runtime: reduce amount of codegen needed per spawned task ([#5213]) + - windows: replace `winapi` dependency with `windows-sys` ([#5204]) + + [#5208]: https://github.com/tokio-rs/tokio/pull/5208 + [#5216]: https://github.com/tokio-rs/tokio/pull/5216 + [#5213]: https://github.com/tokio-rs/tokio/pull/5213 + [#5204]: https://github.com/tokio-rs/tokio/pull/5204 + [#5223]: https://github.com/tokio-rs/tokio/pull/5223 + [#5231]: https://github.com/tokio-rs/tokio/pull/5231 + +# 1.22.0 (November 17, 2022) + +### Added + - runtime: add `Handle::runtime_flavor` ([#5138]) + - sync: add `Mutex::blocking_lock_owned` ([#5130]) + - sync: add `Semaphore::MAX_PERMITS` ([#5144]) + - sync: add `merge()` to semaphore permits ([#4948]) + - sync: add `mpsc::WeakUnboundedSender` ([#5189]) + +### Added (unstable) + + - process: add `Command::process_group` ([#5114]) + - runtime: export metrics about the blocking thread pool ([#5161]) + - task: add `task::id()` and `task::try_id()` ([#5171]) + +### Fixed + - macros: don't take ownership of futures in macros ([#5087]) + - runtime: fix Stacked Borrows violation in `LocalOwnedTasks` ([#5099]) + - runtime: mitigate ABA with 32-bit queue indices when possible ([#5042]) + - task: wake local tasks to the local queue when woken by the same thread ([#5095]) + - time: panic in release mode when `mark_pending` called illegally ([#5093]) + - runtime: fix typo in expect message ([#5169]) + - runtime: fix `unsync_load` on atomic types ([#5175]) + - task: elaborate safety comments in task deallocation ([#5172]) + - runtime: fix `LocalSet` drop in thread local ([#5179]) + - net: remove libc type leakage in a public API ([#5191]) + - runtime: update the alignment of `CachePadded` ([#5106]) + +### Changed + - io: make `tokio::io::copy` continue filling the buffer when writer stalls ([#5066]) + - runtime: remove `coop::budget` from `LocalSet::run_until` ([#5155]) + - sync: make `Notify` panic safe ([#5154]) + +### Documented + - io: fix doc for `write_i8` to use signed integers ([#5040]) + - net: fix doc typos for TCP and UDP `set_tos` methods ([#5073]) + - net: fix function name in `UdpSocket::recv` documentation ([#5150]) + - sync: typo in `TryLockError` for `RwLock::try_write` ([#5160]) + - task: document that spawned tasks execute immediately ([#5117]) + - time: document return type of `timeout` ([#5118]) + - time: document that `timeout` checks only before poll ([#5126]) + - sync: specify return type of `oneshot::Receiver` in docs ([#5198]) + +### Internal changes + - runtime: use const `Mutex::new` for globals ([#5061]) + - runtime: remove `Option` around `mio::Events` in io driver ([#5078]) + - runtime: remove a conditional compilation clause ([#5104]) + - runtime: remove a reference to internal time handle ([#5107]) + - runtime: misc time driver cleanup ([#5120]) + - runtime: move signal driver to runtime module ([#5121]) + - runtime: signal driver now uses I/O driver directly ([#5125]) + - runtime: start decoupling I/O driver and I/O handle ([#5127]) + - runtime: switch `io::handle` refs with scheduler:Handle ([#5128]) + - runtime: remove Arc from I/O driver ([#5134]) + - runtime: use signal driver handle via `scheduler::Handle` ([#5135]) + - runtime: move internal clock fns out of context ([#5139]) + - runtime: remove `runtime::context` module ([#5140]) + - runtime: keep driver cfgs in `driver.rs` ([#5141]) + - runtime: add `runtime::context` to unify thread-locals ([#5143]) + - runtime: rename some confusing internal variables/fns ([#5151]) + - runtime: move `coop` mod into `runtime` ([#5152]) + - runtime: move budget state to context thread-local ([#5157]) + - runtime: move park logic into runtime module ([#5158]) + - runtime: move `Runtime` into its own file ([#5159]) + - runtime: unify entering a runtime with `Handle::enter` ([#5163]) + - runtime: remove handle reference from each scheduler ([#5166]) + - runtime: move `enter` into `context` ([#5167]) + - runtime: combine context and entered thread-locals ([#5168]) + - runtime: fix accidental unsetting of current handle ([#5178]) + - runtime: move `CoreStage` methods to `Core` ([#5182]) + - sync: name mpsc semaphore types ([#5146]) + +[#4948]: https://github.com/tokio-rs/tokio/pull/4948 +[#5040]: https://github.com/tokio-rs/tokio/pull/5040 +[#5042]: https://github.com/tokio-rs/tokio/pull/5042 +[#5061]: https://github.com/tokio-rs/tokio/pull/5061 +[#5066]: https://github.com/tokio-rs/tokio/pull/5066 +[#5073]: https://github.com/tokio-rs/tokio/pull/5073 +[#5078]: https://github.com/tokio-rs/tokio/pull/5078 +[#5087]: https://github.com/tokio-rs/tokio/pull/5087 +[#5093]: https://github.com/tokio-rs/tokio/pull/5093 +[#5095]: https://github.com/tokio-rs/tokio/pull/5095 +[#5099]: https://github.com/tokio-rs/tokio/pull/5099 +[#5104]: https://github.com/tokio-rs/tokio/pull/5104 +[#5106]: https://github.com/tokio-rs/tokio/pull/5106 +[#5107]: https://github.com/tokio-rs/tokio/pull/5107 +[#5114]: https://github.com/tokio-rs/tokio/pull/5114 +[#5117]: https://github.com/tokio-rs/tokio/pull/5117 +[#5118]: https://github.com/tokio-rs/tokio/pull/5118 +[#5120]: https://github.com/tokio-rs/tokio/pull/5120 +[#5121]: https://github.com/tokio-rs/tokio/pull/5121 +[#5125]: https://github.com/tokio-rs/tokio/pull/5125 +[#5126]: https://github.com/tokio-rs/tokio/pull/5126 +[#5127]: https://github.com/tokio-rs/tokio/pull/5127 +[#5128]: https://github.com/tokio-rs/tokio/pull/5128 +[#5130]: https://github.com/tokio-rs/tokio/pull/5130 +[#5134]: https://github.com/tokio-rs/tokio/pull/5134 +[#5135]: https://github.com/tokio-rs/tokio/pull/5135 +[#5138]: https://github.com/tokio-rs/tokio/pull/5138 +[#5138]: https://github.com/tokio-rs/tokio/pull/5138 +[#5139]: https://github.com/tokio-rs/tokio/pull/5139 +[#5140]: https://github.com/tokio-rs/tokio/pull/5140 +[#5141]: https://github.com/tokio-rs/tokio/pull/5141 +[#5143]: https://github.com/tokio-rs/tokio/pull/5143 +[#5144]: https://github.com/tokio-rs/tokio/pull/5144 +[#5144]: https://github.com/tokio-rs/tokio/pull/5144 +[#5146]: https://github.com/tokio-rs/tokio/pull/5146 +[#5150]: https://github.com/tokio-rs/tokio/pull/5150 +[#5151]: https://github.com/tokio-rs/tokio/pull/5151 +[#5152]: https://github.com/tokio-rs/tokio/pull/5152 +[#5154]: https://github.com/tokio-rs/tokio/pull/5154 +[#5155]: https://github.com/tokio-rs/tokio/pull/5155 +[#5157]: https://github.com/tokio-rs/tokio/pull/5157 +[#5158]: https://github.com/tokio-rs/tokio/pull/5158 +[#5159]: https://github.com/tokio-rs/tokio/pull/5159 +[#5160]: https://github.com/tokio-rs/tokio/pull/5160 +[#5161]: https://github.com/tokio-rs/tokio/pull/5161 +[#5163]: https://github.com/tokio-rs/tokio/pull/5163 +[#5166]: https://github.com/tokio-rs/tokio/pull/5166 +[#5167]: https://github.com/tokio-rs/tokio/pull/5167 +[#5168]: https://github.com/tokio-rs/tokio/pull/5168 +[#5169]: https://github.com/tokio-rs/tokio/pull/5169 +[#5171]: https://github.com/tokio-rs/tokio/pull/5171 +[#5172]: https://github.com/tokio-rs/tokio/pull/5172 +[#5175]: https://github.com/tokio-rs/tokio/pull/5175 +[#5178]: https://github.com/tokio-rs/tokio/pull/5178 +[#5179]: https://github.com/tokio-rs/tokio/pull/5179 +[#5182]: https://github.com/tokio-rs/tokio/pull/5182 +[#5189]: https://github.com/tokio-rs/tokio/pull/5189 +[#5191]: https://github.com/tokio-rs/tokio/pull/5191 +[#5198]: https://github.com/tokio-rs/tokio/pull/5198 + +# 1.21.2 (September 27, 2022) + +This release removes the dependency on the `once_cell` crate to restore the MSRV +of 1.21.x, which is the latest minor version at the time of release. ([#5048]) + +[#5048]: https://github.com/tokio-rs/tokio/pull/5048 + +# 1.21.1 (September 13, 2022) + +### Fixed + +- net: fix dependency resolution for socket2 ([#5000]) +- task: ignore failure to set TLS in `LocalSet` Drop ([#4976]) + +[#4976]: https://github.com/tokio-rs/tokio/pull/4976 +[#5000]: https://github.com/tokio-rs/tokio/pull/5000 + +# 1.21.0 (September 2, 2022) + +This release is the first release of Tokio to intentionally support WASM. The +`sync,macros,io-util,rt,time` features are stabilized on WASM. Additionally the +wasm32-wasi target is given unstable support for the `net` feature. + +### Added + +- net: add `device` and `bind_device` methods to TCP/UDP sockets ([#4882]) +- net: add `tos` and `set_tos` methods to TCP and UDP sockets ([#4877]) +- net: add security flags to named pipe `ServerOptions` ([#4845]) +- signal: add more windows signal handlers ([#4924]) +- sync: add `mpsc::Sender::max_capacity` method ([#4904]) +- sync: implement Weak version of `mpsc::Sender` ([#4595]) +- task: add `LocalSet::enter` ([#4765]) +- task: stabilize `JoinSet` and `AbortHandle` ([#4920]) +- tokio: add `track_caller` to public APIs ([#4805], [#4848], [#4852]) +- wasm: initial support for `wasm32-wasi` target ([#4716]) + +### Fixed + +- miri: improve miri compatibility by avoiding temporary references in `linked_list::Link` impls ([#4841]) +- signal: don't register write interest on signal pipe ([#4898]) +- sync: add `#[must_use]` to lock guards ([#4886]) +- sync: fix hang when calling `recv` on closed and reopened broadcast channel ([#4867]) +- task: propagate attributes on task-locals ([#4837]) + +### Changed + +- fs: change panic to error in `File::start_seek` ([#4897]) +- io: reduce syscalls in `poll_read` ([#4840]) +- process: use blocking threadpool for child stdio I/O ([#4824]) +- signal: make `SignalKind` methods const ([#4956]) + +### Internal changes + +- rt: extract `basic_scheduler::Config` ([#4935]) +- rt: move I/O driver into `runtime` module ([#4942]) +- rt: rename internal scheduler types ([#4945]) + +### Documented + +- chore: fix typos and grammar ([#4858], [#4894], [#4928]) +- io: fix typo in `AsyncSeekExt::rewind` docs ([#4893]) +- net: add documentation to `try_read()` for zero-length buffers ([#4937]) +- runtime: remove incorrect panic section for `Builder::worker_threads` ([#4849]) +- sync: doc of `watch::Sender::send` improved ([#4959]) +- task: add cancel safety docs to `JoinHandle` ([#4901]) +- task: expand on cancellation of `spawn_blocking` ([#4811]) +- time: clarify that the first tick of `Interval::tick` happens immediately ([#4951]) + +### Unstable + +- rt: add unstable option to disable the LIFO slot ([#4936]) +- task: fix incorrect signature in `Builder::spawn_on` ([#4953]) +- task: make `task::Builder::spawn*` methods fallible ([#4823]) + +[#4595]: https://github.com/tokio-rs/tokio/pull/4595 +[#4716]: https://github.com/tokio-rs/tokio/pull/4716 +[#4765]: https://github.com/tokio-rs/tokio/pull/4765 +[#4805]: https://github.com/tokio-rs/tokio/pull/4805 +[#4811]: https://github.com/tokio-rs/tokio/pull/4811 +[#4823]: https://github.com/tokio-rs/tokio/pull/4823 +[#4824]: https://github.com/tokio-rs/tokio/pull/4824 +[#4837]: https://github.com/tokio-rs/tokio/pull/4837 +[#4840]: https://github.com/tokio-rs/tokio/pull/4840 +[#4841]: https://github.com/tokio-rs/tokio/pull/4841 +[#4845]: https://github.com/tokio-rs/tokio/pull/4845 +[#4848]: https://github.com/tokio-rs/tokio/pull/4848 +[#4849]: https://github.com/tokio-rs/tokio/pull/4849 +[#4852]: https://github.com/tokio-rs/tokio/pull/4852 +[#4858]: https://github.com/tokio-rs/tokio/pull/4858 +[#4867]: https://github.com/tokio-rs/tokio/pull/4867 +[#4877]: https://github.com/tokio-rs/tokio/pull/4877 +[#4882]: https://github.com/tokio-rs/tokio/pull/4882 +[#4886]: https://github.com/tokio-rs/tokio/pull/4886 +[#4893]: https://github.com/tokio-rs/tokio/pull/4893 +[#4894]: https://github.com/tokio-rs/tokio/pull/4894 +[#4897]: https://github.com/tokio-rs/tokio/pull/4897 +[#4898]: https://github.com/tokio-rs/tokio/pull/4898 +[#4901]: https://github.com/tokio-rs/tokio/pull/4901 +[#4904]: https://github.com/tokio-rs/tokio/pull/4904 +[#4920]: https://github.com/tokio-rs/tokio/pull/4920 +[#4924]: https://github.com/tokio-rs/tokio/pull/4924 +[#4928]: https://github.com/tokio-rs/tokio/pull/4928 +[#4935]: https://github.com/tokio-rs/tokio/pull/4935 +[#4936]: https://github.com/tokio-rs/tokio/pull/4936 +[#4937]: https://github.com/tokio-rs/tokio/pull/4937 +[#4942]: https://github.com/tokio-rs/tokio/pull/4942 +[#4945]: https://github.com/tokio-rs/tokio/pull/4945 +[#4951]: https://github.com/tokio-rs/tokio/pull/4951 +[#4953]: https://github.com/tokio-rs/tokio/pull/4953 +[#4956]: https://github.com/tokio-rs/tokio/pull/4956 +[#4959]: https://github.com/tokio-rs/tokio/pull/4959 + +# 1.20.4 (January 17, 2023) + +Forward ports 1.18.5 changes. + +### Fixed + +- io: fix unsoundness in `ReadHalf::unsplit` ([#5375]) + +[#5375]: https://github.com/tokio-rs/tokio/pull/5375 + +# 1.20.3 (January 3, 2022) + +This release forward ports changes from 1.18.4. + +### Fixed + +- net: fix Windows named pipe server builder to maintain option when toggling + pipe mode ([#5336]). + +[#5336]: https://github.com/tokio-rs/tokio/pull/5336 + +# 1.20.2 (September 27, 2022) + +This release removes the dependency on the `once_cell` crate to restore the MSRV +of the 1.20.x LTS release. ([#5048]) + +[#5048]: https://github.com/tokio-rs/tokio/pull/5048 + # 1.20.1 (July 25, 2022) ### Fixed @@ -116,6 +480,30 @@ This release fixes a bug in `Notified::enable`. ([#4747]) [#4729]: https://github.com/tokio-rs/tokio/pull/4729 [#4739]: https://github.com/tokio-rs/tokio/pull/4739 +# 1.18.5 (January 17, 2023) + +### Fixed + +- io: fix unsoundness in `ReadHalf::unsplit` ([#5375]) + +[#5375]: https://github.com/tokio-rs/tokio/pull/5375 + +# 1.18.4 (January 3, 2022) + +### Fixed + +- net: fix Windows named pipe server builder to maintain option when toggling + pipe mode ([#5336]). + +[#5336]: https://github.com/tokio-rs/tokio/pull/5336 + +# 1.18.3 (September 27, 2022) + +This release removes the dependency on the `once_cell` crate to restore the MSRV +of the 1.18.x LTS release. ([#5048]) + +[#5048]: https://github.com/tokio-rs/tokio/pull/5048 + # 1.18.2 (May 5, 2022) Add missing features for the `winapi` dependency. ([#4663]) @@ -236,7 +624,7 @@ performance improvements. - time: use bit manipulation instead of modulo to improve performance ([#4480]) - net: use `std::future::Ready` instead of our own `Ready` future ([#4271]) - replace deprecated `atomic::spin_loop_hint` with `hint::spin_loop` ([#4491]) -- fix miri failures in intrusive linked lists ([#4397]) +- fix miri failures in intrusive linked lists ([#4397]) ### Documented diff --git a/tokio/Cargo.toml b/tokio/Cargo.toml index 66196249..0f6d30a6 100644 --- a/tokio/Cargo.toml +++ b/tokio/Cargo.toml @@ -5,8 +5,8 @@ name = "tokio" # - Update doc url # - README.md # - Update CHANGELOG.md. -# - Create "v1.0.x" git tag. -version = "1.20.1" +# - Create "v1.x.y" git tag. +version = "1.25.0" edition = "2018" rust-version = "1.49" authors = ["Tokio Contributors "] @@ -52,44 +52,37 @@ net = [ "mio/os-ext", "mio/net", "socket2", - "winapi/fileapi", - "winapi/handleapi", - "winapi/namedpipeapi", - "winapi/winbase", - "winapi/winnt", - "winapi/minwindef", + "windows-sys/Win32_Foundation", + "windows-sys/Win32_Security", + "windows-sys/Win32_Storage_FileSystem", + "windows-sys/Win32_System_Pipes", + "windows-sys/Win32_System_SystemServices", ] process = [ "bytes", - "once_cell", "libc", "mio/os-poll", "mio/os-ext", "mio/net", "signal-hook-registry", - "winapi/handleapi", - "winapi/processthreadsapi", - "winapi/threadpoollegacyapiset", - "winapi/winbase", - "winapi/winnt", - "winapi/minwindef", + "windows-sys/Win32_Foundation", + "windows-sys/Win32_System_Threading", + "windows-sys/Win32_System_WindowsProgramming", ] # Includes basic task execution capabilities -rt = ["once_cell"] +rt = [] rt-multi-thread = [ "num_cpus", "rt", ] signal = [ - "once_cell", "libc", "mio/os-poll", "mio/net", "mio/os-ext", "signal-hook-registry", - "winapi/consoleapi", - "winapi/wincon", - "winapi/minwindef", + "windows-sys/Win32_Foundation", + "windows-sys/Win32_System_Console", ] sync = [] test-util = ["rt", "sync", "time"] @@ -110,13 +103,14 @@ pin-project-lite = "0.2.0" # Everything else is optional... bytes = { version = "1.0.0", optional = true } -once_cell = { version = "1.5.2", optional = true } memchr = { version = "2.2", optional = true } -mio = { version = "0.8.1", optional = true } -socket2 = { version = "0.4.4", optional = true, features = [ "all" ] } +mio = { version = "0.8.4", optional = true } num_cpus = { version = "1.8.0", optional = true } parking_lot = { version = "0.12.0", optional = true } +[target.'cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))'.dependencies] +socket2 = { version = "0.4.4", optional = true, features = [ "all" ] } + # Currently unstable. The API exposed by these features may be broken at any time. # Requires `--cfg tokio_unstable` to enable. [target.'cfg(tokio_unstable)'.dependencies] @@ -128,14 +122,19 @@ signal-hook-registry = { version = "1.1.1", optional = true } [target.'cfg(unix)'.dev-dependencies] libc = { version = "0.2.42" } -nix = { version = "0.24", default-features = false, features = ["fs", "socket"] } +nix = { version = "0.26", default-features = false, features = ["fs", "socket"] } -[target.'cfg(windows)'.dependencies.winapi] -version = "0.3.8" -default-features = false -features = ["std"] +[target.'cfg(windows)'.dependencies.windows-sys] +version = "0.42.0" optional = true +[target.'cfg(docsrs)'.dependencies.windows-sys] +version = "0.42.0" +features = [ + "Win32_Foundation", + "Win32_Security_Authorization", +] + [target.'cfg(windows)'.dev-dependencies.ntapi] version = "0.3.6" @@ -147,16 +146,18 @@ mockall = "0.11.1" tempfile = "3.1.0" async-stream = "0.3" -[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] +[target.'cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))'.dev-dependencies] proptest = "1" -rand = "0.8.0" socket2 = "0.4" -[target.'cfg(target_arch = "wasm32")'.dev-dependencies] +[target.'cfg(not(all(any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown")))'.dev-dependencies] +rand = "0.8.0" + +[target.'cfg(all(any(target_arch = "wasm32", target_arch = "wasm64"), not(target_os = "wasi")))'.dev-dependencies] wasm-bindgen-test = "0.3.0" [target.'cfg(target_os = "freebsd")'.dev-dependencies] -mio-aio = { version = "0.6.0", features = ["tokio"] } +mio-aio = { version = "0.7.0", features = ["tokio"] } [target.'cfg(loom)'.dev-dependencies] loom = { version = "0.5.2", features = ["futures", "checkpoint"] } diff --git a/tokio/LICENSE b/tokio/LICENSE index 8af5baf0..8bdf6bd6 100644 --- a/tokio/LICENSE +++ b/tokio/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2022 Tokio Contributors +Copyright (c) 2023 Tokio Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/tokio/README.md b/tokio/README.md index 6b16d64b..462e6e8b 100644 --- a/tokio/README.md +++ b/tokio/README.md @@ -56,7 +56,7 @@ Make sure you activated the full features of the tokio crate on Cargo.toml: ```toml [dependencies] -tokio = { version = "1.20.1", features = ["full"] } +tokio = { version = "1.25.0", features = ["full"] } ``` Then, on your main.rs: @@ -161,6 +161,16 @@ several other libraries, including: [`mio`]: https://github.com/tokio-rs/mio [`bytes`]: https://github.com/tokio-rs/bytes +## Changelog + +The Tokio repository contains multiple crates. Each crate has its own changelog. + + * `tokio` - [view changelog](https://github.com/tokio-rs/tokio/blob/master/tokio/CHANGELOG.md) + * `tokio-util` - [view changelog](https://github.com/tokio-rs/tokio/blob/master/tokio-util/CHANGELOG.md) + * `tokio-stream` - [view changelog](https://github.com/tokio-rs/tokio/blob/master/tokio-stream/CHANGELOG.md) + * `tokio-macros` - [view changelog](https://github.com/tokio-rs/tokio/blob/master/tokio-macros/CHANGELOG.md) + * `tokio-test` - [view changelog](https://github.com/tokio-rs/tokio/blob/master/tokio-test/CHANGELOG.md) + ## Supported Rust Versions