Use Bytes instead of Vec for more performant data copying between TTY and PTY

This commit is contained in:
Marcin Kulik
2025-06-23 16:31:47 +02:00
parent acf164a1a2
commit c9e9da604f
4 changed files with 12 additions and 7 deletions

1
Cargo.lock generated
View File

@@ -90,6 +90,7 @@ dependencies = [
"async-trait", "async-trait",
"avt", "avt",
"axum", "axum",
"bytes",
"clap", "clap",
"clap_complete", "clap_complete",
"clap_mangen", "clap_mangen",

View File

@@ -43,6 +43,7 @@ tokio-util = { version = "0.7", features = ["rt"] }
rand = "0.9" rand = "0.9"
async-trait = "0.1" async-trait = "0.1"
signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] } signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] }
bytes = "1.0"
[build-dependencies] [build-dependencies]
clap = { version = "4.0", features = ["derive", "wrap_help"] } clap = { version = "4.0", features = ["derive", "wrap_help"] }

View File

@@ -2,6 +2,7 @@ use std::collections::HashMap;
use std::time::SystemTime; use std::time::SystemTime;
use async_trait::async_trait; use async_trait::async_trait;
use bytes::{Buf, BytesMut};
use futures_util::future; use futures_util::future;
use futures_util::stream::StreamExt; use futures_util::stream::StreamExt;
use nix::sys::wait::{WaitPidFlag, WaitStatus}; use nix::sys::wait::{WaitPidFlag, WaitStatus};
@@ -135,8 +136,8 @@ impl<N: Notifier> Session<N> {
Signals::new([SIGWINCH, SIGINT, SIGTERM, SIGQUIT, SIGHUP, SIGALRM, SIGCHLD])?; Signals::new([SIGWINCH, SIGINT, SIGTERM, SIGQUIT, SIGHUP, SIGALRM, SIGCHLD])?;
let mut output_buf = [0u8; BUF_SIZE]; let mut output_buf = [0u8; BUF_SIZE];
let mut input_buf = [0u8; BUF_SIZE]; let mut input_buf = [0u8; BUF_SIZE];
let mut input: Vec<u8> = Vec::with_capacity(BUF_SIZE); let mut input = BytesMut::with_capacity(BUF_SIZE);
let mut output: Vec<u8> = Vec::with_capacity(BUF_SIZE); let mut output = BytesMut::with_capacity(BUF_SIZE);
let mut wait_status = None; let mut wait_status = None;
loop { loop {
@@ -154,7 +155,7 @@ impl<N: Notifier> Session<N> {
result = pty.write(&input), if !input.is_empty() => { result = pty.write(&input), if !input.is_empty() => {
let n = result?; let n = result?;
input.drain(..n); input.advance(n);
} }
result = tty.read(&mut input_buf) => { result = tty.read(&mut input_buf) => {
@@ -171,7 +172,7 @@ impl<N: Notifier> Session<N> {
result = tty.write(&output), if !output.is_empty() => { result = tty.write(&output), if !output.is_empty() => {
let n = result?; let n = result?;
output.drain(..n); output.advance(n);
} }
Some(signal) = signals.next() => { Some(signal) = signals.next() => {

View File

@@ -11,6 +11,8 @@ use std::os::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd};
use std::os::unix::fs::OpenOptionsExt; use std::os::unix::fs::OpenOptionsExt;
use std::thread; use std::thread;
use bytes::{Buf, BytesMut};
use async_trait::async_trait; use async_trait::async_trait;
use nix::errno::Errno; use nix::errno::Errno;
use nix::pty::Winsize; use nix::pty::Winsize;
@@ -135,7 +137,7 @@ fn copy<F: AsFd, G: AsFd>(src_fd: F, dst_fd: G) {
let src_fd = src_fd.as_fd(); let src_fd = src_fd.as_fd();
let dst_fd = dst_fd.as_fd(); let dst_fd = dst_fd.as_fd();
let mut buf = [0u8; BUF_SIZE]; let mut buf = [0u8; BUF_SIZE];
let mut data = Vec::with_capacity(BUF_SIZE); let mut data = BytesMut::with_capacity(BUF_SIZE);
loop { loop {
let mut read_fds = select::FdSet::new(); let mut read_fds = select::FdSet::new();
@@ -177,7 +179,7 @@ fn copy<F: AsFd, G: AsFd>(src_fd: F, dst_fd: G) {
if write_fds.contains(dst_fd) { if write_fds.contains(dst_fd) {
match unistd::write(dst_fd, &data) { match unistd::write(dst_fd, &data) {
Ok(n) => { Ok(n) => {
data.drain(..n); data.advance(n);
} }
Err(Errno::EWOULDBLOCK) => {} Err(Errno::EWOULDBLOCK) => {}
@@ -211,7 +213,7 @@ fn copy<F: AsFd, G: AsFd>(src_fd: F, dst_fd: G) {
match unistd::write(dst_fd, &data) { match unistd::write(dst_fd, &data) {
Ok(n) => { Ok(n) => {
data.drain(..n); data.advance(n);
} }
Err(Errno::EWOULDBLOCK) => {} Err(Errno::EWOULDBLOCK) => {}