Skip to content

Commit fe8f363

Browse files
Chris DrouillardCQ Bot
Chris Drouillard
authored and
CQ Bot
committed
[vfs] Reduce the size of spawned futures
The size of the wrapping future created in ExecutionScope::spawn was twice the size of the task passed into it. This was because the wrapping future was capturing the task in an upvar and then moving it to a local when polling it requiring space for 2 copies of the task. rust-lang/rust#108906 Writing our own future prevents duplicating the space requirements. The task spawned in VolumesDirectory::add_directory_entry is now 15312 bytes, down from 30640 bytes. Bug: b/393365596 Change-Id: Ib90a3ad99d42bd937effcac6bfa39d780ef188f4 Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/1198686 Commit-Queue: Chris Drouillard <[email protected]> Reviewed-by: Chris Suter <[email protected]>
1 parent adfdd06 commit fe8f363

File tree

1 file changed

+29
-20
lines changed

1 file changed

+29
-20
lines changed

src/storage/lib/vfs/rust/src/execution_scope.rs

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use crate::token_registry::TokenRegistry;
2121
use fuchsia_async::{JoinHandle, Scope, Task};
2222
use futures::task::{self, Poll};
2323
use futures::Future;
24+
use pin_project::pin_project;
2425
use std::future::{pending, poll_fn};
2526
use std::pin::pin;
2627
use std::sync::{Arc, Mutex, OnceLock};
@@ -102,26 +103,7 @@ impl ExecutionScope {
102103
/// This way `ExecutionScope` can actually also implement [`futures::task::Spawn`] - it just was
103104
/// not necessary for now.
104105
pub fn spawn(&self, task: impl Future<Output = ()> + Send + 'static) -> JoinHandle<()> {
105-
let executor = self.executor.clone();
106-
self.executor.scope().spawn(async move {
107-
let mut task = std::pin::pin!(task);
108-
poll_fn(|cx| {
109-
let shutdown_state = executor.inner.lock().unwrap().shutdown_state;
110-
match task.as_mut().poll(cx) {
111-
Poll::Ready(()) => Poll::Ready(()),
112-
Poll::Pending => match shutdown_state {
113-
ShutdownState::Active => Poll::Pending,
114-
ShutdownState::Shutdown
115-
if executor.inner.lock().unwrap().active_count > 0 =>
116-
{
117-
Poll::Pending
118-
}
119-
_ => Poll::Ready(()),
120-
},
121-
}
122-
})
123-
.await;
124-
})
106+
self.executor.scope().spawn(FutureWithShutdown { executor: self.executor.clone(), task })
125107
}
126108

127109
pub fn token_registry(&self) -> &TokenRegistry {
@@ -305,6 +287,33 @@ pub async fn yield_to_executor() {
305287
.await;
306288
}
307289

290+
/// A future that wraps another future and watches for the shutdown signal.
291+
#[pin_project]
292+
struct FutureWithShutdown<Task: Future<Output = ()> + Send + 'static> {
293+
executor: Arc<Executor>,
294+
#[pin]
295+
task: Task,
296+
}
297+
298+
impl<Task: Future<Output = ()> + Send + 'static> Future for FutureWithShutdown<Task> {
299+
type Output = ();
300+
301+
fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
302+
let this = self.project();
303+
let shutdown_state = this.executor.inner.lock().unwrap().shutdown_state;
304+
match this.task.poll(cx) {
305+
Poll::Ready(()) => Poll::Ready(()),
306+
Poll::Pending => match shutdown_state {
307+
ShutdownState::Active => Poll::Pending,
308+
ShutdownState::Shutdown if this.executor.inner.lock().unwrap().active_count > 0 => {
309+
Poll::Pending
310+
}
311+
_ => Poll::Ready(()),
312+
},
313+
}
314+
}
315+
}
316+
308317
#[cfg(test)]
309318
mod tests {
310319
use super::{yield_to_executor, ExecutionScope};

0 commit comments

Comments
 (0)