1use 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, ¤t_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 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 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
418pub 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
442pub 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
483pub 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 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 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 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 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 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 assert!(wait.await.expect("await_answer").is_ok());
701
702 {
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 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 assert_matches!(cmp_requeue_response2.count, Some(2));
774 fasync::Timer::new(
777 fasync::MonotonicDuration::from_millis(100).after_now(),
778 )
779 .await;
780 let mut still_pending_count: u32 = 0;
781 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 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 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}