Even more work to create a sane way to replace scripts while they're active. This adds a way to await changes, to ensure they were actually made if we quickly need to use them.
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
dd535b30af
commit
2e19005a30
|
@ -12,8 +12,8 @@ pub mod volatile_scripts;
|
|||
macro_rules! script_hook {
|
||||
($hook_name: ident, $source: ident, $($parameters: expr),*) => {
|
||||
let mut aggregator = $source.get_script_iterator();
|
||||
while let Some(script) = aggregator.get_next() {
|
||||
let script = script.get();
|
||||
while let Some(script_container) = aggregator.get_next() {
|
||||
let script = script_container.get();
|
||||
if let Some(script) = script {
|
||||
if let Some(script) = script.read().as_deref() {
|
||||
if !script.is_suppressed() {
|
||||
|
|
|
@ -12,6 +12,7 @@ use std::fmt::{Debug, Formatter};
|
|||
use std::ops::Deref;
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::thread::JoinHandle;
|
||||
|
||||
pub trait Script: Send + Sync {
|
||||
fn name(&self) -> &StringKey;
|
||||
|
@ -144,15 +145,17 @@ impl Debug for dyn Script {
|
|||
|
||||
type ScriptHolder = Arc<RwLock<Option<Arc<dyn Script>>>>;
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct ScriptContainer {
|
||||
script: ScriptHolder,
|
||||
pub(crate) join_handle: RwLock<Option<JoinHandle<()>>>,
|
||||
}
|
||||
|
||||
impl ScriptContainer {
|
||||
pub fn new(script: Arc<dyn Script>) -> ScriptContainer {
|
||||
Self {
|
||||
script: Arc::new(RwLock::new(Some(script))),
|
||||
join_handle: RwLock::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,14 +172,16 @@ impl ScriptContainer {
|
|||
|
||||
pub fn set(&self, script: Arc<dyn Script>) -> Arc<dyn Script> {
|
||||
if let Some(v) = self.script.read().deref() {
|
||||
v.on_remove();
|
||||
v.mark_for_deletion();
|
||||
}
|
||||
if self.script.is_locked() {
|
||||
let holder = self.script.clone();
|
||||
let new = script.clone();
|
||||
std::thread::spawn(move || {
|
||||
let handle = std::thread::spawn(move || {
|
||||
holder.write().replace(new);
|
||||
});
|
||||
self.join_handle.write().replace(handle);
|
||||
} else {
|
||||
self.script.write().replace(script.clone());
|
||||
};
|
||||
|
@ -185,6 +190,7 @@ impl ScriptContainer {
|
|||
|
||||
pub fn clear(&self) {
|
||||
if let Some(v) = self.script.read().deref() {
|
||||
v.on_remove();
|
||||
v.mark_for_deletion();
|
||||
}
|
||||
if !self.script.is_locked() {
|
||||
|
@ -207,7 +213,19 @@ impl ScriptContainer {
|
|||
|
||||
impl From<ScriptHolder> for ScriptContainer {
|
||||
fn from(a: ScriptHolder) -> Self {
|
||||
Self { script: a }
|
||||
Self {
|
||||
script: a,
|
||||
join_handle: RwLock::new(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for ScriptContainer {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
script: self.script.clone(),
|
||||
join_handle: RwLock::new(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,8 +233,6 @@ impl From<ScriptHolder> for ScriptContainer {
|
|||
mod tests {
|
||||
use super::*;
|
||||
use std::sync::atomic::{AtomicBool, AtomicPtr};
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
||||
pub struct TestScript {
|
||||
name: StringKey,
|
||||
|
@ -361,7 +377,12 @@ mod tests {
|
|||
.downcast_ref::<ReplaceTestScript>()
|
||||
.unwrap()
|
||||
.test(script2);
|
||||
sleep(Duration::from_micros(500));
|
||||
let mut jh = container.join_handle.write();
|
||||
if jh.is_some() {
|
||||
let h = jh.take().unwrap();
|
||||
h.join().unwrap();
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
container.script.read().as_ref().unwrap().name(),
|
||||
&StringKey::new("script2")
|
||||
|
|
Loading…
Reference in New Issue