mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-11-25 13:01:07 +00:00
ts/executor: relax the static bound on enter
The function `enter` is executed in a blocking way from the caller's point of view. This means that we can guaranty that the provided function and its output will outlive the underlying Scheduler Task execution. This requires an unsafe call to `async_task::spawn_unchecked`. See: https://docs.rs/async-task/latest/async_task/fn.spawn_unchecked.html
This commit is contained in:
parent
21d41ca244
commit
5e4fc8b138
3 changed files with 31 additions and 11 deletions
|
@ -209,10 +209,10 @@ impl Context {
|
|||
/// This will block current thread and would panic if run
|
||||
/// from the [`Context`].
|
||||
#[track_caller]
|
||||
pub fn enter<F, O>(&self, f: F) -> O
|
||||
pub fn enter<'a, F, O>(&'a self, f: F) -> O
|
||||
where
|
||||
F: FnOnce() -> O + Send + 'static,
|
||||
O: Send + 'static,
|
||||
F: FnOnce() -> O + Send + 'a,
|
||||
O: Send + 'a,
|
||||
{
|
||||
if let Some(cur) = Context::current().as_ref() {
|
||||
if cur == self {
|
||||
|
|
|
@ -391,14 +391,17 @@ impl Handle {
|
|||
///
|
||||
/// This will block current thread and would panic if run
|
||||
/// from the [`Scheduler`].
|
||||
pub fn enter<F, O>(&self, f: F) -> O
|
||||
pub fn enter<'a, F, O>(&'a self, f: F) -> O
|
||||
where
|
||||
F: FnOnce() -> O + Send + 'static,
|
||||
O: Send + 'static,
|
||||
F: FnOnce() -> O + Send + 'a,
|
||||
O: Send + 'a,
|
||||
{
|
||||
assert!(!self.0.scheduler.is_current());
|
||||
|
||||
let task = self.0.scheduler.tasks.add_sync(f);
|
||||
// Safety: bounding `self` to `'a` and blocking on the task
|
||||
// ensures that the lifetime bounds satisfy the safety
|
||||
// requirements for `TaskQueue::add_sync`.
|
||||
let task = unsafe { self.0.scheduler.tasks.add_sync(f) };
|
||||
self.0.scheduler.wake_up();
|
||||
futures::executor::block_on(task)
|
||||
}
|
||||
|
@ -502,4 +505,13 @@ mod tests {
|
|||
|
||||
assert_eq!(res, 42);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enter_non_static() {
|
||||
let handle = Scheduler::start("enter_non_static", Duration::from_millis(2));
|
||||
|
||||
let mut flag = false;
|
||||
handle.enter(|| flag = true);
|
||||
assert!(flag);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -186,10 +186,16 @@ impl TaskQueue {
|
|||
(task_id, task)
|
||||
}
|
||||
|
||||
pub fn add_sync<F, O>(&self, f: F) -> async_task::Task<O>
|
||||
/// Adds a task to be blocked on immediately.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The function and its output must outlive the execution
|
||||
/// of the resulting task and the retrieval of the result.
|
||||
pub unsafe fn add_sync<F, O>(&self, f: F) -> async_task::Task<O>
|
||||
where
|
||||
F: FnOnce() -> O + Send + 'static,
|
||||
O: Send + 'static,
|
||||
F: FnOnce() -> O + Send,
|
||||
O: Send,
|
||||
{
|
||||
let tasks_clone = Arc::clone(&self.tasks);
|
||||
let mut tasks = self.tasks.lock().unwrap();
|
||||
|
@ -219,7 +225,9 @@ impl TaskQueue {
|
|||
};
|
||||
|
||||
let runnables = Arc::clone(&self.runnables);
|
||||
let (runnable, task) = async_task::spawn(task_fut, move |runnable| {
|
||||
// This is the unsafe call for which the lifetime must hold
|
||||
// until the the Future is Ready and its Output retrieved.
|
||||
let (runnable, task) = async_task::spawn_unchecked(task_fut, move |runnable| {
|
||||
runnables.push(runnable).unwrap();
|
||||
});
|
||||
tasks.insert(Task::new(task_id));
|
||||
|
|
Loading…
Reference in a new issue