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