feat(sandbox): 通过执行租约撤销活动实例
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
//! Native instance monitor; revocation does not depend on the caller polling.
|
||||
use crate::{
|
||||
extension_job::Job,
|
||||
extension_permit::Lease,
|
||||
workspace::{HostError, Result},
|
||||
};
|
||||
use std::{
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc, Condvar, Mutex,
|
||||
},
|
||||
thread::JoinHandle,
|
||||
time::Duration,
|
||||
};
|
||||
struct KillOnExit(Job);
|
||||
impl Drop for KillOnExit {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.0.terminate();
|
||||
}
|
||||
}
|
||||
pub(crate) struct Watch {
|
||||
lease: Lease,
|
||||
cancelled: Arc<(Mutex<bool>, Condvar)>,
|
||||
failed: Arc<AtomicBool>,
|
||||
worker: Option<JoinHandle<()>>,
|
||||
}
|
||||
impl Watch {
|
||||
pub(crate) fn arm(job: &Job, lease: Lease) -> Result<Self> {
|
||||
lease.check()?;
|
||||
let job = KillOnExit(job.clone_for_deadline()?);
|
||||
let cancelled = Arc::new((Mutex::new(false), Condvar::new()));
|
||||
let failed = Arc::new(AtomicBool::new(false));
|
||||
let thread_cancel = Arc::clone(&cancelled);
|
||||
let thread_failed = Arc::clone(&failed);
|
||||
let thread_lease = lease.clone();
|
||||
let worker = std::thread::Builder::new()
|
||||
.name("extension-revocation".into())
|
||||
.spawn(move || {
|
||||
let mut stop = thread_cancel.0.lock().unwrap_or_else(|e| e.into_inner());
|
||||
while !*stop {
|
||||
if thread_lease.check().is_err() {
|
||||
if job.0.terminate().is_err() {
|
||||
thread_failed.store(true, Ordering::Release);
|
||||
}
|
||||
return;
|
||||
}
|
||||
stop = thread_cancel
|
||||
.1
|
||||
.wait_timeout(stop, Duration::from_millis(50))
|
||||
.unwrap_or_else(|e| e.into_inner())
|
||||
.0;
|
||||
}
|
||||
})
|
||||
.map_err(|_| HostError::new("EXTENSION_REVOCATION_WATCH_UNAVAILABLE"))?;
|
||||
Ok(Self {
|
||||
lease,
|
||||
cancelled,
|
||||
failed,
|
||||
worker: Some(worker),
|
||||
})
|
||||
}
|
||||
pub(crate) fn check(&self) -> Result<()> {
|
||||
if self.failed.load(Ordering::Acquire) {
|
||||
return Err(HostError::new("EXTENSION_RESOURCE_TERMINATE_FAILED"));
|
||||
}
|
||||
self.lease.check()?;
|
||||
if self
|
||||
.worker
|
||||
.as_ref()
|
||||
.is_some_and(|worker| worker.is_finished())
|
||||
{
|
||||
return Err(HostError::new("EXTENSION_REVOCATION_WATCH_FAILED"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl Drop for Watch {
|
||||
fn drop(&mut self) {
|
||||
*self.cancelled.0.lock().unwrap_or_else(|e| e.into_inner()) = true;
|
||||
self.cancelled.1.notify_all();
|
||||
if let Some(worker) = self.worker.take() {
|
||||
let _ = worker.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user