1use std::cell::{Cell, RefCell};
4use std::ops::{Deref, DerefMut};
5
6use linux_api::errno::Errno;
7use linux_api::fcntl::DescriptorFlags;
8use linux_api::mman::{MapFlags, ProtFlags};
9use linux_api::posix_types::Pid;
10use linux_api::sched::{Sched, SchedFlags, sched_attr};
11use linux_api::signal::stack_t;
12use shadow_shim_helper_rs::HostId;
13use shadow_shim_helper_rs::explicit_drop::ExplicitDrop;
14use shadow_shim_helper_rs::rootedcell::rc::RootedRc;
15use shadow_shim_helper_rs::rootedcell::refcell::RootedRefCell;
16use shadow_shim_helper_rs::shim_shmem::{HostShmemProtected, ThreadShmem};
17use shadow_shim_helper_rs::syscall_types::{ForeignPtr, SyscallReg};
18use shadow_shim_helper_rs::util::SendPointer;
19use shadow_shmem::allocator::{ShMemBlock, shmalloc};
20
21use super::context::ProcessContext;
22use super::descriptor::descriptor_table::{DescriptorHandle, DescriptorTable};
23use super::host::Host;
24use super::managed_thread::{self, ManagedThread};
25use super::process::{Process, ProcessId};
26use crate::cshadow as c;
27use crate::host::descriptor::DropPosixRecordLocks;
28use crate::host::syscall::condition::{SyscallConditionRef, SyscallConditionRefMut};
29use crate::host::syscall::handler::SyscallHandler;
30use crate::utility::callback_queue::CallbackQueue;
31use crate::utility::{IsSend, ObjectCounter, syscall};
32
33#[derive(Debug)]
35#[must_use]
36pub enum ResumeResult {
37 Blocked,
39 ExitedThread(i32),
41 ExitedProcess,
43}
44
45pub struct Thread {
48 id: ThreadId,
49 host_id: HostId,
50 process_id: ProcessId,
51 sched_policy: Cell<Sched>,
52 sched_attr: Cell<sched_attr>,
53 tid_address: Cell<ForeignPtr<libc::pid_t>>,
56 shim_shared_memory: ShMemBlock<'static, ThreadShmem>,
57 syscallhandler: RootedRefCell<SyscallHandler>,
58 desc_table: Option<RootedRc<RootedRefCell<DescriptorTable>>>,
65 cond: Cell<SendPointer<c::SysCallCondition>>,
68 mthread: RefCell<ManagedThread>,
70 _counter: ObjectCounter,
71}
72
73impl IsSend for Thread {}
74
75impl Thread {
76 pub fn mthread(&self) -> impl Deref<Target = ManagedThread> + '_ {
78 self.mthread.borrow()
79 }
80
81 pub fn update_for_exec(&mut self, host: &Host, mthread: ManagedThread, new_tid: ThreadId) {
85 self.mthread.replace(mthread).handle_process_exit();
86 self.tid_address.set(ForeignPtr::null());
87
88 {
90 let host_shmem_prot = host.shim_shmem_lock_borrow().unwrap();
97
98 let mut thread_shmem =
99 ThreadShmem::clone(&self.shim_shared_memory, &host_shmem_prot.root);
100
101 thread_shmem.tid = new_tid.into();
103
104 unsafe {
106 *thread_shmem
107 .protected
108 .borrow_mut(&host_shmem_prot.root)
109 .sigaltstack_mut() = stack_t::new(
110 std::ptr::null_mut(),
111 linux_api::signal::SigAltStackFlags::SS_DISABLE,
112 0,
113 )
114 };
115
116 self.shim_shared_memory = shmalloc(thread_shmem);
117 }
118
119 self.syscallhandler = RootedRefCell::new(
120 host.root(),
121 SyscallHandler::new(
122 host.id(),
123 self.process_id,
124 new_tid,
125 host.params.use_syscall_counters,
126 ),
127 );
128
129 {
131 let desc_table_rc = self.desc_table.take().unwrap();
133 let mut desc_table = DescriptorTable::clone(&desc_table_rc.borrow(host.root()));
134 let dont_drop_locks = DropPosixRecordLocks::False;
138 desc_table_rc.explicit_drop_recursive(host.root(), (host, dont_drop_locks));
139
140 let to_close: Vec<DescriptorHandle> = desc_table
142 .iter()
143 .filter_map(|(handle, descriptor)| {
144 if descriptor.flags().contains(DescriptorFlags::FD_CLOEXEC) {
145 Some(*handle)
146 } else {
147 None
148 }
149 })
150 .collect();
151
152 CallbackQueue::queue_and_run_with_legacy(|q| {
153 for handle in to_close {
154 let drop_locks = DropPosixRecordLocks::ForPid(self.process_id());
155 log::trace!("Unregistering FD_CLOEXEC descriptor {handle:?}");
156 if let Some(Err(e)) = desc_table
157 .deregister_descriptor(handle)
158 .unwrap()
159 .close(host, drop_locks, q)
160 {
161 log::debug!("Error closing {handle:?}: {e:?}");
162 };
163 }
164 });
165
166 self.desc_table = Some(RootedRc::new(
167 host.root(),
168 RootedRefCell::new(host.root(), desc_table),
169 ));
170 }
171
172 if let Some(c) = unsafe { self.cond.get_mut().ptr().as_mut() } {
173 unsafe { c::syscallcondition_cancel(c) };
174 unsafe { c::syscallcondition_unref(c) };
175 }
176 self.cond = Cell::new(unsafe { SendPointer::new(std::ptr::null_mut()) });
177
178 self.id = new_tid;
179 }
180
181 fn native_syscall_raw(
183 &self,
184 ctx: &ProcessContext,
185 n: i64,
186 args: &[SyscallReg],
187 ) -> libc::c_long {
188 self.mthread
189 .borrow()
190 .native_syscall(&ctx.with_thread(self), n, args)
191 .into()
192 }
193
194 fn native_syscall(
196 &self,
197 ctx: &ProcessContext,
198 n: i64,
199 args: &[SyscallReg],
200 ) -> Result<SyscallReg, Errno> {
201 syscall::raw_return_value_to_result(self.native_syscall_raw(ctx, n, args))
202 }
203
204 pub fn process_id(&self) -> ProcessId {
205 self.process_id
206 }
207
208 pub fn host_id(&self) -> HostId {
209 self.host_id
210 }
211
212 pub fn native_pid(&self) -> Pid {
213 self.mthread.borrow().native_pid()
214 }
215
216 pub fn native_tid(&self) -> Pid {
217 self.mthread.borrow().native_tid()
218 }
219
220 pub fn id(&self) -> ThreadId {
221 self.id
222 }
223
224 pub fn sched_policy(&self) -> Sched {
225 self.sched_policy.get()
226 }
227
228 pub fn sched_priority(&self) -> std::ffi::c_int {
229 self.sched_attr.get().sched_priority.try_into().unwrap()
230 }
231
232 pub fn sched_reset_on_fork(&self) -> bool {
233 let flags = self.sched_attr.get().sched_flags;
234 flags == u64::try_from(SchedFlags::SCHED_FLAG_RESET_ON_FORK.bits()).unwrap()
235 }
236
237 pub fn set_sched_attrs(&self, policy: Sched, reset_on_fork: bool, priority: std::ffi::c_int) {
238 self.sched_policy.set(policy);
239
240 let mut sched_attr = self.sched_attr.get();
241 sched_attr.sched_policy = u32::try_from(i32::from(policy)).unwrap();
242 sched_attr.sched_flags = if reset_on_fork {
243 u64::try_from(SchedFlags::SCHED_FLAG_RESET_ON_FORK.bits()).unwrap()
244 } else {
245 0
246 };
247 sched_attr.sched_priority = priority.try_into().unwrap();
248 self.sched_attr.set(sched_attr);
249 }
250
251 pub fn is_leader(&self) -> bool {
254 self.id == self.process_id.into()
255 }
256
257 pub fn syscall_condition(&self) -> Option<SyscallConditionRef<'_>> {
258 let c = self.cond.get().ptr();
263 if c.is_null() {
264 None
265 } else {
266 Some(unsafe { SyscallConditionRef::borrow_from_c(c) })
267 }
268 }
269
270 pub fn syscall_condition_mut(&self) -> Option<SyscallConditionRefMut<'_>> {
271 let c = self.cond.get().ptr();
274 if c.is_null() {
275 None
276 } else {
277 Some(unsafe { SyscallConditionRefMut::borrow_from_c(c) })
278 }
279 }
280
281 pub fn cleanup_syscall_condition(&self) {
282 if let Some(c) = unsafe {
283 self.cond
284 .replace(SendPointer::new(std::ptr::null_mut()))
285 .ptr()
286 .as_mut()
287 } {
288 unsafe { c::syscallcondition_cancel(c) };
289 unsafe { c::syscallcondition_unref(c) };
290 }
291 }
292
293 pub fn descriptor_table(&self) -> &RootedRc<RootedRefCell<DescriptorTable>> {
294 self.desc_table.as_ref().unwrap()
295 }
296
297 #[track_caller]
298 pub fn descriptor_table_borrow<'a>(
299 &'a self,
300 host: &'a Host,
301 ) -> impl Deref<Target = DescriptorTable> + 'a {
302 self.desc_table.as_ref().unwrap().borrow(host.root())
303 }
304
305 #[track_caller]
306 pub fn descriptor_table_borrow_mut<'a>(
307 &'a self,
308 host: &'a Host,
309 ) -> impl DerefMut<Target = DescriptorTable> + 'a {
310 self.desc_table.as_ref().unwrap().borrow_mut(host.root())
311 }
312
313 pub fn native_munmap(
315 &self,
316 ctx: &ProcessContext,
317 ptr: ForeignPtr<u8>,
318 size: usize,
319 ) -> Result<(), Errno> {
320 self.native_syscall(ctx, libc::SYS_munmap, &[ptr.into(), size.into()])?;
321 Ok(())
322 }
323
324 pub fn native_mmap(
326 &self,
327 ctx: &ProcessContext,
328 addr: ForeignPtr<u8>,
329 len: usize,
330 prot: ProtFlags,
331 flags: MapFlags,
332 fd: i32,
333 offset: i64,
334 ) -> Result<ForeignPtr<u8>, Errno> {
335 Ok(self
336 .native_syscall(
337 ctx,
338 libc::SYS_mmap,
339 &[
340 SyscallReg::from(addr),
341 SyscallReg::from(len),
342 SyscallReg::from(prot.bits()),
343 SyscallReg::from(flags.bits()),
344 SyscallReg::from(fd),
345 SyscallReg::from(offset),
346 ],
347 )?
348 .into())
349 }
350
351 pub fn native_mremap(
353 &self,
354 ctx: &ProcessContext,
355 old_addr: ForeignPtr<u8>,
356 old_len: usize,
357 new_len: usize,
358 flags: i32,
359 new_addr: ForeignPtr<u8>,
360 ) -> Result<ForeignPtr<u8>, Errno> {
361 Ok(self
362 .native_syscall(
363 ctx,
364 libc::SYS_mremap,
365 &[
366 SyscallReg::from(old_addr),
367 SyscallReg::from(old_len),
368 SyscallReg::from(new_len),
369 SyscallReg::from(flags),
370 SyscallReg::from(new_addr),
371 ],
372 )?
373 .into())
374 }
375
376 pub fn native_mprotect(
378 &self,
379 ctx: &ProcessContext,
380 addr: ForeignPtr<u8>,
381 len: usize,
382 prot: ProtFlags,
383 ) -> Result<(), Errno> {
384 self.native_syscall(
385 ctx,
386 libc::SYS_mprotect,
387 &[
388 SyscallReg::from(addr),
389 SyscallReg::from(len),
390 SyscallReg::from(prot.bits()),
391 ],
392 )?;
393 Ok(())
394 }
395
396 pub fn native_open(
398 &self,
399 ctx: &ProcessContext,
400 pathname: ForeignPtr<u8>,
401 flags: i32,
402 mode: i32,
403 ) -> Result<i32, Errno> {
404 let res = self.native_syscall(
405 ctx,
406 libc::SYS_open,
407 &[
408 SyscallReg::from(pathname),
409 SyscallReg::from(flags),
410 SyscallReg::from(mode),
411 ],
412 );
413 Ok(i32::from(res?))
414 }
415
416 pub fn native_close(&self, ctx: &ProcessContext, fd: i32) -> Result<(), Errno> {
418 self.native_syscall(ctx, libc::SYS_close, &[SyscallReg::from(fd)])?;
419 Ok(())
420 }
421
422 pub fn native_brk(
424 &self,
425 ctx: &ProcessContext,
426 addr: ForeignPtr<u8>,
427 ) -> Result<ForeignPtr<u8>, Errno> {
428 let res = self.native_syscall(ctx, libc::SYS_brk, &[SyscallReg::from(addr)])?;
429 Ok(ForeignPtr::from(res))
430 }
431
432 pub fn native_chdir(
434 &self,
435 ctx: &ProcessContext,
436 pathname: ForeignPtr<std::ffi::c_char>,
437 ) -> Result<i32, Errno> {
438 let res = self.native_syscall(ctx, libc::SYS_chdir, &[SyscallReg::from(pathname)]);
439 Ok(i32::from(res?))
440 }
441
442 pub fn malloc_foreign_ptr(
445 &self,
446 ctx: &ProcessContext,
447 size: usize,
448 ) -> Result<ForeignPtr<u8>, Errno> {
449 self.native_mmap(
451 ctx,
452 ForeignPtr::null(),
453 size,
454 ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
455 MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS,
456 -1,
457 0,
458 )
459 }
460
461 pub fn free_foreign_ptr(
463 &self,
464 ctx: &ProcessContext,
465 ptr: ForeignPtr<u8>,
466 size: usize,
467 ) -> Result<(), Errno> {
468 self.native_munmap(ctx, ptr, size)?;
469 Ok(())
470 }
471
472 pub fn wrap_mthread(
475 host: &Host,
476 mthread: ManagedThread,
477 desc_table: RootedRc<RootedRefCell<DescriptorTable>>,
478 pid: ProcessId,
479 tid: ThreadId,
480 ) -> Thread {
481 Self {
482 mthread: RefCell::new(mthread),
483 syscallhandler: RootedRefCell::new(
484 host.root(),
485 SyscallHandler::new(host.id(), pid, tid, host.params.use_syscall_counters),
486 ),
487 cond: Cell::new(unsafe { SendPointer::new(std::ptr::null_mut()) }),
488 id: tid,
489 host_id: host.id(),
490 process_id: pid,
491 sched_policy: Cell::new(Sched::SCHED_NORMAL),
492 sched_attr: Cell::new(sched_attr {
493 size: u32::try_from(std::mem::size_of::<sched_attr>()).unwrap(),
494 sched_policy: u32::try_from(i32::from(Sched::SCHED_NORMAL)).unwrap(),
495 sched_flags: 0,
496 sched_nice: 0,
497 sched_priority: 0,
498 sched_runtime: 0,
499 sched_deadline: 0,
500 sched_period: 0,
501 sched_util_min: 0,
502 sched_util_max: 0,
503 }),
504 tid_address: Cell::new(ForeignPtr::null()),
505 shim_shared_memory: shmalloc(ThreadShmem::new(
506 &host.shim_shmem_lock_borrow().unwrap(),
507 tid.into(),
508 )),
509 desc_table: Some(desc_table),
510 _counter: ObjectCounter::new("Thread"),
511 }
512 }
513
514 pub fn shmem(&self) -> &ShMemBlock<'_, ThreadShmem> {
516 &self.shim_shared_memory
517 }
518
519 pub fn resume(&self, ctx: &ProcessContext) -> ResumeResult {
520 if let Some(c) = unsafe { self.cond.get().ptr().as_mut() } {
523 unsafe { c::syscallcondition_cancel(c) };
524 }
525
526 let mut syscall_handler = self.syscallhandler.borrow_mut(ctx.host.root());
527
528 let res = self
529 .mthread
530 .borrow()
531 .resume(&ctx.with_thread(self), &mut syscall_handler);
532
533 if let Some(c) = unsafe {
535 self.cond
536 .replace(SendPointer::new(std::ptr::null_mut()))
537 .ptr()
538 .as_mut()
539 } {
540 unsafe { c::syscallcondition_unref(c) };
541 }
542
543 match res {
544 managed_thread::ResumeResult::Blocked(cond) => {
545 let cond = cond.into_inner();
547 self.cond.set(unsafe { SendPointer::new(cond) });
548 if let Some(cond) = unsafe { cond.as_mut() } {
549 unsafe { c::syscallcondition_waitNonblock(cond, ctx.host, ctx.process, self) }
550 }
551 ResumeResult::Blocked
552 }
553 managed_thread::ResumeResult::ExitedThread(c) => ResumeResult::ExitedThread(c),
554 managed_thread::ResumeResult::ExitedProcess => ResumeResult::ExitedProcess,
555 }
556 }
557
558 pub fn handle_process_exit(&self) {
559 self.cleanup_syscall_condition();
560 self.mthread.borrow().handle_process_exit();
561 }
562
563 pub fn return_code(&self) -> Option<i32> {
564 self.mthread.borrow().return_code()
565 }
566
567 pub fn is_running(&self) -> bool {
568 self.mthread.borrow().is_running()
569 }
570
571 pub fn get_tid_address(&self) -> ForeignPtr<libc::pid_t> {
572 self.tid_address.get()
573 }
574
575 pub fn set_tid_address(&self, ptr: ForeignPtr<libc::pid_t>) {
578 self.tid_address.set(ptr)
579 }
580
581 pub fn unblocked_signal_pending(
582 &self,
583 process: &Process,
584 host_shmem: &HostShmemProtected,
585 ) -> bool {
586 debug_assert_eq!(process.id(), self.process_id);
587
588 let thread_shmem_protected = self.shmem().protected.borrow(&host_shmem.root);
589
590 let unblocked_signals = !thread_shmem_protected.blocked_signals;
591 let pending_signals = self
592 .shmem()
593 .protected
594 .borrow(&host_shmem.root)
595 .pending_signals
596 | process
597 .shmem()
598 .protected
599 .borrow(&host_shmem.root)
600 .pending_signals;
601
602 !(pending_signals & unblocked_signals).is_empty()
603 }
604}
605
606impl Drop for Thread {
607 fn drop(&mut self) {
608 if let Some(c) = unsafe { self.cond.get_mut().ptr().as_mut() } {
609 unsafe { c::syscallcondition_cancel(c) };
610 unsafe { c::syscallcondition_unref(c) };
611 }
612 }
613}
614
615impl ExplicitDrop for Thread {
616 type ExplicitDropParam<'p> = &'p Host;
617 type ExplicitDropResult = ();
618
619 fn explicit_drop<'p>(mut self, host: Self::ExplicitDropParam<'p>) {
620 if let Some(table) = self.desc_table.take() {
621 let drop_locks = DropPosixRecordLocks::ForPid(self.process_id());
625 table.explicit_drop_recursive(host.root(), (host, drop_locks));
626 }
627 }
628}
629
630#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, Ord, PartialOrd)]
631pub struct ThreadId(u32);
632
633impl TryFrom<libc::pid_t> for ThreadId {
634 type Error = <u32 as TryFrom<libc::pid_t>>::Error;
635
636 fn try_from(value: libc::pid_t) -> Result<Self, Self::Error> {
637 Ok(Self(u32::try_from(value)?))
638 }
639}
640
641impl From<ProcessId> for ThreadId {
642 fn from(value: ProcessId) -> Self {
643 ThreadId(value.into())
645 }
646}
647
648impl From<ThreadId> for libc::pid_t {
649 fn from(val: ThreadId) -> Self {
650 val.0.try_into().unwrap()
651 }
652}
653
654impl std::fmt::Display for ThreadId {
655 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
656 write!(f, "{}", self.0)
657 }
658}
659
660mod export {
661 use shadow_shim_helper_rs::shim_shmem::export::{ShimShmemHostLock, ShimShmemThread};
662 use shadow_shim_helper_rs::syscall_types::UntypedForeignPtr;
663
664 use super::*;
665 use crate::core::worker::Worker;
666 use crate::host::descriptor::socket::Socket;
667 use crate::host::descriptor::socket::inet::InetSocket;
668 use crate::host::descriptor::{CompatFile, Descriptor, File};
669
670 #[unsafe(no_mangle)]
685 unsafe extern "C-unwind" fn thread_nativeSyscall(
686 thread: *const Thread,
687 n: libc::c_long,
688 arg1: SyscallReg,
689 arg2: SyscallReg,
690 arg3: SyscallReg,
691 arg4: SyscallReg,
692 arg5: SyscallReg,
693 arg6: SyscallReg,
694 ) -> libc::c_long {
695 let thread = unsafe { thread.as_ref().unwrap() };
696 Worker::with_active_host(|host| {
697 Worker::with_active_process(|process| {
698 thread.native_syscall_raw(
699 &ProcessContext::new(host, process),
700 n,
701 &[arg1, arg2, arg3, arg4, arg5, arg6],
702 )
703 })
704 .unwrap()
705 })
706 .unwrap()
707 }
708
709 #[unsafe(no_mangle)]
710 pub unsafe extern "C-unwind" fn thread_getID(thread: *const Thread) -> libc::pid_t {
711 let thread = unsafe { thread.as_ref().unwrap() };
712 thread.id().into()
713 }
714
715 #[unsafe(no_mangle)]
717 pub unsafe extern "C-unwind" fn thread_getTidAddress(
718 thread: *const Thread,
719 ) -> UntypedForeignPtr {
720 let thread = unsafe { thread.as_ref().unwrap() };
721 thread.get_tid_address().cast::<()>()
722 }
723
724 #[unsafe(no_mangle)]
727 pub unsafe extern "C-unwind" fn thread_sharedMem(
728 thread: *const Thread,
729 ) -> *const ShimShmemThread {
730 let thread = unsafe { thread.as_ref().unwrap() };
731 &*thread.shim_shared_memory
732 }
733
734 #[unsafe(no_mangle)]
735 pub unsafe extern "C-unwind" fn thread_getProcess(thread: *const Thread) -> *const Process {
736 let thread = unsafe { thread.as_ref().unwrap() };
737 Worker::with_active_host(|host| {
738 let process = host.process_borrow(thread.process_id).unwrap();
739 let p: &Process = &process.borrow(host.root());
740 std::ptr::from_ref(p)
741 })
742 .unwrap()
743 }
744
745 #[unsafe(no_mangle)]
746 pub unsafe extern "C-unwind" fn thread_getHost(thread: *const Thread) -> *const Host {
747 let thread = unsafe { thread.as_ref().unwrap() };
748 Worker::with_active_host(|host| {
749 assert_eq!(host.id(), thread.host_id());
750 std::ptr::from_ref(host)
751 })
752 .unwrap()
753 }
754
755 #[unsafe(no_mangle)]
756 pub unsafe extern "C-unwind" fn thread_clearSysCallCondition(thread: *const Thread) {
757 let thread = unsafe { thread.as_ref().unwrap() };
758 thread.cleanup_syscall_condition();
759 }
760
761 #[unsafe(no_mangle)]
764 pub unsafe extern "C-unwind" fn thread_unblockedSignalPending(
765 thread: *const Thread,
766 host_lock: *const ShimShmemHostLock,
767 ) -> bool {
768 let thread = unsafe { thread.as_ref().unwrap() };
769 let host_lock = unsafe { host_lock.as_ref().unwrap() };
770
771 Worker::with_active_host(|host| {
772 let process = host.process_borrow(thread.process_id()).unwrap();
773 let process = process.borrow(host.root());
774 thread.unblocked_signal_pending(&process, host_lock)
775 })
776 .unwrap()
777 }
778
779 #[unsafe(no_mangle)]
782 pub extern "C-unwind" fn thread_registerDescriptor(
783 thread: *const Thread,
784 desc: *mut Descriptor,
785 ) -> libc::c_int {
786 let thread = unsafe { thread.as_ref().unwrap() };
787 let desc = Descriptor::from_raw(desc).unwrap();
788
789 Worker::with_active_host(|host| {
790 thread
791 .descriptor_table_borrow_mut(host)
792 .register_descriptor(*desc)
793 .unwrap()
794 .into()
795 })
796 .unwrap()
797 }
798
799 #[unsafe(no_mangle)]
801 pub extern "C-unwind" fn thread_getRegisteredDescriptor(
802 thread: *const Thread,
803 handle: libc::c_int,
804 ) -> *const Descriptor {
805 let thread = unsafe { thread.as_ref().unwrap() };
806
807 let handle = match handle.try_into() {
808 Ok(i) => i,
809 Err(_) => {
810 log::debug!("Attempted to get a descriptor with handle {handle}");
811 return std::ptr::null();
812 }
813 };
814
815 Worker::with_active_host(
816 |host| match thread.descriptor_table_borrow(host).get(handle) {
817 Some(d) => std::ptr::from_ref(d),
818 None => std::ptr::null(),
819 },
820 )
821 .unwrap()
822 }
823
824 #[unsafe(no_mangle)]
826 pub extern "C-unwind" fn thread_getRegisteredDescriptorMut(
827 thread: *const Thread,
828 handle: libc::c_int,
829 ) -> *mut Descriptor {
830 let thread = unsafe { thread.as_ref().unwrap() };
831
832 let handle = match handle.try_into() {
833 Ok(i) => i,
834 Err(_) => {
835 log::debug!("Attempted to get a descriptor with handle {handle}");
836 return std::ptr::null_mut();
837 }
838 };
839
840 Worker::with_active_host(|host| {
841 match thread.descriptor_table_borrow_mut(host).get_mut(handle) {
842 Some(d) => d as *mut Descriptor,
843 None => std::ptr::null_mut(),
844 }
845 })
846 .unwrap()
847 }
848
849 #[unsafe(no_mangle)]
851 pub unsafe extern "C-unwind" fn thread_getRegisteredLegacyFile(
852 thread: *const Thread,
853 handle: libc::c_int,
854 ) -> *mut c::LegacyFile {
855 let thread = unsafe { thread.as_ref().unwrap() };
856
857 let handle = match handle.try_into() {
858 Ok(i) => i,
859 Err(_) => {
860 log::debug!("Attempted to get a descriptor with handle {handle}");
861 return std::ptr::null_mut();
862 }
863 };
864
865 Worker::with_active_host(|host| {
866 match thread.descriptor_table_borrow(host).get(handle).map(|x| x.file()) {
867 Some(CompatFile::Legacy(file)) => file.ptr(),
868 Some(CompatFile::New(file)) => {
869 if let File::Socket(Socket::Inet(InetSocket::LegacyTcp(tcp))) = file.inner_file() {
871 tcp.borrow().as_legacy_file()
872 } else {
873 log::warn!(
874 "A descriptor exists for fd={handle}, but it is not a legacy file. Returning NULL."
875 );
876 std::ptr::null_mut()
877 }
878 }
879 None => std::ptr::null_mut(),
880 }
881 }).unwrap()
882 }
883}