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