1use crate::file::{
6 BufferInfo, ConnectionInfo, ConnectionMap, MagmaBuffer, MagmaConnection, MagmaDevice,
7 MagmaSemaphore,
8};
9use crate::image_file::{ImageFile, ImageInfo};
10use bstr::BString;
11use magma::{
12 MAGMA_QUERY_VENDOR_ID, MAGMA_STATUS_OK, MAGMA_VENDOR_ID_INTEL, MAGMA_VENDOR_ID_MALI,
13 magma_buffer_export, magma_buffer_get_handle, magma_buffer_t, magma_command_descriptor,
14 magma_connection_execute_command, magma_connection_execute_inline_commands,
15 magma_connection_flush, magma_connection_import_semaphore2,
16 magma_connection_read_notification_channel, magma_connection_t, magma_device_create_connection,
17 magma_device_import, magma_device_query, magma_device_t, magma_exec_command_buffer,
18 magma_exec_resource, magma_handle_t, magma_inline_command_buffer, magma_query_t,
19 magma_status_t, virtio_magma_buffer_export_ctrl_t, virtio_magma_buffer_export_resp_t,
20 virtio_magma_buffer_get_handle_ctrl_t, virtio_magma_buffer_get_handle_resp_t,
21 virtio_magma_connection_execute_command_ctrl_t,
22 virtio_magma_connection_execute_inline_commands_ctrl_t, virtio_magma_connection_flush_ctrl_t,
23 virtio_magma_connection_flush_resp_t, virtio_magma_connection_read_notification_channel_ctrl_t,
24 virtio_magma_connection_read_notification_channel_resp_t,
25 virtio_magma_connection_release_ctrl_t, virtio_magma_connection_release_resp_t,
26 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_BUFFER_EXPORT,
27 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_BUFFER_GET_HANDLE,
28 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_FLUSH,
29 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_READ_NOTIFICATION_CHANNEL,
30 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_RELEASE,
31 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_DEVICE_CREATE_CONNECTION,
32 virtio_magma_device_create_connection_resp_t, virtio_magma_device_import_ctrl_t,
33 virtio_magma_device_query_resp_t, virtmagma_command_descriptor,
34};
35use starnix_core::mm::memory::MemoryObject;
36use starnix_core::mm::{MemoryAccessor, MemoryAccessorExt};
37use starnix_core::task::CurrentTask;
38use starnix_core::vfs::{Anon, FdFlags, FsNodeInfo, MemoryRegularFile};
39use starnix_logging::track_stub;
40use starnix_sync::{Locked, Unlocked};
41use starnix_types::user_buffer::UserBuffer;
42use starnix_uapi::errors::Errno;
43use starnix_uapi::file_mode::FileMode;
44use starnix_uapi::open_flags::OpenFlags;
45use starnix_uapi::user_address::{UserAddress, UserRef};
46use starnix_uapi::{errno, error};
47use std::mem::ManuallyDrop;
48use std::sync::Arc;
49use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
50
51fn read_objects<T>(
60 current_task: &CurrentTask,
61 addr: UserAddress,
62 item_count: usize,
63) -> Result<Vec<T>, Errno>
64where
65 T: Default + Clone + FromBytes,
66{
67 Ok(if item_count > 0 {
68 let user_ref: UserRef<T> = addr.into();
69 current_task.read_objects_to_vec(user_ref, item_count)?
70 } else {
71 vec![T::default()]
72 })
73}
74
75pub fn create_connection(
84 device: magma_device_t,
85 response: &mut virtio_magma_device_create_connection_resp_t,
86 connections: &mut ConnectionMap,
87) {
88 let mut connection_out: magma_connection_t = 0;
89 response.result_return = {
90 #[allow(
91 clippy::undocumented_unsafe_blocks,
92 reason = "Force documented unsafe blocks in Starnix"
93 )]
94 unsafe {
95 magma_device_create_connection(device, &mut connection_out) as u64
96 }
97 };
98
99 response.connection_out = connection_out;
100 response.hdr.type_ = virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_DEVICE_CREATE_CONNECTION as u32;
101 if response.result_return as i32 == MAGMA_STATUS_OK {
102 connections.insert(
103 response.connection_out,
104 ConnectionInfo::new(Arc::new(MagmaConnection { handle: response.connection_out })),
105 );
106 }
107}
108
109fn attempt_open_path(
116 path: std::path::PathBuf,
117 supported_vendor_list: &Vec<u16>,
118) -> Result<MagmaDevice, Errno> {
119 let path = path.into_os_string().into_string().map_err(|_| errno!(EINVAL))?;
120 let (client_channel, server_channel) = zx::Channel::create();
121
122 fdio::service_connect(&path, server_channel).map_err(|_| errno!(EINVAL))?;
123 let client_channel = ManuallyDrop::new(client_channel);
125 let device_channel = client_channel.raw_handle();
126
127 let mut device_out: u64 = 0;
128 #[allow(
129 clippy::undocumented_unsafe_blocks,
130 reason = "Force documented unsafe blocks in Starnix"
131 )]
132 let result = unsafe { magma_device_import(device_channel, &mut device_out as *mut u64) };
133
134 if result != MAGMA_STATUS_OK {
135 return error!(EINVAL);
136 }
137 let magma_device = MagmaDevice { handle: device_out };
138
139 let mut result_out = 0;
140 let mut result_buffer_out = 0;
141 #[allow(
142 clippy::undocumented_unsafe_blocks,
143 reason = "Force documented unsafe blocks in Starnix"
144 )]
145 let query_result = unsafe {
146 magma_device_query(
147 device_out,
148 MAGMA_QUERY_VENDOR_ID,
149 &mut result_buffer_out,
150 &mut result_out,
151 )
152 };
153 if query_result != MAGMA_STATUS_OK {
154 return error!(EINVAL);
155 }
156
157 let vendor_id = result_out as u16;
158 if !supported_vendor_list.contains(&vendor_id) {
159 return error!(EINVAL);
160 }
161 Ok(magma_device)
162}
163
164pub fn device_import(
173 supported_vendors: &Vec<u16>,
174 _control: virtio_magma_device_import_ctrl_t,
175) -> Result<MagmaDevice, Errno> {
176 let entries = std::fs::read_dir("/svc/fuchsia.gpu.magma.Service")
177 .map_err(|_| errno!(EINVAL))?
178 .filter_map(|x| x.ok());
179
180 let mut magma_devices = entries
181 .filter_map(|entry| attempt_open_path(entry.path().join("device"), supported_vendors).ok());
182 let magma_device = magma_devices.next().ok_or_else(|| errno!(EINVAL))?;
183
184 if magma_devices.next().is_some() {
185 track_stub!(TODO("https://fxbug.dev/297445280"), "expose multiple magma devices");
186 }
187
188 Ok(magma_device)
189}
190
191fn get_magma_vendor_id(supported_vendor_list: &Vec<u16>) -> Result<u64, Errno> {
192 let entries = std::fs::read_dir("/svc/fuchsia.gpu.magma.Service")
193 .map_err(|_| errno!(EINVAL))?
194 .filter_map(|x| x.ok());
195
196 let mut magma_devices = entries.filter_map(|entry| {
197 attempt_open_path(entry.path().join("device"), supported_vendor_list).ok()
198 });
199 let magma_device = magma_devices.next().ok_or_else(|| errno!(EINVAL))?;
200 let mut result_out = 0;
201 let mut result_buffer_out = 0;
202 #[allow(
203 clippy::undocumented_unsafe_blocks,
204 reason = "Force documented unsafe blocks in Starnix"
205 )]
206 let query_result = unsafe {
207 magma_device_query(
208 magma_device.handle,
209 MAGMA_QUERY_VENDOR_ID,
210 &mut result_buffer_out,
211 &mut result_out,
212 )
213 };
214 if query_result != MAGMA_STATUS_OK {
215 return error!(EINVAL);
216 }
217 return Ok(result_out);
218}
219
220pub fn get_magma_params(supported_vendor_list: &Vec<u16>) -> BString {
222 if let Some(magma_vendor_id) = get_magma_vendor_id(supported_vendor_list).ok() {
223 const MAGMA_VENDOR_ID_MALI_U64: u64 = MAGMA_VENDOR_ID_MALI as u64;
224 const MAGMA_VENDOR_ID_INTEL_U64: u64 = MAGMA_VENDOR_ID_INTEL as u64;
225 let gpu_type = match magma_vendor_id {
226 MAGMA_VENDOR_ID_MALI_U64 => "mali",
227 MAGMA_VENDOR_ID_INTEL_U64 => "intel",
228 _ => "default",
229 };
230 return BString::from(
231 "androidboot.vendor.apex.com.fuchsia.vulkan=com.fuchsia.vulkan.".to_owned() + gpu_type,
232 );
233 }
234 return b"androidboot.vendor.apex.com.fuchsia.vulkan=com.fuchsia.vulkan.default".into();
235}
236
237#[repr(C)]
240#[derive(KnownLayout, FromBytes, IntoBytes, Immutable, Default, Debug)]
241struct WireDescriptor {
242 resource_count: u32,
243 command_buffer_count: u32,
244 wait_semaphore_count: u32,
245 signal_semaphore_count: u32,
246 flags: u64,
247}
248
249pub fn execute_command<F>(
257 current_task: &CurrentTask,
258 control: virtio_magma_connection_execute_command_ctrl_t,
259 connection: &Arc<MagmaConnection>,
260 get_semaphore: F,
261) -> Result<i32, Errno>
262where
263 F: Fn(u64) -> Result<Arc<MagmaSemaphore>, i32>,
264{
265 let virtmagma_command_descriptor_addr =
266 UserRef::<virtmagma_command_descriptor>::new(control.descriptor.into());
267 let command_descriptor = current_task.read_object(virtmagma_command_descriptor_addr)?;
268
269 let wire_descriptor: WireDescriptor =
272 current_task.read_object(UserAddress::from(command_descriptor.descriptor).into())?;
273
274 let semaphore_count =
275 wire_descriptor.wait_semaphore_count + wire_descriptor.signal_semaphore_count;
276
277 let mut status: i32 = MAGMA_STATUS_OK;
278 let mut wait_semaphore_count: u32 = 0;
279 let mut signal_semaphore_count: u32 = 0;
280 let mut child_semaphore_ids: Vec<u64> = vec![];
281
282 if semaphore_count > 0 {
283 let semaphore_ids: Vec<u64> = read_objects(
284 current_task,
285 command_descriptor.semaphores.into(),
286 semaphore_count as usize,
287 )?;
288
289 for (i, id) in semaphore_ids.iter().enumerate() {
290 match get_semaphore(*id) {
291 Ok(semaphore) => {
292 let ids_ref = &semaphore.ids;
293 for id in ids_ref {
294 child_semaphore_ids.push(*id);
295 }
296 if i < wire_descriptor.wait_semaphore_count as usize {
297 wait_semaphore_count += ids_ref.len() as u32;
298 } else {
299 signal_semaphore_count += ids_ref.len() as u32;
300 }
301 }
302 Err(s) => {
303 status = s;
304 break;
305 }
306 }
307 }
308 } else {
309 child_semaphore_ids.push(0);
311 }
312
313 if status == MAGMA_STATUS_OK {
314 let mut magma_command_descriptor = magma_command_descriptor {
317 resource_count: wire_descriptor.resource_count,
318 command_buffer_count: wire_descriptor.command_buffer_count,
319 wait_semaphore_count,
320 signal_semaphore_count,
321 flags: wire_descriptor.flags,
322 ..Default::default()
323 };
324
325 let mut resources: Vec<magma_exec_resource> = read_objects(
327 current_task,
328 command_descriptor.resources.into(),
329 wire_descriptor.resource_count as usize,
330 )?;
331 let mut command_buffers: Vec<magma_exec_command_buffer> = read_objects(
332 current_task,
333 command_descriptor.command_buffers.into(),
334 wire_descriptor.command_buffer_count as usize,
335 )?;
336
337 magma_command_descriptor.resources = &mut resources[0] as *mut magma_exec_resource;
340 magma_command_descriptor.command_buffers =
341 &mut command_buffers[0] as *mut magma_exec_command_buffer;
342 magma_command_descriptor.semaphore_ids = &mut child_semaphore_ids[0] as *mut u64;
343
344 status = {
345 #[allow(
346 clippy::undocumented_unsafe_blocks,
347 reason = "Force documented unsafe blocks in Starnix"
348 )]
349 unsafe {
350 magma_connection_execute_command(
351 connection.handle,
352 control.context_id,
353 &mut magma_command_descriptor as *mut magma_command_descriptor,
354 )
355 }
356 };
357 }
358
359 Ok(status)
360}
361
362pub fn execute_inline_commands<F>(
370 current_task: &CurrentTask,
371 control: virtio_magma_connection_execute_inline_commands_ctrl_t,
372 connection: &Arc<MagmaConnection>,
373 get_semaphore: F,
374) -> Result<magma_status_t, Errno>
375where
376 F: Fn(u64) -> Result<Arc<MagmaSemaphore>, i32>,
377{
378 let command_buffers_addr = UserAddress::from(control.command_buffers);
379
380 let descriptors: Vec<virtmagma_command_descriptor> =
383 read_objects(current_task, command_buffers_addr, control.command_count as usize)?;
384
385 let mut commands =
386 vec![magma_inline_command_buffer::default(); std::cmp::max(descriptors.len(), 1)];
387
388 let mut commands_vec = Vec::<Vec<u8>>::with_capacity(control.command_count as usize);
389 let mut semaphore_ids_vec = Vec::<Vec<u64>>::with_capacity(control.command_count as usize);
390
391 let mut status: i32 = MAGMA_STATUS_OK;
392
393 for i in 0..control.command_count as usize {
394 let size = descriptors[i].command_buffer_size;
395 let data = current_task.read_buffer(&UserBuffer {
396 address: UserAddress::from(descriptors[i].command_buffers),
397 length: size as usize,
398 })?;
399 commands_vec.push(data);
400 commands[i].size = size;
401
402 let semaphore_count =
403 (descriptors[i].semaphore_size / core::mem::size_of::<u64>() as u64) as u32;
404
405 let mut child_semaphore_ids: Vec<u64> = vec![];
406 if semaphore_count > 0 {
407 let semaphore_ids = read_objects(
408 current_task,
409 UserAddress::from(descriptors[i].semaphores),
410 semaphore_count as usize,
411 )?;
412
413 for id in semaphore_ids.iter() {
414 match get_semaphore(*id) {
415 Ok(semaphore) => {
416 let child_ids_ref = &semaphore.ids;
417 for child_id in child_ids_ref {
418 child_semaphore_ids.push(*child_id);
419 }
420 }
421 Err(s) => {
422 status = s;
423 break;
424 }
425 }
426 }
427 }
428 commands[i].semaphore_count = child_semaphore_ids.len() as u32;
429 semaphore_ids_vec.push(child_semaphore_ids);
430 }
431
432 if status == MAGMA_STATUS_OK {
433 status = {
434 #[allow(
435 clippy::undocumented_unsafe_blocks,
436 reason = "Force documented unsafe blocks in Starnix"
437 )]
438 unsafe {
439 for i in 0..control.command_count as usize {
440 commands[i].data = &mut commands_vec[i][0] as *mut u8 as *mut std::ffi::c_void;
441 commands[i].semaphore_ids = if commands[i].semaphore_count == 0 {
442 std::ptr::null_mut()
443 } else {
444 &mut semaphore_ids_vec[i][0]
445 };
446 }
447 magma_connection_execute_inline_commands(
448 connection.handle,
449 control.context_id,
450 control.command_count,
451 &mut commands[0],
452 )
453 }
454 };
455 }
456
457 Ok(status)
458}
459
460pub fn export_buffer(
476 locked: &mut Locked<Unlocked>,
477 current_task: &CurrentTask,
478 _control: virtio_magma_buffer_export_ctrl_t,
479 response: &mut virtio_magma_buffer_export_resp_t,
480 buffer: &Arc<MagmaBuffer>,
481 connections: &ConnectionMap,
482) -> Result<(), Errno> {
483 let mut buffer_handle_out = 0;
484 #[allow(
485 clippy::undocumented_unsafe_blocks,
486 reason = "Force documented unsafe blocks in Starnix"
487 )]
488 let status = unsafe {
489 magma_buffer_export(
490 buffer.handle as magma_buffer_t,
491 &mut buffer_handle_out as *mut magma_handle_t,
492 )
493 };
494 if status == MAGMA_STATUS_OK {
495 #[allow(
496 clippy::undocumented_unsafe_blocks,
497 reason = "Force documented unsafe blocks in Starnix"
498 )]
499 let vmo = unsafe { zx::Vmo::from(zx::NullableHandle::from_raw(buffer_handle_out)) };
500 let memory = MemoryObject::from(vmo);
501
502 let mut image_info_opt: Option<ImageInfo> = None;
503 'outer: for image_map in connections.values() {
504 for (image, info) in image_map.buffer_map.iter() {
505 if *image == buffer.handle {
506 if let BufferInfo::Image(image_info) = info.clone() {
507 image_info_opt = Some(image_info);
508 break 'outer;
509 }
510 }
511 }
512 }
513
514 let file = {
515 if let Some(image_info) = image_info_opt {
516 ImageFile::new_file(locked, current_task, image_info, memory)
517 } else {
518 Anon::new_private_file(
520 locked,
521 current_task,
522 Box::new(MemoryRegularFile::new(Arc::new(memory))),
523 OpenFlags::RDWR,
524 "[fuchsia:magma_export_buffer]",
525 )
526 }
527 };
528
529 let fd = current_task.add_file(locked, file, FdFlags::empty())?;
530 response.buffer_handle_out = fd.raw() as u64;
531 }
532
533 response.result_return = status as u64;
534 response.hdr.type_ = virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_BUFFER_EXPORT as u32;
535
536 Ok(())
537}
538
539pub fn flush(
543 _control: virtio_magma_connection_flush_ctrl_t,
544 response: &mut virtio_magma_connection_flush_resp_t,
545 connection: &Arc<MagmaConnection>,
546) {
547 response.result_return = {
548 #[allow(
549 clippy::undocumented_unsafe_blocks,
550 reason = "Force documented unsafe blocks in Starnix"
551 )]
552 unsafe {
553 magma_connection_flush(connection.handle) as u64
554 }
555 };
556 response.hdr.type_ = virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_FLUSH as u32;
557}
558
559pub fn get_buffer_handle(
569 locked: &mut Locked<Unlocked>,
570 current_task: &CurrentTask,
571 _control: virtio_magma_buffer_get_handle_ctrl_t,
572 response: &mut virtio_magma_buffer_get_handle_resp_t,
573 buffer: &Arc<MagmaBuffer>,
574) -> Result<(), Errno> {
575 let mut buffer_handle_out = 0;
576 #[allow(
577 clippy::undocumented_unsafe_blocks,
578 reason = "Force documented unsafe blocks in Starnix"
579 )]
580 let status = unsafe {
581 magma_buffer_get_handle(
582 buffer.handle as magma_buffer_t,
583 &mut buffer_handle_out as *mut magma_handle_t,
584 )
585 };
586
587 if status != MAGMA_STATUS_OK {
588 response.result_return = status as u64;
589 } else {
590 #[allow(
591 clippy::undocumented_unsafe_blocks,
592 reason = "Force documented unsafe blocks in Starnix"
593 )]
594 let vmo = unsafe { zx::Vmo::from(zx::NullableHandle::from_raw(buffer_handle_out)) };
595 let memory = MemoryObject::from(vmo);
596 let file = Anon::new_private_file(
598 locked,
599 current_task,
600 Box::new(MemoryRegularFile::new(Arc::new(memory))),
601 OpenFlags::RDWR,
602 "[fuchsia:magma_buffer]",
603 );
604 let fd = current_task.add_file(locked, file, FdFlags::empty())?;
605 response.handle_out = fd.raw() as u64;
606 response.result_return = MAGMA_STATUS_OK as u64;
607 }
608
609 response.hdr.type_ = virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_BUFFER_GET_HANDLE as u32;
610
611 Ok(())
612}
613
614pub fn query(
622 locked: &mut Locked<Unlocked>,
623 current_task: &CurrentTask,
624 device: magma_device_t,
625 id: magma_query_t,
626 response: &mut virtio_magma_device_query_resp_t,
627) -> Result<(), Errno> {
628 let mut result_buffer_out = 0;
629 let mut result_out = 0;
630 response.result_return = {
631 #[allow(
632 clippy::undocumented_unsafe_blocks,
633 reason = "Force documented unsafe blocks in Starnix"
634 )]
635 unsafe {
636 magma_device_query(device, id, &mut result_buffer_out, &mut result_out) as u64
637 }
638 };
639
640 if result_buffer_out != zx::sys::ZX_HANDLE_INVALID {
641 #[allow(
642 clippy::undocumented_unsafe_blocks,
643 reason = "Force documented unsafe blocks in Starnix"
644 )]
645 let vmo = unsafe { zx::Vmo::from(zx::NullableHandle::from_raw(result_buffer_out)) };
646 let memory = MemoryObject::from(vmo);
647 let memory_size = memory.get_size();
648 let mut info = FsNodeInfo::new(FileMode::from_bits(0o600), current_task.current_fscred());
650 info.size = memory_size as usize;
652 let file = Anon::new_private_file_extended(
653 locked,
654 current_task,
655 Box::new(MemoryRegularFile::new(Arc::new(memory))),
656 OpenFlags::RDWR,
657 "[fuchsia:magma_vmo]",
658 info,
659 );
660 let fd = current_task.add_file(locked, file, FdFlags::empty())?;
661 response.result_buffer_out = fd.raw() as u64;
662 } else {
663 response.result_buffer_out = u64::MAX;
664 }
665
666 response.result_out = result_out;
667
668 Ok(())
669}
670
671pub fn read_notification_channel(
679 current_task: &CurrentTask,
680 control: virtio_magma_connection_read_notification_channel_ctrl_t,
681 response: &mut virtio_magma_connection_read_notification_channel_resp_t,
682 connection: &Arc<MagmaConnection>,
683) -> Result<(), Errno> {
684 let mut buffer = vec![0; std::cmp::max(control.buffer_size as usize, 1)];
687 let mut buffer_size_out = 0;
688 let mut more_data_out: u8 = 0;
689
690 response.result_return = {
691 #[allow(
692 clippy::undocumented_unsafe_blocks,
693 reason = "Force documented unsafe blocks in Starnix"
694 )]
695 unsafe {
696 magma_connection_read_notification_channel(
697 connection.handle,
698 &mut buffer[0] as *mut u8 as *mut std::ffi::c_void,
699 control.buffer_size,
700 &mut buffer_size_out,
701 &mut more_data_out as *mut u8,
702 ) as u64
703 }
704 };
705
706 response.more_data_out = more_data_out as u64;
707 response.buffer_size_out = buffer_size_out;
708 response.hdr.type_ =
709 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_READ_NOTIFICATION_CHANNEL as u32;
710
711 current_task.write_memory(UserAddress::from(control.buffer), &buffer)?;
712
713 Ok(())
714}
715
716pub fn release_connection(
726 control: virtio_magma_connection_release_ctrl_t,
727 response: &mut virtio_magma_connection_release_resp_t,
728 connections: &mut ConnectionMap,
729) {
730 let connection = control.connection as magma_connection_t;
731 if connections.contains_key(&connection) {
732 connections.remove(&connection);
733 }
734 response.hdr.type_ = virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_RELEASE as u32;
735}
736
737pub fn import_semaphore2(
738 connection: &Arc<MagmaConnection>,
739 counter: zx::Counter,
740 flags: u64,
741) -> (i32, u64, u64) {
742 let mut semaphore = 0;
743 let mut semaphore_id = 0;
744 #[allow(
745 clippy::undocumented_unsafe_blocks,
746 reason = "Force documented unsafe blocks in Starnix"
747 )]
748 let status = unsafe {
749 magma_connection_import_semaphore2(
750 connection.handle,
751 counter.into_raw(),
752 flags,
753 &mut semaphore,
754 &mut semaphore_id,
755 )
756 };
757 (status, semaphore, semaphore_id)
758}