use super::completion::TaskExecution;
use super::{
TaskCompletion, TaskGroup, TaskGroupLifecycleState, TaskId, TaskKind, TaskMeta, TaskName, TaskState,
MAX_INLINE_TASK_FUTURE_SIZE,
};
use crate::critical::CriticalRegistration;
use crate::RuntimeResult;
use std::future::Future;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::time::Instant;
impl TaskGroup {
pub(super) fn spawn_inner<F>(&self, name: TaskName, kind: TaskKind, future: F) -> RuntimeResult<TaskId>
where
F: Future<Output = ()> + Send + 'static,
{
let (task_id, join_handle) = self.spawn_inner_with_handle(name, kind, false, None, None, future)?;
drop(join_handle);
Ok(task_id)
}
pub(super) fn spawn_operation_task<F>(
&self,
name: TaskName,
kind: TaskKind,
operation: u64,
future: F,
) -> RuntimeResult<TaskId>
where
F: Future<Output = ()> + Send + 'static,
{
let (task_id, join_handle) = self.spawn_inner_with_handle(name, kind, false, None, Some(operation), future)?;
drop(join_handle);
Ok(task_id)
}
pub(super) fn spawn_inner_with_handle<F>(
&self,
name: TaskName,
kind: TaskKind,
propagate_panic: bool,
critical: Option<CriticalRegistration>,
operation: Option<u64>,
future: F,
) -> RuntimeResult<(TaskId, tokio::task::JoinHandle<()>)>
where
F: Future<Output = ()> + Send + 'static,
{
if std::mem::size_of::<F>() > MAX_INLINE_TASK_FUTURE_SIZE {
self.spawn_registered(name, kind, propagate_panic, critical, operation, Box::pin(future))
} else {
self.spawn_registered(name, kind, propagate_panic, critical, operation, future)
}
}
pub(super) fn spawn_registered<F>(
&self,
name: TaskName,
kind: TaskKind,
propagate_panic: bool,
critical: Option<CriticalRegistration>,
operation: Option<u64>,
future: F,
) -> RuntimeResult<(TaskId, tokio::task::JoinHandle<()>)>
where
F: Future<Output = ()> + Send + 'static,
{
let task_id = TaskId::new(self.inner.id, self.inner.next_task_id.fetch_add(1, Ordering::Relaxed));
let completion = Arc::new(TaskCompletion::new());
let meta = TaskMeta {
id: task_id,
name,
group_id: self.inner.id,
group_name: self.inner.name.clone(),
kind,
state: TaskState::Queued,
started_at: Instant::now(),
abort_handle: None,
abort_requested: false,
completion: completion.clone(),
operation,
};
let wrapped = TaskExecution::new(
future,
self.inner.clone(),
task_id,
completion,
propagate_panic,
critical,
)
.run();
let tracked = {
let _spawn_guard = self.inner.spawn_gate.lock();
let state = self.inner.lifecycle_state();
if state != TaskGroupLifecycleState::Open {
return Err(state.admission_error(crate::RuntimeOperation::SpawnTaskGroupTask));
}
self.inner.registry.insert_task(meta);
self.inner.tracker.track_future(wrapped)
};
let join_handle = self.inner.runtime.tokio_handle().spawn(tracked);
let abort_handle = join_handle.abort_handle();
let abort_requested = if let Some(mut meta) = self.inner.registry.tasks.get_mut(&task_id) {
meta.abort_handle = Some(abort_handle);
meta.state = TaskState::Running;
meta.abort_requested
} else {
false
};
if abort_requested {
join_handle.abort();
}
Ok((task_id, join_handle))
}
pub(super) fn abort_task_inner(&self, task_id: TaskId) -> Option<Arc<TaskCompletion>> {
let (abort_handle, completion) = {
let mut meta = self.inner.registry.tasks.get_mut(&task_id)?;
meta.abort_requested = true;
(meta.abort_handle.clone(), meta.completion.clone())
};
if let Some(abort_handle) = abort_handle {
abort_handle.abort();
}
Some(completion)
}
}