mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-11-29 06:50:59 +00:00
ts/async_wrapper: remove fd from reactor before dropping its handle
The I/O handle was dropped prior to removing it from the reactor, which caused `Poller::delete` to fail due to an invalid file descriptor. This used to happen silently unless the same fd was added again, e.g. by changing states in the pipeline as follow: Null -> Playing -> Null -> Playing. In which case `Poller::add` failed due to an already existing file. This commit makes sure the fd is removed from the reactor prior to dropping the handle. In order to achieve this, a new task is spawned on the `Context` on which the I/O was originally registered, allowing it to access the proper `Reactor`. The I/O can then safely be dropped. Because the I/O handle is moved to the spawned future, this solution requires adding the `Send + 'static` bounds to the I/O handle used within the `Async` wrapper. This appears not too restrictive for existing implementations though. Other attempts were considered, but they would cause deadlocks. This new approach also solves a potential race condition where a fd could be re-registered in a `Reactor` before it was removed.
This commit is contained in:
parent
06273ed628
commit
a45f944edd
4 changed files with 62 additions and 72 deletions
|
@ -19,7 +19,7 @@ gst-net = { package = "gstreamer-net", git = "https://gitlab.freedesktop.org/gst
|
||||||
gst-rtp = { package = "gstreamer-rtp", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs" }
|
gst-rtp = { package = "gstreamer-rtp", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs" }
|
||||||
once_cell = "1"
|
once_cell = "1"
|
||||||
pin-project-lite = "0.2.0"
|
pin-project-lite = "0.2.0"
|
||||||
polling = "2.0.0"
|
polling = "2.2.0"
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
slab = "0.4.2"
|
slab = "0.4.2"
|
||||||
socket2 = {features = ["all"], version = "0.4"}
|
socket2 = {features = ["all"], version = "0.4"}
|
||||||
|
|
|
@ -28,6 +28,8 @@ use std::os::windows::io::{AsRawSocket, RawSocket};
|
||||||
|
|
||||||
use socket2::{Domain, Protocol, SockAddr, Socket, Type};
|
use socket2::{Domain, Protocol, SockAddr, Socket, Type};
|
||||||
|
|
||||||
|
use crate::runtime::RUNTIME_CAT;
|
||||||
|
|
||||||
use super::scheduler::{self, Scheduler};
|
use super::scheduler::{self, Scheduler};
|
||||||
use super::{Reactor, Readable, ReadableOwned, Source, Writable, WritableOwned};
|
use super::{Reactor, Readable, ReadableOwned, Source, Writable, WritableOwned};
|
||||||
|
|
||||||
|
@ -87,7 +89,7 @@ use super::{Reactor, Readable, ReadableOwned, Source, Writable, WritableOwned};
|
||||||
/// [`Shutdown`][`std::net::Shutdown`].
|
/// [`Shutdown`][`std::net::Shutdown`].
|
||||||
///
|
///
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Async<T> {
|
pub struct Async<T: Send + 'static> {
|
||||||
/// A source registered in the reactor.
|
/// A source registered in the reactor.
|
||||||
pub(super) source: Arc<Source>,
|
pub(super) source: Arc<Source>,
|
||||||
|
|
||||||
|
@ -95,13 +97,13 @@ pub struct Async<T> {
|
||||||
io: Option<T>,
|
io: Option<T>,
|
||||||
|
|
||||||
// The [`Handle`] on the [`Scheduler`] on which this Async wrapper is registered.
|
// The [`Handle`] on the [`Scheduler`] on which this Async wrapper is registered.
|
||||||
handle: scheduler::HandleWeak,
|
sched: scheduler::HandleWeak,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Unpin for Async<T> {}
|
impl<T: Send + 'static> Unpin for Async<T> {}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
impl<T: AsRawFd> Async<T> {
|
impl<T: AsRawFd + Send + 'static> Async<T> {
|
||||||
/// Creates an async I/O handle.
|
/// Creates an async I/O handle.
|
||||||
///
|
///
|
||||||
/// This method will put the handle in non-blocking mode and register it in
|
/// This method will put the handle in non-blocking mode and register it in
|
||||||
|
@ -132,7 +134,7 @@ impl<T: AsRawFd> Async<T> {
|
||||||
Ok(Async {
|
Ok(Async {
|
||||||
source,
|
source,
|
||||||
io: Some(io),
|
io: Some(io),
|
||||||
handle: Scheduler::current()
|
sched: Scheduler::current()
|
||||||
.expect("Attempt to create an Async wrapper outside of a Context")
|
.expect("Attempt to create an Async wrapper outside of a Context")
|
||||||
.downgrade(),
|
.downgrade(),
|
||||||
})
|
})
|
||||||
|
@ -140,14 +142,14 @@ impl<T: AsRawFd> Async<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
impl<T: AsRawFd> AsRawFd for Async<T> {
|
impl<T: AsRawFd + Send + 'static> AsRawFd for Async<T> {
|
||||||
fn as_raw_fd(&self) -> RawFd {
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
self.source.raw
|
self.source.raw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
impl<T: AsRawSocket> Async<T> {
|
impl<T: AsRawSocket + Send + 'static> Async<T> {
|
||||||
/// Creates an async I/O handle.
|
/// Creates an async I/O handle.
|
||||||
///
|
///
|
||||||
/// This method will put the handle in non-blocking mode and register it in
|
/// This method will put the handle in non-blocking mode and register it in
|
||||||
|
@ -183,7 +185,7 @@ impl<T: AsRawSocket> Async<T> {
|
||||||
Ok(Async {
|
Ok(Async {
|
||||||
source,
|
source,
|
||||||
io: Some(io),
|
io: Some(io),
|
||||||
handle: Scheduler::current()
|
sched: Scheduler::current()
|
||||||
.expect("Attempt to create an Async wrapper outside of a Context")
|
.expect("Attempt to create an Async wrapper outside of a Context")
|
||||||
.downgrade(),
|
.downgrade(),
|
||||||
})
|
})
|
||||||
|
@ -191,13 +193,13 @@ impl<T: AsRawSocket> Async<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
impl<T: AsRawSocket> AsRawSocket for Async<T> {
|
impl<T: AsRawSocket + Send + 'static> AsRawSocket for Async<T> {
|
||||||
fn as_raw_socket(&self) -> RawSocket {
|
fn as_raw_socket(&self) -> RawSocket {
|
||||||
self.source.raw
|
self.source.raw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Async<T> {
|
impl<T: Send + 'static> Async<T> {
|
||||||
/// Gets a reference to the inner I/O handle.
|
/// Gets a reference to the inner I/O handle.
|
||||||
pub fn get_ref(&self) -> &T {
|
pub fn get_ref(&self) -> &T {
|
||||||
self.io.as_ref().unwrap()
|
self.io.as_ref().unwrap()
|
||||||
|
@ -358,32 +360,39 @@ impl<T> Async<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> AsRef<T> for Async<T> {
|
impl<T: Send + 'static> AsRef<T> for Async<T> {
|
||||||
fn as_ref(&self) -> &T {
|
fn as_ref(&self) -> &T {
|
||||||
self.get_ref()
|
self.get_ref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> AsMut<T> for Async<T> {
|
impl<T: Send + 'static> AsMut<T> for Async<T> {
|
||||||
fn as_mut(&mut self) -> &mut T {
|
fn as_mut(&mut self) -> &mut T {
|
||||||
self.get_mut()
|
self.get_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Drop for Async<T> {
|
impl<T: Send + 'static> Drop for Async<T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if let Some(io) = self.io.take() {
|
if let Some(io) = self.io.take() {
|
||||||
// Drop the I/O handle to close it.
|
if let Some(sched) = self.sched.upgrade() {
|
||||||
drop(io);
|
let source = Arc::clone(&self.source);
|
||||||
|
sched.spawn_and_awake(async move {
|
||||||
if let Some(handle) = self.handle.upgrade() {
|
Reactor::with_mut(|reactor| {
|
||||||
handle.remove_soure(Arc::clone(&self.source));
|
if let Err(err) = reactor.remove_io(&source) {
|
||||||
|
gst::error!(RUNTIME_CAT, "Failed to remove fd {}: {}", source.raw, err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
drop(io);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
drop(io);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Read> AsyncRead for Async<T> {
|
impl<T: Read + Send + 'static> AsyncRead for Async<T> {
|
||||||
fn poll_read(
|
fn poll_read(
|
||||||
mut self: Pin<&mut Self>,
|
mut self: Pin<&mut Self>,
|
||||||
cx: &mut Context<'_>,
|
cx: &mut Context<'_>,
|
||||||
|
@ -413,7 +422,7 @@ impl<T: Read> AsyncRead for Async<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> AsyncRead for &Async<T>
|
impl<T: Send + 'static> AsyncRead for &Async<T>
|
||||||
where
|
where
|
||||||
for<'a> &'a T: Read,
|
for<'a> &'a T: Read,
|
||||||
{
|
{
|
||||||
|
@ -446,7 +455,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Write> AsyncWrite for Async<T> {
|
impl<T: Write + Send + 'static> AsyncWrite for Async<T> {
|
||||||
fn poll_write(
|
fn poll_write(
|
||||||
mut self: Pin<&mut Self>,
|
mut self: Pin<&mut Self>,
|
||||||
cx: &mut Context<'_>,
|
cx: &mut Context<'_>,
|
||||||
|
@ -490,7 +499,7 @@ impl<T: Write> AsyncWrite for Async<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> AsyncWrite for &Async<T>
|
impl<T: Send + 'static> AsyncWrite for &Async<T>
|
||||||
where
|
where
|
||||||
for<'a> &'a T: Write,
|
for<'a> &'a T: Write,
|
||||||
{
|
{
|
||||||
|
|
|
@ -186,6 +186,12 @@ impl Reactor {
|
||||||
|
|
||||||
// Register the file descriptor.
|
// Register the file descriptor.
|
||||||
if let Err(err) = self.poller.add(raw, Event::none(source.key)) {
|
if let Err(err) = self.poller.add(raw, Event::none(source.key)) {
|
||||||
|
gst::error!(
|
||||||
|
crate::runtime::RUNTIME_CAT,
|
||||||
|
"Failed to register fd {}: {}",
|
||||||
|
source.raw,
|
||||||
|
err,
|
||||||
|
);
|
||||||
self.sources.remove(source.key);
|
self.sources.remove(source.key);
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
@ -465,27 +471,27 @@ impl Source {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Waits until the I/O source is readable.
|
/// Waits until the I/O source is readable.
|
||||||
pub fn readable<T>(handle: &Async<T>) -> Readable<'_, T> {
|
pub fn readable<T: Send + 'static>(handle: &Async<T>) -> Readable<'_, T> {
|
||||||
Readable(Self::ready(handle, READ))
|
Readable(Self::ready(handle, READ))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Waits until the I/O source is readable.
|
/// Waits until the I/O source is readable.
|
||||||
pub fn readable_owned<T>(handle: Arc<Async<T>>) -> ReadableOwned<T> {
|
pub fn readable_owned<T: Send + 'static>(handle: Arc<Async<T>>) -> ReadableOwned<T> {
|
||||||
ReadableOwned(Self::ready(handle, READ))
|
ReadableOwned(Self::ready(handle, READ))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Waits until the I/O source is writable.
|
/// Waits until the I/O source is writable.
|
||||||
pub fn writable<T>(handle: &Async<T>) -> Writable<'_, T> {
|
pub fn writable<T: Send + 'static>(handle: &Async<T>) -> Writable<'_, T> {
|
||||||
Writable(Self::ready(handle, WRITE))
|
Writable(Self::ready(handle, WRITE))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Waits until the I/O source is writable.
|
/// Waits until the I/O source is writable.
|
||||||
pub fn writable_owned<T>(handle: Arc<Async<T>>) -> WritableOwned<T> {
|
pub fn writable_owned<T: Send + 'static>(handle: Arc<Async<T>>) -> WritableOwned<T> {
|
||||||
WritableOwned(Self::ready(handle, WRITE))
|
WritableOwned(Self::ready(handle, WRITE))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Waits until the I/O source is readable or writable.
|
/// Waits until the I/O source is readable or writable.
|
||||||
fn ready<H: Borrow<Async<T>> + Clone, T>(handle: H, dir: usize) -> Ready<H, T> {
|
fn ready<H: Borrow<Async<T>> + Clone, T: Send + 'static>(handle: H, dir: usize) -> Ready<H, T> {
|
||||||
Ready {
|
Ready {
|
||||||
handle,
|
handle,
|
||||||
dir,
|
dir,
|
||||||
|
@ -498,9 +504,9 @@ impl Source {
|
||||||
|
|
||||||
/// Future for [`Async::readable`](crate::runtime::Async::readable).
|
/// Future for [`Async::readable`](crate::runtime::Async::readable).
|
||||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||||
pub struct Readable<'a, T>(Ready<&'a Async<T>, T>);
|
pub struct Readable<'a, T: Send + 'static>(Ready<&'a Async<T>, T>);
|
||||||
|
|
||||||
impl<T> Future for Readable<'_, T> {
|
impl<T: Send + 'static> Future for Readable<'_, T> {
|
||||||
type Output = io::Result<()>;
|
type Output = io::Result<()>;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
@ -510,7 +516,7 @@ impl<T> Future for Readable<'_, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> fmt::Debug for Readable<'_, T> {
|
impl<T: Send + 'static> fmt::Debug for Readable<'_, T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("Readable").finish()
|
f.debug_struct("Readable").finish()
|
||||||
}
|
}
|
||||||
|
@ -518,9 +524,9 @@ impl<T> fmt::Debug for Readable<'_, T> {
|
||||||
|
|
||||||
/// Future for [`Async::readable_owned`](crate::runtime::Async::readable_owned).
|
/// Future for [`Async::readable_owned`](crate::runtime::Async::readable_owned).
|
||||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||||
pub struct ReadableOwned<T>(Ready<Arc<Async<T>>, T>);
|
pub struct ReadableOwned<T: Send + 'static>(Ready<Arc<Async<T>>, T>);
|
||||||
|
|
||||||
impl<T> Future for ReadableOwned<T> {
|
impl<T: Send + 'static> Future for ReadableOwned<T> {
|
||||||
type Output = io::Result<()>;
|
type Output = io::Result<()>;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
@ -534,7 +540,7 @@ impl<T> Future for ReadableOwned<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> fmt::Debug for ReadableOwned<T> {
|
impl<T: Send + 'static> fmt::Debug for ReadableOwned<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("ReadableOwned").finish()
|
f.debug_struct("ReadableOwned").finish()
|
||||||
}
|
}
|
||||||
|
@ -542,9 +548,9 @@ impl<T> fmt::Debug for ReadableOwned<T> {
|
||||||
|
|
||||||
/// Future for [`Async::writable`](crate::runtime::Async::writable).
|
/// Future for [`Async::writable`](crate::runtime::Async::writable).
|
||||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||||
pub struct Writable<'a, T>(Ready<&'a Async<T>, T>);
|
pub struct Writable<'a, T: Send + 'static>(Ready<&'a Async<T>, T>);
|
||||||
|
|
||||||
impl<T> Future for Writable<'_, T> {
|
impl<T: Send + 'static> Future for Writable<'_, T> {
|
||||||
type Output = io::Result<()>;
|
type Output = io::Result<()>;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
@ -554,7 +560,7 @@ impl<T> Future for Writable<'_, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> fmt::Debug for Writable<'_, T> {
|
impl<T: Send + 'static> fmt::Debug for Writable<'_, T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("Writable").finish()
|
f.debug_struct("Writable").finish()
|
||||||
}
|
}
|
||||||
|
@ -562,9 +568,9 @@ impl<T> fmt::Debug for Writable<'_, T> {
|
||||||
|
|
||||||
/// Future for [`Async::writable_owned`](crate::runtime::Async::writable_owned).
|
/// Future for [`Async::writable_owned`](crate::runtime::Async::writable_owned).
|
||||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||||
pub struct WritableOwned<T>(Ready<Arc<Async<T>>, T>);
|
pub struct WritableOwned<T: Send + 'static>(Ready<Arc<Async<T>>, T>);
|
||||||
|
|
||||||
impl<T> Future for WritableOwned<T> {
|
impl<T: Send + 'static> Future for WritableOwned<T> {
|
||||||
type Output = io::Result<()>;
|
type Output = io::Result<()>;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
@ -578,13 +584,13 @@ impl<T> Future for WritableOwned<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> fmt::Debug for WritableOwned<T> {
|
impl<T: Send + 'static> fmt::Debug for WritableOwned<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("WritableOwned").finish()
|
f.debug_struct("WritableOwned").finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Ready<H: Borrow<Async<T>>, T> {
|
struct Ready<H: Borrow<Async<T>>, T: Send + 'static> {
|
||||||
handle: H,
|
handle: H,
|
||||||
dir: usize,
|
dir: usize,
|
||||||
ticks: Option<(usize, usize)>,
|
ticks: Option<(usize, usize)>,
|
||||||
|
@ -592,9 +598,9 @@ struct Ready<H: Borrow<Async<T>>, T> {
|
||||||
_guard: Option<RemoveOnDrop<H, T>>,
|
_guard: Option<RemoveOnDrop<H, T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H: Borrow<Async<T>>, T> Unpin for Ready<H, T> {}
|
impl<H: Borrow<Async<T>>, T: Send + 'static> Unpin for Ready<H, T> {}
|
||||||
|
|
||||||
impl<H: Borrow<Async<T>> + Clone, T> Future for Ready<H, T> {
|
impl<H: Borrow<Async<T>> + Clone, T: Send + 'static> Future for Ready<H, T> {
|
||||||
type Output = io::Result<()>;
|
type Output = io::Result<()>;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
@ -656,14 +662,14 @@ impl<H: Borrow<Async<T>> + Clone, T> Future for Ready<H, T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove waker when dropped.
|
/// Remove waker when dropped.
|
||||||
struct RemoveOnDrop<H: Borrow<Async<T>>, T> {
|
struct RemoveOnDrop<H: Borrow<Async<T>>, T: Send + 'static> {
|
||||||
handle: H,
|
handle: H,
|
||||||
dir: usize,
|
dir: usize,
|
||||||
key: usize,
|
key: usize,
|
||||||
_marker: PhantomData<fn() -> T>,
|
_marker: PhantomData<fn() -> T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H: Borrow<Async<T>>, T> Drop for RemoveOnDrop<H, T> {
|
impl<H: Borrow<Async<T>>, T: Send + 'static + 'static> Drop for RemoveOnDrop<H, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let mut state = self.handle.borrow().source.state.lock().unwrap();
|
let mut state = self.handle.borrow().source.state.lock().unwrap();
|
||||||
let wakers = &mut state[self.dir].wakers;
|
let wakers = &mut state[self.dir].wakers;
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
//
|
//
|
||||||
// Take a look at the license at the top of the repository in the LICENSE file.
|
// Take a look at the license at the top of the repository in the LICENSE file.
|
||||||
|
|
||||||
use concurrent_queue::ConcurrentQueue;
|
|
||||||
|
|
||||||
use futures::channel::oneshot;
|
use futures::channel::oneshot;
|
||||||
use futures::pin_mut;
|
use futures::pin_mut;
|
||||||
|
|
||||||
|
@ -22,22 +20,18 @@ use std::time::{Duration, Instant};
|
||||||
use waker_fn::waker_fn;
|
use waker_fn::waker_fn;
|
||||||
|
|
||||||
use super::task::{SubTaskOutput, TaskId, TaskQueue};
|
use super::task::{SubTaskOutput, TaskId, TaskQueue};
|
||||||
use super::{CallOnDrop, JoinHandle, Reactor, Source};
|
use super::{CallOnDrop, JoinHandle, Reactor};
|
||||||
use crate::runtime::RUNTIME_CAT;
|
use crate::runtime::RUNTIME_CAT;
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
static CURRENT_SCHEDULER: RefCell<Option<HandleWeak>> = RefCell::new(None);
|
static CURRENT_SCHEDULER: RefCell<Option<HandleWeak>> = RefCell::new(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct CleanUpOps(Arc<Source>);
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) struct Scheduler {
|
pub(super) struct Scheduler {
|
||||||
context_name: Arc<str>,
|
context_name: Arc<str>,
|
||||||
max_throttling: Duration,
|
max_throttling: Duration,
|
||||||
tasks: TaskQueue,
|
tasks: TaskQueue,
|
||||||
cleanup_ops: ConcurrentQueue<CleanUpOps>,
|
|
||||||
must_awake: Mutex<bool>,
|
must_awake: Mutex<bool>,
|
||||||
must_awake_cvar: Condvar,
|
must_awake_cvar: Condvar,
|
||||||
}
|
}
|
||||||
|
@ -108,7 +102,6 @@ impl Scheduler {
|
||||||
context_name: context_name.clone(),
|
context_name: context_name.clone(),
|
||||||
max_throttling,
|
max_throttling,
|
||||||
tasks: TaskQueue::new(context_name),
|
tasks: TaskQueue::new(context_name),
|
||||||
cleanup_ops: ConcurrentQueue::bounded(1000),
|
|
||||||
must_awake: Mutex::new(false),
|
must_awake: Mutex::new(false),
|
||||||
must_awake_cvar: Condvar::new(),
|
must_awake_cvar: Condvar::new(),
|
||||||
}));
|
}));
|
||||||
|
@ -191,13 +184,7 @@ impl Scheduler {
|
||||||
break Ok(t);
|
break Ok(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
Reactor::with_mut(|reactor| {
|
Reactor::with_mut(|reactor| reactor.react().ok());
|
||||||
while let Ok(op) = self.cleanup_ops.pop() {
|
|
||||||
let _ = reactor.remove_io(&op.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
reactor.react().ok()
|
|
||||||
});
|
|
||||||
|
|
||||||
while let Ok(runnable) = self.tasks.pop_runnable() {
|
while let Ok(runnable) = self.tasks.pop_runnable() {
|
||||||
panic::catch_unwind(|| runnable.run()).map_err(|err| {
|
panic::catch_unwind(|| runnable.run()).map_err(|err| {
|
||||||
|
@ -424,18 +411,6 @@ impl Handle {
|
||||||
self.0.scheduler.wake_up();
|
self.0.scheduler.wake_up();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_soure(&self, source: Arc<Source>) {
|
|
||||||
if self
|
|
||||||
.0
|
|
||||||
.scheduler
|
|
||||||
.cleanup_ops
|
|
||||||
.push(CleanUpOps(source))
|
|
||||||
.is_err()
|
|
||||||
{
|
|
||||||
gst::warning!(RUNTIME_CAT, "scheduler: cleanup_ops is full");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn has_sub_tasks(&self, task_id: TaskId) -> bool {
|
pub fn has_sub_tasks(&self, task_id: TaskId) -> bool {
|
||||||
self.0.scheduler.tasks.has_sub_tasks(task_id)
|
self.0.scheduler.tasks.has_sub_tasks(task_id)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue