2021-10-14 00:06:53 +00:00
|
|
|
use actix_web::web::Bytes;
|
2021-08-31 02:19:47 +00:00
|
|
|
use std::{
|
2023-11-10 00:20:59 +00:00
|
|
|
ffi::OsStr,
|
2021-09-04 00:53:53 +00:00
|
|
|
future::Future,
|
2021-08-31 02:19:47 +00:00
|
|
|
pin::Pin,
|
2023-07-10 20:29:41 +00:00
|
|
|
process::{ExitStatus, Stdio},
|
2023-12-18 05:14:39 +00:00
|
|
|
sync::{
|
|
|
|
atomic::{AtomicU8, Ordering},
|
|
|
|
Arc, Mutex,
|
|
|
|
},
|
|
|
|
task::{Context, Poll, Wake, Waker},
|
2023-08-05 17:41:06 +00:00
|
|
|
time::{Duration, Instant},
|
2021-08-31 02:19:47 +00:00
|
|
|
};
|
2021-09-14 01:22:42 +00:00
|
|
|
use tokio::{
|
|
|
|
io::{AsyncRead, AsyncWriteExt, ReadBuf},
|
2023-08-05 17:41:06 +00:00
|
|
|
process::{Child, ChildStdin, ChildStdout, Command},
|
2021-09-14 01:22:42 +00:00
|
|
|
};
|
2023-12-22 19:20:36 +00:00
|
|
|
use tracing::Span;
|
2023-12-22 19:12:19 +00:00
|
|
|
use uuid::Uuid;
|
2021-09-04 00:53:53 +00:00
|
|
|
|
2023-12-22 19:12:19 +00:00
|
|
|
use crate::{
|
|
|
|
error_code::ErrorCode,
|
|
|
|
future::{LocalBoxFuture, WithTimeout},
|
|
|
|
};
|
2023-09-02 01:50:10 +00:00
|
|
|
|
2023-07-22 21:47:59 +00:00
|
|
|
struct MetricsGuard {
|
|
|
|
start: Instant,
|
|
|
|
armed: bool,
|
2023-12-22 19:12:19 +00:00
|
|
|
command: Arc<str>,
|
2023-07-22 21:47:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl MetricsGuard {
|
2023-12-22 19:12:19 +00:00
|
|
|
fn guard(command: Arc<str>) -> Self {
|
|
|
|
metrics::increment_counter!("pict-rs.process.start", "command" => command.to_string());
|
2023-07-22 21:47:59 +00:00
|
|
|
|
|
|
|
Self {
|
|
|
|
start: Instant::now(),
|
|
|
|
armed: true,
|
|
|
|
command,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn disarm(mut self) {
|
|
|
|
self.armed = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for MetricsGuard {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
metrics::histogram!(
|
|
|
|
"pict-rs.process.duration",
|
|
|
|
self.start.elapsed().as_secs_f64(),
|
2023-12-22 19:12:19 +00:00
|
|
|
"command" => self.command.to_string(),
|
2023-07-22 21:47:59 +00:00
|
|
|
"completed" => (!self.armed).to_string(),
|
|
|
|
);
|
|
|
|
|
2023-12-22 19:12:19 +00:00
|
|
|
metrics::increment_counter!("pict-rs.process.end", "completed" => (!self.armed).to_string() , "command" => self.command.to_string());
|
2023-07-22 21:47:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-09 19:16:12 +00:00
|
|
|
#[derive(Debug)]
|
2023-07-14 00:21:28 +00:00
|
|
|
struct StatusError(ExitStatus);
|
2021-09-09 19:16:12 +00:00
|
|
|
|
2021-08-31 02:19:47 +00:00
|
|
|
pub(crate) struct Process {
|
2023-12-22 19:12:19 +00:00
|
|
|
command: Arc<str>,
|
2021-09-14 01:22:42 +00:00
|
|
|
child: Child,
|
2023-07-22 21:47:59 +00:00
|
|
|
guard: MetricsGuard,
|
2023-08-05 17:41:06 +00:00
|
|
|
timeout: Duration,
|
2023-12-22 19:12:19 +00:00
|
|
|
id: Uuid,
|
2022-04-07 02:40:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl std::fmt::Debug for Process {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
f.debug_struct("Process").field("child", &"Child").finish()
|
|
|
|
}
|
2021-08-31 02:19:47 +00:00
|
|
|
}
|
|
|
|
|
2023-12-18 05:14:39 +00:00
|
|
|
struct ProcessReadState {
|
|
|
|
flags: AtomicU8,
|
|
|
|
parent: Mutex<Option<Waker>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ProcessReadWaker {
|
|
|
|
state: Arc<ProcessReadState>,
|
|
|
|
flag: u8,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) struct ProcessRead {
|
2023-12-22 19:12:19 +00:00
|
|
|
stdout: ChildStdout,
|
|
|
|
handle: LocalBoxFuture<'static, std::io::Result<()>>,
|
2023-12-18 05:14:39 +00:00
|
|
|
closed: bool,
|
|
|
|
state: Arc<ProcessReadState>,
|
2023-12-22 19:12:19 +00:00
|
|
|
span: Option<Span>,
|
|
|
|
command: Arc<str>,
|
|
|
|
id: Uuid,
|
2021-09-04 00:53:53 +00:00
|
|
|
}
|
|
|
|
|
2023-07-10 20:29:41 +00:00
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
|
|
pub(crate) enum ProcessError {
|
2023-07-17 02:51:14 +00:00
|
|
|
#[error("Required command {0} not found, make sure it exists in pict-rs' $PATH")]
|
2023-12-22 19:12:19 +00:00
|
|
|
NotFound(Arc<str>),
|
2023-07-10 20:29:41 +00:00
|
|
|
|
2023-07-17 02:51:14 +00:00
|
|
|
#[error("Cannot run command {0} due to invalid permissions on binary, make sure the pict-rs user has permission to run it")]
|
2023-12-22 19:12:19 +00:00
|
|
|
PermissionDenied(Arc<str>),
|
2023-07-17 02:51:14 +00:00
|
|
|
|
2023-07-10 20:29:41 +00:00
|
|
|
#[error("Reached process spawn limit")]
|
|
|
|
LimitReached,
|
|
|
|
|
2023-08-05 17:41:06 +00:00
|
|
|
#[error("{0} timed out")]
|
2023-12-22 19:12:19 +00:00
|
|
|
Timeout(Arc<str>),
|
2023-08-05 17:41:06 +00:00
|
|
|
|
2023-07-17 18:30:08 +00:00
|
|
|
#[error("{0} Failed with {1}")]
|
2023-12-22 19:12:19 +00:00
|
|
|
Status(Arc<str>, ExitStatus),
|
2023-07-10 20:29:41 +00:00
|
|
|
|
|
|
|
#[error("Unknown process error")]
|
|
|
|
Other(#[source] std::io::Error),
|
|
|
|
}
|
|
|
|
|
2023-09-02 01:50:10 +00:00
|
|
|
impl ProcessError {
|
|
|
|
pub(crate) const fn error_code(&self) -> ErrorCode {
|
|
|
|
match self {
|
|
|
|
Self::NotFound(_) => ErrorCode::COMMAND_NOT_FOUND,
|
|
|
|
Self::PermissionDenied(_) => ErrorCode::COMMAND_PERMISSION_DENIED,
|
|
|
|
Self::LimitReached | Self::Other(_) => ErrorCode::COMMAND_ERROR,
|
|
|
|
Self::Timeout(_) => ErrorCode::COMMAND_TIMEOUT,
|
|
|
|
Self::Status(_, _) => ErrorCode::COMMAND_FAILURE,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-31 02:19:47 +00:00
|
|
|
impl Process {
|
2023-11-10 00:20:59 +00:00
|
|
|
pub(crate) fn run<T>(
|
|
|
|
command: &str,
|
|
|
|
args: &[T],
|
|
|
|
envs: &[(&str, &OsStr)],
|
|
|
|
timeout: u64,
|
|
|
|
) -> Result<Self, ProcessError>
|
|
|
|
where
|
|
|
|
T: AsRef<OsStr>,
|
|
|
|
{
|
2023-12-22 19:12:19 +00:00
|
|
|
let command: Arc<str> = Arc::from(String::from(command));
|
|
|
|
|
2023-11-10 00:20:59 +00:00
|
|
|
let res = tracing::trace_span!(parent: None, "Create command", %command).in_scope(|| {
|
|
|
|
Self::spawn(
|
2023-12-22 19:12:19 +00:00
|
|
|
command.clone(),
|
|
|
|
Command::new(command.as_ref())
|
|
|
|
.args(args)
|
|
|
|
.envs(envs.iter().copied()),
|
2023-11-10 00:20:59 +00:00
|
|
|
timeout,
|
|
|
|
)
|
|
|
|
});
|
2023-07-10 20:29:41 +00:00
|
|
|
|
|
|
|
match res {
|
|
|
|
Ok(this) => Ok(this),
|
|
|
|
Err(e) => match e.kind() {
|
2023-12-22 19:12:19 +00:00
|
|
|
std::io::ErrorKind::NotFound => Err(ProcessError::NotFound(command)),
|
2023-07-17 02:51:14 +00:00
|
|
|
std::io::ErrorKind::PermissionDenied => {
|
2023-12-22 19:12:19 +00:00
|
|
|
Err(ProcessError::PermissionDenied(command))
|
2023-07-17 02:51:14 +00:00
|
|
|
}
|
2023-07-10 20:29:41 +00:00
|
|
|
std::io::ErrorKind::WouldBlock => Err(ProcessError::LimitReached),
|
|
|
|
_ => Err(ProcessError::Other(e)),
|
|
|
|
},
|
|
|
|
}
|
2021-09-14 01:22:42 +00:00
|
|
|
}
|
|
|
|
|
2023-12-22 19:12:19 +00:00
|
|
|
fn spawn(command: Arc<str>, cmd: &mut Command, timeout: u64) -> std::io::Result<Self> {
|
2023-07-14 00:21:57 +00:00
|
|
|
tracing::trace_span!(parent: None, "Spawn command", %command).in_scope(|| {
|
2023-12-22 19:12:19 +00:00
|
|
|
let guard = MetricsGuard::guard(command.clone());
|
2023-07-22 21:47:59 +00:00
|
|
|
|
2023-07-10 20:29:41 +00:00
|
|
|
let cmd = cmd
|
|
|
|
.stdin(Stdio::piped())
|
|
|
|
.stdout(Stdio::piped())
|
|
|
|
.kill_on_drop(true);
|
2021-09-25 20:23:05 +00:00
|
|
|
|
2023-07-14 00:21:57 +00:00
|
|
|
cmd.spawn().map(|child| Process {
|
|
|
|
child,
|
2023-12-22 19:12:19 +00:00
|
|
|
command,
|
2023-07-22 21:47:59 +00:00
|
|
|
guard,
|
2023-08-05 17:41:06 +00:00
|
|
|
timeout: Duration::from_secs(timeout),
|
2023-12-22 19:12:19 +00:00
|
|
|
id: Uuid::now_v7(),
|
2023-07-14 00:21:57 +00:00
|
|
|
})
|
2022-04-07 17:56:40 +00:00
|
|
|
})
|
2021-08-31 02:19:47 +00:00
|
|
|
}
|
|
|
|
|
2023-12-22 19:12:19 +00:00
|
|
|
#[tracing::instrument(skip(self), fields(command = %self.command, id = %self.id))]
|
2023-08-05 17:41:06 +00:00
|
|
|
pub(crate) async fn wait(self) -> Result<(), ProcessError> {
|
|
|
|
let Process {
|
|
|
|
command,
|
|
|
|
mut child,
|
|
|
|
guard,
|
|
|
|
timeout,
|
2023-12-22 19:12:19 +00:00
|
|
|
id: _,
|
2023-08-05 17:41:06 +00:00
|
|
|
} = self;
|
|
|
|
|
2023-09-05 02:58:57 +00:00
|
|
|
let res = child.wait().with_timeout(timeout).await;
|
2023-07-10 20:29:41 +00:00
|
|
|
|
|
|
|
match res {
|
2023-08-05 17:41:06 +00:00
|
|
|
Ok(Ok(status)) if status.success() => {
|
|
|
|
guard.disarm();
|
2023-07-22 21:47:59 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2023-08-05 17:41:06 +00:00
|
|
|
Ok(Ok(status)) => Err(ProcessError::Status(command, status)),
|
|
|
|
Ok(Err(e)) => Err(ProcessError::Other(e)),
|
|
|
|
Err(_) => {
|
|
|
|
child.kill().await.map_err(ProcessError::Other)?;
|
|
|
|
|
|
|
|
Err(ProcessError::Timeout(command))
|
|
|
|
}
|
2021-10-23 19:14:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-18 05:14:39 +00:00
|
|
|
pub(crate) fn bytes_read(self, input: Bytes) -> ProcessRead {
|
2022-10-02 02:17:18 +00:00
|
|
|
self.spawn_fn(move |mut stdin| {
|
2022-09-25 22:35:52 +00:00
|
|
|
let mut input = input;
|
|
|
|
async move { stdin.write_all_buf(&mut input).await }
|
|
|
|
})
|
2021-09-04 00:53:53 +00:00
|
|
|
}
|
|
|
|
|
2023-12-18 05:14:39 +00:00
|
|
|
pub(crate) fn read(self) -> ProcessRead {
|
2022-10-02 02:17:18 +00:00
|
|
|
self.spawn_fn(|_| async { Ok(()) })
|
2022-09-25 20:17:33 +00:00
|
|
|
}
|
|
|
|
|
2023-06-01 22:33:43 +00:00
|
|
|
#[allow(unknown_lints)]
|
|
|
|
#[allow(clippy::let_with_type_underscore)]
|
2022-10-02 03:47:52 +00:00
|
|
|
#[tracing::instrument(level = "trace", skip_all)]
|
2023-12-18 05:14:39 +00:00
|
|
|
fn spawn_fn<F, Fut>(self, f: F) -> ProcessRead
|
2022-09-25 22:35:52 +00:00
|
|
|
where
|
|
|
|
F: FnOnce(ChildStdin) -> Fut + 'static,
|
|
|
|
Fut: Future<Output = std::io::Result<()>>,
|
|
|
|
{
|
2023-08-05 17:41:06 +00:00
|
|
|
let Process {
|
|
|
|
command,
|
|
|
|
mut child,
|
|
|
|
guard,
|
|
|
|
timeout,
|
2023-12-22 19:12:19 +00:00
|
|
|
id,
|
2023-08-05 17:41:06 +00:00
|
|
|
} = self;
|
2021-09-04 00:53:53 +00:00
|
|
|
|
2023-08-05 17:41:06 +00:00
|
|
|
let stdin = child.stdin.take().expect("stdin exists");
|
|
|
|
let stdout = child.stdout.take().expect("stdout exists");
|
|
|
|
|
2023-12-22 19:12:19 +00:00
|
|
|
let handle = Box::pin(async move {
|
|
|
|
let child_fut = async {
|
|
|
|
(f)(stdin).await?;
|
|
|
|
|
|
|
|
child.wait().await
|
|
|
|
};
|
|
|
|
|
|
|
|
let error = match child_fut.with_timeout(timeout).await {
|
|
|
|
Ok(Ok(status)) if status.success() => {
|
|
|
|
guard.disarm();
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
Ok(Ok(status)) => {
|
|
|
|
std::io::Error::new(std::io::ErrorKind::Other, StatusError(status))
|
|
|
|
}
|
|
|
|
Ok(Err(e)) => e,
|
|
|
|
Err(_) => std::io::ErrorKind::TimedOut.into(),
|
|
|
|
};
|
|
|
|
|
|
|
|
child.kill().await?;
|
|
|
|
|
|
|
|
Err(error)
|
|
|
|
});
|
2021-09-04 00:53:53 +00:00
|
|
|
|
2022-04-07 02:40:49 +00:00
|
|
|
ProcessRead {
|
2023-12-22 19:12:19 +00:00
|
|
|
stdout,
|
|
|
|
handle,
|
2023-12-18 05:14:39 +00:00
|
|
|
closed: false,
|
|
|
|
state: ProcessReadState::new_woken(),
|
2023-12-22 19:12:19 +00:00
|
|
|
span: None,
|
|
|
|
command,
|
|
|
|
id,
|
2022-04-07 02:40:49 +00:00
|
|
|
}
|
2021-09-04 00:53:53 +00:00
|
|
|
}
|
2021-08-31 02:19:47 +00:00
|
|
|
}
|
|
|
|
|
2023-12-18 05:14:39 +00:00
|
|
|
impl ProcessReadState {
|
|
|
|
fn new_woken() -> Arc<Self> {
|
|
|
|
Arc::new(Self {
|
|
|
|
flags: AtomicU8::new(0xff),
|
|
|
|
parent: Mutex::new(None),
|
|
|
|
})
|
|
|
|
}
|
2023-07-14 00:21:28 +00:00
|
|
|
|
2023-12-18 05:14:39 +00:00
|
|
|
fn clone_parent(&self) -> Option<Waker> {
|
|
|
|
let guard = self.parent.lock().unwrap();
|
2023-12-22 18:03:05 +00:00
|
|
|
guard.as_ref().cloned()
|
2023-12-18 05:14:39 +00:00
|
|
|
}
|
2023-07-14 00:21:28 +00:00
|
|
|
|
2023-12-18 05:14:39 +00:00
|
|
|
fn into_parts(self) -> (AtomicU8, Option<Waker>) {
|
|
|
|
let ProcessReadState { flags, parent } = self;
|
2023-08-05 17:41:06 +00:00
|
|
|
|
2023-12-18 05:14:39 +00:00
|
|
|
let parent = parent.lock().unwrap().take();
|
|
|
|
|
|
|
|
(flags, parent)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ProcessRead {
|
|
|
|
fn get_waker(&self, flag: u8) -> Option<Waker> {
|
|
|
|
let mask = 0xff ^ flag;
|
|
|
|
let previous = self.state.flags.fetch_and(mask, Ordering::AcqRel);
|
|
|
|
let active = previous & flag;
|
|
|
|
|
|
|
|
if active == flag {
|
|
|
|
Some(
|
|
|
|
Arc::new(ProcessReadWaker {
|
|
|
|
state: self.state.clone(),
|
|
|
|
flag,
|
|
|
|
})
|
|
|
|
.into(),
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
2023-08-05 17:41:06 +00:00
|
|
|
|
2023-12-22 18:03:05 +00:00
|
|
|
fn set_parent_waker(&self, parent: &Waker) -> bool {
|
2023-12-18 05:14:39 +00:00
|
|
|
let mut guard = self.state.parent.lock().unwrap();
|
|
|
|
if let Some(waker) = guard.as_mut() {
|
|
|
|
if !waker.will_wake(parent) {
|
|
|
|
*waker = parent.clone();
|
2023-12-22 18:03:05 +00:00
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
2023-08-05 17:41:06 +00:00
|
|
|
}
|
2023-12-18 05:14:39 +00:00
|
|
|
} else {
|
|
|
|
*guard = Some(parent.clone());
|
2023-12-22 18:03:05 +00:00
|
|
|
true
|
2022-04-07 02:40:49 +00:00
|
|
|
}
|
2023-12-18 05:14:39 +00:00
|
|
|
}
|
2023-12-22 18:03:05 +00:00
|
|
|
|
|
|
|
fn mark_all_woken(&self) {
|
|
|
|
self.state.flags.store(0xff, Ordering::Release);
|
|
|
|
}
|
2023-12-18 05:14:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const HANDLE_WAKER: u8 = 0b_0100;
|
|
|
|
|
|
|
|
impl AsyncRead for ProcessRead {
|
|
|
|
fn poll_read(
|
|
|
|
mut self: Pin<&mut Self>,
|
|
|
|
cx: &mut Context<'_>,
|
|
|
|
buf: &mut ReadBuf<'_>,
|
|
|
|
) -> Poll<std::io::Result<()>> {
|
2023-12-22 19:12:19 +00:00
|
|
|
let command = self.command.clone();
|
|
|
|
let id = self.id;
|
|
|
|
let span = self
|
|
|
|
.span
|
|
|
|
.get_or_insert_with(|| tracing::info_span!("process task", %command, %id))
|
|
|
|
.clone();
|
2023-12-18 05:14:39 +00:00
|
|
|
let guard = span.enter();
|
|
|
|
|
|
|
|
let value = loop {
|
|
|
|
// always poll for bytes when poll_read is called
|
2023-07-14 00:21:28 +00:00
|
|
|
let before_size = buf.filled().len();
|
|
|
|
|
2023-12-22 19:12:19 +00:00
|
|
|
if let Poll::Ready(res) = Pin::new(&mut self.stdout).poll_read(cx, buf) {
|
2023-12-18 05:14:39 +00:00
|
|
|
if let Err(e) = res {
|
|
|
|
self.closed = true;
|
2023-07-14 00:21:28 +00:00
|
|
|
|
2023-12-18 05:14:39 +00:00
|
|
|
break Poll::Ready(Err(e));
|
|
|
|
} else if buf.filled().len() == before_size {
|
|
|
|
self.closed = true;
|
2023-07-14 00:21:28 +00:00
|
|
|
|
2023-12-18 05:14:39 +00:00
|
|
|
break Poll::Ready(Ok(()));
|
|
|
|
} else {
|
|
|
|
break Poll::Ready(Ok(()));
|
2023-07-14 00:21:28 +00:00
|
|
|
}
|
2023-12-22 19:20:21 +00:00
|
|
|
} else if self.closed {
|
|
|
|
// Stop if we're closed
|
|
|
|
break Poll::Ready(Ok(()));
|
2023-12-18 05:14:39 +00:00
|
|
|
} else if let Some(waker) = self.get_waker(HANDLE_WAKER) {
|
|
|
|
// only poll handle if we've been explicitly woken
|
|
|
|
let mut handle_cx = Context::from_waker(&waker);
|
|
|
|
|
2023-12-22 19:12:19 +00:00
|
|
|
if let Poll::Ready(res) = Pin::new(&mut self.handle).poll(&mut handle_cx) {
|
2023-12-22 18:03:05 +00:00
|
|
|
self.closed = true;
|
2023-12-22 19:20:21 +00:00
|
|
|
|
|
|
|
if let Err(e) = res {
|
|
|
|
break Poll::Ready(Err(e));
|
|
|
|
}
|
2023-12-18 05:14:39 +00:00
|
|
|
}
|
2023-12-22 18:03:05 +00:00
|
|
|
} else if self.set_parent_waker(cx.waker()) {
|
|
|
|
// if we updated the stored waker, mark all as woken an try polling again
|
|
|
|
// This doesn't actually "wake" the waker, it just allows the handle to be polled
|
|
|
|
// again next iteration
|
|
|
|
self.mark_all_woken();
|
2023-12-18 05:14:39 +00:00
|
|
|
} else {
|
2023-12-22 18:03:05 +00:00
|
|
|
// if the waker hasn't changed and nothing polled ready, return pending
|
2023-12-18 05:14:39 +00:00
|
|
|
break Poll::Pending;
|
|
|
|
}
|
|
|
|
};
|
2023-07-14 00:21:28 +00:00
|
|
|
|
2023-12-18 05:14:39 +00:00
|
|
|
drop(guard);
|
2023-07-14 00:21:28 +00:00
|
|
|
|
2023-12-18 05:14:39 +00:00
|
|
|
value
|
2021-09-04 00:53:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-18 05:14:39 +00:00
|
|
|
impl Wake for ProcessReadWaker {
|
|
|
|
fn wake(self: Arc<Self>) {
|
|
|
|
match Arc::try_unwrap(self) {
|
|
|
|
Ok(ProcessReadWaker { state, flag }) => match Arc::try_unwrap(state) {
|
|
|
|
Ok(state) => {
|
|
|
|
let (flags, parent) = state.into_parts();
|
|
|
|
|
|
|
|
flags.fetch_and(flag, Ordering::AcqRel);
|
|
|
|
|
|
|
|
if let Some(parent) = parent {
|
|
|
|
parent.wake();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(state) => {
|
|
|
|
state.flags.fetch_or(flag, Ordering::AcqRel);
|
|
|
|
|
|
|
|
if let Some(waker) = state.clone_parent() {
|
|
|
|
waker.wake();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Err(this) => this.wake_by_ref(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn wake_by_ref(self: &Arc<Self>) {
|
|
|
|
self.state.flags.fetch_or(self.flag, Ordering::AcqRel);
|
|
|
|
|
|
|
|
if let Some(parent) = self.state.clone_parent() {
|
|
|
|
parent.wake();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-09 19:16:12 +00:00
|
|
|
impl std::fmt::Display for StatusError {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
2023-07-14 00:21:28 +00:00
|
|
|
write!(f, "Command failed with bad status: {}", self.0)
|
2021-09-09 19:16:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::error::Error for StatusError {}
|