1use crate::mm::{MemoryAccessor, MemoryAccessorExt, MemoryManager, TaskMemoryAccessor};
6use crate::mutable_state::{state_accessor, state_implementation};
7use crate::ptrace::{AtomicStopState, PtraceEventData, PtraceState, PtraceStatus, StopState};
8use crate::signals::{KernelSignal, SignalDetail, SignalInfo, SignalState};
9use crate::task::memory_attribution::MemoryAttributionLifecycleEvent;
10use crate::task::run_state::RunState;
11use crate::task::tracing::ZirconIdentity;
12use crate::task::{
13 AbstractUnixSocketNamespace, AbstractVsockSocketNamespace, CurrentCreds, CurrentTask,
14 EventHandler, ExitStatus, Kernel, NormalPriority, Pid, RealtimePriority, SchedulerState,
15 SchedulingPolicy, SeccompFilterContainer, SeccompState, SeccompStateValue, TaskRunningState,
16 ThreadGroup, ThreadState, UtsNamespaceHandle, WaitCanceler, Waiter, ZombieProcess, ZombieState,
17};
18use crate::vfs::{FdTable, FsContext, FsString, SharedFdTable};
19use atomic_bitflags::atomic_bitflags;
20use fuchsia_rcu::{RcuArc, RcuDroppable, RcuDroppableArc, RcuReadGuard, RcuReadScope};
21use macro_rules_attribute::apply;
22use starnix_logging::{log_warn, set_zx_name};
23use starnix_registers::HeapRegs;
24use starnix_sync::{
25 LockDepGuard, LockDepMutex, LockDepReadGuard, LockDepRwLock, LockDepWriteGuard,
26 TaskCommandLevel, TaskCredsLock,
27};
28use starnix_task_command::TaskCommand;
29use starnix_types::arch::ArchWidth;
30use starnix_types::stats::TaskTimeStats;
31use starnix_uapi::auth::{CAP_SYS_PTRACE, Credentials, FsCred};
32use starnix_uapi::errors::Errno;
33use starnix_uapi::signals::{SIGCHLD, SigSet, Signal, sigaltstack_contains_pointer};
34use starnix_uapi::user_address::{
35 ArchSpecific, MappingMultiArchUserRef, UserAddress, UserCString, UserRef,
36};
37use starnix_uapi::{
38 CLD_TRAPPED, FUTEX_BITSET_MATCH_ANY, errno, error, from_status_like_fdio, pid_t, sigaction_t,
39 sigaltstack, tid_t, uapi,
40};
41use std::collections::VecDeque;
42use std::mem::MaybeUninit;
43use std::ops::Deref;
44use std::sync::atomic::{AtomicBool, Ordering};
45use std::sync::{Arc, Weak};
46use std::{cmp, fmt};
47use zx::{Signals, Task as _};
48
49atomic_bitflags! {
50 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
51 pub struct TaskFlags: u8 {
52 const EXITED = 1 << 0;
53 const SIGNALS_AVAILABLE = 1 << 1;
54 const TEMPORARY_SIGNAL_MASK = 1 << 2;
55 const DUMP_ON_EXIT = 1 << 3;
58 const KERNEL_SIGNALS_AVAILABLE = 1 << 4;
59 const SPAWNED = 1 << 5;
61 }
62}
63
64pub struct CapturedThreadState {
71 pub thread_state: ThreadState<HeapRegs>,
74
75 pub dirty: bool,
78}
79
80impl ArchSpecific for CapturedThreadState {
81 fn is_arch32(&self) -> bool {
82 self.thread_state.is_arch32()
83 }
84}
85
86#[derive(Debug)]
87pub struct RobustList {
88 pub next: RobustListPtr,
89}
90
91pub type RobustListPtr =
92 MappingMultiArchUserRef<RobustList, uapi::robust_list, uapi::arch32::robust_list>;
93
94impl From<uapi::robust_list> for RobustList {
95 fn from(robust_list: uapi::robust_list) -> Self {
96 Self { next: RobustListPtr::from(robust_list.next) }
97 }
98}
99
100#[cfg(target_arch = "aarch64")]
101impl From<uapi::arch32::robust_list> for RobustList {
102 fn from(robust_list: uapi::arch32::robust_list) -> Self {
103 Self { next: RobustListPtr::from(robust_list.next) }
104 }
105}
106
107#[derive(Debug)]
108pub struct RobustListHead {
109 pub list: RobustList,
110 pub futex_offset: isize,
111}
112
113pub type RobustListHeadPtr =
114 MappingMultiArchUserRef<RobustListHead, uapi::robust_list_head, uapi::arch32::robust_list_head>;
115
116impl From<uapi::robust_list_head> for RobustListHead {
117 fn from(robust_list_head: uapi::robust_list_head) -> Self {
118 Self {
119 list: robust_list_head.list.into(),
120 futex_offset: robust_list_head.futex_offset as isize,
121 }
122 }
123}
124
125#[cfg(target_arch = "aarch64")]
126impl From<uapi::arch32::robust_list_head> for RobustListHead {
127 fn from(robust_list_head: uapi::arch32::robust_list_head) -> Self {
128 Self {
129 list: robust_list_head.list.into(),
130 futex_offset: robust_list_head.futex_offset as isize,
131 }
132 }
133}
134
135pub struct TaskMutableState {
136 pub clear_child_tid: UserRef<tid_t>,
138
139 signals: SignalState,
142
143 pub run_state: RunState,
145
146 kernel_signals: VecDeque<KernelSignal>,
154
155 exit_status: Option<ExitStatus>,
157
158 pub scheduler_state: SchedulerState,
160
161 pub uts_ns: UtsNamespaceHandle,
169
170 no_new_privs: bool,
176
177 pub oom_score_adj: i32,
179
180 pub seccomp_filters: SeccompFilterContainer,
182
183 pub robust_list_head: RobustListHeadPtr,
186
187 pub timerslack_ns: u64,
193
194 pub default_timerslack_ns: u64,
200
201 pub ptrace: Option<Box<PtraceState>>,
204
205 pub captured_thread_state: Option<Box<CapturedThreadState>>,
207
208 last_applied_role: Option<String>,
210
211 pub cpuset_path: String,
213}
214
215impl TaskMutableState {
216 pub fn no_new_privs(&self) -> bool {
217 self.no_new_privs
218 }
219
220 pub fn enable_no_new_privs(&mut self) {
223 self.no_new_privs = true;
224 }
225
226 pub fn get_timerslack<T: zx::Timeline>(&self) -> zx::Duration<T> {
227 zx::Duration::from_nanos(self.timerslack_ns as i64)
228 }
229
230 pub fn set_timerslack_ns(&mut self, ns: u64) {
234 if ns == 0 {
235 self.timerslack_ns = self.default_timerslack_ns;
236 } else {
237 self.timerslack_ns = ns;
238 }
239 }
240
241 pub fn is_ptraced(&self) -> bool {
242 self.ptrace.is_some()
243 }
244
245 pub fn is_ptraced_without_cap_sys_ptrace(&self) -> bool {
248 self.ptrace.as_ref().is_some_and(|ptrace| {
249 ptrace.core_state.task.upgrade().is_none_or(|tracer| {
250 !tracer.real_creds().cap_effective.contains(CAP_SYS_PTRACE)
253 })
254 })
255 }
256
257 pub fn is_ptrace_listening(&self) -> bool {
258 self.ptrace.as_ref().is_some_and(|ptrace| ptrace.stop_status == PtraceStatus::Listening)
259 }
260
261 pub fn ptrace_on_signal_consume(&mut self) -> bool {
262 self.ptrace.as_mut().is_some_and(|ptrace: &mut Box<PtraceState>| {
263 if ptrace.stop_status.is_continuing() {
264 ptrace.stop_status = PtraceStatus::Default;
265 false
266 } else {
267 true
268 }
269 })
270 }
271
272 pub fn notify_ptracers(&mut self) {
273 if let Some(ptrace) = &self.ptrace {
274 ptrace.tracer_waiters().notify_all();
275 }
276 }
277
278 pub fn wait_on_ptracer(&self, waiter: &Waiter) {
279 if let Some(ptrace) = &self.ptrace {
280 ptrace.tracee_waiters.wait_async(&waiter);
281 }
282 }
283
284 pub fn notify_ptracees(&mut self) {
285 if let Some(ptrace) = &self.ptrace {
286 ptrace.tracee_waiters.notify_all();
287 }
288 }
289
290 pub fn take_captured_state(&mut self) -> Option<Box<CapturedThreadState>> {
291 if self.captured_thread_state.is_some() {
292 let mut state = None;
293 std::mem::swap(&mut state, &mut self.captured_thread_state);
294 return state;
295 }
296 None
297 }
298
299 pub fn copy_state_from(&mut self, current_task: &CurrentTask) {
300 self.captured_thread_state = Some(Box::new(CapturedThreadState {
301 thread_state: current_task.thread_state.extended_snapshot::<HeapRegs>(),
302 dirty: false,
303 }));
304 }
305
306 pub fn signal_mask(&self) -> SigSet {
308 self.signals.mask()
309 }
310
311 pub fn is_signal_masked(&self, signal: Signal) -> bool {
313 self.signals.mask().has_signal(signal)
314 }
315
316 pub fn is_signal_masked_by_saved_mask(&self, signal: Signal) -> bool {
320 self.signals.saved_mask().is_some_and(|mask| mask.has_signal(signal))
321 }
322
323 pub fn restore_signal_mask(&mut self) {
326 self.signals.restore_mask();
327 }
328
329 pub fn is_blocked(&self) -> bool {
331 self.run_state.is_blocked()
332 }
333
334 pub fn set_run_state(&mut self, run_state: RunState) {
336 self.run_state = run_state;
337 }
338
339 pub fn run_state(&self) -> RunState {
340 self.run_state.clone()
341 }
342
343 pub fn on_signal_stack(&self, stack_pointer_register: u64) -> bool {
344 self.signals
345 .alt_stack
346 .map(|signal_stack| sigaltstack_contains_pointer(&signal_stack, stack_pointer_register))
347 .unwrap_or(false)
348 }
349
350 pub fn set_sigaltstack(&mut self, stack: Option<sigaltstack>) {
351 self.signals.alt_stack = stack;
352 }
353
354 pub fn sigaltstack(&self) -> Option<sigaltstack> {
355 self.signals.alt_stack
356 }
357
358 pub fn wait_on_signal(&mut self, waiter: &Waiter) {
359 self.signals.signal_wait.wait_async(waiter);
360 }
361
362 pub fn signals_mut(&mut self) -> &mut SignalState {
363 &mut self.signals
364 }
365
366 pub fn wait_on_signal_fd_events(
367 &self,
368 waiter: &Waiter,
369 mask: SigSet,
370 handler: EventHandler,
371 ) -> WaitCanceler {
372 self.signals.signal_wait.wait_async_signal_mask(waiter, mask, handler)
373 }
374
375 pub fn notify_signal_waiters(&self, signal: &Signal) {
376 self.signals.signal_wait.notify_signal(signal);
377 }
378
379 pub fn thaw(&mut self) {
381 if let RunState::Frozen(waiter) = self.run_state() {
382 waiter.notify();
383 }
384 }
385
386 pub fn is_frozen(&self) -> bool {
387 matches!(self.run_state(), RunState::Frozen(_))
388 }
389
390 #[cfg(test)]
391 pub fn kernel_signals_for_test(&self) -> &VecDeque<KernelSignal> {
392 &self.kernel_signals
393 }
394}
395
396#[apply(state_implementation!)]
397impl TaskMutableState<Base = Task> {
398 pub fn set_stopped(
399 &mut self,
400 stopped: StopState,
401 siginfo: Option<SignalInfo>,
402 current_task: Option<&CurrentTask>,
403 event: Option<PtraceEventData>,
404 ) {
405 if stopped.ptrace_only() && self.ptrace.is_none() {
406 return;
407 }
408
409 if self.base.load_stopped().is_illegal_transition(stopped) {
410 return;
411 }
412
413 self.store_stopped(stopped);
417 if stopped.is_stopped() {
418 if let Some(ref current_task) = current_task {
419 self.copy_state_from(current_task);
420 }
421 }
422 if let Some(ptrace) = &mut self.ptrace {
423 ptrace.set_last_signal(siginfo);
424 ptrace.set_last_event(event);
425 }
426 if stopped == StopState::Waking || stopped == StopState::ForceWaking {
427 self.notify_ptracees();
428 }
429 if !stopped.is_in_progress() {
430 self.notify_ptracers();
431 }
432 }
433
434 pub fn enqueue_signal(&mut self, signal: SignalInfo) {
436 self.signals.enqueue(signal);
437 self.set_flags(TaskFlags::SIGNALS_AVAILABLE, self.signals.is_any_pending());
438 }
439
440 pub fn enqueue_signal_front(&mut self, signal: SignalInfo) {
444 self.signals.jump_queue(signal);
445 self.set_flags(TaskFlags::SIGNALS_AVAILABLE, self.signals.is_any_pending());
446 }
447
448 pub fn set_signal_mask(&mut self, mask: SigSet) {
450 self.signals.set_mask(mask);
451 self.set_flags(TaskFlags::SIGNALS_AVAILABLE, self.signals.is_any_pending());
452 }
453
454 pub fn set_temporary_signal_mask(&mut self, mask: SigSet) {
458 self.signals.set_temporary_mask(mask);
459 self.set_flags(TaskFlags::SIGNALS_AVAILABLE, self.signals.is_any_pending());
460 }
461
462 pub fn pending_signal_count(&self) -> usize {
464 self.signals.num_queued() + self.base.thread_group().num_signals_queued()
465 }
466
467 pub fn has_signal_pending(&self, signal: Signal) -> bool {
469 self.signals.has_queued(signal) || self.base.thread_group().has_signal_queued(signal)
470 }
471
472 pub fn prepare_signal_info(
474 &mut self,
475 stopped: StopState,
476 ) -> Option<(Weak<ThreadGroup>, SignalInfo)> {
477 if !stopped.is_stopped() {
478 return None;
479 }
480
481 if let Some(ptrace) = &self.ptrace {
482 if let Some(last_signal) = ptrace.get_last_signal_ref() {
483 let signal_info = SignalInfo::with_detail(
484 SIGCHLD,
485 CLD_TRAPPED as i32,
486 SignalDetail::SIGCHLD {
487 pid: self.base.tid.clone(),
488 uid: self.base.real_creds().uid,
489 status: last_signal.signal.number() as i32,
490 },
491 );
492
493 return Some((ptrace.core_state.thread_group.clone(), signal_info));
494 }
495 }
496
497 None
498 }
499
500 pub fn set_ptrace(&mut self, tracer: Option<Box<PtraceState>>) -> Result<(), Errno> {
501 if tracer.is_some() && self.ptrace.is_some() {
502 return error!(EPERM);
503 }
504
505 if tracer.is_none() {
506 if let Ok(tg_stop_state) = self.base.thread_group().load_stopped().as_in_progress() {
508 self.set_stopped(tg_stop_state, None, None, None);
509 }
510 }
511 self.ptrace = tracer;
512 Ok(())
513 }
514
515 pub fn can_accept_ptrace_commands(&mut self) -> bool {
516 !self.base.load_stopped().is_waking_or_awake()
517 && self.is_ptraced()
518 && !self.is_ptrace_listening()
519 }
520
521 fn store_stopped(&mut self, state: StopState) {
522 self.base.stop_state.store(state, Ordering::Relaxed)
527 }
528
529 pub fn update_flags(&mut self, clear: TaskFlags, set: TaskFlags) {
530 debug_assert_eq!(clear ^ set, clear | set);
535 let observed = self.base.flags();
536 let swapped = self.base.flags.swap((observed | set) & !clear, Ordering::Relaxed);
537 debug_assert_eq!(swapped, observed);
538 }
539
540 pub fn set_flags(&mut self, flag: TaskFlags, v: bool) {
541 let (clear, set) = if v { (TaskFlags::empty(), flag) } else { (flag, TaskFlags::empty()) };
542
543 self.update_flags(clear, set);
544 }
545
546 pub fn set_spawned(&mut self) {
547 self.set_flags(TaskFlags::SPAWNED, true);
548 }
549
550 pub fn set_exit_status(&mut self, status: ExitStatus) {
551 self.set_flags(TaskFlags::EXITED, true);
552 self.exit_status = Some(status);
553 }
554
555 pub fn set_exit_status_if_not_already(&mut self, status: ExitStatus) {
556 self.set_flags(TaskFlags::EXITED, true);
557 self.exit_status.get_or_insert(status);
558 }
559
560 pub fn pending_signals(&self) -> SigSet {
563 self.signals.pending() | self.base.thread_group().get_pending_signals()
564 }
565
566 pub fn task_specific_pending_signals(&self) -> SigSet {
569 self.signals.pending()
570 }
571
572 pub fn is_any_signal_allowed_by_mask(&self, mask: SigSet) -> bool {
574 self.signals.is_any_allowed_by_mask(mask)
575 || self.base.thread_group().is_any_signal_allowed_by_mask(mask)
576 }
577
578 pub fn is_any_signal_pending(&self) -> bool {
581 let mask = self.signal_mask();
582 self.signals.is_any_pending()
583 || self.base.thread_group().is_any_signal_allowed_by_mask(mask)
584 }
585
586 fn take_next_signal_where<F>(&mut self, predicate: F) -> Option<SignalInfo>
588 where
589 F: Fn(&SignalInfo) -> bool,
590 {
591 if let Some(signal) = self.signals.take_next_where(&predicate) {
592 self.set_flags(TaskFlags::SIGNALS_AVAILABLE, self.signals.is_any_pending());
593 Some(signal)
594 } else {
595 self.base.thread_group().take_next_signal_where(&predicate)
596 }
597 }
598
599 pub fn take_specific_signal(&mut self, siginfo: SignalInfo) -> Option<SignalInfo> {
603 let signal_mask = self.signal_mask();
604 if signal_mask.has_signal(siginfo.signal) {
605 return None;
606 }
607
608 let predicate = |s: &SignalInfo| s.signal == siginfo.signal;
609 self.take_next_signal_where(predicate)
610 }
611
612 pub fn take_any_signal(&mut self) -> Option<SignalInfo> {
616 let signal_mask = self.signal_mask();
617 let predicate = |s: &SignalInfo| !signal_mask.has_signal(s.signal) || s.force;
618 self.take_next_signal_where(predicate)
619 }
620
621 pub fn take_signal_with_mask(&mut self, signal_mask: SigSet) -> Option<SignalInfo> {
625 let predicate = |s: &SignalInfo| !signal_mask.has_signal(s.signal);
626 self.take_next_signal_where(predicate)
627 }
628
629 pub fn enqueue_kernel_signal(&mut self, signal: KernelSignal) {
631 self.kernel_signals.push_back(signal);
632 self.set_flags(TaskFlags::KERNEL_SIGNALS_AVAILABLE, true);
633 }
634
635 pub fn take_kernel_signal(&mut self) -> Option<KernelSignal> {
639 let signal = self.kernel_signals.pop_front();
640 if self.kernel_signals.is_empty() {
641 self.set_flags(TaskFlags::KERNEL_SIGNALS_AVAILABLE, false);
642 }
643 signal
644 }
645
646 #[cfg(test)]
647 pub fn queued_signal_count(&self, signal: Signal) -> usize {
648 self.signals.queued_count(signal)
649 + self.base.thread_group().pending_signals.lock().queued_count(signal)
650 }
651}
652
653#[derive(Debug, Clone, Copy, PartialEq, Eq)]
654pub enum TaskStateCode {
655 Running,
657
658 Sleeping,
660
661 TracingStop,
663
664 Zombie,
666}
667
668impl TaskStateCode {
669 pub fn code_char(&self) -> char {
670 match self {
671 TaskStateCode::Running => 'R',
672 TaskStateCode::Sleeping => 'S',
673 TaskStateCode::TracingStop => 't',
674 TaskStateCode::Zombie => 'Z',
675 }
676 }
677
678 pub fn name(&self) -> &'static str {
679 match self {
680 TaskStateCode::Running => "running",
681 TaskStateCode::Sleeping => "sleeping",
682 TaskStateCode::TracingStop => "tracing stop",
683 TaskStateCode::Zombie => "zombie",
684 }
685 }
686}
687
688#[derive(Debug, RcuDroppable)]
693pub struct TaskPersistentInfoState {
694 pub tid: Pid,
696 pub pid: Pid,
697
698 command: LockDepMutex<TaskCommand, TaskCommandLevel>,
700
701 creds: RcuDroppableArc<Credentials>,
704
705 creds_lock: LockDepRwLock<(), TaskCredsLock>,
708}
709
710pub struct CredentialsReadGuard<'a> {
712 _lock: LockDepReadGuard<'a, ()>,
713 creds: RcuReadGuard<Credentials>,
714}
715
716impl<'a> Deref for CredentialsReadGuard<'a> {
717 type Target = Credentials;
718
719 fn deref(&self) -> &Self::Target {
720 self.creds.deref()
721 }
722}
723
724pub struct CredentialsWriteGuard<'a> {
727 _lock: LockDepWriteGuard<'a, ()>,
728 creds: &'a RcuDroppableArc<Credentials>,
729}
730
731impl<'a> CredentialsWriteGuard<'a> {
732 pub fn update(&mut self, creds: Arc<Credentials>) {
733 self.creds.update(creds);
734 }
735}
736
737impl TaskPersistentInfoState {
738 fn new(
739 tid: Pid,
740 pid: Pid,
741 command: TaskCommand,
742 creds: Arc<Credentials>,
743 ) -> TaskPersistentInfo {
744 Arc::new(Self {
745 tid,
746 pid,
747 command: command.into(),
748 creds: RcuDroppableArc::new(creds),
749 creds_lock: Default::default(),
750 })
751 }
752
753 pub fn command_guard(&self) -> LockDepGuard<'_, TaskCommand> {
754 self.command.lock()
755 }
756
757 pub fn real_creds(&self) -> RcuReadGuard<Credentials> {
759 self.creds.read()
760 }
761
762 pub fn clone_creds(&self) -> Arc<Credentials> {
765 self.creds.to_arc()
766 }
767
768 pub fn lock_creds(&self) -> CredentialsReadGuard<'_> {
771 let lock = self.creds_lock.read();
772 CredentialsReadGuard { _lock: lock, creds: self.creds.read() }
773 }
774
775 pub(in crate::task) fn write_current_task_creds(
778 self: &Arc<Self>,
779 ) -> CurrentTaskCredentialsWriteGuard {
780 let persistent_info = self.clone();
781 let lock = unsafe {
783 let raw_lock = self.creds_lock.write();
784 std::mem::transmute::<LockDepWriteGuard<'_, ()>, LockDepWriteGuard<'static, ()>>(
785 raw_lock,
786 )
787 };
788 CurrentTaskCredentialsWriteGuard { _lock: lock, persistent_info }
789 }
790}
791
792impl std::borrow::Borrow<Pid> for TaskPersistentInfoState {
793 fn borrow(&self) -> &Pid {
794 &self.tid
795 }
796}
797
798impl PartialEq for TaskPersistentInfoState {
799 fn eq(&self, other: &Self) -> bool {
800 self.tid == other.tid
801 }
802}
803
804impl Eq for TaskPersistentInfoState {}
805
806impl PartialOrd for TaskPersistentInfoState {
807 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
808 Some(self.cmp(other))
809 }
810}
811
812impl Ord for TaskPersistentInfoState {
813 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
814 self.tid.cmp(&other.tid)
815 }
816}
817
818impl std::hash::Hash for TaskPersistentInfoState {
819 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
820 self.tid.hash(state);
821 }
822}
823
824pub type TaskPersistentInfo = Arc<TaskPersistentInfoState>;
825
826pub struct CurrentTaskCredentialsWriteGuard {
827 _lock: LockDepWriteGuard<'static, ()>,
831 pub persistent_info: TaskPersistentInfo,
832}
833
834impl CurrentTaskCredentialsWriteGuard {
835 pub fn update(self, current_task: &CurrentTask, creds: Arc<Credentials>) {
836 self.persistent_info.creds.update(creds.clone());
837 *current_task.current_creds.borrow_mut() = CurrentCreds::Cached(creds);
838
839 let maybe_node = current_task.running_state().proc_pid_directory_cache.get();
842 if let Some(node) = maybe_node {
843 let creds = current_task.real_creds().euid_as_fscred();
844 unsafe {
848 node.force_chown(creds);
849 }
850 }
851 }
852}
853
854pub struct Task {
878 pub weak_self: Weak<Self>,
880
881 pub tid: Pid,
887
888 pub pid: Pid,
890
891 pub kernel: Arc<Kernel>,
893
894 pub thread_group: Arc<ThreadGroup>,
899
900 pub running_state: RcuArc<TaskRunningState>,
904
905 stop_state: AtomicStopState,
909
910 flags: AtomicTaskFlags,
914
915 mutable_state:
917 starnix_sync::LockDepRwLock<TaskMutableState, starnix_sync::TaskMutableStateLock>,
918
919 pub persistent_info: TaskPersistentInfo,
924
925 vfork_event: Option<Arc<zx::Event>>,
929
930 pub seccomp_filter_state: SeccompState,
933
934 pub trace_syscalls: AtomicBool,
936}
937
938#[derive(Debug)]
940pub struct PageFaultExceptionReport {
941 pub faulting_address: u64,
942 pub not_present: bool, pub is_write: bool, pub is_execute: bool, }
946
947impl Task {
948 pub fn kernel(&self) -> &Arc<Kernel> {
949 &self.kernel
950 }
951
952 pub fn thread_group(&self) -> &Arc<ThreadGroup> {
953 &self.thread_group
954 }
955
956 pub fn has_same_address_space(&self, other: Option<&Arc<MemoryManager>>) -> bool {
957 match (self.mm(), other) {
958 (Ok(this), Some(other)) => Arc::ptr_eq(&this, other),
959 (Err(_), None) => true,
960 _ => false,
961 }
962 }
963
964 pub fn flags(&self) -> TaskFlags {
965 self.flags.load(Ordering::Relaxed)
966 }
967
968 pub fn is_spawned(&self) -> bool {
969 self.flags().contains(TaskFlags::SPAWNED)
970 }
971
972 pub fn set_ptrace_zombie(&self, pids: &mut crate::task::PidTableGuard<'_>) {
975 if !self.is_spawned() {
976 return;
978 }
979
980 let pgid = self.thread_group().read().process_group.leader.clone();
981 let exit_signal = self.thread_group().read().exit_signal.clone();
982 let mut state = self.write();
983 state.set_stopped(StopState::ForceAwake, None, None, None);
984 if let Some(ptrace) = &mut state.ptrace {
985 ptrace.last_signal_waitable = true;
987 let tracer_tg = ptrace.core_state.thread_group.upgrade();
988 if let Some(tracer_tg) = tracer_tg {
989 drop(state);
990 let mut tracer_state = tracer_tg.write();
991 if !tracer_state.is_running() {
992 return;
994 }
995
996 let exit_status = self.exit_status().unwrap_or_else(|| {
997 starnix_logging::log_error!("Exiting without an exit code.");
998 ExitStatus::Exit(u8::MAX)
999 });
1000 let zombie = ZombieProcess {
1001 task: self
1002 .weak_self
1003 .upgrade()
1004 .expect("Task strong reference must exist while &self is held"),
1005 pgid,
1006 state: ZombieState {
1007 exit_status,
1008 time_stats: TaskTimeStats::default(),
1010 },
1011 exit_signal,
1012 is_canonical: false,
1013 };
1014
1015 tracer_state.zombie_ptracees.add(pids, self.tid.clone(), zombie);
1016 };
1017 }
1018 }
1019
1020 pub fn ptrace_disconnect(&self) {
1022 let tracer_tg = self
1025 .read()
1026 .ptrace
1027 .as_ref()
1028 .map(|p| p.core_state.thread_group.clone())
1029 .and_then(|tg| tg.upgrade());
1030 if let Some(tg) = tracer_tg {
1031 tg.ptracees.lock().remove(&self.persistent_info);
1032 }
1033 }
1034
1035 pub fn exit_status(&self) -> Option<ExitStatus> {
1036 self.is_exitted().then(|| self.read().exit_status.clone()).flatten()
1037 }
1038
1039 pub fn is_exitted(&self) -> bool {
1040 self.flags().contains(TaskFlags::EXITED)
1041 }
1042
1043 pub fn load_stopped(&self) -> StopState {
1044 self.stop_state.load(Ordering::Relaxed)
1045 }
1046
1047 pub fn from_weak(weak: &Weak<Task>) -> Result<Arc<Task>, Errno> {
1049 weak.upgrade().ok_or_else(|| errno!(ESRCH))
1050 }
1051
1052 #[allow(clippy::let_and_return)]
1059 pub fn new(
1060 tid: Pid,
1061 command: TaskCommand,
1062 thread_group: Arc<ThreadGroup>,
1063 files: SharedFdTable,
1064 mm: Option<Arc<MemoryManager>>,
1065 fs: Arc<FsContext>,
1068 creds: Arc<Credentials>,
1069 abstract_socket_namespace: Arc<AbstractUnixSocketNamespace>,
1070 abstract_vsock_namespace: Arc<AbstractVsockSocketNamespace>,
1071 signal_mask: SigSet,
1072 kernel_signals: VecDeque<KernelSignal>,
1073 vfork_event: Option<Arc<zx::Event>>,
1074 scheduler_state: SchedulerState,
1075 uts_ns: UtsNamespaceHandle,
1076 no_new_privs: bool,
1077 seccomp_filter_state: SeccompState,
1078 seccomp_filters: SeccompFilterContainer,
1079 robust_list_head: RobustListHeadPtr,
1080 timerslack_ns: u64,
1081 ) -> Arc<Self> {
1082 let pid = thread_group.leader.clone();
1083 Arc::new_cyclic(|weak_self| {
1084 let task = Task {
1085 weak_self: weak_self.clone(),
1086 tid: tid.clone(),
1087 pid: pid.clone(),
1088 kernel: Arc::clone(&thread_group.kernel),
1089 thread_group,
1090 running_state: RcuArc::new(Some(Arc::new(TaskRunningState {
1091 thread: Default::default(),
1092 files: Some(files).into(),
1093 mm: RcuArc::new(mm),
1094 fs: RcuArc::new(Some(fs)),
1095 abstract_socket_namespace,
1096 abstract_vsock_namespace,
1097 proc_pid_directory_cache: Default::default(),
1098 }))),
1099 vfork_event,
1100 stop_state: AtomicStopState::new(StopState::Awake),
1101 flags: AtomicTaskFlags::new(TaskFlags::empty()),
1102 mutable_state: TaskMutableState {
1103 clear_child_tid: UserRef::default(),
1104 signals: SignalState::with_mask(signal_mask),
1105 run_state: RunState::default(),
1106 kernel_signals,
1107 exit_status: None,
1108 scheduler_state,
1109 uts_ns,
1110 no_new_privs,
1111 oom_score_adj: Default::default(),
1112 seccomp_filters,
1113 robust_list_head,
1114 timerslack_ns,
1115 default_timerslack_ns: timerslack_ns,
1117 ptrace: None,
1118 captured_thread_state: None,
1119 last_applied_role: None,
1120 cpuset_path: "/".to_string(),
1121 }
1122 .into(),
1123 persistent_info: TaskPersistentInfoState::new(tid, pid, command, creds),
1124 seccomp_filter_state,
1125 trace_syscalls: AtomicBool::new(false),
1126 };
1127
1128 #[cfg(any(test, debug_assertions))]
1129 {
1130 let _l1 = task.persistent_info.lock_creds();
1132 let _l2 = task.read();
1133 let _l3 = task.persistent_info.command_guard();
1134 }
1135 task
1136 })
1137 }
1138
1139 state_accessor!(Task, mutable_state);
1140
1141 pub fn real_creds(&self) -> RcuReadGuard<Credentials> {
1146 self.persistent_info.real_creds()
1147 }
1148
1149 pub fn clone_creds(&self) -> Arc<Credentials> {
1154 self.persistent_info.clone_creds()
1155 }
1156
1157 pub fn ptracer_task(&self) -> Option<Arc<Task>> {
1158 self.read().ptrace.as_ref().and_then(|p| p.core_state.task.upgrade())
1159 }
1160
1161 pub fn is_running(&self) -> bool {
1167 self.running_state.is_some()
1168 }
1169
1170 #[track_caller]
1177 pub fn running_state(&self) -> Result<Arc<TaskRunningState>, Errno> {
1178 self.running_state.upgrade().ok_or_else(|| errno!(ESRCH))
1179 }
1180
1181 #[track_caller]
1189 pub fn files(&self) -> Result<Arc<FdTable>, Errno> {
1190 self.running_state()?.files()
1191 }
1192
1193 #[track_caller]
1201 pub fn fs(&self) -> Result<Arc<FsContext>, Errno> {
1202 Ok(self.running_state()?.fs())
1203 }
1204
1205 #[track_caller]
1214 pub fn mm(&self) -> Result<Arc<MemoryManager>, Errno> {
1215 let _scope = RcuReadScope::new();
1218 self.running_state()?.mm.upgrade().ok_or_else(|| errno!(EINVAL))
1219 }
1220
1221 pub(crate) fn set_scheduler_policy_priority_and_reset_on_fork(
1224 &self,
1225 policy: SchedulingPolicy,
1226 priority: RealtimePriority,
1227 reset_on_fork: bool,
1228 ) -> Result<(), Errno> {
1229 self.update_scheduler_state_then_role(|scheduler_state| {
1230 scheduler_state.policy = policy;
1231 scheduler_state.realtime_priority = priority;
1232 scheduler_state.reset_on_fork = reset_on_fork;
1233 })
1234 }
1235
1236 pub(crate) fn set_scheduler_priority(&self, priority: RealtimePriority) -> Result<(), Errno> {
1238 self.update_scheduler_state_then_role(|scheduler_state| {
1239 scheduler_state.realtime_priority = priority
1240 })
1241 }
1242
1243 pub(crate) fn set_scheduler_nice(&self, nice: NormalPriority) -> Result<(), Errno> {
1245 self.update_scheduler_state_then_role(|scheduler_state| {
1246 scheduler_state.normal_priority = nice
1247 })
1248 }
1249
1250 pub fn set_scheduler_state(&self, scheduler_state: SchedulerState) -> Result<(), Errno> {
1252 self.update_scheduler_state_then_role(|task_scheduler_state| {
1253 *task_scheduler_state = scheduler_state
1254 })
1255 }
1256
1257 pub fn sync_scheduler_state_to_role(&self) -> Result<(), Errno> {
1262 self.update_scheduler_state_then_role(|_| {})
1263 }
1264
1265 fn update_scheduler_state_then_role(
1266 &self,
1267 updater: impl FnOnce(&mut SchedulerState),
1268 ) -> Result<(), Errno> {
1269 let process_name = self.thread_group().read().leader_command();
1270 let thread_name = self.command();
1271
1272 let (new_scheduler_state, cpuset_path, last_applied_role) = {
1273 let mut state = self.write();
1274 updater(&mut state.scheduler_state);
1275 (state.scheduler_state, state.cpuset_path.clone(), state.last_applied_role.clone())
1276 };
1277
1278 let scheduler = &self.thread_group().kernel.scheduler;
1279 let role_name = scheduler.resolve_role_name(
1280 &process_name,
1281 &thread_name,
1282 &cpuset_path,
1283 new_scheduler_state,
1284 );
1285 if last_applied_role.as_deref() == Some(role_name) {
1286 return Ok(());
1287 }
1288 scheduler.set_thread_role(self, role_name)?;
1289 self.write().last_applied_role = Some(role_name.to_string());
1294 Ok(())
1295 }
1296
1297 pub fn signal_vfork(&self) {
1299 if let Some(event) = &self.vfork_event {
1300 if let Err(status) = event.signal(Signals::NONE, Signals::USER_0) {
1301 log_warn!("Failed to set vfork signal {status}");
1302 }
1303 };
1304 }
1305
1306 pub fn wait_for_execve(&self, task_to_wait: Weak<Task>) -> Result<(), Errno> {
1309 let event = task_to_wait.upgrade().and_then(|t| t.vfork_event.clone());
1310 if let Some(event) = event {
1311 event
1312 .wait_one(zx::Signals::USER_0, zx::MonotonicInstant::INFINITE)
1313 .map_err(|status| from_status_like_fdio!(status))?;
1314 }
1315 Ok(())
1316 }
1317
1318 pub fn clear_child_tid_if_needed(&self) -> Result<(), Errno> {
1326 let mut state = self.write();
1327 let user_tid = state.clear_child_tid;
1328 if !user_tid.is_null() {
1329 let zero: tid_t = 0;
1330 self.write_object(user_tid, &zero)?;
1331 self.kernel().shared_futexes.wake(
1332 self,
1333 user_tid.addr(),
1334 usize::MAX,
1335 FUTEX_BITSET_MATCH_ANY,
1336 )?;
1337 state.clear_child_tid = UserRef::default();
1338 }
1339 Ok(())
1340 }
1341
1342 pub fn get_task(&self, tid: tid_t) -> Result<Arc<Task>, Errno> {
1343 self.kernel().pids.get(tid)?.get_task()
1344 }
1345
1346 pub fn get_pid(&self) -> pid_t {
1347 self.pid.id
1348 }
1349
1350 pub fn get_tid(&self) -> tid_t {
1351 self.tid.id
1352 }
1353
1354 pub fn is_leader(&self) -> bool {
1355 self.get_pid() == self.get_tid()
1356 }
1357
1358 pub fn read_argv(&self, max_len: usize) -> Result<Vec<FsString>, Errno> {
1359 let Ok(mm) = self.mm() else {
1361 return Ok(vec![]);
1362 };
1363 let (argv_start, argv_end) = {
1364 let mm_state = mm.state.read();
1365 (mm_state.argv_start, mm_state.argv_end)
1366 };
1367
1368 let len_to_read = std::cmp::min(argv_end - argv_start, max_len);
1369 self.read_nul_delimited_c_string_list(argv_start, len_to_read)
1370 }
1371
1372 pub fn read_argv0(&self) -> Result<FsString, Errno> {
1373 let Ok(mm) = self.mm() else {
1375 return Ok(FsString::default());
1376 };
1377 let argv_start = {
1378 let mm_state = mm.state.read();
1379 mm_state.argv_start
1380 };
1381 let argv_start = UserCString::new(&ArchWidth::Arch64, argv_start);
1383 self.read_path(argv_start)
1384 }
1385
1386 pub fn read_env(&self, max_len: usize) -> Result<Vec<FsString>, Errno> {
1387 let Ok(mm) = self.mm() else { return Ok(vec![]) };
1389 let (env_start, env_end) = {
1390 let mm_state = mm.state.read();
1391 (mm_state.environ_start, mm_state.environ_end)
1392 };
1393
1394 let len_to_read = std::cmp::min(env_end - env_start, max_len);
1395 self.read_nul_delimited_c_string_list(env_start, len_to_read)
1396 }
1397
1398 pub fn thread_runtime_info(&self) -> Result<zx::TaskRuntimeInfo, Errno> {
1399 self.running_state()?
1400 .thread
1401 .get()
1402 .ok_or_else(|| errno!(EINVAL))?
1403 .get_runtime_info()
1404 .map_err(|status| from_status_like_fdio!(status))
1405 }
1406
1407 pub fn real_fscred(&self) -> FsCred {
1408 self.real_creds().as_fscred()
1409 }
1410
1411 pub fn interrupt(&self) {
1416 let Ok(running_state) = self.running_state() else {
1417 log_warn!("Cannot interrupt dead task {}", self.get_tid());
1418 return;
1419 };
1420
1421 self.read().run_state.wake();
1422 if let Some(thread) = running_state.thread.get() {
1423 #[allow(
1424 clippy::undocumented_unsafe_blocks,
1425 reason = "Force documented unsafe blocks in Starnix"
1426 )]
1427 let status = unsafe { zx::sys::zx_restricted_kick(thread.raw_handle(), 0) };
1428 if status != zx::sys::ZX_OK {
1429 assert_eq!(status, zx::sys::ZX_ERR_BAD_STATE);
1433 }
1434 }
1435 }
1436
1437 pub fn command(&self) -> TaskCommand {
1438 self.persistent_info.command.lock().clone()
1439 }
1440
1441 pub fn set_command_name(&self, mut new_name: TaskCommand) {
1442 let Ok(running_state) = self.running_state() else {
1443 log_warn!("Cannot set command name for dead task {}", self.get_tid());
1444 return;
1445 };
1446
1447 if let Ok(argv0) = self.read_argv0() {
1451 let argv0 = TaskCommand::from_path_bytes(&argv0);
1452 if let Some(embedded_name) = argv0.try_embed(&new_name) {
1453 new_name = embedded_name;
1454 }
1455 }
1456
1457 let mut command_guard = self.persistent_info.command_guard();
1461
1462 if let Some(thread) = running_state.thread.get() {
1464 set_zx_name(thread.thread.as_ref(), new_name.as_bytes());
1465 }
1466
1467 if self.is_leader() {
1469 set_zx_name(&*self.thread_group().process, new_name.as_bytes());
1470 let _ = zx::Thread::raise_user_exception(
1471 zx::RaiseExceptionOptions::TARGET_JOB_DEBUGGER,
1472 zx::sys::ZX_EXCP_USER_CODE_PROCESS_NAME_CHANGED,
1473 0,
1474 );
1475 }
1476
1477 *command_guard = new_name;
1480 drop(command_guard);
1481
1482 if self.is_leader() {
1483 if let Some(notifier) = &self.thread_group().read().notifier {
1484 let _ = notifier.send(MemoryAttributionLifecycleEvent::name_change(self.tid.id));
1485 }
1486 }
1487
1488 if let Err(err) = self.sync_scheduler_state_to_role() {
1489 log_warn!(err:?; "Failed to update scheduler role after thread name change.");
1490 }
1491 }
1492
1493 pub fn set_seccomp_state(&self, state: SeccompStateValue) -> Result<(), Errno> {
1494 self.seccomp_filter_state.set(&state)
1495 }
1496
1497 pub fn state_code(&self) -> TaskStateCode {
1498 let status = self.read();
1499 if status.exit_status.is_some() {
1500 TaskStateCode::Zombie
1501 } else if status.run_state.is_blocked() {
1502 let stop_state = self.load_stopped();
1503 if stop_state.ptrace_only() && stop_state.is_stopped() {
1504 TaskStateCode::TracingStop
1505 } else {
1506 TaskStateCode::Sleeping
1507 }
1508 } else {
1509 TaskStateCode::Running
1510 }
1511 }
1512
1513 pub fn time_stats(&self) -> TaskTimeStats {
1514 use zx::Task;
1515 let running_state = match self.running_state() {
1517 Ok(running_state) => running_state,
1518 Err(_) => return TaskTimeStats::default(),
1519 };
1520 let info = match running_state.thread.get() {
1521 Some(thread) => thread.get_runtime_info().expect("Failed to get thread stats"),
1522 None => return TaskTimeStats::default(),
1523 };
1524
1525 TaskTimeStats {
1526 user_time: zx::MonotonicDuration::from_nanos(info.cpu_time),
1527 system_time: zx::MonotonicDuration::default(),
1529 }
1530 }
1531
1532 pub fn get_signal_action(&self, signal: Signal) -> sigaction_t {
1533 self.thread_group().signal_actions.get(signal)
1534 }
1535
1536 pub fn should_check_for_pending_signals(&self) -> bool {
1537 self.flags().intersects(
1538 TaskFlags::KERNEL_SIGNALS_AVAILABLE
1539 | TaskFlags::SIGNALS_AVAILABLE
1540 | TaskFlags::TEMPORARY_SIGNAL_MASK,
1541 ) || self.thread_group.has_pending_signals.load(Ordering::Relaxed)
1542 }
1543
1544 pub fn get_zircon_identity(&self) -> Option<ZirconIdentity> {
1549 let process = self.thread_group().get_process_koid().ok()?;
1550 let thread = self.running_state().ok()?.thread.get()?.koid;
1551 Some(ZirconIdentity { process, thread })
1552 }
1553
1554 pub fn record_pid_koid_mapping(&self) {
1556 if !self.kernel().trace_event_manager.is_recording() {
1557 return;
1558 }
1559 if let Some(identity) = self.get_zircon_identity() {
1560 self.kernel().trace_event_manager.record(self.get_pid(), self.get_tid(), identity);
1561 }
1562 }
1563}
1564
1565impl Drop for Task {
1566 fn drop(&mut self) {
1567 debug_assert!(self.running_state.is_none());
1568 }
1569}
1570
1571impl MemoryAccessor for Task {
1572 fn read_memory<'a>(
1573 &self,
1574 addr: UserAddress,
1575 bytes: &'a mut [MaybeUninit<u8>],
1576 ) -> Result<&'a mut [u8], Errno> {
1577 self.mm()?.syscall_read_memory(addr, bytes)
1582 }
1583
1584 fn read_memory_partial_until_null_byte<'a>(
1585 &self,
1586 addr: UserAddress,
1587 bytes: &'a mut [MaybeUninit<u8>],
1588 ) -> Result<&'a mut [u8], Errno> {
1589 self.mm()?.syscall_read_memory_partial_until_null_byte(addr, bytes)
1594 }
1595
1596 fn read_memory_partial<'a>(
1597 &self,
1598 addr: UserAddress,
1599 bytes: &'a mut [MaybeUninit<u8>],
1600 ) -> Result<&'a mut [u8], Errno> {
1601 self.mm()?.syscall_read_memory_partial(addr, bytes)
1606 }
1607
1608 fn write_memory(&self, addr: UserAddress, bytes: &[u8]) -> Result<usize, Errno> {
1609 self.mm()?.syscall_write_memory(addr, bytes)
1614 }
1615
1616 fn write_memory_partial(&self, addr: UserAddress, bytes: &[u8]) -> Result<usize, Errno> {
1617 self.mm()?.syscall_write_memory_partial(addr, bytes)
1622 }
1623
1624 fn zero(&self, addr: UserAddress, length: usize) -> Result<usize, Errno> {
1625 self.mm()?.syscall_zero(addr, length)
1630 }
1631}
1632
1633impl TaskMemoryAccessor for Task {
1634 fn maximum_valid_address(&self) -> Option<UserAddress> {
1635 self.mm().map(|mm| mm.maximum_valid_user_address).ok()
1636 }
1637}
1638
1639impl fmt::Debug for Task {
1640 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1641 write!(f, "{}:{}[{}]", self.pid, self.tid, *self.persistent_info.command.lock())
1642 }
1643}
1644
1645impl cmp::PartialEq for Task {
1646 fn eq(&self, other: &Self) -> bool {
1647 let ptr: *const Task = self;
1648 let other_ptr: *const Task = other;
1649 ptr == other_ptr
1650 }
1651}
1652
1653impl cmp::Eq for Task {}
1654
1655#[cfg(test)]
1656mod test {
1657 use super::*;
1658 use crate::security;
1659 use crate::testing::*;
1660 use starnix_uapi::auth::{CAP_SYS_ADMIN, Capabilities};
1661 use starnix_uapi::resource_limits::Resource;
1662 use starnix_uapi::signals::SIGCHLD;
1663 use starnix_uapi::{CLONE_SIGHAND, CLONE_THREAD, CLONE_VM, rlimit};
1664
1665 #[::fuchsia::test]
1666 async fn test_tid_allocation() {
1667 spawn_kernel_and_run(async |current_task| {
1668 let kernel = current_task.kernel();
1669 assert_eq!(current_task.get_tid(), 1);
1670 let another_current = create_task(&kernel, "another-task");
1671 let another_tid = another_current.get_tid();
1672 assert!(another_tid >= 2);
1673
1674 let pids = &kernel.pids;
1675 assert_eq!(pids.get(1).unwrap().get_task().unwrap().get_tid(), 1);
1676 assert_eq!(pids.get(another_tid).unwrap().get_task().unwrap().get_tid(), another_tid);
1677 })
1678 .await;
1679 }
1680
1681 #[::fuchsia::test]
1682 async fn test_clone_pid_and_parent_pid() {
1683 spawn_kernel_and_run(async |current_task| {
1684 let thread = current_task.clone_task_for_test(
1685 (CLONE_THREAD | CLONE_VM | CLONE_SIGHAND) as u64,
1686 Some(SIGCHLD),
1687 );
1688 assert_eq!(current_task.get_pid(), thread.get_pid());
1689 assert_ne!(current_task.get_tid(), thread.get_tid());
1690 assert_eq!(current_task.pid, thread.thread_group().leader);
1691
1692 let child_task = current_task.clone_task_for_test(0, Some(SIGCHLD));
1693 assert_ne!(current_task.get_pid(), child_task.get_pid());
1694 assert_ne!(current_task.get_tid(), child_task.get_tid());
1695 assert_eq!(current_task.get_pid(), child_task.thread_group().read().get_ppid());
1696 })
1697 .await;
1698 }
1699
1700 #[::fuchsia::test]
1701 async fn test_root_capabilities() {
1702 spawn_kernel_and_run(async |current_task| {
1703 assert!(security::is_task_capable_noaudit(current_task, CAP_SYS_ADMIN));
1704 assert_eq!(current_task.real_creds().cap_inheritable, Capabilities::empty());
1705
1706 current_task.set_creds(Credentials::with_ids(1, 1));
1707 assert!(!security::is_task_capable_noaudit(current_task, CAP_SYS_ADMIN));
1708 })
1709 .await;
1710 }
1711
1712 #[::fuchsia::test]
1713 async fn test_is_spawned() {
1714 spawn_kernel_and_run(async |current_task| {
1715 assert!(current_task.is_spawned());
1717
1718 let child = current_task
1720 .clone_task(
1721 0,
1722 Some(SIGCHLD),
1723 UserRef::default(),
1724 UserRef::default(),
1725 UserRef::default(),
1726 )
1727 .expect("failed to create task in test");
1728 assert!(!child.is_spawned());
1729 child.release(());
1730
1731 let test_child = current_task.clone_task_for_test(0, Some(SIGCHLD));
1734 assert!(test_child.is_spawned());
1735 })
1736 .await;
1737 }
1738
1739 #[::fuchsia::test]
1740 async fn test_clone_rlimit() {
1741 spawn_kernel_and_run(async |current_task| {
1742 let prev_fsize = current_task.thread_group().get_rlimit(Resource::FSIZE);
1743 assert_ne!(prev_fsize, 10);
1744 current_task
1745 .thread_group()
1746 .limits
1747 .lock()
1748 .set(Resource::FSIZE, rlimit { rlim_cur: 10, rlim_max: 100 });
1749 let current_fsize = current_task.thread_group().get_rlimit(Resource::FSIZE);
1750 assert_eq!(current_fsize, 10);
1751
1752 let child_task = current_task.clone_task_for_test(0, Some(SIGCHLD));
1753 let child_fsize = child_task.thread_group().get_rlimit(Resource::FSIZE);
1754 assert_eq!(child_fsize, 10)
1755 })
1756 .await;
1757 }
1758
1759 #[::fuchsia::test]
1760 async fn test_set_command_name_syncs_scheduler_role() {
1761 use crate::task::{RoleOverrides, SchedulerManager};
1762
1763 let mut builder = RoleOverrides::new();
1764 builder.add("renamed-thread", "renamed-thread", None, "test-role");
1765 let overrides = builder.build().unwrap();
1766
1767 let scheduler_manager = SchedulerManager::new_for_tests(None, overrides);
1768
1769 spawn_kernel_with_scheduler_and_run_sync(scheduler_manager, |current_task| {
1770 current_task.thread_group().write().did_exec = true;
1772
1773 let scheduler = ¤t_task.thread_group().kernel.scheduler;
1774
1775 let initial_role = scheduler.role_name(current_task).unwrap();
1777 assert_ne!(initial_role, "test-role");
1778
1779 current_task
1781 .set_command_name(starnix_task_command::TaskCommand::new(b"renamed-thread"));
1782
1783 let renamed_role = scheduler.role_name(current_task).unwrap();
1784 assert_eq!(renamed_role, "test-role");
1785 })
1786 .await;
1787 }
1788
1789 #[::fuchsia::test]
1790 async fn test_fork_does_not_inherit_custom_role() {
1791 use crate::task::{RoleOverrides, SchedulerManager};
1792
1793 let mut builder = RoleOverrides::new();
1794 builder.add("renamed-thread", "renamed-thread", None, "test-role");
1795 let overrides = builder.build().unwrap();
1796
1797 let scheduler_manager = SchedulerManager::new_for_tests(None, overrides);
1798
1799 spawn_kernel_with_scheduler_and_run_sync(scheduler_manager, |current_task| {
1800 let child = current_task.clone_task_for_test(0, None);
1802
1803 let scheduler = ¤t_task.thread_group().kernel.scheduler;
1804
1805 let initial_role = scheduler.role_name(&child).unwrap();
1807 assert_ne!(initial_role, "test-role");
1808
1809 child.set_command_name(starnix_task_command::TaskCommand::new(b"renamed-thread"));
1812
1813 let renamed_role = scheduler.role_name(&child).unwrap();
1814 assert_ne!(renamed_role, "test-role");
1815 })
1816 .await;
1817 }
1818}