use std::sync::Arc;
use crate::atom::Atom;
use crate::error::LoadError;
use crate::module::{Module, ModuleOrigin, PurgeError};
use crate::namespace::NamespaceId;
use crate::native::CodeManagementFacility;
use super::spawning::drain_pending_spawns;
use super::{Scheduler, SharedState, namespace_registry};
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct HotLoadResult {
pub module_name: Atom,
pub generation: u64,
pub had_old_version: bool,
pub on_load_required: bool,
pub on_load_succeeded: bool,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct PurgeResult {
pub module_name: Atom,
pub processes_killed: usize,
}
impl Scheduler {
pub fn hot_load_module(&self, bytes: &[u8]) -> Result<HotLoadResult, LoadError> {
self.hot_load_module_in(NamespaceId::DEFAULT, bytes)
}
pub fn load_embedded_module(
&self,
module_name: &str,
) -> Result<Option<HotLoadResult>, LoadError> {
self.load_embedded_module_in(NamespaceId::DEFAULT, module_name)
}
pub fn load_module_in(
&self,
namespace: NamespaceId,
bytes: &[u8],
) -> Result<HotLoadResult, LoadError> {
self.hot_load_module_in(namespace, bytes)
}
pub fn hot_load_module_in(
&self,
namespace: NamespaceId,
bytes: &[u8],
) -> Result<HotLoadResult, LoadError> {
let registry = namespace_registry_for_load(&self.shared, namespace)?;
hot_load_module_in_shared(&self.shared, namespace, ®istry, bytes)
}
pub fn load_embedded_module_in(
&self,
namespace: NamespaceId,
module_name: &str,
) -> Result<Option<HotLoadResult>, LoadError> {
let Some(bytes) = crate::loader::embedded_module_bytes(module_name) else {
return Ok(None);
};
let registry = namespace_registry_for_load(&self.shared, namespace)?;
hot_load_module_in_shared_with_origin(
&self.shared,
namespace,
®istry,
&bytes,
ModuleOrigin::Embedded,
)
.map(Some)
}
pub fn purge_module(&self, name: Atom) -> Result<PurgeResult, PurgeError> {
self.purge_module_in(NamespaceId::DEFAULT, name)
}
pub fn force_purge_module(&self, name: Atom) -> Result<PurgeResult, PurgeError> {
self.force_purge_module_in(NamespaceId::DEFAULT, name)
}
pub fn purge_module_in(
&self,
namespace: NamespaceId,
name: Atom,
) -> Result<PurgeResult, PurgeError> {
let Some(registry) = namespace_registry(&self.shared, namespace) else {
return Err(PurgeError::NoOldVersion { module: name });
};
drain_pending_spawns(&self.shared, &self.inject_queues);
purge_module_in_shared(&self.shared, namespace, ®istry, name)
}
pub fn force_purge_module_in(
&self,
namespace: NamespaceId,
name: Atom,
) -> Result<PurgeResult, PurgeError> {
let Some(registry) = namespace_registry(&self.shared, namespace) else {
return Err(PurgeError::NoOldVersion { module: name });
};
drain_pending_spawns(&self.shared, &self.inject_queues);
force_purge_module_in_shared(&self.shared, namespace, ®istry, name)
}
pub fn lookup_module_in(&self, namespace: NamespaceId, name: Atom) -> Option<Arc<Module>> {
namespace_registry(&self.shared, namespace)?.lookup(name)
}
pub fn delete_module(&self, name: Atom) -> bool {
self.shared.module_registry.delete_module(name)
}
pub fn check_old_code(&self, name: Atom) -> bool {
self.shared.module_registry.has_old_code(name)
}
pub fn check_process_code(&self, pid: u64, name: Atom) -> bool {
let Some(old) = self.shared.module_registry.lookup_old(name) else {
return false;
};
process_references_old_code(&self.shared, pid, &old)
}
}
pub(in crate::scheduler) struct SchedulerCodeManagementFacility {
pub(super) shared: Arc<SharedState>,
}
impl CodeManagementFacility for SchedulerCodeManagementFacility {
fn load_module(&self, bytes: &[u8]) -> Result<HotLoadResult, LoadError> {
hot_load_module_shared(&self.shared, bytes)
}
fn purge_module(&self, module: Atom) -> Result<PurgeResult, PurgeError> {
purge_module_shared(&self.shared, module)
}
fn delete_module(&self, module: Atom) -> bool {
self.shared.module_registry.delete_module(module)
}
fn check_old_code(&self, module: Atom) -> bool {
self.shared.module_registry.has_old_code(module)
}
fn check_process_code(&self, pid: u64, module: Atom) -> bool {
let Some(old) = self.shared.module_registry.lookup_old(module) else {
return false;
};
process_references_old_code(&self.shared, pid, &old)
}
fn module_origin(&self, module: Atom) -> Option<ModuleOrigin> {
self.shared.module_registry.origin(module)
}
fn all_loaded_modules(&self) -> Vec<(Atom, ModuleOrigin)> {
self.shared.module_registry.all_loaded()
}
}
mod helpers;
use helpers::{
force_purge_module_in_shared, hot_load_module_in_shared, hot_load_module_in_shared_with_origin,
hot_load_module_shared, namespace_registry_for_load, process_references_old_code,
purge_module_in_shared, purge_module_shared,
};