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

This commit is contained in:
Deukhoofd 2022-06-18 19:44:13 +02:00
parent dd535b30af
commit 2e19005a30
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
2 changed files with 29 additions and 8 deletions

View File

@ -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() {

View File

@ -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")