html-to-markdown 2.27.2 → 2.27.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +8 -8
- data/ext/html-to-markdown-rb/native/Cargo.toml +1 -1
- data/lib/html_to_markdown/version.rb +1 -1
- data/rust-vendor/getrandom/.cargo-checksum.json +1 -1
- data/rust-vendor/getrandom/.cargo_vcs_info.json +1 -1
- data/rust-vendor/getrandom/CHANGELOG.md +62 -43
- data/rust-vendor/getrandom/Cargo.lock +49 -56
- data/rust-vendor/getrandom/Cargo.toml +2 -2
- data/rust-vendor/getrandom/Cargo.toml.orig +2 -2
- data/rust-vendor/getrandom/src/backends/efi_rng.rs +8 -10
- data/rust-vendor/getrandom/src/backends/getentropy.rs +13 -4
- data/rust-vendor/getrandom/src/backends/linux_android_with_fallback.rs +10 -25
- data/rust-vendor/getrandom/src/backends/netbsd.rs +17 -25
- data/rust-vendor/getrandom/src/backends/rdrand.rs +15 -9
- data/rust-vendor/getrandom/src/backends/rndr.rs +2 -1
- data/rust-vendor/getrandom/src/backends/vxworks.rs +7 -3
- data/rust-vendor/getrandom/src/backends/windows.rs +21 -5
- data/rust-vendor/getrandom/src/utils/lazy_bool.rs +39 -0
- data/rust-vendor/getrandom/src/utils/lazy_ptr.rs +57 -0
- data/rust-vendor/html-to-markdown-rs/Cargo.toml +2 -2
- data/rust-vendor/html-to-markdown-rs/src/converter/text_node.rs +2 -1
- data/rust-vendor/html-to-markdown-rs/tests/issue_216_217_regressions.rs +82 -0
- data/rust-vendor/quote/.cargo-checksum.json +1 -1
- data/rust-vendor/quote/.cargo_vcs_info.json +1 -1
- data/rust-vendor/quote/.github/workflows/ci.yml +2 -2
- data/rust-vendor/quote/Cargo.lock +21 -21
- data/rust-vendor/quote/Cargo.toml +2 -2
- data/rust-vendor/quote/Cargo.toml.orig +2 -2
- data/rust-vendor/quote/README.md +0 -1
- data/rust-vendor/quote/src/lib.rs +1 -1
- data/rust-vendor/quote/src/to_tokens.rs +7 -0
- data/rust-vendor/quote/tests/ui/not-quotable.stderr +1 -1
- data/rust-vendor/quote/tests/ui/not-repeatable.stderr +3 -11
- data/rust-vendor/r-efi/.cargo-checksum.json +1 -1
- data/rust-vendor/r-efi/.cargo_vcs_info.json +1 -1
- data/rust-vendor/r-efi/AUTHORS +1 -0
- data/rust-vendor/r-efi/Cargo.lock +1 -1
- data/rust-vendor/r-efi/Cargo.toml +1 -3
- data/rust-vendor/r-efi/Cargo.toml.orig +1 -5
- data/rust-vendor/r-efi/NEWS.md +16 -0
- data/rust-vendor/r-efi/src/base.rs +1 -1
- data/rust-vendor/r-efi/src/lib.rs +27 -12
- data/rust-vendor/r-efi/src/protocols/absolute_pointer.rs +4 -4
- data/rust-vendor/r-efi/src/protocols/block_io.rs +8 -8
- data/rust-vendor/r-efi/src/protocols/bus_specific_driver_override.rs +2 -2
- data/rust-vendor/r-efi/src/protocols/debug_support.rs +10 -10
- data/rust-vendor/r-efi/src/protocols/debugport.rs +8 -8
- data/rust-vendor/r-efi/src/protocols/decompress.rs +4 -4
- data/rust-vendor/r-efi/src/protocols/device_path_from_text.rs +4 -4
- data/rust-vendor/r-efi/src/protocols/device_path_to_text.rs +4 -4
- data/rust-vendor/r-efi/src/protocols/device_path_utilities.rs +16 -16
- data/rust-vendor/r-efi/src/protocols/disk_io.rs +4 -4
- data/rust-vendor/r-efi/src/protocols/disk_io2.rs +8 -8
- data/rust-vendor/r-efi/src/protocols/driver_binding.rs +6 -6
- data/rust-vendor/r-efi/src/protocols/driver_diagnostics2.rs +2 -2
- data/rust-vendor/r-efi/src/protocols/driver_family_override.rs +2 -2
- data/rust-vendor/r-efi/src/protocols/file.rs +28 -28
- data/rust-vendor/r-efi/src/protocols/graphics_output.rs +6 -6
- data/rust-vendor/r-efi/src/protocols/hii_database.rs +24 -24
- data/rust-vendor/r-efi/src/protocols/hii_font.rs +8 -8
- data/rust-vendor/r-efi/src/protocols/hii_font_ex.rs +10 -10
- data/rust-vendor/r-efi/src/protocols/hii_string.rs +10 -10
- data/rust-vendor/r-efi/src/protocols/ip4.rs +16 -16
- data/rust-vendor/r-efi/src/protocols/ip6.rs +18 -18
- data/rust-vendor/r-efi/src/protocols/load_file.rs +2 -2
- data/rust-vendor/r-efi/src/protocols/loaded_image.rs +2 -2
- data/rust-vendor/r-efi/src/protocols/managed_network.rs +16 -16
- data/rust-vendor/r-efi/src/protocols/memory_attribute.rs +6 -6
- data/rust-vendor/r-efi/src/protocols/mp_services.rs +15 -15
- data/rust-vendor/r-efi/src/protocols/pci_io.rs +26 -26
- data/rust-vendor/r-efi/src/protocols/platform_driver_override.rs +6 -6
- data/rust-vendor/r-efi/src/protocols/rng.rs +4 -4
- data/rust-vendor/r-efi/src/protocols/service_binding.rs +4 -4
- data/rust-vendor/r-efi/src/protocols/shell.rs +81 -81
- data/rust-vendor/r-efi/src/protocols/shell_dynamic_command.rs +4 -4
- data/rust-vendor/r-efi/src/protocols/simple_file_system.rs +2 -2
- data/rust-vendor/r-efi/src/protocols/simple_network.rs +26 -26
- data/rust-vendor/r-efi/src/protocols/simple_text_input.rs +4 -4
- data/rust-vendor/r-efi/src/protocols/simple_text_input_ex.rs +11 -11
- data/rust-vendor/r-efi/src/protocols/simple_text_output.rs +18 -18
- data/rust-vendor/r-efi/src/protocols/tcp4.rs +20 -20
- data/rust-vendor/r-efi/src/protocols/tcp6.rs +18 -18
- data/rust-vendor/r-efi/src/protocols/timestamp.rs +3 -3
- data/rust-vendor/r-efi/src/protocols/udp4.rs +16 -16
- data/rust-vendor/r-efi/src/protocols/udp6.rs +14 -14
- data/rust-vendor/r-efi/src/system.rs +115 -115
- data/rust-vendor/r-efi/src/vendor/intel/console_control.rs +6 -6
- data/rust-vendor/r-efi-5.3.0/.cargo-checksum.json +1 -0
- data/rust-vendor/r-efi-5.3.0/.cargo_vcs_info.json +6 -0
- data/rust-vendor/r-efi-5.3.0/.github/workflows/publish.yml +39 -0
- data/rust-vendor/r-efi-5.3.0/.github/workflows/rust-tests.yml +125 -0
- data/rust-vendor/r-efi-5.3.0/AUTHORS +74 -0
- data/rust-vendor/r-efi-5.3.0/Cargo.lock +16 -0
- data/rust-vendor/r-efi-5.3.0/Cargo.toml +70 -0
- data/rust-vendor/r-efi-5.3.0/Cargo.toml.orig +51 -0
- data/rust-vendor/r-efi-5.3.0/Makefile +85 -0
- data/rust-vendor/r-efi-5.3.0/NEWS.md +301 -0
- data/rust-vendor/r-efi-5.3.0/README.md +99 -0
- data/rust-vendor/r-efi-5.3.0/examples/freestanding.rs +34 -0
- data/rust-vendor/r-efi-5.3.0/examples/gop-query.rs +188 -0
- data/rust-vendor/r-efi-5.3.0/examples/hello-world.rs +55 -0
- data/rust-vendor/r-efi-5.3.0/src/base.rs +993 -0
- data/rust-vendor/r-efi-5.3.0/src/hii.rs +1300 -0
- data/rust-vendor/r-efi-5.3.0/src/lib.rs +182 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/absolute_pointer.rs +69 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/block_io.rs +70 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/bus_specific_driver_override.rs +32 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/debug_support.rs +835 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/debugport.rs +42 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/decompress.rs +37 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/device_path.rs +82 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/device_path_from_text.rs +26 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/device_path_to_text.rs +30 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/device_path_utilities.rs +63 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/disk_io.rs +40 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/disk_io2.rs +58 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/driver_binding.rs +42 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/driver_diagnostics2.rs +38 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/driver_family_override.rs +23 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/file.rs +183 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/graphics_output.rs +103 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/hii_database.rs +299 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/hii_font.rs +87 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/hii_font_ex.rs +107 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/hii_package_list.rs +14 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/hii_string.rs +71 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/ip4.rs +202 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/ip6.rs +264 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/load_file.rs +26 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/load_file2.rs +15 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/loaded_image.rs +39 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/loaded_image_device_path.rs +13 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/managed_network.rs +147 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/memory_attribute.rs +40 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/mp_services.rs +121 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/pci_io.rs +203 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/platform_driver_override.rs +46 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/rng.rs +83 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/service_binding.rs +20 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/shell.rs +295 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/shell_dynamic_command.rs +33 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/shell_parameters.rs +23 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/simple_file_system.rs +26 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/simple_network.rs +196 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/simple_text_input.rs +38 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/simple_text_input_ex.rs +85 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/simple_text_output.rs +86 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/tcp4.rs +224 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/tcp6.rs +202 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/timestamp.rs +32 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/udp4.rs +151 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols/udp6.rs +137 -0
- data/rust-vendor/r-efi-5.3.0/src/protocols.rs +54 -0
- data/rust-vendor/r-efi-5.3.0/src/system.rs +1130 -0
- data/rust-vendor/r-efi-5.3.0/src/vendor/intel/console_control.rs +37 -0
- data/rust-vendor/r-efi-5.3.0/src/vendor.rs +10 -0
- data/rust-vendor/tokio/.cargo-checksum.json +1 -1
- data/rust-vendor/tokio/.cargo_vcs_info.json +1 -1
- data/rust-vendor/tokio/CHANGELOG.md +94 -0
- data/rust-vendor/tokio/Cargo.lock +1549 -0
- data/rust-vendor/tokio/Cargo.toml +96 -83
- data/rust-vendor/tokio/Cargo.toml.orig +7 -7
- data/rust-vendor/tokio/README.md +1 -1
- data/rust-vendor/tokio/src/fs/open_options.rs +4 -1
- data/rust-vendor/tokio/src/fs/read.rs +4 -1
- data/rust-vendor/tokio/src/fs/write.rs +4 -1
- data/rust-vendor/tokio/src/io/async_write.rs +3 -4
- data/rust-vendor/tokio/src/io/poll_evented.rs +23 -1
- data/rust-vendor/tokio/src/io/stderr.rs +15 -1
- data/rust-vendor/tokio/src/io/stdout.rs +14 -0
- data/rust-vendor/tokio/src/io/util/async_write_ext.rs +2 -2
- data/rust-vendor/tokio/src/io/util/write_buf.rs +11 -2
- data/rust-vendor/tokio/src/lib.rs +12 -28
- data/rust-vendor/tokio/src/macros/select.rs +6 -8
- data/rust-vendor/tokio/src/net/tcp/socket.rs +25 -1
- data/rust-vendor/tokio/src/net/tcp/stream.rs +40 -1
- data/rust-vendor/tokio/src/process/unix/pidfd_reaper.rs +1 -41
- data/rust-vendor/tokio/src/runtime/blocking/pool.rs +18 -14
- data/rust-vendor/tokio/src/runtime/builder.rs +10 -4
- data/rust-vendor/tokio/src/runtime/handle.rs +3 -2
- data/rust-vendor/tokio/src/runtime/io/driver/uring.rs +49 -61
- data/rust-vendor/tokio/src/runtime/io/driver.rs +6 -5
- data/rust-vendor/tokio/src/runtime/mod.rs +20 -1
- data/rust-vendor/tokio/src/runtime/runtime.rs +71 -1
- data/rust-vendor/tokio/src/runtime/scheduler/current_thread/mod.rs +24 -8
- data/rust-vendor/tokio/src/runtime/scheduler/multi_thread/worker.rs +5 -0
- data/rust-vendor/tokio/src/runtime/task/core.rs +1 -0
- data/rust-vendor/tokio/src/runtime/task/join.rs +7 -3
- data/rust-vendor/tokio/src/runtime/task/list.rs +5 -3
- data/rust-vendor/tokio/src/runtime/task/mod.rs +0 -5
- data/rust-vendor/tokio/src/runtime/tests/loom_blocking.rs +39 -1
- data/rust-vendor/tokio/src/signal/mod.rs +6 -17
- data/rust-vendor/tokio/src/signal/registry.rs +1 -1
- data/rust-vendor/tokio/src/signal/unix.rs +24 -44
- data/rust-vendor/tokio/src/signal/windows/sys.rs +52 -64
- data/rust-vendor/tokio/src/signal/windows.rs +35 -23
- data/rust-vendor/tokio/src/sync/mpsc/mod.rs +3 -1
- data/rust-vendor/tokio/src/sync/oneshot.rs +13 -0
- data/rust-vendor/tokio/src/sync/rwlock.rs +4 -5
- data/rust-vendor/tokio/src/sync/tests/loom_oneshot.rs +27 -1
- data/rust-vendor/tokio/src/task/blocking.rs +16 -1
- data/rust-vendor/tokio/src/task/builder.rs +2 -2
- data/rust-vendor/tokio/src/task/mod.rs +1 -1
- data/rust-vendor/tokio/src/task/spawn.rs +8 -3
- data/rust-vendor/tokio/src/task/yield_now.rs +13 -23
- data/rust-vendor/tokio/src/time/clock.rs +62 -0
- data/rust-vendor/tokio/src/util/memchr.rs +32 -4
- data/rust-vendor/tokio/src/util/sharded_list.rs +6 -4
- data/rust-vendor/tokio/tests/fs_link.rs +54 -0
- data/rust-vendor/tokio/tests/io_async_fd_memory_leak.rs +209 -0
- data/rust-vendor/tokio/tests/io_write_buf.rs +56 -0
- data/rust-vendor/tokio/tests/process_issue_7144.rs +8 -0
- data/rust-vendor/tokio/tests/rt_basic.rs +41 -0
- data/rust-vendor/tokio/tests/rt_common_before_park.rs +92 -0
- data/rust-vendor/tokio/tests/rt_metrics.rs +1 -1
- data/rust-vendor/tokio/tests/rt_panic.rs +12 -0
- data/rust-vendor/tokio/tests/rt_shutdown_err.rs +82 -0
- data/rust-vendor/tokio/tests/rt_threaded.rs +49 -1
- data/rust-vendor/tokio/tests/rt_unstable_metrics.rs +32 -0
- data/rust-vendor/tokio/tests/tcp_connect.rs +2 -3
- data/rust-vendor/tokio/tests/tcp_shutdown.rs +1 -3
- data/rust-vendor/tokio/tests/tcp_socket.rs +3 -4
- data/rust-vendor/tokio/tests/tcp_stream.rs +3 -0
- metadata +78 -3
- data/rust-vendor/getrandom/src/utils/lazy.rs +0 -64
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
//! Regression test for issue #7563 - Memory leak when fd closed before AsyncFd drop
|
|
2
|
+
//!
|
|
3
|
+
//! This test uses a custom global allocator to track actual memory usage,
|
|
4
|
+
//! avoiding false positives from RSS measurements which include freed-but-retained memory.
|
|
5
|
+
|
|
6
|
+
#![cfg(all(unix, target_os = "linux", feature = "full"))]
|
|
7
|
+
|
|
8
|
+
use std::alloc::{GlobalAlloc, Layout, System};
|
|
9
|
+
use std::sync::atomic::{AtomicUsize, Ordering};
|
|
10
|
+
|
|
11
|
+
/// A tracking allocator that counts bytes currently allocated
|
|
12
|
+
struct TrackingAllocator {
|
|
13
|
+
allocated: AtomicUsize,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
impl TrackingAllocator {
|
|
17
|
+
const fn new() -> Self {
|
|
18
|
+
Self {
|
|
19
|
+
allocated: AtomicUsize::new(0),
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
unsafe impl GlobalAlloc for TrackingAllocator {
|
|
25
|
+
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
|
26
|
+
let ptr = unsafe { System.alloc(layout) };
|
|
27
|
+
if !ptr.is_null() {
|
|
28
|
+
self.allocated.fetch_add(layout.size(), Ordering::Relaxed);
|
|
29
|
+
}
|
|
30
|
+
ptr
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
|
34
|
+
unsafe { System.dealloc(ptr, layout) };
|
|
35
|
+
self.allocated.fetch_sub(layout.size(), Ordering::Relaxed);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
|
|
39
|
+
let new_ptr = unsafe { System.realloc(ptr, layout, new_size) };
|
|
40
|
+
if !new_ptr.is_null() {
|
|
41
|
+
// Subtract old size, add new size
|
|
42
|
+
if new_size > layout.size() {
|
|
43
|
+
self.allocated
|
|
44
|
+
.fetch_add(new_size - layout.size(), Ordering::Relaxed);
|
|
45
|
+
} else {
|
|
46
|
+
self.allocated
|
|
47
|
+
.fetch_sub(layout.size() - new_size, Ordering::Relaxed);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
new_ptr
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
#[global_allocator]
|
|
55
|
+
static GLOBAL: TrackingAllocator = TrackingAllocator::new();
|
|
56
|
+
|
|
57
|
+
fn allocated_bytes() -> usize {
|
|
58
|
+
GLOBAL.allocated.load(Ordering::Relaxed)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
#[tokio::test]
|
|
62
|
+
async fn memory_leak_when_fd_closed_before_drop() {
|
|
63
|
+
use nix::sys::socket::{self, AddressFamily, SockFlag, SockType};
|
|
64
|
+
use std::os::unix::io::{AsRawFd, RawFd};
|
|
65
|
+
use std::sync::Arc;
|
|
66
|
+
use tokio::io::unix::AsyncFd;
|
|
67
|
+
|
|
68
|
+
struct RawFdWrapper {
|
|
69
|
+
fd: RawFd,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
impl AsRawFd for RawFdWrapper {
|
|
73
|
+
fn as_raw_fd(&self) -> RawFd {
|
|
74
|
+
self.fd
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
struct ArcFd(Arc<RawFdWrapper>);
|
|
79
|
+
|
|
80
|
+
impl AsRawFd for ArcFd {
|
|
81
|
+
fn as_raw_fd(&self) -> RawFd {
|
|
82
|
+
self.0.as_raw_fd()
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
fn set_nonblocking(fd: RawFd) {
|
|
87
|
+
use nix::fcntl::{OFlag, F_GETFL, F_SETFL};
|
|
88
|
+
|
|
89
|
+
let flags = nix::fcntl::fcntl(fd, F_GETFL).expect("fcntl(F_GETFL)");
|
|
90
|
+
|
|
91
|
+
if flags < 0 {
|
|
92
|
+
panic!(
|
|
93
|
+
"bad return value from fcntl(F_GETFL): {} ({:?})",
|
|
94
|
+
flags,
|
|
95
|
+
nix::Error::last()
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let flags = OFlag::from_bits_truncate(flags) | OFlag::O_NONBLOCK;
|
|
100
|
+
|
|
101
|
+
nix::fcntl::fcntl(fd, F_SETFL(flags)).expect("fcntl(F_SETFL)");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Warm up - let runtime and allocator stabilize
|
|
105
|
+
for _ in 0..100 {
|
|
106
|
+
tokio::task::yield_now().await;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const ITERATIONS: usize = 1000;
|
|
110
|
+
|
|
111
|
+
// Phase 1: Warm up allocations
|
|
112
|
+
for _ in 0..ITERATIONS {
|
|
113
|
+
let (fd_a, _fd_b) = socket::socketpair(
|
|
114
|
+
AddressFamily::Unix,
|
|
115
|
+
SockType::Stream,
|
|
116
|
+
None,
|
|
117
|
+
SockFlag::empty(),
|
|
118
|
+
)
|
|
119
|
+
.unwrap();
|
|
120
|
+
|
|
121
|
+
let raw_fd = fd_a.as_raw_fd();
|
|
122
|
+
set_nonblocking(raw_fd);
|
|
123
|
+
std::mem::forget(fd_a);
|
|
124
|
+
|
|
125
|
+
let wrapper = Arc::new(RawFdWrapper { fd: raw_fd });
|
|
126
|
+
let async_fd = AsyncFd::new(ArcFd(wrapper)).unwrap();
|
|
127
|
+
|
|
128
|
+
// Close fd before dropping AsyncFd - this triggers the bug
|
|
129
|
+
unsafe {
|
|
130
|
+
libc::close(raw_fd);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
drop(async_fd);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Let things settle
|
|
137
|
+
tokio::task::yield_now().await;
|
|
138
|
+
let baseline = allocated_bytes();
|
|
139
|
+
|
|
140
|
+
// Phase 2: Run more iterations and check for growth
|
|
141
|
+
for _ in 0..ITERATIONS {
|
|
142
|
+
let (fd_a, _fd_b) = socket::socketpair(
|
|
143
|
+
AddressFamily::Unix,
|
|
144
|
+
SockType::Stream,
|
|
145
|
+
None,
|
|
146
|
+
SockFlag::empty(),
|
|
147
|
+
)
|
|
148
|
+
.unwrap();
|
|
149
|
+
|
|
150
|
+
let raw_fd = fd_a.as_raw_fd();
|
|
151
|
+
set_nonblocking(raw_fd);
|
|
152
|
+
std::mem::forget(fd_a);
|
|
153
|
+
|
|
154
|
+
let wrapper = Arc::new(RawFdWrapper { fd: raw_fd });
|
|
155
|
+
let async_fd = AsyncFd::new(ArcFd(wrapper)).unwrap();
|
|
156
|
+
|
|
157
|
+
unsafe {
|
|
158
|
+
libc::close(raw_fd);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
drop(async_fd);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
tokio::task::yield_now().await;
|
|
165
|
+
let after_phase2 = allocated_bytes();
|
|
166
|
+
|
|
167
|
+
// Phase 3: Run even more iterations
|
|
168
|
+
for _ in 0..ITERATIONS {
|
|
169
|
+
let (fd_a, _fd_b) = socket::socketpair(
|
|
170
|
+
AddressFamily::Unix,
|
|
171
|
+
SockType::Stream,
|
|
172
|
+
None,
|
|
173
|
+
SockFlag::empty(),
|
|
174
|
+
)
|
|
175
|
+
.unwrap();
|
|
176
|
+
|
|
177
|
+
let raw_fd = fd_a.as_raw_fd();
|
|
178
|
+
set_nonblocking(raw_fd);
|
|
179
|
+
std::mem::forget(fd_a);
|
|
180
|
+
|
|
181
|
+
let wrapper = Arc::new(RawFdWrapper { fd: raw_fd });
|
|
182
|
+
let async_fd = AsyncFd::new(ArcFd(wrapper)).unwrap();
|
|
183
|
+
|
|
184
|
+
unsafe {
|
|
185
|
+
libc::close(raw_fd);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
drop(async_fd);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
tokio::task::yield_now().await;
|
|
192
|
+
let after_phase3 = allocated_bytes();
|
|
193
|
+
|
|
194
|
+
let growth_phase2 = after_phase2.saturating_sub(baseline);
|
|
195
|
+
let growth_phase3 = after_phase3.saturating_sub(after_phase2);
|
|
196
|
+
|
|
197
|
+
// If there's a leak, each phase adds ~250KB (1000 * ~256 bytes per ScheduledIo)
|
|
198
|
+
// If fixed, memory should stabilize (minimal growth between phases)
|
|
199
|
+
// Allow 64KB tolerance for normal allocation variance
|
|
200
|
+
let threshold = 64 * 1024; // 64KB
|
|
201
|
+
|
|
202
|
+
assert!(
|
|
203
|
+
growth_phase2 < threshold || growth_phase3 < threshold,
|
|
204
|
+
"Memory leak detected: allocations keep growing without stabilizing. \
|
|
205
|
+
Phase 1->2: +{growth_phase2} bytes, Phase 2->3: +{growth_phase3} bytes. \
|
|
206
|
+
(baseline: {baseline} bytes, phase2: {after_phase2} bytes, phase3: {after_phase3} bytes). \
|
|
207
|
+
Expected at least one phase with <{threshold} bytes growth.",
|
|
208
|
+
);
|
|
209
|
+
}
|
|
@@ -54,3 +54,59 @@ async fn write_all() {
|
|
|
54
54
|
assert_eq!(wr.cnt, 1);
|
|
55
55
|
assert_eq!(buf.position(), 4);
|
|
56
56
|
}
|
|
57
|
+
|
|
58
|
+
#[tokio::test]
|
|
59
|
+
async fn write_buf_vectored() {
|
|
60
|
+
struct Wr {
|
|
61
|
+
buf: BytesMut,
|
|
62
|
+
cnt: usize,
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
impl AsyncWrite for Wr {
|
|
66
|
+
fn poll_write(
|
|
67
|
+
self: Pin<&mut Self>,
|
|
68
|
+
_cx: &mut Context<'_>,
|
|
69
|
+
_buf: &[u8],
|
|
70
|
+
) -> Poll<io::Result<usize>> {
|
|
71
|
+
panic!("shouldn't be called")
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
|
75
|
+
Ok(()).into()
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
|
79
|
+
Ok(()).into()
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
fn poll_write_vectored(
|
|
83
|
+
mut self: Pin<&mut Self>,
|
|
84
|
+
_cx: &mut Context<'_>,
|
|
85
|
+
bufs: &[io::IoSlice<'_>],
|
|
86
|
+
) -> Poll<Result<usize, io::Error>> {
|
|
87
|
+
let mut n = 0;
|
|
88
|
+
for buf in bufs {
|
|
89
|
+
self.buf.extend_from_slice(buf);
|
|
90
|
+
n += buf.len();
|
|
91
|
+
}
|
|
92
|
+
self.cnt += 1;
|
|
93
|
+
Ok(n).into()
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
fn is_write_vectored(&self) -> bool {
|
|
97
|
+
true
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let mut wr = Wr {
|
|
102
|
+
buf: BytesMut::with_capacity(64),
|
|
103
|
+
cnt: 0,
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
let mut buf = Cursor::new(&b"hello world"[..]);
|
|
107
|
+
|
|
108
|
+
assert_ok!(wr.write_buf(&mut buf).await);
|
|
109
|
+
assert_eq!(wr.buf, b"hello world"[..]);
|
|
110
|
+
assert_eq!(wr.cnt, 1);
|
|
111
|
+
assert_eq!(buf.position(), 11);
|
|
112
|
+
}
|
|
@@ -17,7 +17,15 @@ async fn issue_7144() {
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
async fn has_strace() -> bool {
|
|
21
|
+
Command::new("strace").arg("-V").output().await.is_ok()
|
|
22
|
+
}
|
|
23
|
+
|
|
20
24
|
async fn test_one() {
|
|
25
|
+
if !has_strace().await {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
21
29
|
let mut t = Command::new("strace")
|
|
22
30
|
.args("-o /dev/null -D sleep 5".split(' '))
|
|
23
31
|
.spawn()
|
|
@@ -456,3 +456,44 @@ fn rt() -> Runtime {
|
|
|
456
456
|
.build()
|
|
457
457
|
.unwrap()
|
|
458
458
|
}
|
|
459
|
+
|
|
460
|
+
#[test]
|
|
461
|
+
fn before_park_yields() {
|
|
462
|
+
use futures::task::ArcWake;
|
|
463
|
+
use std::sync::Arc;
|
|
464
|
+
use tokio::runtime::Builder;
|
|
465
|
+
use tokio::sync::Notify;
|
|
466
|
+
|
|
467
|
+
struct MyWaker(Notify);
|
|
468
|
+
|
|
469
|
+
impl ArcWake for MyWaker {
|
|
470
|
+
fn wake_by_ref(arc_self: &Arc<Self>) {
|
|
471
|
+
arc_self.0.notify_one();
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
let notify = Arc::new(MyWaker(Notify::new()));
|
|
476
|
+
let notify2 = notify.clone();
|
|
477
|
+
let waker = futures::task::waker(notify2);
|
|
478
|
+
let woken = Arc::new(AtomicBool::new(false));
|
|
479
|
+
let woken2 = woken.clone();
|
|
480
|
+
|
|
481
|
+
let rt = Builder::new_current_thread()
|
|
482
|
+
.enable_all()
|
|
483
|
+
.on_thread_park(move || {
|
|
484
|
+
if !woken2.swap(true, Ordering::SeqCst) {
|
|
485
|
+
let mut cx = Context::from_waker(&waker);
|
|
486
|
+
// `yield_now` pushes the waker to the defer slot.
|
|
487
|
+
let fut = std::pin::pin!(tokio::task::yield_now());
|
|
488
|
+
let _ = fut.poll(&mut cx);
|
|
489
|
+
}
|
|
490
|
+
})
|
|
491
|
+
.build()
|
|
492
|
+
.unwrap();
|
|
493
|
+
|
|
494
|
+
rt.block_on(async {
|
|
495
|
+
notify.0.notified().await;
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
assert!(woken.load(Ordering::SeqCst));
|
|
499
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#![warn(rust_2018_idioms)]
|
|
2
|
+
#![cfg(feature = "full")]
|
|
3
|
+
#![cfg(not(target_os = "wasi"))] // Wasi doesn't support threads
|
|
4
|
+
|
|
5
|
+
use std::sync::atomic::{AtomicBool, Ordering};
|
|
6
|
+
use std::sync::Arc;
|
|
7
|
+
use tokio::runtime::Builder;
|
|
8
|
+
use tokio::sync::Notify;
|
|
9
|
+
|
|
10
|
+
#[test]
|
|
11
|
+
fn before_park_wakes_block_on_task() {
|
|
12
|
+
let notify = Arc::new(Notify::new());
|
|
13
|
+
let notify2 = notify.clone();
|
|
14
|
+
let woken = Arc::new(AtomicBool::new(false));
|
|
15
|
+
let woken2 = woken.clone();
|
|
16
|
+
|
|
17
|
+
let rt = Builder::new_current_thread()
|
|
18
|
+
.enable_all()
|
|
19
|
+
.on_thread_park(move || {
|
|
20
|
+
// Only wake once to avoid busy loop if something goes wrong,
|
|
21
|
+
// though in this test we expect it to unpark immediately.
|
|
22
|
+
if !woken2.swap(true, Ordering::SeqCst) {
|
|
23
|
+
notify2.notify_one();
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
.build()
|
|
27
|
+
.unwrap();
|
|
28
|
+
|
|
29
|
+
rt.block_on(async {
|
|
30
|
+
// This will block until `notify` is notified.
|
|
31
|
+
// `before_park` should run when the runtime is about to park.
|
|
32
|
+
// It will notify `notify`, which should wake this task.
|
|
33
|
+
// The runtime should then see the task is woken and NOT park.
|
|
34
|
+
notify.notified().await;
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
assert!(woken.load(Ordering::SeqCst));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
#[test]
|
|
41
|
+
fn before_park_spawns_task() {
|
|
42
|
+
let notify = Arc::new(Notify::new());
|
|
43
|
+
let notify2 = notify.clone();
|
|
44
|
+
let woken = Arc::new(AtomicBool::new(false));
|
|
45
|
+
let woken2 = woken.clone();
|
|
46
|
+
|
|
47
|
+
let rt = Builder::new_current_thread()
|
|
48
|
+
.enable_all()
|
|
49
|
+
.on_thread_park(move || {
|
|
50
|
+
if !woken2.swap(true, Ordering::SeqCst) {
|
|
51
|
+
let notify = notify2.clone();
|
|
52
|
+
tokio::spawn(async move {
|
|
53
|
+
notify.notify_one();
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
.build()
|
|
58
|
+
.unwrap();
|
|
59
|
+
|
|
60
|
+
rt.block_on(async {
|
|
61
|
+
// This will block until `notify` is notified.
|
|
62
|
+
// `before_park` should run when the runtime is about to park.
|
|
63
|
+
// It will spawn a task that notifies `notify`.
|
|
64
|
+
// The runtime should see the new task and NOT park.
|
|
65
|
+
// If it parks, it will deadlock.
|
|
66
|
+
notify.notified().await;
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
assert!(woken.load(Ordering::SeqCst));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
#[test]
|
|
73
|
+
fn wake_from_other_thread_block_on() {
|
|
74
|
+
let rt = Builder::new_current_thread().enable_all().build().unwrap();
|
|
75
|
+
let handle = rt.handle().clone();
|
|
76
|
+
let notify = Arc::new(Notify::new());
|
|
77
|
+
let notify2 = notify.clone();
|
|
78
|
+
|
|
79
|
+
let th = std::thread::spawn(move || {
|
|
80
|
+
// Give the main thread time to park
|
|
81
|
+
std::thread::sleep(std::time::Duration::from_millis(5));
|
|
82
|
+
handle.block_on(async move {
|
|
83
|
+
notify2.notify_one();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
rt.block_on(async {
|
|
88
|
+
notify.notified().await;
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
th.join().unwrap();
|
|
92
|
+
}
|
|
@@ -152,7 +152,7 @@ fn worker_park_unpark_count() {
|
|
|
152
152
|
let metrics = rt.metrics();
|
|
153
153
|
rt.block_on(rt.spawn(async {})).unwrap();
|
|
154
154
|
drop(rt);
|
|
155
|
-
|
|
155
|
+
assert_eq!(0, metrics.worker_park_unpark_count(0) % 2);
|
|
156
156
|
|
|
157
157
|
let rt = threaded();
|
|
158
158
|
let metrics = rt.metrics();
|
|
@@ -82,6 +82,18 @@ fn builder_global_queue_interval_panic_caller() -> Result<(), Box<dyn Error>> {
|
|
|
82
82
|
Ok(())
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
#[test]
|
|
86
|
+
fn builder_event_interval_interval_panic_caller() -> Result<(), Box<dyn Error>> {
|
|
87
|
+
let panic_location_file = test_panic(|| {
|
|
88
|
+
let _ = Builder::new_multi_thread().event_interval(0).build();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// The panic location should be in this file
|
|
92
|
+
assert_eq!(&panic_location_file.unwrap(), file!());
|
|
93
|
+
|
|
94
|
+
Ok(())
|
|
95
|
+
}
|
|
96
|
+
|
|
85
97
|
fn current_thread() -> Runtime {
|
|
86
98
|
tokio::runtime::Builder::new_current_thread()
|
|
87
99
|
.enable_all()
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#![warn(rust_2018_idioms)]
|
|
2
|
+
#![cfg(feature = "full")]
|
|
3
|
+
#![cfg(not(miri))] // No socket in miri.
|
|
4
|
+
|
|
5
|
+
use std::io;
|
|
6
|
+
use tokio::net::TcpListener;
|
|
7
|
+
use tokio::runtime::Builder;
|
|
8
|
+
|
|
9
|
+
fn rt() -> tokio::runtime::Runtime {
|
|
10
|
+
Builder::new_current_thread().enable_all().build().unwrap()
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
#[test]
|
|
14
|
+
fn test_is_rt_shutdown_err() {
|
|
15
|
+
let rt1 = rt();
|
|
16
|
+
let rt2 = rt();
|
|
17
|
+
|
|
18
|
+
let listener = rt1.block_on(async { TcpListener::bind("127.0.0.1:0").await.unwrap() });
|
|
19
|
+
|
|
20
|
+
drop(rt1);
|
|
21
|
+
|
|
22
|
+
rt2.block_on(async {
|
|
23
|
+
let res = listener.accept().await;
|
|
24
|
+
assert!(res.is_err());
|
|
25
|
+
let err = res.as_ref().unwrap_err();
|
|
26
|
+
assert!(tokio::runtime::is_rt_shutdown_err(err));
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#[test]
|
|
31
|
+
fn test_is_not_rt_shutdown_err() {
|
|
32
|
+
let err = io::Error::new(io::ErrorKind::Other, "some other error");
|
|
33
|
+
assert!(!tokio::runtime::is_rt_shutdown_err(&err));
|
|
34
|
+
|
|
35
|
+
let err = io::Error::new(io::ErrorKind::NotFound, "not found");
|
|
36
|
+
assert!(!tokio::runtime::is_rt_shutdown_err(&err));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
#[test]
|
|
40
|
+
#[cfg_attr(panic = "abort", ignore)]
|
|
41
|
+
fn test_join_error_panic() {
|
|
42
|
+
let rt = rt();
|
|
43
|
+
let handle = rt.spawn(async {
|
|
44
|
+
panic!("oops");
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
let join_err = rt.block_on(handle).unwrap_err();
|
|
48
|
+
let io_err: io::Error = join_err.into();
|
|
49
|
+
assert!(!tokio::runtime::is_rt_shutdown_err(&io_err));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
#[test]
|
|
53
|
+
fn test_join_error_cancelled() {
|
|
54
|
+
let rt = rt();
|
|
55
|
+
let handle = rt.spawn(async {
|
|
56
|
+
std::future::pending::<()>().await;
|
|
57
|
+
});
|
|
58
|
+
handle.abort();
|
|
59
|
+
let join_err = rt.block_on(handle).unwrap_err();
|
|
60
|
+
let io_err: io::Error = join_err.into();
|
|
61
|
+
assert!(!tokio::runtime::is_rt_shutdown_err(&io_err));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
#[test]
|
|
65
|
+
fn test_other_error_kinds_and_strings() {
|
|
66
|
+
// TimedOut
|
|
67
|
+
let err = io::Error::new(io::ErrorKind::TimedOut, "timed out");
|
|
68
|
+
assert!(!tokio::runtime::is_rt_shutdown_err(&err));
|
|
69
|
+
|
|
70
|
+
// Interrupted
|
|
71
|
+
let err = io::Error::from(io::ErrorKind::Interrupted);
|
|
72
|
+
assert!(!tokio::runtime::is_rt_shutdown_err(&err));
|
|
73
|
+
|
|
74
|
+
// String that contains the shutdown message but has a prefix/suffix
|
|
75
|
+
let msg = "A Tokio 1.x context was found, but it is being shutdown. (extra info)";
|
|
76
|
+
let err = io::Error::new(io::ErrorKind::Other, msg);
|
|
77
|
+
assert!(!tokio::runtime::is_rt_shutdown_err(&err));
|
|
78
|
+
|
|
79
|
+
let msg = "Error: A Tokio 1.x context was found, but it is being shutdown.";
|
|
80
|
+
let err = io::Error::new(io::ErrorKind::Other, msg);
|
|
81
|
+
assert!(!tokio::runtime::is_rt_shutdown_err(&err));
|
|
82
|
+
}
|
|
@@ -6,7 +6,7 @@ use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
|
|
6
6
|
use tokio::net::{TcpListener, TcpStream};
|
|
7
7
|
use tokio::runtime;
|
|
8
8
|
use tokio::sync::oneshot;
|
|
9
|
-
use tokio_test::{assert_err, assert_ok};
|
|
9
|
+
use tokio_test::{assert_err, assert_ok, assert_pending};
|
|
10
10
|
|
|
11
11
|
use std::future::{poll_fn, Future};
|
|
12
12
|
use std::pin::Pin;
|
|
@@ -692,6 +692,54 @@ fn mutex_in_block_in_place() {
|
|
|
692
692
|
})
|
|
693
693
|
}
|
|
694
694
|
|
|
695
|
+
#[test]
|
|
696
|
+
/// Deferred tasks should be woken before starting the [`tokio::task::block_in_place`]
|
|
697
|
+
// https://github.com/tokio-rs/tokio/issues/7877
|
|
698
|
+
fn wake_deferred_tasks_before_block_in_place() {
|
|
699
|
+
let (tx1, rx1) = oneshot::channel::<()>();
|
|
700
|
+
let (tx2, rx2) = oneshot::channel::<()>();
|
|
701
|
+
|
|
702
|
+
let deferred_task = tokio_test::task::spawn(tokio::task::yield_now());
|
|
703
|
+
let deffered_task = Arc::new(Mutex::new(deferred_task));
|
|
704
|
+
|
|
705
|
+
let rt = runtime::Builder::new_multi_thread()
|
|
706
|
+
.worker_threads(1)
|
|
707
|
+
.build()
|
|
708
|
+
.unwrap();
|
|
709
|
+
|
|
710
|
+
let jh = {
|
|
711
|
+
let deferred_task = Arc::clone(&deffered_task);
|
|
712
|
+
rt.spawn(async move {
|
|
713
|
+
{
|
|
714
|
+
let mut lock = deferred_task.lock().unwrap();
|
|
715
|
+
assert_pending!(lock.poll());
|
|
716
|
+
}
|
|
717
|
+
tokio::task::block_in_place(|| {
|
|
718
|
+
// signal that the `block_in_place` has started
|
|
719
|
+
tx2.send(()).unwrap();
|
|
720
|
+
// wait for the shutdown signal
|
|
721
|
+
rx1.blocking_recv().unwrap();
|
|
722
|
+
});
|
|
723
|
+
})
|
|
724
|
+
};
|
|
725
|
+
|
|
726
|
+
// wait for the `block_in_place` to start
|
|
727
|
+
rx2.blocking_recv().unwrap();
|
|
728
|
+
|
|
729
|
+
// check that the deferred task was woken before the `block_in_place` ends
|
|
730
|
+
let is_woken = {
|
|
731
|
+
let lock = deffered_task.lock().unwrap();
|
|
732
|
+
lock.is_woken()
|
|
733
|
+
};
|
|
734
|
+
|
|
735
|
+
// signal the `block_in_place` to shutdown
|
|
736
|
+
tx1.send(()).unwrap();
|
|
737
|
+
|
|
738
|
+
rt.block_on(jh).unwrap();
|
|
739
|
+
|
|
740
|
+
assert!(is_woken);
|
|
741
|
+
}
|
|
742
|
+
|
|
695
743
|
// Testing the tuning logic is tricky as it is inherently timing based, and more
|
|
696
744
|
// of a heuristic than an exact behavior. This test checks that the interval
|
|
697
745
|
// changes over time based on load factors. There are no assertions, completion
|
|
@@ -62,6 +62,38 @@ fn num_idle_blocking_threads() {
|
|
|
62
62
|
assert_eq!(1, rt.metrics().num_idle_blocking_threads());
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
#[test]
|
|
66
|
+
fn num_idle_blocking_threads_is_zero_after_shutdown() {
|
|
67
|
+
let rt = current_thread();
|
|
68
|
+
let handle = rt.handle().clone();
|
|
69
|
+
|
|
70
|
+
// Spawn a blocking task to create a worker thread.
|
|
71
|
+
let _ = rt.block_on(rt.spawn_blocking(move || {}));
|
|
72
|
+
|
|
73
|
+
// Wait for the thread to become idle.
|
|
74
|
+
rt.block_on(async {
|
|
75
|
+
time::sleep(Duration::from_millis(5)).await;
|
|
76
|
+
});
|
|
77
|
+
if handle.metrics().num_idle_blocking_threads() == 0 {
|
|
78
|
+
rt.block_on(async {
|
|
79
|
+
time::sleep(Duration::from_secs(1)).await;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
assert_eq!(1, handle.metrics().num_idle_blocking_threads());
|
|
83
|
+
|
|
84
|
+
// Drop the runtime, which triggers shutdown and joins all blocking
|
|
85
|
+
// threads. Before the fix for #6439, the shutdown path incremented
|
|
86
|
+
// num_idle_threads a second time for each idle worker, so this
|
|
87
|
+
// counter stayed at 1 instead of going back to 0.
|
|
88
|
+
drop(rt);
|
|
89
|
+
|
|
90
|
+
assert_eq!(
|
|
91
|
+
0,
|
|
92
|
+
handle.metrics().num_idle_blocking_threads(),
|
|
93
|
+
"num_idle_blocking_threads should be 0 after shutdown (see #6439)"
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
65
97
|
#[test]
|
|
66
98
|
fn blocking_queue_depth() {
|
|
67
99
|
let rt = tokio::runtime::Builder::new_current_thread()
|
|
@@ -181,7 +181,6 @@ mod linux {
|
|
|
181
181
|
use std::{net, thread};
|
|
182
182
|
|
|
183
183
|
#[tokio::test]
|
|
184
|
-
#[expect(deprecated)] // set_linger is deprecated
|
|
185
184
|
fn poll_hup() {
|
|
186
185
|
let addr = assert_ok!("127.0.0.1:0".parse());
|
|
187
186
|
let mut srv = assert_ok!(TcpListener::bind(&addr));
|
|
@@ -189,7 +188,7 @@ mod linux {
|
|
|
189
188
|
|
|
190
189
|
tokio::spawn(async move {
|
|
191
190
|
let (mut client, _) = assert_ok!(srv.accept().await);
|
|
192
|
-
assert_ok!(client.
|
|
191
|
+
assert_ok!(client.set_zero_linger());
|
|
193
192
|
assert_ok!(client.write_all(b"hello world").await);
|
|
194
193
|
|
|
195
194
|
// TODO: Drop?
|
|
@@ -198,7 +197,7 @@ mod linux {
|
|
|
198
197
|
/*
|
|
199
198
|
let t = thread::spawn(move || {
|
|
200
199
|
let mut client = assert_ok!(srv.accept()).0;
|
|
201
|
-
client.
|
|
200
|
+
client.set_zero_linger().unwrap();
|
|
202
201
|
client.write(b"hello world").unwrap();
|
|
203
202
|
thread::sleep(Duration::from_millis(200));
|
|
204
203
|
});
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
#![cfg(all(feature = "full", not(target_os = "wasi"), not(miri)))] // Wasi doesn't support bind
|
|
3
3
|
// No `socket` on miri.
|
|
4
4
|
|
|
5
|
-
use std::time::Duration;
|
|
6
5
|
use tokio::io::{self, AsyncReadExt, AsyncWriteExt};
|
|
7
6
|
use tokio::net::{TcpListener, TcpStream};
|
|
8
7
|
use tokio::sync::oneshot::channel;
|
|
@@ -33,7 +32,6 @@ async fn shutdown() {
|
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
#[tokio::test]
|
|
36
|
-
#[expect(deprecated)] // set_linger is deprecated
|
|
37
35
|
async fn shutdown_after_tcp_reset() {
|
|
38
36
|
let srv = assert_ok!(TcpListener::bind("127.0.0.1:0").await);
|
|
39
37
|
let addr = assert_ok!(srv.local_addr());
|
|
@@ -51,7 +49,7 @@ async fn shutdown_after_tcp_reset() {
|
|
|
51
49
|
|
|
52
50
|
let (stream, _) = assert_ok!(srv.accept().await);
|
|
53
51
|
// By setting linger to 0 we will trigger a TCP reset
|
|
54
|
-
stream.
|
|
52
|
+
stream.set_zero_linger().unwrap();
|
|
55
53
|
connected_rx.await.unwrap();
|
|
56
54
|
|
|
57
55
|
drop(stream);
|