Skip to main content

starnix_kernel_runner/
serve_protocols.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::Container;
6use anyhow::{Context as _, Error};
7use fidl::endpoints::{ControlHandle, RequestStream, ServerEnd};
8use fidl_fuchsia_component_runner as frunner;
9use fidl_fuchsia_element as felement;
10use fidl_fuchsia_io as fio;
11use fidl_fuchsia_memory_attribution as fattribution;
12use fidl_fuchsia_posix as fposix;
13use fidl_fuchsia_starnix_binder as fbinder;
14use fidl_fuchsia_starnix_container as fstarcontainer;
15use fuchsia_async::{
16    DurationExt, {self as fasync},
17};
18use futures::channel::oneshot;
19use futures::{
20    AsyncReadExt, AsyncWriteExt, Future, FutureExt, StreamExt, TryFutureExt, TryStreamExt, pin_mut,
21    select,
22};
23use starnix_core::execution::{create_init_child_process, execute_task_with_prerun_result};
24use starnix_core::fs::devpts::create_main_and_replica;
25use starnix_core::fs::fuchsia::create_fuchsia_pipe;
26use starnix_core::task::dynamic_thread_spawner::SpawnRequestBuilder;
27use starnix_core::task::{CurrentTask, ExitStatus, Kernel, LockedAndTask, ProcessEntryRef};
28use starnix_core::vfs::buffers::{VecInputBuffer, VecOutputBuffer};
29use starnix_core::vfs::file_server::serve_file_at;
30use starnix_core::vfs::socket::VsockSocket;
31use starnix_core::vfs::{FdFlags, FileHandle};
32use starnix_logging::{log_error, log_warn};
33use starnix_modules_framebuffer::Framebuffer;
34use starnix_sync::{Locked, Unlocked};
35use starnix_task_command::TaskCommand;
36use starnix_uapi::auth::Credentials;
37use starnix_uapi::errors::Errno;
38use starnix_uapi::open_flags::OpenFlags;
39use starnix_uapi::signals::UncheckedSignal;
40use starnix_uapi::{errno, error, uapi};
41use std::ffi::CString;
42use std::ops::DerefMut;
43
44use super::start_component;
45
46pub fn expose_root(
47    locked: &mut Locked<Unlocked>,
48    system_task: &CurrentTask,
49    server_end: ServerEnd<fio::DirectoryMarker>,
50) -> Result<(), Error> {
51    let root_file = system_task.open_file(locked, "/".into(), OpenFlags::RDONLY)?;
52    serve_file_at(server_end.into_channel().into(), system_task, &root_file, Credentials::root())?;
53    Ok(())
54}
55
56pub async fn serve_component_runner(
57    request_stream: frunner::ComponentRunnerRequestStream,
58    system_task: &CurrentTask,
59) -> Result<(), Error> {
60    request_stream
61        .try_for_each_concurrent(None, |event| async {
62            match event {
63                frunner::ComponentRunnerRequest::Start { start_info, controller, .. } => {
64                    if let Err(e) = start_component(start_info, controller, system_task).await {
65                        log_error!("failed to start component: {:?}", e);
66                    }
67                }
68                frunner::ComponentRunnerRequest::_UnknownMethod { ordinal, .. } => {
69                    log_warn!("Unknown ComponentRunner request: {ordinal}");
70                }
71            }
72            Ok(())
73        })
74        .await
75        .map_err(Error::from)
76}
77
78fn to_winsize(window_size: Option<fstarcontainer::ConsoleWindowSize>) -> uapi::winsize {
79    window_size
80        .map(|window_size| uapi::winsize {
81            ws_row: window_size.rows,
82            ws_col: window_size.cols,
83            ws_xpixel: window_size.x_pixels,
84            ws_ypixel: window_size.y_pixels,
85        })
86        .unwrap_or(uapi::winsize::default())
87}
88
89async fn spawn_console(
90    kernel: &Kernel,
91    payload: fstarcontainer::ControllerSpawnConsoleRequest,
92) -> Result<Result<u8, fstarcontainer::SpawnConsoleError>, Error> {
93    if let (Some(console_in), Some(console_out), Some(binary_path)) =
94        (payload.console_in, payload.console_out, payload.binary_path)
95    {
96        let binary_path = CString::new(binary_path)?;
97        let argv = payload
98            .argv
99            .unwrap_or(vec![])
100            .into_iter()
101            .map(CString::new)
102            .collect::<Result<Vec<_>, _>>()?;
103        let environ = payload
104            .environ
105            .unwrap_or(vec![])
106            .into_iter()
107            .map(CString::new)
108            .collect::<Result<Vec<_>, _>>()?;
109        let window_size = to_winsize(payload.window_size);
110        let current_task = create_init_child_process(
111            kernel.kthreads.unlocked_for_async().deref_mut(),
112            &kernel.weak_self.upgrade().expect("Kernel must still be alive"),
113            TaskCommand::new(binary_path.as_bytes()),
114            Credentials::with_ids(0, 0),
115            None,
116        )?;
117        let (sender, receiver) = oneshot::channel();
118        let pty = execute_task_with_prerun_result(
119            kernel.kthreads.unlocked_for_async().deref_mut(),
120            current_task,
121            move |locked, current_task| {
122                let executable = current_task.open_file(
123                    locked,
124                    binary_path.as_bytes().into(),
125                    OpenFlags::RDONLY,
126                )?;
127                current_task.exec(locked, executable, binary_path, argv, environ)?;
128                let (pty, pts) = create_main_and_replica(locked, &current_task, window_size)?;
129                let fd_flags = FdFlags::empty();
130                assert_eq!(0, current_task.add_file(locked, pts.clone(), fd_flags)?.raw());
131                assert_eq!(1, current_task.add_file(locked, pts.clone(), fd_flags)?.raw());
132                assert_eq!(2, current_task.add_file(locked, pts, fd_flags)?.raw());
133                Ok(pty)
134            },
135            move |result| {
136                let _ = match result {
137                    Ok(ExitStatus::Exit(exit_code)) => sender.send(Ok(exit_code)),
138                    _ => sender.send(Err(fstarcontainer::SpawnConsoleError::Canceled)),
139                };
140            },
141            None,
142        )?;
143        let _ = forward_to_pty(kernel, console_in, console_out, pty).map_err(|e| {
144            log_error!("failed to forward to terminal {:?}", e);
145        });
146
147        Ok(receiver.await?)
148    } else {
149        Ok(Err(fstarcontainer::SpawnConsoleError::InvalidArgs))
150    }
151}
152
153pub async fn serve_container_controller(
154    request_stream: fstarcontainer::ControllerRequestStream,
155    system_task: &CurrentTask,
156) -> Result<(), Error> {
157    request_stream
158        .map_err(Error::from)
159        .try_for_each_concurrent(None, |event| async {
160            match event {
161                fstarcontainer::ControllerRequest::VsockConnect {
162                    payload:
163                        fstarcontainer::ControllerVsockConnectRequest { port, bridge_socket, .. },
164                    ..
165                } => {
166                    let Some(port) = port else {
167                        log_warn!("vsock connection missing port");
168                        return Ok(());
169                    };
170                    let Some(bridge_socket) = bridge_socket else {
171                        log_warn!("vsock connection missing bridge_socket");
172                        return Ok(());
173                    };
174                    connect_to_vsock(port, bridge_socket, system_task).await.unwrap_or_else(|e| {
175                        log_error!("failed to connect to vsock {:?}", e);
176                    });
177                }
178                fstarcontainer::ControllerRequest::SpawnConsole { payload, responder } => {
179                    responder.send(spawn_console(system_task.kernel(), payload).await?)?;
180                }
181                fstarcontainer::ControllerRequest::GetVmoReferences { payload, responder } => {
182                    if let Some(koid) = payload.koid {
183                        let thread_groups = system_task.kernel().pids.read().get_thread_groups();
184                        let mut results = vec![];
185                        for thread_group in thread_groups {
186                            if let Ok(leader) = system_task.get_task(thread_group.leader) {
187                                if let Ok(files) = leader.files() {
188                                    let fds = files.get_all_fds();
189                                    for fd in fds {
190                                        if let Ok(file) = files.get(fd) {
191                                            if let Ok(memory) = file.get_memory(
192                                                system_task
193                                                    .kernel()
194                                                    .kthreads
195                                                    .unlocked_for_async()
196                                                    .deref_mut(),
197                                                system_task,
198                                                None,
199                                                starnix_core::mm::ProtectionFlags::READ,
200                                            ) {
201                                                let memory_koid = memory
202                                                    .info()
203                                                    .expect("Failed to get memory info")
204                                                    .koid;
205                                                if memory_koid.raw_koid() == koid {
206                                                    let process_name = thread_group
207                                                        .process
208                                                        .get_name()
209                                                        .unwrap_or_default();
210                                                    results.push(fstarcontainer::VmoReference {
211                                                        process_name: Some(
212                                                            process_name.to_string(),
213                                                        ),
214                                                        pid: Some(leader.get_pid() as u64),
215                                                        fd: Some(fd.raw()),
216                                                        koid: Some(koid),
217                                                        ..Default::default()
218                                                    });
219                                                }
220                                            }
221                                        }
222                                    }
223                                }
224                            }
225                        }
226                        let _ =
227                            responder.send(&fstarcontainer::ControllerGetVmoReferencesResponse {
228                                references: Some(results),
229                                ..Default::default()
230                            });
231                    }
232                }
233                fstarcontainer::ControllerRequest::GetJobHandle { responder } => {
234                    let _result = responder.send(fstarcontainer::ControllerGetJobHandleResponse {
235                        job: Some(
236                            fuchsia_runtime::job_default()
237                                .duplicate_handle(zx::Rights::SAME_RIGHTS)
238                                .expect("Failed to dup handle"),
239                        ),
240                        ..Default::default()
241                    });
242                }
243                fstarcontainer::ControllerRequest::SendSignal {
244                    payload:
245                        fstarcontainer::ControllerSendSignalRequest {
246                            pid: Some(pid),
247                            signal: Some(signal),
248                            ..
249                        },
250                    responder,
251                } => {
252                    let pids = system_task.kernel().pids.read();
253                    if let Some(ProcessEntryRef::Process(target_thread_group)) =
254                        pids.get_process(pid)
255                    {
256                        #[allow(
257                            clippy::undocumented_unsafe_blocks,
258                            reason = "Force documented unsafe blocks in Starnix"
259                        )]
260                        match unsafe {
261                            target_thread_group.send_signal_unchecked_debug(
262                                system_task,
263                                UncheckedSignal::new(signal),
264                            )
265                        } {
266                            Ok(_) => {
267                                let _result = responder.send(Ok(()));
268                            }
269                            Err(_) => {
270                                let _result =
271                                    responder.send(Err(fstarcontainer::SignalError::InvalidSignal));
272                            }
273                        };
274                    } else {
275                        let _result =
276                            responder.send(Err(fstarcontainer::SignalError::InvalidTarget));
277                    };
278                }
279                // The request did not contain both a signal and a target pid.
280                fstarcontainer::ControllerRequest::SendSignal { responder, .. } => {
281                    log_error!("malformed SendSignal request");
282                    let _result = responder.send(Err(fstarcontainer::SignalError::InvalidTarget));
283                }
284                fstarcontainer::ControllerRequest::SetSyscallLogFilter { payload, responder } => {
285                    if let Some(process_name) = payload.process_name {
286                        system_task.kernel().add_syscall_log_filter(&process_name);
287                        let _ = responder.send(Ok(()));
288                    } else {
289                        let _ = responder.send(Err(
290                            fstarcontainer::SetSyscallLogFilterError::MissingProcessName,
291                        ));
292                    }
293                }
294                fstarcontainer::ControllerRequest::ClearSyscallLogFilters { responder } => {
295                    system_task.kernel().clear_syscall_log_filters();
296                    let _ = responder.send();
297                }
298                fstarcontainer::ControllerRequest::_UnknownMethod { .. } => (),
299            }
300            Ok(())
301        })
302        .await
303}
304
305async fn connect_to_vsock(
306    port: u32,
307    bridge_socket: fidl::Socket,
308    system_task: &CurrentTask,
309) -> Result<(), Error> {
310    let socket = loop {
311        if let Ok(socket) = system_task.kernel().default_abstract_vsock_namespace.lookup(&port) {
312            break socket;
313        };
314        fasync::Timer::new(fasync::MonotonicDuration::from_millis(100).after_now()).await;
315    };
316
317    let pipe = create_fuchsia_pipe(
318        system_task.kernel().kthreads.unlocked_for_async().deref_mut(),
319        system_task,
320        bridge_socket,
321        OpenFlags::RDWR | OpenFlags::NONBLOCK,
322    )?;
323    socket.downcast_socket::<VsockSocket>().unwrap().remote_connection(
324        system_task.kernel().kthreads.unlocked_for_async().deref_mut(),
325        &socket,
326        system_task,
327        pipe,
328    )?;
329
330    Ok(())
331}
332
333fn forward_to_pty(
334    kernel: &Kernel,
335    console_in: fidl::Socket,
336    console_out: fidl::Socket,
337    pty: FileHandle,
338) -> Result<(), Error> {
339    // Matches fuchsia.io.Transfer capacity, somewhat arbitrarily.
340    const BUFFER_CAPACITY: usize = 8192;
341
342    let mut rx = fuchsia_async::Socket::from_socket(console_in);
343    let mut tx = fuchsia_async::Socket::from_socket(console_out);
344    let pty_sink = pty.clone();
345    let closure = async move |locked_and_task: LockedAndTask<'_>| {
346        let _result: Result<(), Error> = (async || {
347            let mut buffer = vec![0u8; BUFFER_CAPACITY];
348            loop {
349                let bytes = rx.read(&mut buffer[..]).await?;
350                if bytes == 0 {
351                    return Ok(());
352                }
353                pty_sink.write(
354                    &mut locked_and_task.unlocked(),
355                    locked_and_task.current_task(),
356                    &mut VecInputBuffer::new(&buffer[..bytes]),
357                )?;
358            }
359        })()
360        .await;
361    };
362    let req = SpawnRequestBuilder::new()
363        .with_debug_name("forward-to-pty-in")
364        .with_async_closure(closure)
365        .build();
366    kernel.kthreads.spawner().spawn_from_request(req);
367
368    let pty_source = pty;
369    let closure = move |locked: &mut Locked<Unlocked>, current_task: &CurrentTask| {
370        let _result: Result<(), Error> =
371            fasync::LocalExecutor::default().run_singlethreaded(async {
372                let mut buffer = VecOutputBuffer::new(BUFFER_CAPACITY);
373                loop {
374                    buffer.reset();
375                    let bytes = pty_source.read(locked, current_task, &mut buffer)?;
376                    if bytes == 0 {
377                        return Ok(());
378                    }
379                    tx.write_all(buffer.data()).await?;
380                }
381            });
382    };
383    let req = SpawnRequestBuilder::new()
384        .with_debug_name("forward-to-pty-out")
385        .with_sync_closure(closure)
386        .build();
387    kernel.kthreads.spawner().spawn_from_request(req);
388
389    Ok(())
390}
391
392pub async fn serve_graphical_presenter(
393    mut request_stream: felement::GraphicalPresenterRequestStream,
394    kernel: &Kernel,
395) -> Result<(), Error> {
396    while let Some(request) = request_stream.next().await {
397        match request.context("reading graphical presenter request")? {
398            felement::GraphicalPresenterRequest::PresentView {
399                view_spec,
400                annotation_controller: _,
401                view_controller_request: _,
402                responder,
403            } => match view_spec.viewport_creation_token {
404                Some(token) => {
405                    let fb = Framebuffer::get(kernel).context("getting framebuffer from kernel")?;
406                    fb.present_view(token);
407                    let _ = responder.send(Ok(()));
408                }
409                None => {
410                    let _ = responder.send(Err(felement::PresentViewError::InvalidArgs));
411                }
412            },
413        }
414    }
415    Ok(())
416}
417
418/// Serves the memory attribution provider for the Kernel ELF component.
419pub fn serve_memory_attribution_provider_elfkernel(
420    mut request_stream: fattribution::ProviderRequestStream,
421    container: &Container,
422) -> impl Future<Output = Result<(), Error>> {
423    let observer = container.new_memory_attribution_observer(request_stream.control_handle());
424    async move {
425        while let Some(event) = request_stream.try_next().await? {
426            match event {
427                fattribution::ProviderRequest::Get { responder } => {
428                    observer.next(responder);
429                }
430                fattribution::ProviderRequest::_UnknownMethod {
431                    ordinal, control_handle, ..
432                } => {
433                    log_error!("Invalid request to AttributionProvider: {ordinal}");
434                    control_handle.shutdown_with_epitaph(zx::Status::INVALID_ARGS);
435                }
436            }
437        }
438        Ok(())
439    }
440}
441
442/// Serves the memory attribution provider for the Container component.
443pub fn serve_memory_attribution_provider_container(
444    mut request_stream: fattribution::ProviderRequestStream,
445    kernel: &Kernel,
446) -> impl Future<Output = ()> + use<> {
447    let observer = kernel.new_memory_attribution_observer(request_stream.control_handle());
448    async move {
449        while let Some(event) = request_stream
450            .try_next()
451            .await
452            .inspect_err(|err| {
453                log_warn!("Error while serving container memory attribution: {:?}", err)
454            })
455            .ok()
456            .flatten()
457        {
458            match event {
459                fattribution::ProviderRequest::Get { responder } => {
460                    observer.next(responder);
461                }
462                fattribution::ProviderRequest::_UnknownMethod {
463                    ordinal, control_handle, ..
464                } => {
465                    log_error!("Invalid request to AttributionProvider: {ordinal}");
466                    control_handle.shutdown_with_epitaph(zx::Status::INVALID_ARGS);
467                }
468            }
469        }
470    }
471}
472
473async fn select_first<O>(f1: impl Future<Output = O>, f2: impl Future<Output = O>) -> O {
474    let f1 = f1.fuse();
475    let f2 = f2.fuse();
476    pin_mut!(f1, f2);
477    select! {
478        f1 = f1 => f1,
479        f2 = f2 => f2,
480    }
481}
482
483/// Serve the LutexController protocol.
484pub async fn serve_lutex_controller(
485    request_stream: fbinder::LutexControllerRequestStream,
486    current_task: &CurrentTask,
487) -> Result<(), Error> {
488    let kernel = current_task.kernel();
489    request_stream
490        .map_err(Error::from)
491        .try_for_each_concurrent(None, |event| async move {
492            match event {
493                fbinder::LutexControllerRequest::WaitBitset { payload, responder } => {
494                    let deadline_and_receiver = (|| {
495                        let mut unlocked = kernel.kthreads.unlocked_for_async();
496                        let vmo = payload.vmo.ok_or_else(|| errno!(EINVAL))?;
497                        let offset = payload.offset.ok_or_else(|| errno!(EINVAL))?;
498                        let value = payload.value.ok_or_else(|| errno!(EINVAL))?;
499                        let mask = payload.mask.unwrap_or(u32::MAX);
500                        let deadline = payload.deadline.map(zx::MonotonicInstant::from_nanos);
501                        kernel
502                            .shared_futexes
503                            .external_wait(&mut unlocked, vmo.into(), offset, value, mask)
504                            .map(|(event, receiver)| (deadline, event, receiver))
505                    })();
506                    let result = match deadline_and_receiver {
507                        Ok((deadline, event, receiver)) => {
508                            // We construct a specific `wait_fut` to explicitly bind the lifecycle
509                            // of the `event` to the duration of this wait operation. If the FIDL
510                            // client disconnects (or the future is otherwise dropped/cancelled),
511                            // the `event` is immediately dropped. This zeros the strong reference
512                            // count on the `InterruptibleEvent`, signaling to the `FutexTable`
513                            // that this external waiter is now stale and should be garbage
514                            // collected on its next cleanup pass.
515                            let wait_fut = async move {
516                                let _event = event;
517                                let receiver = receiver.map_err(|_| errno!(EINTR));
518                                if let Some(deadline) = deadline {
519                                    let timer =
520                                        fasync::Timer::new(deadline).map(|_| error!(ETIMEDOUT));
521                                    select_first(timer, receiver).await
522                                } else {
523                                    receiver.await
524                                }
525                            };
526                            wait_fut.await
527                        }
528                        Err(e) => Err(e),
529                    };
530                    let result = result.map_err(|e: Errno| {
531                        fposix::Errno::from_primitive(e.code.error_code() as i32)
532                            .unwrap_or(fposix::Errno::Einval)
533                    });
534                    responder
535                        .send(result)
536                        .context("Unable to send LutexControllerRequest::WaitBitset response")?;
537                }
538                fbinder::LutexControllerRequest::WakeBitset { payload, responder } => {
539                    let result = (|| {
540                        let mut unlocked = kernel.kthreads.unlocked_for_async();
541                        let vmo = payload.vmo.ok_or_else(|| errno!(EINVAL))?;
542                        let offset = payload.offset.ok_or_else(|| errno!(EINVAL))?;
543                        let count = payload.count.ok_or_else(|| errno!(EINVAL))?;
544                        let mask = payload.mask.unwrap_or(u32::MAX);
545                        kernel.shared_futexes.external_wake(
546                            &mut unlocked,
547                            vmo.into(),
548                            offset,
549                            count as usize,
550                            mask,
551                        )
552                    })();
553                    let result = result
554                        .map(|count| fbinder::WakeResponse {
555                            count: Some(count as u64),
556                            ..fbinder::WakeResponse::default()
557                        })
558                        .map_err(|e: Errno| {
559                            fposix::Errno::from_primitive(e.code.error_code() as i32)
560                                .unwrap_or(fposix::Errno::Einval)
561                        });
562                    responder
563                        .send(result)
564                        .context("Unable to send LutexControllerRequest::WakeBitset response")?;
565                }
566                fbinder::LutexControllerRequest::CmpRequeue { payload, responder } => {
567                    let result = (|| {
568                        let mut unlocked = kernel.kthreads.unlocked_for_async();
569                        let first_vmo = payload.first_vmo.ok_or_else(|| errno!(EINVAL))?;
570                        let first_offset = payload.first_offset.ok_or_else(|| errno!(EINVAL))?;
571                        let second_vmo = payload.second_vmo;
572                        let second_offset = payload.second_offset.ok_or_else(|| errno!(EINVAL))?;
573                        let wake_count = payload.wake_count.ok_or_else(|| errno!(EINVAL))?;
574                        let requeue_count = payload.requeue_count.ok_or_else(|| errno!(EINVAL))?;
575                        let cmp_val = payload.cmp_val;
576                        kernel.shared_futexes.external_requeue(
577                            &mut unlocked,
578                            first_vmo.into(),
579                            first_offset,
580                            second_vmo.map(Into::into),
581                            second_offset,
582                            wake_count as usize,
583                            requeue_count as usize,
584                            cmp_val,
585                        )
586                    })();
587                    let result = result
588                        .map(|count| fbinder::CmpRequeueResponse {
589                            count: Some(count as u64),
590                            ..fbinder::CmpRequeueResponse::default()
591                        })
592                        .map_err(|e: Errno| {
593                            fposix::Errno::from_primitive(e.code.error_code() as i32)
594                                .unwrap_or(fposix::Errno::Einval)
595                        });
596                    responder
597                        .send(result)
598                        .context("Unable to send LutexControllerRequest::Requeue response")?;
599                }
600                fbinder::LutexControllerRequest::_UnknownMethod { ordinal, .. } => {
601                    log_warn!("Unknown LutexController ordinal: {}", ordinal);
602                }
603            }
604            Ok(())
605        })
606        .await
607        .context("failed fbinder::LutexController request")
608}
609
610#[cfg(test)]
611mod tests {
612    use super::*;
613    use assert_matches::assert_matches;
614    use fidl_fuchsia_posix as fposix;
615    use starnix_core::testing::*;
616    use zx;
617
618    #[fuchsia::test]
619    async fn lutex_controller_test() {
620        spawn_kernel_and_run(async |mut _locked, current_task| {
621            let (sender, receiver) = oneshot::channel::<()>();
622            current_task.kernel.kthreads.spawn_future(
623                {
624                    let kernel = current_task.kernel.clone();
625                    move || async move {
626                        let (lutex_controller, stream) = fidl::endpoints::create_proxy_and_stream::<
627                            fbinder::LutexControllerMarker,
628                        >();
629
630                        // Spawn the server
631                        let server_fut =
632                            serve_lutex_controller(stream, kernel.kthreads.system_task());
633
634                        let client_fut = async move {
635                            const VMO_SIZE: usize = 4 * 1024;
636                            let vmo = zx::Vmo::create(VMO_SIZE as u64).expect("Vmo::create");
637                            // Wait on an incorrect value.
638                            let wait = lutex_controller
639                                .wait_bitset(fbinder::WaitBitsetRequest {
640                                    vmo: Some(
641                                        vmo.duplicate_handle(zx::Rights::SAME_RIGHTS)
642                                            .expect("duplicate vmo"),
643                                    ),
644                                    offset: Some(0),
645                                    value: Some(1),
646                                    ..Default::default()
647                                })
648                                .await
649                                .expect("got_answer");
650                            assert_matches!(wait, Err(fposix::Errno::Eagain));
651
652                            // Wait with a timeout
653                            let wait = lutex_controller
654                                .wait_bitset(fbinder::WaitBitsetRequest {
655                                    vmo: Some(
656                                        vmo.duplicate_handle(zx::Rights::SAME_RIGHTS)
657                                            .expect("duplicate vmo"),
658                                    ),
659                                    offset: Some(0),
660                                    value: Some(0),
661                                    deadline: Some(0),
662                                    ..Default::default()
663                                })
664                                .await
665                                .expect("got_answer");
666                            assert_matches!(wait, Err(fposix::Errno::Etimedout));
667
668                            let mut wait = Box::pin(
669                                lutex_controller.wait_bitset(fbinder::WaitBitsetRequest {
670                                    vmo: Some(
671                                        vmo.duplicate_handle(zx::Rights::SAME_RIGHTS)
672                                            .expect("duplicate vmo"),
673                                    ),
674                                    offset: Some(0),
675                                    value: Some(0),
676                                    deadline: None,
677                                    ..Default::default()
678                                }),
679                            );
680                            // The wait is correct, the future should stay pending until a wake.
681                            assert!(futures::poll!(&mut wait).is_pending());
682
683                            let waken_up: fbinder::WakeResponse = lutex_controller
684                                .wake_bitset(fbinder::WakeBitsetRequest {
685                                    vmo: Some(
686                                        vmo.duplicate_handle(zx::Rights::SAME_RIGHTS)
687                                            .expect("duplicate vmo"),
688                                    ),
689                                    offset: Some(0),
690                                    count: Some(1),
691                                    mask: None,
692                                    ..Default::default()
693                                })
694                                .await
695                                .expect("wake_answer")
696                                .expect("wake_response");
697                            assert_eq!(waken_up.count, Some(1));
698
699                            // The wait should now return.
700                            assert!(wait.await.expect("await_answer").is_ok());
701
702                            // test cmp_requeue
703                            {
704                                let vmo2 = zx::Vmo::create(VMO_SIZE as u64).expect("Vmo::create");
705                                let mut wait1 = Box::pin(
706                                    lutex_controller.wait_bitset(fbinder::WaitBitsetRequest {
707                                        vmo: Some(
708                                            vmo.duplicate_handle(zx::Rights::SAME_RIGHTS)
709                                                .expect("duplicate vmo"),
710                                        ),
711                                        offset: Some(4),
712                                        value: Some(0),
713                                        deadline: None,
714                                        ..Default::default()
715                                    }),
716                                );
717                                let mut wait2 = Box::pin(
718                                    lutex_controller.wait_bitset(fbinder::WaitBitsetRequest {
719                                        vmo: Some(
720                                            vmo.duplicate_handle(zx::Rights::SAME_RIGHTS)
721                                                .expect("duplicate vmo"),
722                                        ),
723                                        offset: Some(4),
724                                        value: Some(0),
725                                        deadline: None,
726                                        ..Default::default()
727                                    }),
728                                );
729                                let cmp_requeue_response = lutex_controller
730                                    .cmp_requeue(fbinder::CmpRequeueRequest {
731                                        first_vmo: Some(
732                                            vmo.duplicate_handle(zx::Rights::SAME_RIGHTS)
733                                                .expect("duplicate vmo"),
734                                        ),
735                                        first_offset: Some(4),
736                                        second_vmo: Some(
737                                            vmo2.duplicate_handle(zx::Rights::SAME_RIGHTS)
738                                                .expect("duplicate vmo"),
739                                        ),
740                                        second_offset: Some(8),
741                                        wake_count: Some(1),
742                                        requeue_count: Some(1),
743                                        cmp_val: Some(0xBAD),
744                                        ..Default::default()
745                                    })
746                                    .await
747                                    .expect("got_answer")
748                                    .unwrap_err();
749                                // 0xBAD is not 0x0, so EAGAIN expected
750                                assert_matches!(cmp_requeue_response, fposix::Errno::Eagain);
751                                let cmp_requeue_response2: fbinder::CmpRequeueResponse =
752                                    lutex_controller
753                                        .cmp_requeue(fbinder::CmpRequeueRequest {
754                                            first_vmo: Some(
755                                                vmo.duplicate_handle(zx::Rights::SAME_RIGHTS)
756                                                    .expect("duplicate vmo"),
757                                            ),
758                                            first_offset: Some(4),
759                                            second_vmo: Some(
760                                                vmo2.duplicate_handle(zx::Rights::SAME_RIGHTS)
761                                                    .expect("duplicate vmo"),
762                                            ),
763                                            second_offset: Some(8),
764                                            wake_count: Some(1),
765                                            requeue_count: Some(1),
766                                            cmp_val: Some(0x0),
767                                            ..Default::default()
768                                        })
769                                        .await
770                                        .expect("got_answer")
771                                        .expect("got_response");
772                                // 1 woken, 1 re-queued
773                                assert_matches!(cmp_requeue_response2.count, Some(2));
774                                // give wait1 and wait2 a chance to complete; we don't rely on this
775                                // being long enough however
776                                fasync::Timer::new(
777                                    fasync::MonotonicDuration::from_millis(100).after_now(),
778                                )
779                                .await;
780                                let mut still_pending_count: u32 = 0;
781                                // Up to one of wait1 and wait2 can be completed by this point, so at
782                                // least one must still be pending.
783                                let wait1_poll = futures::poll!(&mut wait1);
784                                if wait1_poll.is_pending() {
785                                    still_pending_count += 1;
786                                }
787                                let wait2_poll = futures::poll!(&mut wait2);
788                                if wait2_poll.is_pending() {
789                                    still_pending_count += 1;
790                                }
791                                assert!(still_pending_count >= 1);
792                                // at this point exactly one of wait1 or wait2 will remain pending until
793                                // we wake it via vmo2 - we don't know which of wait1 or wait2 we're
794                                // waking here (which is fine)
795                                let vmo2_wake_response: fbinder::WakeResponse = lutex_controller
796                                    .wake_bitset(fbinder::WakeBitsetRequest {
797                                        vmo: Some(
798                                            vmo2.duplicate_handle(zx::Rights::SAME_RIGHTS)
799                                                .expect("duplicate vmo"),
800                                        ),
801                                        offset: Some(8),
802                                        count: Some(1),
803                                        mask: None,
804                                        ..Default::default()
805                                    })
806                                    .await
807                                    .expect("wake_answer")
808                                    .expect("wake_response");
809                                assert_eq!(vmo2_wake_response.count, Some(1));
810                                // Now we know that both wait1 and wait2 are unblocked, so we can
811                                // wait on both of them.
812                                if wait1_poll.is_pending() {
813                                    assert!(wait1.await.expect("await_answer").is_ok());
814                                }
815                                if wait2_poll.is_pending() {
816                                    assert!(wait2.await.expect("await_answer").is_ok());
817                                }
818                            }
819                        };
820
821                        let (server_res, _) = futures::join!(server_fut, client_fut);
822                        server_res.expect("server failed");
823                        let _ = sender.send(());
824                    }
825                },
826                "lutex_controller_test",
827            );
828            receiver.await.expect("test failed");
829        })
830        .await;
831    }
832}