mirror of
https://github.com/alacritty/alacritty.git
synced 2024-11-18 13:55:23 -05:00
Port from mio to polling
This patch replaces the mio crate with the polling. Now that smol-rs/polling#96 has been merged, we should be at full feature parity with mio v0.6 now. Fixes #7104. Fixes #6486.
This commit is contained in:
parent
ace987f343
commit
c2f8abecfb
10 changed files with 711 additions and 586 deletions
349
Cargo.lock
generated
349
Cargo.lock
generated
|
@ -14,7 +14,7 @@ version = "0.8.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
|
@ -53,7 +53,7 @@ dependencies = [
|
|||
"notify",
|
||||
"objc",
|
||||
"once_cell",
|
||||
"parking_lot 0.12.1",
|
||||
"parking_lot",
|
||||
"png",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
@ -100,18 +100,16 @@ dependencies = [
|
|||
"home",
|
||||
"libc",
|
||||
"log",
|
||||
"mio 0.6.23",
|
||||
"mio-anonymous-pipes",
|
||||
"mio-extras",
|
||||
"miow 0.3.7",
|
||||
"miow",
|
||||
"nix 0.26.2",
|
||||
"parking_lot 0.12.1",
|
||||
"parking_lot",
|
||||
"piper",
|
||||
"polling",
|
||||
"regex-automata",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"signal-hook",
|
||||
"signal-hook-mio",
|
||||
"toml 0.7.4",
|
||||
"unicode-width",
|
||||
"vte",
|
||||
|
@ -336,12 +334,6 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
|
@ -421,7 +413,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "9fdf5e01086b6be750428ba4a40619f847eb2e95756eee84b18e06e5f0b50342"
|
||||
dependencies = [
|
||||
"lazy-bytes-cast",
|
||||
"winapi 0.3.9",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -480,6 +472,15 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f057a694a54f12365049b0958a1685bb52d567f5593b355fbf685838e873d400"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "copypasta"
|
||||
version = "0.8.2"
|
||||
|
@ -553,7 +554,7 @@ version = "1.3.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -562,7 +563,7 @@ version = "0.5.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
|
@ -572,7 +573,7 @@ version = "0.8.15"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -595,7 +596,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"pkg-config",
|
||||
"servo-fontconfig",
|
||||
"winapi 0.3.9",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -659,7 +660,7 @@ dependencies = [
|
|||
"libc",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"winapi 0.3.9",
|
||||
"winapi",
|
||||
"wio",
|
||||
]
|
||||
|
||||
|
@ -707,6 +708,12 @@ dependencies = [
|
|||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
|
||||
|
||||
[[package]]
|
||||
name = "fdeflate"
|
||||
version = "0.3.0"
|
||||
|
@ -722,7 +729,7 @@ version = "0.2.21"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall 0.2.16",
|
||||
"windows-sys 0.48.0",
|
||||
|
@ -818,20 +825,10 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
name = "futures-io"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"fuchsia-zircon-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon-sys"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
|
||||
|
||||
[[package]]
|
||||
name = "gethostname"
|
||||
|
@ -840,7 +837,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi 0.3.9",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -850,7 +847,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "bb65d4ba3173c56a500b555b532f72c42e8d1fe64962b518897f8959fae2c177"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi 0.3.9",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -859,7 +856,7 @@ version = "0.2.10"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
@ -995,15 +992,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io-lifetimes"
|
||||
version = "1.0.11"
|
||||
|
@ -1015,15 +1003,6 @@ dependencies = [
|
|||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iovec"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.7"
|
||||
|
@ -1049,7 +1028,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
|
||||
dependencies = [
|
||||
"cesu8",
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"combine",
|
||||
"jni-sys",
|
||||
"log",
|
||||
|
@ -1082,16 +1061,6 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
dependencies = [
|
||||
"winapi 0.2.8",
|
||||
"winapi-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "khronos_api"
|
||||
version = "3.1.0"
|
||||
|
@ -1130,12 +1099,6 @@ version = "1.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "lazycell"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.147"
|
||||
|
@ -1148,8 +1111,8 @@ version = "0.7.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"winapi 0.3.9",
|
||||
"cfg-if",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1247,25 +1210,6 @@ dependencies = [
|
|||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.6.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"fuchsia-zircon",
|
||||
"fuchsia-zircon-sys",
|
||||
"iovec",
|
||||
"kernel32-sys",
|
||||
"libc",
|
||||
"log",
|
||||
"miow 0.2.2",
|
||||
"net2",
|
||||
"slab",
|
||||
"winapi 0.2.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.8"
|
||||
|
@ -1278,61 +1222,13 @@ dependencies = [
|
|||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio-anonymous-pipes"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bc513025fe5005a3aa561b50fdb2cda5a150b84800ae02acd8aa9ed62ca1a6b"
|
||||
dependencies = [
|
||||
"mio 0.6.23",
|
||||
"miow 0.3.7",
|
||||
"parking_lot 0.11.2",
|
||||
"spsc-buffer",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio-extras"
|
||||
version = "2.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19"
|
||||
dependencies = [
|
||||
"lazycell",
|
||||
"log",
|
||||
"mio 0.6.23",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio-uds"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0"
|
||||
dependencies = [
|
||||
"iovec",
|
||||
"libc",
|
||||
"mio 0.6.23",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d"
|
||||
dependencies = [
|
||||
"kernel32-sys",
|
||||
"net2",
|
||||
"winapi 0.2.8",
|
||||
"ws2_32-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
|
||||
dependencies = [
|
||||
"winapi 0.3.9",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1365,17 +1261,6 @@ dependencies = [
|
|||
"jni-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "net2"
|
||||
version = "0.2.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74d0df99cfcd2530b2e694f6e17e7f37b8e26bb23983ac530c0c97408837c631"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"libc",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.24.3"
|
||||
|
@ -1383,7 +1268,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"memoffset 0.6.5",
|
||||
]
|
||||
|
@ -1396,7 +1281,7 @@ checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4"
|
|||
dependencies = [
|
||||
"autocfg",
|
||||
"bitflags 1.3.2",
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"memoffset 0.6.5",
|
||||
]
|
||||
|
@ -1408,7 +1293,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"memoffset 0.7.1",
|
||||
"static_assertions",
|
||||
|
@ -1437,7 +1322,7 @@ dependencies = [
|
|||
"inotify",
|
||||
"kqueue",
|
||||
"libc",
|
||||
"mio 0.8.8",
|
||||
"mio",
|
||||
"walkdir",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
@ -1561,17 +1446,6 @@ dependencies = [
|
|||
"redox_syscall 0.3.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core 0.8.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
|
@ -1579,21 +1453,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core 0.9.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall 0.2.16",
|
||||
"smallvec",
|
||||
"winapi 0.3.9",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1602,7 +1462,7 @@ version = "0.9.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall 0.3.5",
|
||||
"smallvec",
|
||||
|
@ -1615,6 +1475,23 @@ version = "2.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
|
||||
|
||||
[[package]]
|
||||
name = "piper"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"fastrand",
|
||||
"futures-io",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.27"
|
||||
|
@ -1634,6 +1511,20 @@ dependencies = [
|
|||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "3.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62a79e457c9898100b4298d57d69ec53d06f9a6ed352431ce5f377e082d2e846"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"concurrent-queue",
|
||||
"pin-project-lite",
|
||||
"rustix 0.38.8",
|
||||
"tracing",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "1.3.1"
|
||||
|
@ -1748,9 +1639,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.4"
|
||||
version = "0.38.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5"
|
||||
checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f"
|
||||
dependencies = [
|
||||
"bitflags 2.3.3",
|
||||
"errno",
|
||||
|
@ -1887,18 +1778,6 @@ dependencies = [
|
|||
"signal-hook-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-mio"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mio 0.6.23",
|
||||
"mio-uds",
|
||||
"signal-hook",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.1"
|
||||
|
@ -1914,15 +1793,6 @@ version = "0.3.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "238abfbb77c1915110ad968465608b68e869e0772622c9656714e73e5a1a522f"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slotmap"
|
||||
version = "1.0.6"
|
||||
|
@ -1997,12 +1867,6 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spsc-buffer"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be6c3f39c37a4283ee4b43d1311c828f2e1fb0541e76ea0cb1a2abd9ef2f5b3b"
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
|
@ -2061,7 +1925,7 @@ dependencies = [
|
|||
"arrayref",
|
||||
"arrayvec",
|
||||
"bytemuck",
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"log",
|
||||
"tiny-skia-path",
|
||||
]
|
||||
|
@ -2120,6 +1984,23 @@ dependencies = [
|
|||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"pin-project-lite",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.9"
|
||||
|
@ -2222,7 +2103,7 @@ version = "0.2.87"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
|
@ -2247,7 +2128,7 @@ version = "0.4.37"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
|
@ -2463,12 +2344,6 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
@ -2479,12 +2354,6 @@ dependencies = [
|
|||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
|
@ -2497,7 +2366,7 @@ version = "0.1.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi 0.3.9",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2506,7 +2375,7 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c17110f57155602a80dca10be03852116403c9ff3cd25b079d666f2aa3df6e"
|
||||
dependencies = [
|
||||
"winapi 0.3.9",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2676,7 +2545,7 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
"raw-window-handle",
|
||||
"redox_syscall 0.3.5",
|
||||
"rustix 0.38.4",
|
||||
"rustix 0.38.8",
|
||||
"sctk-adwaita",
|
||||
"serde",
|
||||
"smithay-client-toolkit 0.17.0",
|
||||
|
@ -2710,7 +2579,7 @@ version = "0.10.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
|
||||
dependencies = [
|
||||
"winapi 0.3.9",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2719,17 +2588,7 @@ version = "0.2.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5"
|
||||
dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ws2_32-sys"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
|
||||
dependencies = [
|
||||
"winapi 0.2.8",
|
||||
"winapi-build",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2760,7 +2619,7 @@ checksum = "592b4883219f345e712b3209c62654ebda0bb50887f330cbd018d0f654bfd507"
|
|||
dependencies = [
|
||||
"gethostname 0.2.3",
|
||||
"nix 0.24.3",
|
||||
"winapi 0.3.9",
|
||||
"winapi",
|
||||
"winapi-wsapoll",
|
||||
"x11rb-protocol 0.10.0",
|
||||
]
|
||||
|
@ -2777,7 +2636,7 @@ dependencies = [
|
|||
"libloading",
|
||||
"nix 0.26.2",
|
||||
"once_cell",
|
||||
"winapi 0.3.9",
|
||||
"winapi",
|
||||
"winapi-wsapoll",
|
||||
"x11rb-protocol 0.12.0",
|
||||
]
|
||||
|
|
|
@ -569,6 +569,6 @@ impl WindowContext {
|
|||
impl Drop for WindowContext {
|
||||
fn drop(&mut self) {
|
||||
// Shutdown the terminal's PTY.
|
||||
let _ = self.notifier.0.send(Msg::Shutdown);
|
||||
self.notifier.0.send(Msg::Shutdown);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,9 +23,8 @@ bitflags = { version = "2.2.1", features = ["serde"] }
|
|||
home = "0.5.5"
|
||||
libc = "0.2"
|
||||
log = "0.4"
|
||||
mio = "0.6.20"
|
||||
mio-extras = "2"
|
||||
parking_lot = "0.12.0"
|
||||
polling = "3.0.0"
|
||||
regex-automata = "0.3.6"
|
||||
serde = { version = "1", features = ["derive", "rc"] }
|
||||
serde_yaml = "0.8"
|
||||
|
@ -36,12 +35,11 @@ vte = { version = "0.12.0", default-features = false, features = ["ansi", "serde
|
|||
[target.'cfg(unix)'.dependencies]
|
||||
nix = { version = "0.26.2", default-features = false, features = ["term"] }
|
||||
signal-hook = "0.3.10"
|
||||
signal-hook-mio = { version = "0.2.1", features = ["support-v0_6"] }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
mio-anonymous-pipes = "0.2"
|
||||
miow = "0.3"
|
||||
windows-sys = { version = "0.48", features = [
|
||||
piper = "0.2.1"
|
||||
miow = "0.3.0"
|
||||
windows-sys = { version = "0.48.0", features = [
|
||||
"Win32_System_Console",
|
||||
"Win32_Foundation",
|
||||
"Win32_Security",
|
||||
|
|
|
@ -5,15 +5,14 @@ use std::collections::VecDeque;
|
|||
use std::fs::File;
|
||||
use std::io::{self, ErrorKind, Read, Write};
|
||||
use std::marker::Send;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::sync::mpsc::{self, Receiver, Sender, TryRecvError};
|
||||
use std::sync::Arc;
|
||||
use std::thread::JoinHandle;
|
||||
use std::time::Instant;
|
||||
|
||||
use log::error;
|
||||
#[cfg(not(windows))]
|
||||
use mio::unix::UnixReady;
|
||||
use mio::{self, Events, PollOpt, Ready};
|
||||
use mio_extras::channel::{self, Receiver, Sender};
|
||||
use polling::{Event as PollingEvent, Events, PollMode};
|
||||
|
||||
use crate::event::{self, Event, EventListener, WindowSize};
|
||||
use crate::sync::FairMutex;
|
||||
|
@ -21,7 +20,7 @@ use crate::term::Term;
|
|||
use crate::{ansi, thread, tty};
|
||||
|
||||
/// Max bytes to read from the PTY before forced terminal synchronization.
|
||||
const READ_BUFFER_SIZE: usize = 0x10_0000;
|
||||
pub(crate) const READ_BUFFER_SIZE: usize = 0x10_0000;
|
||||
|
||||
/// Max bytes to read from the PTY while the terminal is locked.
|
||||
const MAX_LOCKED_READ: usize = u16::MAX as usize;
|
||||
|
@ -39,14 +38,14 @@ pub enum Msg {
|
|||
Resize(WindowSize),
|
||||
}
|
||||
|
||||
/// The main event!.. loop.
|
||||
/// The main event loop.
|
||||
///
|
||||
/// Handles all the PTY I/O and runs the PTY parser which updates terminal
|
||||
/// state.
|
||||
pub struct EventLoop<T: tty::EventedPty, U: EventListener> {
|
||||
poll: mio::Poll,
|
||||
poll: Arc<polling::Poller>,
|
||||
pty: T,
|
||||
rx: Receiver<Msg>,
|
||||
rx: PeekableReceiver<Msg>,
|
||||
tx: Sender<Msg>,
|
||||
terminal: Arc<FairMutex<Term<U>>>,
|
||||
event_proxy: U,
|
||||
|
@ -54,97 +53,6 @@ pub struct EventLoop<T: tty::EventedPty, U: EventListener> {
|
|||
ref_test: bool,
|
||||
}
|
||||
|
||||
/// Helper type which tracks how much of a buffer has been written.
|
||||
struct Writing {
|
||||
source: Cow<'static, [u8]>,
|
||||
written: usize,
|
||||
}
|
||||
|
||||
pub struct Notifier(pub Sender<Msg>);
|
||||
|
||||
impl event::Notify for Notifier {
|
||||
fn notify<B>(&self, bytes: B)
|
||||
where
|
||||
B: Into<Cow<'static, [u8]>>,
|
||||
{
|
||||
let bytes = bytes.into();
|
||||
// terminal hangs if we send 0 bytes through.
|
||||
if bytes.len() == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let _ = self.0.send(Msg::Input(bytes));
|
||||
}
|
||||
}
|
||||
|
||||
impl event::OnResize for Notifier {
|
||||
fn on_resize(&mut self, window_size: WindowSize) {
|
||||
let _ = self.0.send(Msg::Resize(window_size));
|
||||
}
|
||||
}
|
||||
|
||||
/// All of the mutable state needed to run the event loop.
|
||||
///
|
||||
/// Contains list of items to write, current write state, etc. Anything that
|
||||
/// would otherwise be mutated on the `EventLoop` goes here.
|
||||
#[derive(Default)]
|
||||
pub struct State {
|
||||
write_list: VecDeque<Cow<'static, [u8]>>,
|
||||
writing: Option<Writing>,
|
||||
parser: ansi::Processor,
|
||||
}
|
||||
|
||||
impl State {
|
||||
#[inline]
|
||||
fn ensure_next(&mut self) {
|
||||
if self.writing.is_none() {
|
||||
self.goto_next();
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn goto_next(&mut self) {
|
||||
self.writing = self.write_list.pop_front().map(Writing::new);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn take_current(&mut self) -> Option<Writing> {
|
||||
self.writing.take()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn needs_write(&self) -> bool {
|
||||
self.writing.is_some() || !self.write_list.is_empty()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_current(&mut self, new: Option<Writing>) {
|
||||
self.writing = new;
|
||||
}
|
||||
}
|
||||
|
||||
impl Writing {
|
||||
#[inline]
|
||||
fn new(c: Cow<'static, [u8]>) -> Writing {
|
||||
Writing { source: c, written: 0 }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance(&mut self, n: usize) {
|
||||
self.written += n;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn remaining_bytes(&self) -> &[u8] {
|
||||
&self.source[self.written..]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn finished(&self) -> bool {
|
||||
self.written >= self.source.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> EventLoop<T, U>
|
||||
where
|
||||
T: tty::EventedPty + event::OnResize + Send + 'static,
|
||||
|
@ -158,12 +66,12 @@ where
|
|||
hold: bool,
|
||||
ref_test: bool,
|
||||
) -> EventLoop<T, U> {
|
||||
let (tx, rx) = channel::channel();
|
||||
let (tx, rx) = mpsc::channel();
|
||||
EventLoop {
|
||||
poll: mio::Poll::new().expect("create mio Poll"),
|
||||
poll: polling::Poller::new().expect("create Poll").into(),
|
||||
pty,
|
||||
tx,
|
||||
rx,
|
||||
rx: PeekableReceiver::new(rx),
|
||||
terminal,
|
||||
event_proxy,
|
||||
hold,
|
||||
|
@ -171,15 +79,15 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub fn channel(&self) -> Sender<Msg> {
|
||||
self.tx.clone()
|
||||
pub fn channel(&self) -> EventLoopSender {
|
||||
EventLoopSender { sender: self.tx.clone(), poller: self.poll.clone() }
|
||||
}
|
||||
|
||||
/// Drain the channel.
|
||||
///
|
||||
/// Returns `false` when a shutdown message was received.
|
||||
fn drain_recv_channel(&mut self, state: &mut State) -> bool {
|
||||
while let Ok(msg) = self.rx.try_recv() {
|
||||
while let Some(msg) = self.rx.recv() {
|
||||
match msg {
|
||||
Msg::Input(input) => state.write_list.push_back(input),
|
||||
Msg::Resize(window_size) => self.pty.on_resize(window_size),
|
||||
|
@ -190,20 +98,6 @@ where
|
|||
true
|
||||
}
|
||||
|
||||
/// Returns a `bool` indicating whether or not the event loop should continue running.
|
||||
#[inline]
|
||||
fn channel_event(&mut self, token: mio::Token, state: &mut State) -> bool {
|
||||
if !self.drain_recv_channel(state) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.poll
|
||||
.reregister(&self.rx, token, Ready::readable(), PollOpt::edge() | PollOpt::oneshot())
|
||||
.unwrap();
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn pty_read<X>(
|
||||
&mut self,
|
||||
|
@ -313,17 +207,15 @@ where
|
|||
let mut state = State::default();
|
||||
let mut buf = [0u8; READ_BUFFER_SIZE];
|
||||
|
||||
let mut tokens = (0..).map(Into::into);
|
||||
|
||||
let poll_opts = PollOpt::edge() | PollOpt::oneshot();
|
||||
|
||||
let channel_token = tokens.next().unwrap();
|
||||
self.poll.register(&self.rx, channel_token, Ready::readable(), poll_opts).unwrap();
|
||||
let poll_opts = PollMode::Level;
|
||||
let mut interest = PollingEvent::readable(0);
|
||||
|
||||
// Register TTY through EventedRW interface.
|
||||
self.pty.register(&self.poll, &mut tokens, Ready::readable(), poll_opts).unwrap();
|
||||
unsafe {
|
||||
self.pty.register(&self.poll, interest, poll_opts).unwrap();
|
||||
}
|
||||
|
||||
let mut events = Events::with_capacity(1024);
|
||||
let mut events = Events::with_capacity(NonZeroUsize::new(1024).unwrap());
|
||||
|
||||
let mut pipe = if self.ref_test {
|
||||
Some(File::create("./alacritty.recording").expect("create alacritty recording"))
|
||||
|
@ -337,7 +229,8 @@ where
|
|||
let timeout =
|
||||
handler.sync_timeout().map(|st| st.saturating_duration_since(Instant::now()));
|
||||
|
||||
if let Err(err) = self.poll.poll(&mut events, timeout) {
|
||||
events.clear();
|
||||
if let Err(err) = self.poll.wait(&mut events, timeout) {
|
||||
match err.kind() {
|
||||
ErrorKind::Interrupted => continue,
|
||||
_ => panic!("EventLoop polling error: {err:?}"),
|
||||
|
@ -345,21 +238,20 @@ where
|
|||
}
|
||||
|
||||
// Handle synchronized update timeout.
|
||||
if events.is_empty() {
|
||||
if events.is_empty() && self.rx.peek().is_none() {
|
||||
state.parser.stop_sync(&mut *self.terminal.lock());
|
||||
self.event_proxy.send_event(Event::Wakeup);
|
||||
continue;
|
||||
}
|
||||
|
||||
for event in events.iter() {
|
||||
match event.token() {
|
||||
token if token == channel_token => {
|
||||
if !self.channel_event(channel_token, &mut state) {
|
||||
break 'event_loop;
|
||||
}
|
||||
},
|
||||
// Handle channel events, if there are any.
|
||||
if !self.drain_recv_channel(&mut state) {
|
||||
break;
|
||||
}
|
||||
|
||||
token if token == self.pty.child_event_token() => {
|
||||
for event in events.iter() {
|
||||
match event.key {
|
||||
tty::PTY_CHILD_EVENT_TOKEN => {
|
||||
if let Some(tty::ChildEvent::Exited) = self.pty.next_child_event() {
|
||||
if self.hold {
|
||||
// With hold enabled, make sure the PTY is drained.
|
||||
|
@ -374,17 +266,13 @@ where
|
|||
}
|
||||
},
|
||||
|
||||
token
|
||||
if token == self.pty.read_token()
|
||||
|| token == self.pty.write_token() =>
|
||||
{
|
||||
#[cfg(unix)]
|
||||
if UnixReady::from(event.readiness()).is_hup() {
|
||||
tty::PTY_READ_WRITE_TOKEN => {
|
||||
if event.is_interrupt() {
|
||||
// Don't try to do I/O on a dead PTY.
|
||||
continue;
|
||||
}
|
||||
|
||||
if event.readiness().is_readable() {
|
||||
if event.readable {
|
||||
if let Err(err) = self.pty_read(&mut state, &mut buf, pipe.as_mut())
|
||||
{
|
||||
// On Linux, a `read` on the master side of a PTY can fail
|
||||
|
@ -402,7 +290,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
if event.readiness().is_writable() {
|
||||
if event.writable {
|
||||
if let Err(err) = self.pty_write(&mut state) {
|
||||
error!("Error writing to PTY in event loop: {}", err);
|
||||
break 'event_loop;
|
||||
|
@ -414,19 +302,152 @@ where
|
|||
}
|
||||
|
||||
// Register write interest if necessary.
|
||||
let mut interest = Ready::readable();
|
||||
if state.needs_write() {
|
||||
interest.insert(Ready::writable());
|
||||
let needs_write = state.needs_write();
|
||||
if needs_write != interest.writable {
|
||||
interest.writable = needs_write;
|
||||
|
||||
// Re-register with new interest.
|
||||
self.pty.reregister(&self.poll, interest, poll_opts).unwrap();
|
||||
}
|
||||
// Reregister with new interest.
|
||||
self.pty.reregister(&self.poll, interest, poll_opts).unwrap();
|
||||
}
|
||||
|
||||
// The evented instances are not dropped here so deregister them explicitly.
|
||||
let _ = self.poll.deregister(&self.rx);
|
||||
let _ = self.pty.deregister(&self.poll);
|
||||
|
||||
(self, state)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper type which tracks how much of a buffer has been written.
|
||||
struct Writing {
|
||||
source: Cow<'static, [u8]>,
|
||||
written: usize,
|
||||
}
|
||||
|
||||
pub struct Notifier(pub EventLoopSender);
|
||||
|
||||
impl event::Notify for Notifier {
|
||||
fn notify<B>(&self, bytes: B)
|
||||
where
|
||||
B: Into<Cow<'static, [u8]>>,
|
||||
{
|
||||
let bytes = bytes.into();
|
||||
// Terminal hangs if we send 0 bytes through.
|
||||
if bytes.len() == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
self.0.send(Msg::Input(bytes));
|
||||
}
|
||||
}
|
||||
|
||||
impl event::OnResize for Notifier {
|
||||
fn on_resize(&mut self, window_size: WindowSize) {
|
||||
self.0.send(Msg::Resize(window_size));
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EventLoopSender {
|
||||
sender: Sender<Msg>,
|
||||
poller: Arc<polling::Poller>,
|
||||
}
|
||||
|
||||
impl EventLoopSender {
|
||||
pub fn send(&self, msg: Msg) {
|
||||
let _ = self.sender.send(msg);
|
||||
let _ = self.poller.notify();
|
||||
}
|
||||
}
|
||||
|
||||
/// All of the mutable state needed to run the event loop.
|
||||
///
|
||||
/// Contains list of items to write, current write state, etc. Anything that
|
||||
/// would otherwise be mutated on the `EventLoop` goes here.
|
||||
#[derive(Default)]
|
||||
pub struct State {
|
||||
write_list: VecDeque<Cow<'static, [u8]>>,
|
||||
writing: Option<Writing>,
|
||||
parser: ansi::Processor,
|
||||
}
|
||||
|
||||
impl State {
|
||||
#[inline]
|
||||
fn ensure_next(&mut self) {
|
||||
if self.writing.is_none() {
|
||||
self.goto_next();
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn goto_next(&mut self) {
|
||||
self.writing = self.write_list.pop_front().map(Writing::new);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn take_current(&mut self) -> Option<Writing> {
|
||||
self.writing.take()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn needs_write(&self) -> bool {
|
||||
self.writing.is_some() || !self.write_list.is_empty()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_current(&mut self, new: Option<Writing>) {
|
||||
self.writing = new;
|
||||
}
|
||||
}
|
||||
|
||||
impl Writing {
|
||||
#[inline]
|
||||
fn new(c: Cow<'static, [u8]>) -> Writing {
|
||||
Writing { source: c, written: 0 }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance(&mut self, n: usize) {
|
||||
self.written += n;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn remaining_bytes(&self) -> &[u8] {
|
||||
&self.source[self.written..]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn finished(&self) -> bool {
|
||||
self.written >= self.source.len()
|
||||
}
|
||||
}
|
||||
|
||||
struct PeekableReceiver<T> {
|
||||
rx: Receiver<T>,
|
||||
peeked: Option<T>,
|
||||
}
|
||||
|
||||
impl<T> PeekableReceiver<T> {
|
||||
fn new(rx: Receiver<T>) -> Self {
|
||||
Self { rx, peeked: None }
|
||||
}
|
||||
|
||||
fn peek(&mut self) -> Option<&T> {
|
||||
if self.peeked.is_none() {
|
||||
self.peeked = self.rx.try_recv().ok();
|
||||
}
|
||||
|
||||
self.peeked.as_ref()
|
||||
}
|
||||
|
||||
fn recv(&mut self) -> Option<T> {
|
||||
if self.peeked.is_some() {
|
||||
self.peeked.take()
|
||||
} else {
|
||||
match self.rx.try_recv() {
|
||||
Err(TryRecvError::Disconnected) => panic!("event loop channel closed"),
|
||||
res => res.ok(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
//! TTY related functionality.
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::{env, io};
|
||||
|
||||
use crate::config::Config;
|
||||
|
||||
use polling::{Event, PollMode, Poller};
|
||||
|
||||
#[cfg(not(windows))]
|
||||
mod unix;
|
||||
#[cfg(not(windows))]
|
||||
|
@ -22,20 +25,15 @@ pub trait EventedReadWrite {
|
|||
type Reader: io::Read;
|
||||
type Writer: io::Write;
|
||||
|
||||
fn register(
|
||||
&mut self,
|
||||
_: &mio::Poll,
|
||||
_: &mut dyn Iterator<Item = mio::Token>,
|
||||
_: mio::Ready,
|
||||
_: mio::PollOpt,
|
||||
) -> io::Result<()>;
|
||||
fn reregister(&mut self, _: &mio::Poll, _: mio::Ready, _: mio::PollOpt) -> io::Result<()>;
|
||||
fn deregister(&mut self, _: &mio::Poll) -> io::Result<()>;
|
||||
/// # Safety
|
||||
///
|
||||
/// The underlying sources must outlive their registration in the `Poller`.
|
||||
unsafe fn register(&mut self, _: &Arc<Poller>, _: Event, _: PollMode) -> io::Result<()>;
|
||||
fn reregister(&mut self, _: &Arc<Poller>, _: Event, _: PollMode) -> io::Result<()>;
|
||||
fn deregister(&mut self, _: &Arc<Poller>) -> io::Result<()>;
|
||||
|
||||
fn reader(&mut self) -> &mut Self::Reader;
|
||||
fn read_token(&self) -> mio::Token;
|
||||
fn writer(&mut self) -> &mut Self::Writer;
|
||||
fn write_token(&self) -> mio::Token;
|
||||
}
|
||||
|
||||
/// Events concerning TTY child processes.
|
||||
|
@ -51,8 +49,6 @@ pub enum ChildEvent {
|
|||
/// notified if the PTY child process does something we care about (other than writing to the TTY).
|
||||
/// In particular, this allows for race-free child exit notification on UNIX (cf. `SIGCHLD`).
|
||||
pub trait EventedPty: EventedReadWrite {
|
||||
fn child_event_token(&self) -> mio::Token;
|
||||
|
||||
/// Tries to retrieve an event.
|
||||
///
|
||||
/// Returns `Some(event)` on success, or `None` if there are no events to retrieve.
|
||||
|
|
|
@ -2,26 +2,34 @@
|
|||
|
||||
use std::ffi::CStr;
|
||||
use std::fs::File;
|
||||
use std::io::{Error, ErrorKind, Result};
|
||||
use std::io::{Error, ErrorKind, Read, Result};
|
||||
use std::mem::MaybeUninit;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||
use std::os::unix::net::UnixStream;
|
||||
use std::os::unix::process::CommandExt;
|
||||
use std::process::{Child, Command, Stdio};
|
||||
use std::sync::Arc;
|
||||
use std::{env, ptr};
|
||||
|
||||
use libc::{self, c_int, winsize, TIOCSCTTY};
|
||||
use log::error;
|
||||
use mio::unix::EventedFd;
|
||||
use nix::pty::openpty;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
use nix::sys::termios::{self, InputFlags, SetArg};
|
||||
use polling::{Event, PollMode, Poller};
|
||||
use signal_hook::consts as sigconsts;
|
||||
use signal_hook_mio::v0_6::Signals;
|
||||
use signal_hook::low_level::pipe as signal_pipe;
|
||||
|
||||
use crate::config::PtyConfig;
|
||||
use crate::event::{OnResize, WindowSize};
|
||||
use crate::tty::{ChildEvent, EventedPty, EventedReadWrite};
|
||||
|
||||
// Interest in PTY read/writes.
|
||||
pub(crate) const PTY_READ_WRITE_TOKEN: usize = 0;
|
||||
|
||||
// Interest in new child events.
|
||||
pub(crate) const PTY_CHILD_EVENT_TOKEN: usize = 1;
|
||||
|
||||
macro_rules! die {
|
||||
($($arg:tt)*) => {{
|
||||
error!($($arg)*);
|
||||
|
@ -103,9 +111,7 @@ fn get_pw_entry(buf: &mut [i8; 1024]) -> Result<Passwd<'_>> {
|
|||
pub struct Pty {
|
||||
child: Child,
|
||||
file: File,
|
||||
token: mio::Token,
|
||||
signals: Signals,
|
||||
signals_token: mio::Token,
|
||||
signals: UnixStream,
|
||||
}
|
||||
|
||||
impl Pty {
|
||||
|
@ -254,7 +260,14 @@ pub fn new(config: &PtyConfig, window_size: WindowSize, window_id: u64) -> Resul
|
|||
}
|
||||
|
||||
// Prepare signal handling before spawning child.
|
||||
let signals = Signals::new([sigconsts::SIGCHLD]).expect("error preparing signal handling");
|
||||
let signals = {
|
||||
let (sender, recv) = UnixStream::pair()?;
|
||||
|
||||
// Register the recv end of the pipe for SIGCHLD.
|
||||
signal_pipe::register(sigconsts::SIGCHLD, sender)?;
|
||||
recv.set_nonblocking(true)?;
|
||||
recv
|
||||
};
|
||||
|
||||
match builder.spawn() {
|
||||
Ok(child) => {
|
||||
|
@ -264,13 +277,7 @@ pub fn new(config: &PtyConfig, window_size: WindowSize, window_id: u64) -> Resul
|
|||
set_nonblocking(master);
|
||||
}
|
||||
|
||||
let mut pty = Pty {
|
||||
child,
|
||||
file: unsafe { File::from_raw_fd(master) },
|
||||
token: mio::Token::from(0),
|
||||
signals,
|
||||
signals_token: mio::Token::from(0),
|
||||
};
|
||||
let mut pty = Pty { child, file: unsafe { File::from_raw_fd(master) }, signals };
|
||||
pty.on_resize(window_size);
|
||||
Ok(pty)
|
||||
},
|
||||
|
@ -300,46 +307,47 @@ impl EventedReadWrite for Pty {
|
|||
type Writer = File;
|
||||
|
||||
#[inline]
|
||||
fn register(
|
||||
unsafe fn register(
|
||||
&mut self,
|
||||
poll: &mio::Poll,
|
||||
token: &mut dyn Iterator<Item = mio::Token>,
|
||||
interest: mio::Ready,
|
||||
poll_opts: mio::PollOpt,
|
||||
poll: &Arc<Poller>,
|
||||
mut interest: Event,
|
||||
poll_opts: PollMode,
|
||||
) -> Result<()> {
|
||||
self.token = token.next().unwrap();
|
||||
poll.register(&EventedFd(&self.file.as_raw_fd()), self.token, interest, poll_opts)?;
|
||||
interest.key = PTY_READ_WRITE_TOKEN;
|
||||
unsafe {
|
||||
poll.add_with_mode(&self.file, interest, poll_opts)?;
|
||||
}
|
||||
|
||||
self.signals_token = token.next().unwrap();
|
||||
poll.register(
|
||||
&self.signals,
|
||||
self.signals_token,
|
||||
mio::Ready::readable(),
|
||||
mio::PollOpt::level(),
|
||||
)
|
||||
unsafe {
|
||||
poll.add_with_mode(
|
||||
&self.signals,
|
||||
Event::readable(PTY_CHILD_EVENT_TOKEN),
|
||||
PollMode::Level,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reregister(
|
||||
&mut self,
|
||||
poll: &mio::Poll,
|
||||
interest: mio::Ready,
|
||||
poll_opts: mio::PollOpt,
|
||||
poll: &Arc<Poller>,
|
||||
mut interest: Event,
|
||||
poll_opts: PollMode,
|
||||
) -> Result<()> {
|
||||
poll.reregister(&EventedFd(&self.file.as_raw_fd()), self.token, interest, poll_opts)?;
|
||||
interest.key = PTY_READ_WRITE_TOKEN;
|
||||
poll.modify_with_mode(&self.file, interest, poll_opts)?;
|
||||
|
||||
poll.reregister(
|
||||
poll.modify_with_mode(
|
||||
&self.signals,
|
||||
self.signals_token,
|
||||
mio::Ready::readable(),
|
||||
mio::PollOpt::level(),
|
||||
Event::readable(PTY_CHILD_EVENT_TOKEN),
|
||||
PollMode::Level,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn deregister(&mut self, poll: &mio::Poll) -> Result<()> {
|
||||
poll.deregister(&EventedFd(&self.file.as_raw_fd()))?;
|
||||
poll.deregister(&self.signals)
|
||||
fn deregister(&mut self, poll: &Arc<Poller>) -> Result<()> {
|
||||
poll.delete(&self.file)?;
|
||||
poll.delete(&self.signals)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -347,44 +355,33 @@ impl EventedReadWrite for Pty {
|
|||
&mut self.file
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read_token(&self) -> mio::Token {
|
||||
self.token
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn writer(&mut self) -> &mut File {
|
||||
&mut self.file
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_token(&self) -> mio::Token {
|
||||
self.token
|
||||
}
|
||||
}
|
||||
|
||||
impl EventedPty for Pty {
|
||||
#[inline]
|
||||
fn next_child_event(&mut self) -> Option<ChildEvent> {
|
||||
self.signals.pending().next().and_then(|signal| {
|
||||
if signal != sigconsts::SIGCHLD {
|
||||
return None;
|
||||
// See if there has been a SIGCHLD.
|
||||
let mut buf = [0u8; 1];
|
||||
if let Err(err) = self.signals.read(&mut buf) {
|
||||
if err.kind() != ErrorKind::WouldBlock {
|
||||
error!("Error reading from signal pipe: {}", err);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
match self.child.try_wait() {
|
||||
Err(e) => {
|
||||
error!("Error checking child process termination: {}", e);
|
||||
None
|
||||
},
|
||||
Ok(None) => None,
|
||||
Ok(_) => Some(ChildEvent::Exited),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn child_event_token(&self) -> mio::Token {
|
||||
self.signals_token
|
||||
// Match on the child process.
|
||||
match self.child.try_wait() {
|
||||
Err(err) => {
|
||||
error!("Error checking child process termination: {}", err);
|
||||
None
|
||||
},
|
||||
Ok(None) => None,
|
||||
Ok(_) => Some(ChildEvent::Exited),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
276
alacritty_terminal/src/tty/windows/blocking.rs
Normal file
276
alacritty_terminal/src/tty/windows/blocking.rs
Normal file
|
@ -0,0 +1,276 @@
|
|||
//! Code for running a reader/writer on another thread while driving it through `polling`.
|
||||
|
||||
use std::io::prelude::*;
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::task::{Context, Poll, Wake, Waker};
|
||||
use std::{io, thread};
|
||||
|
||||
use piper::{pipe, Reader, Writer};
|
||||
use polling::os::iocp::{CompletionPacket, PollerIocpExt};
|
||||
use polling::{Event, PollMode, Poller};
|
||||
|
||||
use crate::thread::spawn_named;
|
||||
|
||||
struct Registration {
|
||||
interest: Mutex<Option<Interest>>,
|
||||
end: PipeEnd,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum PipeEnd {
|
||||
Reader,
|
||||
Writer,
|
||||
}
|
||||
|
||||
struct Interest {
|
||||
/// The event to send about completion.
|
||||
event: Event,
|
||||
|
||||
/// The poller to send the event to.
|
||||
poller: Arc<Poller>,
|
||||
|
||||
/// The mode that we are in.
|
||||
mode: PollMode,
|
||||
}
|
||||
|
||||
/// Poll a reader in another thread.
|
||||
pub struct UnblockedReader<R> {
|
||||
/// The event to send about completion.
|
||||
interest: Arc<Registration>,
|
||||
|
||||
/// The pipe that we are reading from.
|
||||
pipe: Reader,
|
||||
|
||||
/// Is this the first time registering?
|
||||
first_register: bool,
|
||||
|
||||
/// We logically own the reader, but we don't actually use it.
|
||||
_reader: PhantomData<R>,
|
||||
}
|
||||
|
||||
impl<R: Read + Send + 'static> UnblockedReader<R> {
|
||||
/// Spawn a new unblocked reader.
|
||||
pub fn new(mut source: R, pipe_capacity: usize) -> Self {
|
||||
// Create a new pipe.
|
||||
let (reader, mut writer) = pipe(pipe_capacity);
|
||||
let interest = Arc::new(Registration {
|
||||
interest: Mutex::<Option<Interest>>::new(None),
|
||||
end: PipeEnd::Reader,
|
||||
});
|
||||
|
||||
// Spawn the reader thread.
|
||||
spawn_named("alacritty-tty-reader-thread", move || {
|
||||
let waker = Waker::from(Arc::new(ThreadWaker(thread::current())));
|
||||
let mut context = Context::from_waker(&waker);
|
||||
|
||||
loop {
|
||||
// Read from the reader into the pipe.
|
||||
match writer.poll_fill(&mut context, &mut source) {
|
||||
Poll::Ready(Ok(0)) => {
|
||||
// Either the pipe is closed or the reader is at its EOF.
|
||||
// In any case, we are done.
|
||||
return;
|
||||
},
|
||||
|
||||
Poll::Ready(Ok(_)) => {
|
||||
// Keep reading.
|
||||
continue;
|
||||
},
|
||||
|
||||
Poll::Ready(Err(e)) if e.kind() == io::ErrorKind::Interrupted => {
|
||||
// We were interrupted; continue.
|
||||
continue;
|
||||
},
|
||||
|
||||
Poll::Ready(Err(e)) => {
|
||||
log::error!("error writing to pipe: {}", e);
|
||||
return;
|
||||
},
|
||||
|
||||
Poll::Pending => {
|
||||
// We are now waiting on the other end to advance. Park the
|
||||
// thread until they do.
|
||||
thread::park();
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Self { interest, pipe: reader, first_register: true, _reader: PhantomData }
|
||||
}
|
||||
|
||||
/// Register interest in the reader.
|
||||
pub fn register(&mut self, poller: &Arc<Poller>, event: Event, mode: PollMode) {
|
||||
let mut interest = self.interest.interest.lock().unwrap();
|
||||
*interest = Some(Interest { event, poller: poller.clone(), mode });
|
||||
|
||||
// Send the event to start off with if we have any data.
|
||||
if (!self.pipe.is_empty() && event.readable) || self.first_register {
|
||||
self.first_register = false;
|
||||
poller.post(CompletionPacket::new(event)).ok();
|
||||
}
|
||||
}
|
||||
|
||||
/// Deregister interest in the reader.
|
||||
pub fn deregister(&self) {
|
||||
let mut interest = self.interest.interest.lock().unwrap();
|
||||
*interest = None;
|
||||
}
|
||||
|
||||
/// Try to read from the reader.
|
||||
pub fn try_read(&mut self, buf: &mut [u8]) -> usize {
|
||||
let waker = Waker::from(self.interest.clone());
|
||||
|
||||
match self.pipe.poll_drain_bytes(&mut Context::from_waker(&waker), buf) {
|
||||
Poll::Pending => 0,
|
||||
Poll::Ready(n) => n,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read + Send + 'static> Read for UnblockedReader<R> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
Ok(self.try_read(buf))
|
||||
}
|
||||
}
|
||||
|
||||
/// Poll a writer in another thread.
|
||||
pub struct UnblockedWriter<W> {
|
||||
/// The interest to send about completion.
|
||||
interest: Arc<Registration>,
|
||||
|
||||
/// The pipe that we are writing to.
|
||||
pipe: Writer,
|
||||
|
||||
/// We logically own the writer, but we don't actually use it.
|
||||
_reader: PhantomData<W>,
|
||||
}
|
||||
|
||||
impl<W: Write + Send + 'static> UnblockedWriter<W> {
|
||||
/// Spawn a new unblocked writer.
|
||||
pub fn new(mut sink: W, pipe_capacity: usize) -> Self {
|
||||
// Create a new pipe.
|
||||
let (mut reader, writer) = pipe(pipe_capacity);
|
||||
let interest = Arc::new(Registration {
|
||||
interest: Mutex::<Option<Interest>>::new(None),
|
||||
end: PipeEnd::Writer,
|
||||
});
|
||||
|
||||
// Spawn the writer thread.
|
||||
spawn_named("alacritty-tty-writer-thread", move || {
|
||||
let waker = Waker::from(Arc::new(ThreadWaker(thread::current())));
|
||||
let mut context = Context::from_waker(&waker);
|
||||
|
||||
loop {
|
||||
// Write from the pipe into the writer.
|
||||
match reader.poll_drain(&mut context, &mut sink) {
|
||||
Poll::Ready(Ok(0)) => {
|
||||
// Either the pipe is closed or the writer is full.
|
||||
// In any case, we are done.
|
||||
return;
|
||||
},
|
||||
|
||||
Poll::Ready(Ok(_)) => {
|
||||
// Keep writing.
|
||||
continue;
|
||||
},
|
||||
|
||||
Poll::Ready(Err(e)) if e.kind() == io::ErrorKind::Interrupted => {
|
||||
// We were interrupted; continue.
|
||||
continue;
|
||||
},
|
||||
|
||||
Poll::Ready(Err(e)) => {
|
||||
log::error!("error writing to pipe: {}", e);
|
||||
return;
|
||||
},
|
||||
|
||||
Poll::Pending => {
|
||||
// We are now waiting on the other end to advance. Park the
|
||||
// thread until they do.
|
||||
thread::park();
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Self { interest, pipe: writer, _reader: PhantomData }
|
||||
}
|
||||
|
||||
/// Register interest in the writer.
|
||||
pub fn register(&self, poller: &Arc<Poller>, event: Event, mode: PollMode) {
|
||||
let mut interest = self.interest.interest.lock().unwrap();
|
||||
*interest = Some(Interest { event, poller: poller.clone(), mode });
|
||||
|
||||
// Send the event to start off with if we have room for data.
|
||||
if !self.pipe.is_full() && event.writable {
|
||||
poller.post(CompletionPacket::new(event)).ok();
|
||||
}
|
||||
}
|
||||
|
||||
/// Deregister interest in the writer.
|
||||
pub fn deregister(&self) {
|
||||
let mut interest = self.interest.interest.lock().unwrap();
|
||||
*interest = None;
|
||||
}
|
||||
|
||||
/// Try to write to the writer.
|
||||
pub fn try_write(&mut self, buf: &[u8]) -> usize {
|
||||
let waker = Waker::from(self.interest.clone());
|
||||
|
||||
match self.pipe.poll_fill_bytes(&mut Context::from_waker(&waker), buf) {
|
||||
Poll::Pending => 0,
|
||||
Poll::Ready(n) => n,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Write + Send + 'static> Write for UnblockedWriter<W> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
Ok(self.try_write(buf))
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
// Nothing to flush.
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct ThreadWaker(thread::Thread);
|
||||
|
||||
impl Wake for ThreadWaker {
|
||||
fn wake(self: Arc<Self>) {
|
||||
self.0.unpark();
|
||||
}
|
||||
|
||||
fn wake_by_ref(self: &Arc<Self>) {
|
||||
self.0.unpark();
|
||||
}
|
||||
}
|
||||
|
||||
impl Wake for Registration {
|
||||
fn wake(self: Arc<Self>) {
|
||||
self.wake_by_ref();
|
||||
}
|
||||
|
||||
fn wake_by_ref(self: &Arc<Self>) {
|
||||
let mut interest_lock = self.interest.lock().unwrap();
|
||||
if let Some(interest) = interest_lock.as_ref() {
|
||||
// Send the event to the poller.
|
||||
let send_event = match self.end {
|
||||
PipeEnd::Reader => interest.event.readable,
|
||||
PipeEnd::Writer => interest.event.writable,
|
||||
};
|
||||
|
||||
if send_event {
|
||||
interest.poller.post(CompletionPacket::new(interest.event)).ok();
|
||||
|
||||
// Clear the event if we're in oneshot mode.
|
||||
if matches!(interest.mode, PollMode::Oneshot | PollMode::EdgeOneshot) {
|
||||
*interest_lock = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
use std::ffi::c_void;
|
||||
use std::io::Error;
|
||||
use std::sync::atomic::{AtomicPtr, Ordering};
|
||||
use std::sync::{mpsc, Arc, Mutex};
|
||||
|
||||
use mio_extras::channel::{channel, Receiver, Sender};
|
||||
use polling::os::iocp::{CompletionPacket, PollerIocpExt};
|
||||
use polling::{Event, Poller};
|
||||
|
||||
use windows_sys::Win32::Foundation::{BOOLEAN, HANDLE};
|
||||
use windows_sys::Win32::System::Threading::{
|
||||
|
@ -12,27 +14,43 @@ use windows_sys::Win32::System::Threading::{
|
|||
|
||||
use crate::tty::ChildEvent;
|
||||
|
||||
struct Interest {
|
||||
poller: Arc<Poller>,
|
||||
event: Event,
|
||||
}
|
||||
|
||||
struct ChildExitSender {
|
||||
sender: mpsc::Sender<ChildEvent>,
|
||||
interest: Arc<Mutex<Option<Interest>>>,
|
||||
}
|
||||
|
||||
/// WinAPI callback to run when child process exits.
|
||||
extern "system" fn child_exit_callback(ctx: *mut c_void, timed_out: BOOLEAN) {
|
||||
if timed_out != 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let event_tx: Box<_> = unsafe { Box::from_raw(ctx as *mut Sender<ChildEvent>) };
|
||||
let _ = event_tx.send(ChildEvent::Exited);
|
||||
let event_tx: Box<_> = unsafe { Box::from_raw(ctx as *mut ChildExitSender) };
|
||||
let _ = event_tx.sender.send(ChildEvent::Exited);
|
||||
let interest = event_tx.interest.lock().unwrap();
|
||||
if let Some(interest) = interest.as_ref() {
|
||||
interest.poller.post(CompletionPacket::new(interest.event)).ok();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ChildExitWatcher {
|
||||
wait_handle: AtomicPtr<c_void>,
|
||||
event_rx: Receiver<ChildEvent>,
|
||||
event_rx: mpsc::Receiver<ChildEvent>,
|
||||
interest: Arc<Mutex<Option<Interest>>>,
|
||||
}
|
||||
|
||||
impl ChildExitWatcher {
|
||||
pub fn new(child_handle: HANDLE) -> Result<ChildExitWatcher, Error> {
|
||||
let (event_tx, event_rx) = channel::<ChildEvent>();
|
||||
let (event_tx, event_rx) = mpsc::channel();
|
||||
|
||||
let mut wait_handle: HANDLE = 0;
|
||||
let sender_ref = Box::new(event_tx);
|
||||
let interest = Arc::new(Mutex::new(None));
|
||||
let sender_ref = Box::new(ChildExitSender { sender: event_tx, interest: interest.clone() });
|
||||
|
||||
let success = unsafe {
|
||||
RegisterWaitForSingleObject(
|
||||
|
@ -51,13 +69,22 @@ impl ChildExitWatcher {
|
|||
Ok(ChildExitWatcher {
|
||||
wait_handle: AtomicPtr::from(wait_handle as *mut c_void),
|
||||
event_rx,
|
||||
interest,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn event_rx(&self) -> &Receiver<ChildEvent> {
|
||||
pub fn event_rx(&self) -> &mpsc::Receiver<ChildEvent> {
|
||||
&self.event_rx
|
||||
}
|
||||
|
||||
pub fn register(&self, poller: &Arc<Poller>, event: Event) {
|
||||
*self.interest.lock().unwrap() = Some(Interest { poller: poller.clone(), event });
|
||||
}
|
||||
|
||||
pub fn deregister(&self) {
|
||||
*self.interest.lock().unwrap() = None;
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ChildExitWatcher {
|
||||
|
@ -72,36 +99,28 @@ impl Drop for ChildExitWatcher {
|
|||
mod tests {
|
||||
use std::os::windows::io::AsRawHandle;
|
||||
use std::process::Command;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use mio::{Events, Poll, PollOpt, Ready, Token};
|
||||
|
||||
use super::super::PTY_CHILD_EVENT_TOKEN;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
pub fn event_is_emitted_when_child_exits() {
|
||||
const WAIT_TIMEOUT: Duration = Duration::from_millis(200);
|
||||
|
||||
let poller = Arc::new(Poller::new().unwrap());
|
||||
|
||||
let mut child = Command::new("cmd.exe").spawn().unwrap();
|
||||
let child_exit_watcher = ChildExitWatcher::new(child.as_raw_handle() as HANDLE).unwrap();
|
||||
|
||||
let mut events = Events::with_capacity(1);
|
||||
let poll = Poll::new().unwrap();
|
||||
let child_events_token = Token::from(0usize);
|
||||
|
||||
poll.register(
|
||||
child_exit_watcher.event_rx(),
|
||||
child_events_token,
|
||||
Ready::readable(),
|
||||
PollOpt::oneshot(),
|
||||
)
|
||||
.unwrap();
|
||||
child_exit_watcher.register(&poller, Event::readable(PTY_CHILD_EVENT_TOKEN));
|
||||
|
||||
child.kill().unwrap();
|
||||
|
||||
// Poll for the event or fail with timeout if nothing has been sent.
|
||||
poll.poll(&mut events, Some(WAIT_TIMEOUT)).unwrap();
|
||||
assert_eq!(events.iter().next().unwrap().token(), child_events_token);
|
||||
let mut events = polling::Events::new();
|
||||
poller.wait(&mut events, Some(WAIT_TIMEOUT)).unwrap();
|
||||
assert_eq!(events.iter().next().unwrap().key, PTY_CHILD_EVENT_TOKEN);
|
||||
// Verify that at least one `ChildEvent::Exited` was received.
|
||||
assert_eq!(child_exit_watcher.event_rx().try_recv(), Ok(ChildEvent::Exited));
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@ use std::io::Error;
|
|||
use std::os::windows::io::IntoRawHandle;
|
||||
use std::{mem, ptr};
|
||||
|
||||
use mio_anonymous_pipes::{EventedAnonRead, EventedAnonWrite};
|
||||
|
||||
use windows_sys::core::{HRESULT, PWSTR};
|
||||
use windows_sys::Win32::Foundation::{HANDLE, S_OK};
|
||||
use windows_sys::Win32::System::Console::{
|
||||
|
@ -21,9 +19,12 @@ use windows_sys::Win32::System::Threading::{
|
|||
|
||||
use crate::config::PtyConfig;
|
||||
use crate::event::{OnResize, WindowSize};
|
||||
use crate::tty::windows::blocking::{UnblockedReader, UnblockedWriter};
|
||||
use crate::tty::windows::child::ChildExitWatcher;
|
||||
use crate::tty::windows::{cmdline, win32_string, Pty};
|
||||
|
||||
const PIPE_CAPACITY: usize = crate::event_loop::READ_BUFFER_SIZE;
|
||||
|
||||
/// Load the pseudoconsole API from conpty.dll if possible, otherwise use the
|
||||
/// standard Windows API.
|
||||
///
|
||||
|
@ -220,8 +221,8 @@ pub fn new(config: &PtyConfig, window_size: WindowSize) -> Option<Pty> {
|
|||
}
|
||||
}
|
||||
|
||||
let conin = EventedAnonWrite::new(conin);
|
||||
let conout = EventedAnonRead::new(conout);
|
||||
let conin = UnblockedWriter::new(conin, PIPE_CAPACITY);
|
||||
let conout = UnblockedReader::new(conout, PIPE_CAPACITY);
|
||||
|
||||
let child_watcher = ChildExitWatcher::new(proc_info.hProcess).unwrap();
|
||||
let conpty = Conpty { handle: pty_handle as HPCON, api };
|
||||
|
|
|
@ -3,17 +3,27 @@ use std::io::{self, Error, ErrorKind, Result};
|
|||
use std::iter::once;
|
||||
use std::os::windows::ffi::OsStrExt;
|
||||
use std::sync::mpsc::TryRecvError;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::config::{Program, PtyConfig};
|
||||
use crate::event::{OnResize, WindowSize};
|
||||
use crate::tty::windows::child::ChildExitWatcher;
|
||||
use crate::tty::{ChildEvent, EventedPty, EventedReadWrite};
|
||||
|
||||
mod blocking;
|
||||
mod child;
|
||||
mod conpty;
|
||||
|
||||
use blocking::{UnblockedReader, UnblockedWriter};
|
||||
use conpty::Conpty as Backend;
|
||||
use mio_anonymous_pipes::{EventedAnonRead as ReadPipe, EventedAnonWrite as WritePipe};
|
||||
use miow::pipe::{AnonRead, AnonWrite};
|
||||
use polling::{Event, Poller};
|
||||
|
||||
pub const PTY_CHILD_EVENT_TOKEN: usize = 1;
|
||||
pub const PTY_READ_WRITE_TOKEN: usize = 2;
|
||||
|
||||
type ReadPipe = UnblockedReader<AnonRead>;
|
||||
type WritePipe = UnblockedWriter<AnonWrite>;
|
||||
|
||||
pub struct Pty {
|
||||
// XXX: Backend is required to be the first field, to ensure correct drop order. Dropping
|
||||
|
@ -21,9 +31,6 @@ pub struct Pty {
|
|||
backend: Backend,
|
||||
conout: ReadPipe,
|
||||
conin: WritePipe,
|
||||
read_token: mio::Token,
|
||||
write_token: mio::Token,
|
||||
child_event_token: mio::Token,
|
||||
child_watcher: ChildExitWatcher,
|
||||
}
|
||||
|
||||
|
@ -39,51 +46,29 @@ impl Pty {
|
|||
conin: impl Into<WritePipe>,
|
||||
child_watcher: ChildExitWatcher,
|
||||
) -> Self {
|
||||
Self {
|
||||
backend: backend.into(),
|
||||
conout: conout.into(),
|
||||
conin: conin.into(),
|
||||
read_token: 0.into(),
|
||||
write_token: 0.into(),
|
||||
child_event_token: 0.into(),
|
||||
child_watcher,
|
||||
}
|
||||
Self { backend: backend.into(), conout: conout.into(), conin: conin.into(), child_watcher }
|
||||
}
|
||||
}
|
||||
|
||||
fn with_key(mut event: Event, key: usize) -> Event {
|
||||
event.key = key;
|
||||
event
|
||||
}
|
||||
|
||||
impl EventedReadWrite for Pty {
|
||||
type Reader = ReadPipe;
|
||||
type Writer = WritePipe;
|
||||
|
||||
#[inline]
|
||||
fn register(
|
||||
unsafe fn register(
|
||||
&mut self,
|
||||
poll: &mio::Poll,
|
||||
token: &mut dyn Iterator<Item = mio::Token>,
|
||||
interest: mio::Ready,
|
||||
poll_opts: mio::PollOpt,
|
||||
poll: &Arc<Poller>,
|
||||
interest: polling::Event,
|
||||
poll_opts: polling::PollMode,
|
||||
) -> io::Result<()> {
|
||||
self.read_token = token.next().unwrap();
|
||||
self.write_token = token.next().unwrap();
|
||||
|
||||
if interest.is_readable() {
|
||||
poll.register(&self.conout, self.read_token, mio::Ready::readable(), poll_opts)?
|
||||
} else {
|
||||
poll.register(&self.conout, self.read_token, mio::Ready::empty(), poll_opts)?
|
||||
}
|
||||
if interest.is_writable() {
|
||||
poll.register(&self.conin, self.write_token, mio::Ready::writable(), poll_opts)?
|
||||
} else {
|
||||
poll.register(&self.conin, self.write_token, mio::Ready::empty(), poll_opts)?
|
||||
}
|
||||
|
||||
self.child_event_token = token.next().unwrap();
|
||||
poll.register(
|
||||
self.child_watcher.event_rx(),
|
||||
self.child_event_token,
|
||||
mio::Ready::readable(),
|
||||
poll_opts,
|
||||
)?;
|
||||
self.conin.register(poll, with_key(interest, PTY_READ_WRITE_TOKEN), poll_opts);
|
||||
self.conout.register(poll, with_key(interest, PTY_READ_WRITE_TOKEN), poll_opts);
|
||||
self.child_watcher.register(poll, with_key(interest, PTY_CHILD_EVENT_TOKEN));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -91,36 +76,23 @@ impl EventedReadWrite for Pty {
|
|||
#[inline]
|
||||
fn reregister(
|
||||
&mut self,
|
||||
poll: &mio::Poll,
|
||||
interest: mio::Ready,
|
||||
poll_opts: mio::PollOpt,
|
||||
poll: &Arc<Poller>,
|
||||
interest: polling::Event,
|
||||
poll_opts: polling::PollMode,
|
||||
) -> io::Result<()> {
|
||||
if interest.is_readable() {
|
||||
poll.reregister(&self.conout, self.read_token, mio::Ready::readable(), poll_opts)?;
|
||||
} else {
|
||||
poll.reregister(&self.conout, self.read_token, mio::Ready::empty(), poll_opts)?;
|
||||
}
|
||||
if interest.is_writable() {
|
||||
poll.reregister(&self.conin, self.write_token, mio::Ready::writable(), poll_opts)?;
|
||||
} else {
|
||||
poll.reregister(&self.conin, self.write_token, mio::Ready::empty(), poll_opts)?;
|
||||
}
|
||||
|
||||
poll.reregister(
|
||||
self.child_watcher.event_rx(),
|
||||
self.child_event_token,
|
||||
mio::Ready::readable(),
|
||||
poll_opts,
|
||||
)?;
|
||||
self.conin.register(poll, with_key(interest, PTY_READ_WRITE_TOKEN), poll_opts);
|
||||
self.conout.register(poll, with_key(interest, PTY_READ_WRITE_TOKEN), poll_opts);
|
||||
self.child_watcher.register(poll, with_key(interest, PTY_CHILD_EVENT_TOKEN));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn deregister(&mut self, poll: &mio::Poll) -> io::Result<()> {
|
||||
poll.deregister(&self.conout)?;
|
||||
poll.deregister(&self.conin)?;
|
||||
poll.deregister(self.child_watcher.event_rx())?;
|
||||
fn deregister(&mut self, _poll: &Arc<Poller>) -> io::Result<()> {
|
||||
self.conin.deregister();
|
||||
self.conout.deregister();
|
||||
self.child_watcher.deregister();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -129,27 +101,13 @@ impl EventedReadWrite for Pty {
|
|||
&mut self.conout
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read_token(&self) -> mio::Token {
|
||||
self.read_token
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn writer(&mut self) -> &mut Self::Writer {
|
||||
&mut self.conin
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_token(&self) -> mio::Token {
|
||||
self.write_token
|
||||
}
|
||||
}
|
||||
|
||||
impl EventedPty for Pty {
|
||||
fn child_event_token(&self) -> mio::Token {
|
||||
self.child_event_token
|
||||
}
|
||||
|
||||
fn next_child_event(&mut self) -> Option<ChildEvent> {
|
||||
match self.child_watcher.event_rx().try_recv() {
|
||||
Ok(ev) => Some(ev),
|
||||
|
|
Loading…
Reference in a new issue