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