Skip to main content

starnix_core/task/
task.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::mm::{
6    MappingAccess, MemoryAccessor, MemoryAccessorExt, MemoryManager, TaskMemoryAccessor,
7};
8use crate::mutable_state::{state_accessor, state_implementation};
9use crate::ptrace::{AtomicStopState, PtraceEventData, PtraceState, PtraceStatus, StopState};
10use crate::signals::{KernelSignal, SignalDetail, SignalInfo, SignalState};
11use crate::task::memory_attribution::MemoryAttributionLifecycleEvent;
12use crate::task::run_state::RunState;
13use crate::task::tracing::ZirconIdentity;
14use crate::task::{
15    AbstractUnixSocketNamespace, AbstractVsockSocketNamespace, CurrentCreds, CurrentTask,
16    EventHandler, ExitStatus, Kernel, NormalPriority, Pid, RealtimePriority, SchedulerState,
17    SchedulingPolicy, SeccompFilterContainer, SeccompState, SeccompStateValue, TaskRunningState,
18    ThreadGroup, ThreadState, UtsNamespaceHandle, WaitCanceler, Waiter, ZombieProcess, ZombieState,
19};
20use crate::vfs::{FdTable, FsContext, FsString, SharedFdTable, SharedFsContext};
21use atomic_bitflags::atomic_bitflags;
22use fuchsia_rcu::{RcuArc, RcuDroppable, RcuDroppableArc, RcuReadGuard, RcuReadScope};
23use macro_rules_attribute::apply;
24use starnix_logging::{log_warn, set_zx_name};
25use starnix_registers::HeapRegs;
26use starnix_sync::{
27    LockDepGuard, LockDepMutex, LockDepReadGuard, LockDepRwLock, LockDepWriteGuard,
28    TaskCommandLevel, TaskCredsLock,
29};
30use starnix_task_command::TaskCommand;
31use starnix_types::arch::ArchWidth;
32use starnix_types::stats::TaskTimeStats;
33use starnix_types::user_buffer::UserBuffer;
34use starnix_uapi::auth::{CAP_SYS_PTRACE, Credentials, FsCred};
35use starnix_uapi::errors::Errno;
36use starnix_uapi::signals::{SIGCHLD, SIGKILL, SigSet, Signal, sigaltstack_contains_pointer};
37use starnix_uapi::user_address::{
38    ArchSpecific, MappingMultiArchUserRef, UserAddress, UserCString, UserRef,
39};
40use starnix_uapi::{
41    CLD_TRAPPED, FUTEX_BITSET_MATCH_ANY, errno, error, from_status_like_fdio, pid_t, sigaction_t,
42    sigaltstack, tid_t, uapi,
43};
44use std::collections::VecDeque;
45use std::mem::MaybeUninit;
46use std::ops::Deref;
47use std::sync::atomic::{AtomicBool, Ordering};
48use std::sync::{Arc, Weak};
49use std::{cmp, fmt};
50use zx::{Signals, Task as _};
51
52atomic_bitflags! {
53    #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
54    pub struct TaskFlags: u8 {
55        const EXITED                   = 1 << 0;
56        const SIGNALS_AVAILABLE        = 1 << 1;
57        const TEMPORARY_SIGNAL_MASK    = 1 << 2;
58        /// Whether the executor should dump the stack of this task when it exits.
59        /// Currently used to implement ExitStatus::CoreDump.
60        const DUMP_ON_EXIT             = 1 << 3;
61        const KERNEL_SIGNALS_AVAILABLE = 1 << 4;
62        /// Whether the executor has successfully spawned a thread for this task.
63        const SPAWNED                  = 1 << 5;
64        /// Whether the current unit of work executing on this task has been cancelled.
65        ///
66        /// Used by reusable kernel worker threads (such as AIO workers) to abort blocking
67        /// operations with `EINTR`.
68        const WORK_CANCELLED           = 1 << 6;
69        /// Whether this task is running a userspace handler for a signal whose default action is to
70        /// dump core, delivered during shutdown. Cleared on `rt_sigreturn`. Shutdown lets such
71        /// tasks run until the deferred shutdown deadline; see `ThreadGroup::shut_down()`. Known
72        /// limitations, all bounded by that deadline:
73        /// - A handler that isn't writing a crash dump (e.g. one that blocks) gets the time too.
74        /// - It's a single bit, so returning from a nested handler clears it for the outer one.
75        /// - A handler that leaves via `siglongjmp` keeps it set.
76        /// - It isn't set for crashes that started before shutdown.
77        const IN_CORE_DUMP_SIGNAL_HANDLER = 1 << 7;
78    }
79}
80
81/// This contains thread state that tracers can inspect and modify.  It is
82/// captured when a thread stops, and optionally copied back (if dirty) when a
83/// thread starts again.  An alternative implementation would involve the
84/// tracers acting on thread state directly; however, this would involve sharing
85/// CurrentTask structures across multiple threads, which goes against the
86/// intent of the design of CurrentTask.
87pub struct CapturedThreadState {
88    /// The thread state of the traced task.  This is copied out when the thread
89    /// stops.
90    pub thread_state: ThreadState<HeapRegs>,
91
92    /// Indicates that the last ptrace operation changed the thread state, so it
93    /// should be written back to the original thread.
94    pub dirty: bool,
95}
96
97impl ArchSpecific for CapturedThreadState {
98    fn is_arch32(&self) -> bool {
99        self.thread_state.is_arch32()
100    }
101}
102
103#[derive(Debug)]
104pub struct RobustList {
105    pub next: RobustListPtr,
106}
107
108pub type RobustListPtr =
109    MappingMultiArchUserRef<RobustList, uapi::robust_list, uapi::arch32::robust_list>;
110
111impl From<uapi::robust_list> for RobustList {
112    fn from(robust_list: uapi::robust_list) -> Self {
113        Self { next: RobustListPtr::from(robust_list.next) }
114    }
115}
116
117#[cfg(target_arch = "aarch64")]
118impl From<uapi::arch32::robust_list> for RobustList {
119    fn from(robust_list: uapi::arch32::robust_list) -> Self {
120        Self { next: RobustListPtr::from(robust_list.next) }
121    }
122}
123
124#[derive(Debug)]
125pub struct RobustListHead {
126    pub list: RobustList,
127    pub futex_offset: isize,
128}
129
130pub type RobustListHeadPtr =
131    MappingMultiArchUserRef<RobustListHead, uapi::robust_list_head, uapi::arch32::robust_list_head>;
132
133impl From<uapi::robust_list_head> for RobustListHead {
134    fn from(robust_list_head: uapi::robust_list_head) -> Self {
135        Self {
136            list: robust_list_head.list.into(),
137            futex_offset: robust_list_head.futex_offset as isize,
138        }
139    }
140}
141
142#[cfg(target_arch = "aarch64")]
143impl From<uapi::arch32::robust_list_head> for RobustListHead {
144    fn from(robust_list_head: uapi::arch32::robust_list_head) -> Self {
145        Self {
146            list: robust_list_head.list.into(),
147            futex_offset: robust_list_head.futex_offset as isize,
148        }
149    }
150}
151
152pub struct TaskMutableState {
153    // See https://man7.org/linux/man-pages/man2/set_tid_address.2.html
154    pub clear_child_tid: UserRef<tid_t>,
155
156    /// Signal handler related state. This is grouped together for when atomicity is needed during
157    /// signal sending and delivery.
158    signals: SignalState,
159
160    /// The current run state of the task.
161    run_state: RunState,
162
163    /// Internal signals that have a higher priority than a regular signal.
164    ///
165    /// Storing in a separate queue outside of `SignalState` ensures the internal signals will
166    /// never be ignored or masked when dequeuing. Higher priority ensures that no user signals
167    /// will jump the queue, e.g. ptrace, which delays the delivery.
168    ///
169    /// This design is not about observable consequence, but about convenient implementation.
170    kernel_signals: VecDeque<KernelSignal>,
171
172    /// The exit status that this task exited with.
173    exit_status: Option<ExitStatus>,
174
175    /// The UTS namespace assigned to this thread.
176    ///
177    /// This field is kept in the mutable state because the UTS namespace of a thread
178    /// can be forked using `clone()` or `unshare()` syscalls.
179    ///
180    /// We use UtsNamespaceHandle because the UTS properties can be modified
181    /// by any other thread that shares this namespace.
182    pub uts_ns: UtsNamespaceHandle,
183
184    /// Bit that determines whether a newly started program can have privileges its parent does
185    /// not have. See `PR_SET_NO_NEW_PRIVS` in `prctl(2)` for details.
186    ///
187    /// Once set to true, this bit cannot be reverted to false. Accessor methods for this field
188    /// ensure this property.
189    no_new_privs: bool,
190
191    /// Userspace hint about how to adjust the OOM score for this process.
192    pub oom_score_adj: i32,
193
194    /// List of currently installed seccomp_filters
195    pub seccomp_filters: SeccompFilterContainer,
196
197    /// A pointer to the head of the robust futex list of this thread in
198    /// userspace. See get_robust_list(2)
199    pub robust_list_head: RobustListHeadPtr,
200
201    /// The timer slack used to group timer expirations for the calling thread.
202    ///
203    /// Timers may expire up to `timerslack_ns` late, but never early.
204    ///
205    /// If this value is 0, the task's default timerslack is used.
206    pub timerslack_ns: u64,
207
208    /// The default value for `timerslack_ns`. This value cannot change during the lifetime of a
209    /// task.
210    ///
211    /// This value is set to the `timerslack_ns` of the creating thread, and thus is not constant
212    /// across tasks.
213    pub default_timerslack_ns: u64,
214
215    /// Information that a tracer needs to communicate with this process, if it
216    /// is being traced.
217    pub ptrace: Option<Box<PtraceState>>,
218
219    /// Information that a tracer needs to inspect this process.
220    pub captured_thread_state: Option<Box<CapturedThreadState>>,
221
222    /// The cpuset cgroup path of this task.
223    pub cpuset_path: String,
224}
225
226impl TaskMutableState {
227    pub fn no_new_privs(&self) -> bool {
228        self.no_new_privs
229    }
230
231    /// Sets the value of no_new_privs to true.  It is an error to set
232    /// it to anything else.
233    pub fn enable_no_new_privs(&mut self) {
234        self.no_new_privs = true;
235    }
236
237    pub fn get_timerslack<T: zx::Timeline>(&self) -> zx::Duration<T> {
238        zx::Duration::from_nanos(self.timerslack_ns as i64)
239    }
240
241    /// Sets the current timerslack of the task to `ns`.
242    ///
243    /// If `ns` is zero, the current timerslack gets reset to the task's default timerslack.
244    pub fn set_timerslack_ns(&mut self, ns: u64) {
245        if ns == 0 {
246            self.timerslack_ns = self.default_timerslack_ns;
247        } else {
248            self.timerslack_ns = ns;
249        }
250    }
251
252    pub fn is_ptraced(&self) -> bool {
253        self.ptrace.is_some()
254    }
255
256    /// Returns true if the task is being traced via `ptrace(2)` by a tracer that does not hold
257    /// [`CAP_SYS_PTRACE`] in its effective capability set.
258    pub fn is_ptraced_without_cap_sys_ptrace(&self) -> bool {
259        self.ptrace.as_ref().is_some_and(|ptrace| {
260            ptrace.core_state.task.upgrade().is_none_or(|tracer| {
261                // TODO(https://fxbug.dev/322893829): Verify CAP_SYS_PTRACE in the tracee's user
262                // namespace once user namespaces are supported.
263                !tracer.real_creds().cap_effective.contains(CAP_SYS_PTRACE)
264            })
265        })
266    }
267
268    pub fn is_ptrace_listening(&self) -> bool {
269        self.ptrace.as_ref().is_some_and(|ptrace| ptrace.stop_status == PtraceStatus::Listening)
270    }
271
272    pub fn ptrace_on_signal_consume(&mut self) -> bool {
273        self.ptrace.as_mut().is_some_and(|ptrace: &mut Box<PtraceState>| {
274            if ptrace.stop_status.is_continuing() {
275                ptrace.stop_status = PtraceStatus::Default;
276                false
277            } else {
278                true
279            }
280        })
281    }
282
283    pub fn notify_ptracers(&mut self) {
284        if let Some(ptrace) = &self.ptrace {
285            ptrace.tracer_waiters().notify_all();
286        }
287    }
288
289    pub fn wait_on_ptracer(&self, waiter: &Waiter) {
290        if let Some(ptrace) = &self.ptrace {
291            ptrace.tracee_waiters.wait_async(&waiter);
292        }
293    }
294
295    pub fn notify_ptracees(&mut self) {
296        if let Some(ptrace) = &self.ptrace {
297            ptrace.tracee_waiters.notify_all();
298        }
299    }
300
301    pub fn take_captured_state(&mut self) -> Option<Box<CapturedThreadState>> {
302        self.captured_thread_state.take()
303    }
304
305    /// Captures the thread's register state if not already captured.
306    ///
307    /// If a snapshot is already present, this is a no-op to preserve any tracer
308    /// modifications (dirty register state) across consecutive stop events prior
309    /// to resumption and write-back.
310    fn copy_state_from(&mut self, current_task: &CurrentTask) {
311        if self.captured_thread_state.is_none() {
312            self.captured_thread_state = Some(Box::new(CapturedThreadState {
313                thread_state: current_task.thread_state.extended_snapshot::<HeapRegs>(),
314                dirty: false,
315            }));
316        }
317    }
318
319    /// Returns the task's currently active signal mask.
320    pub fn signal_mask(&self) -> SigSet {
321        self.signals.mask()
322    }
323
324    /// Returns true if `signal` is currently blocked by this task's signal mask.
325    pub fn is_signal_masked(&self, signal: Signal) -> bool {
326        self.signals.mask().has_signal(signal)
327    }
328
329    /// Returns true if `signal` is blocked by the saved signal mask.
330    ///
331    /// Note that the current signal mask may still not be blocking the signal.
332    pub fn is_signal_masked_by_saved_mask(&self, signal: Signal) -> bool {
333        self.signals.saved_mask().is_some_and(|mask| mask.has_signal(signal))
334    }
335
336    /// Returns true if the task's current `RunState` is blocked.
337    pub fn is_blocked(&self) -> bool {
338        self.run_state.is_blocked()
339    }
340
341    /// Sets the task's `RunState` to `run_state` and returns the previous `RunState`.
342    ///
343    /// # Safety
344    /// If `run_state` is `RunState::Event(event_ref)`, the caller must guarantee that `event_ref`
345    /// points to a live `InterruptibleEvent` until `run_state` is reset to `RunState::Running`
346    /// under `Task::write()`.
347    pub(super) unsafe fn set_run_state(&mut self, run_state: RunState) -> RunState {
348        std::mem::replace(&mut self.run_state, run_state)
349    }
350
351    pub fn run_state(&self) -> RunState {
352        self.run_state.clone()
353    }
354
355    /// Unblocks the task by interrupting whatever wait it is currently blocked upon.
356    pub fn wake(&self) {
357        // SAFETY: Holding `&self` (the task's state lock guard) ensures that if `self.run_state` is
358        // `RunState::Event`, the blocked thread has not yet cleared `run_state` in
359        // `CurrentTask::run_in_state_internal`, so the `InterruptibleEvent` outlives this call.
360        unsafe { self.run_state.wake() };
361    }
362
363    pub fn on_signal_stack(&self, stack_pointer_register: u64) -> bool {
364        self.signals
365            .alt_stack
366            .map(|signal_stack| sigaltstack_contains_pointer(&signal_stack, stack_pointer_register))
367            .unwrap_or(false)
368    }
369
370    pub fn set_sigaltstack(&mut self, stack: Option<sigaltstack>) {
371        self.signals.alt_stack = stack;
372    }
373
374    pub fn sigaltstack(&self) -> Option<sigaltstack> {
375        self.signals.alt_stack
376    }
377
378    pub fn wait_on_signal(&mut self, waiter: &Waiter) {
379        self.signals.signal_wait.wait_async(waiter);
380    }
381
382    pub fn signals_mut(&mut self) -> &mut SignalState {
383        &mut self.signals
384    }
385
386    pub fn wait_on_signal_fd_events(
387        &self,
388        waiter: &Waiter,
389        mask: SigSet,
390        handler: EventHandler,
391    ) -> WaitCanceler {
392        self.signals.signal_wait.wait_async_signal_mask(waiter, mask, handler)
393    }
394
395    pub fn notify_signal_waiters(&self, signal: &Signal) {
396        self.signals.signal_wait.notify_signal(signal);
397    }
398
399    /// Thaw the task if has been frozen
400    pub fn thaw(&mut self) {
401        if let RunState::Frozen(waiter) = &self.run_state {
402            waiter.notify();
403        }
404    }
405
406    pub fn is_frozen(&self) -> bool {
407        matches!(self.run_state, RunState::Frozen(_))
408    }
409
410    #[cfg(test)]
411    pub fn kernel_signals_for_test(&self) -> &VecDeque<KernelSignal> {
412        &self.kernel_signals
413    }
414}
415
416#[apply(state_implementation!)]
417impl TaskMutableState<Base = Task> {
418    pub fn set_stopped(
419        &mut self,
420        stopped: StopState,
421        siginfo: Option<SignalInfo>,
422        current_task: Option<&CurrentTask>,
423        event: Option<PtraceEventData>,
424    ) {
425        if stopped.ptrace_only() && self.ptrace.is_none() {
426            return;
427        }
428
429        if self.base.load_stopped().is_illegal_transition(stopped) {
430            return;
431        }
432
433        // TODO(https://g-issues.fuchsia.dev/issues/306438676): When task can be
434        // stopped inside user code, task will need to be either restarted or
435        // stopped here.
436        self.store_stopped(stopped);
437        if stopped.is_stopped() {
438            if let Some(ref current_task) = current_task {
439                self.copy_state_from(current_task);
440            }
441        }
442        if let Some(ptrace) = &mut self.ptrace {
443            ptrace.set_last_signal(siginfo);
444            ptrace.set_last_event(event);
445        }
446        if stopped == StopState::Waking || stopped == StopState::ForceWaking {
447            self.notify_ptracees();
448        }
449        if !stopped.is_in_progress() {
450            self.notify_ptracers();
451        }
452    }
453
454    /// Enqueues a signal at the back of the task's signal queue.
455    pub fn enqueue_signal(&mut self, signal: SignalInfo) {
456        self.signals.enqueue(signal);
457        self.set_flags(TaskFlags::SIGNALS_AVAILABLE, self.signals.is_any_pending());
458    }
459
460    /// Enqueues `signal` at the front of the task's signal queue.
461    ///
462    /// [`Self::enqueue_signal`] is the more common API to use.
463    pub fn enqueue_signal_front(&mut self, signal: SignalInfo) {
464        self.signals.jump_queue(signal);
465        self.set_flags(TaskFlags::SIGNALS_AVAILABLE, self.signals.is_any_pending());
466    }
467
468    /// Sets the current signal mask of the task.
469    pub fn set_signal_mask(&mut self, mask: SigSet) {
470        self.signals.set_mask(mask);
471        self.set_flags(TaskFlags::SIGNALS_AVAILABLE, self.signals.is_any_pending());
472    }
473
474    /// Sets a temporary signal mask for the task.
475    ///
476    /// This mask should be removed by a matching call to `restore_signal_mask`.
477    pub fn set_temporary_signal_mask(&mut self, mask: SigSet) {
478        self.signals.set_temporary_mask(mask);
479        let (signals_clear, signals_set) = if self.signals.is_any_pending() {
480            (TaskFlags::empty(), TaskFlags::SIGNALS_AVAILABLE)
481        } else {
482            (TaskFlags::SIGNALS_AVAILABLE, TaskFlags::empty())
483        };
484        self.update_flags(signals_clear, signals_set | TaskFlags::TEMPORARY_SIGNAL_MASK);
485    }
486
487    /// Removes the currently active, temporary, signal mask and restores the
488    /// previously active signal mask.
489    pub fn restore_signal_mask(&mut self) {
490        self.signals.restore_mask();
491        let (signals_clear, signals_set) = if self.signals.is_any_pending() {
492            (TaskFlags::empty(), TaskFlags::SIGNALS_AVAILABLE)
493        } else {
494            (TaskFlags::SIGNALS_AVAILABLE, TaskFlags::empty())
495        };
496        self.update_flags(signals_clear | TaskFlags::TEMPORARY_SIGNAL_MASK, signals_set);
497    }
498
499    /// Returns the number of pending signals for this task, without considering the signal mask.
500    pub fn pending_signal_count(&self) -> usize {
501        self.signals.num_queued() + self.base.thread_group().num_signals_queued()
502    }
503
504    /// Returns `true` if `signal` is pending for this task, without considering the signal mask.
505    pub fn has_signal_pending(&self, signal: Signal) -> bool {
506        self.signals.has_queued(signal) || self.base.thread_group().has_signal_queued(signal)
507    }
508
509    // Prepare a SignalInfo to be sent to the tracer, if any.
510    pub fn prepare_signal_info(
511        &mut self,
512        stopped: StopState,
513    ) -> Option<(Weak<ThreadGroup>, SignalInfo)> {
514        if !stopped.is_stopped() {
515            return None;
516        }
517
518        if let Some(ptrace) = &self.ptrace {
519            if let Some(last_signal) = ptrace.get_last_signal_ref() {
520                let signal_info = SignalInfo::with_detail(
521                    SIGCHLD,
522                    CLD_TRAPPED as i32,
523                    SignalDetail::SIGCHLD {
524                        pid: self.base.tid.clone(),
525                        uid: self.base.real_creds().uid,
526                        status: last_signal.signal.number() as i32,
527                    },
528                );
529
530                return Some((ptrace.core_state.thread_group.clone(), signal_info));
531            }
532        }
533
534        None
535    }
536
537    pub fn set_ptrace(&mut self, tracer: Option<Box<PtraceState>>) -> Result<(), Errno> {
538        if tracer.is_some() && self.ptrace.is_some() {
539            return error!(EPERM);
540        }
541
542        if tracer.is_none() {
543            // Handle the case where this is called while the thread group is being released.
544            if let Ok(tg_stop_state) = self.base.thread_group().load_stopped().as_in_progress() {
545                self.set_stopped(tg_stop_state, None, None, None);
546            }
547        }
548        self.ptrace = tracer;
549        Ok(())
550    }
551
552    pub fn can_accept_ptrace_commands(&mut self) -> bool {
553        !self.base.load_stopped().is_waking_or_awake()
554            && self.is_ptraced()
555            && !self.is_ptrace_listening()
556    }
557
558    fn store_stopped(&mut self, state: StopState) {
559        // We don't actually use the guard but we require it to enforce that the
560        // caller holds the thread group's mutable state lock (identified by
561        // mutable access to the thread group's mutable state).
562
563        self.base.stop_state.store(state, Ordering::Relaxed)
564    }
565
566    pub fn update_flags(&mut self, clear: TaskFlags, set: TaskFlags) {
567        // We don't actually use the guard but we require it to enforce that the
568        // caller holds the task's mutable state lock (identified by mutable
569        // access to the task's mutable state).
570
571        debug_assert_eq!(clear ^ set, clear | set);
572        let observed = self.base.flags();
573        let swapped = self.base.flags.swap((observed | set) & !clear, Ordering::Relaxed);
574        debug_assert_eq!(swapped, observed);
575    }
576
577    pub fn set_flags(&mut self, flag: TaskFlags, v: bool) {
578        let (clear, set) = if v { (TaskFlags::empty(), flag) } else { (flag, TaskFlags::empty()) };
579
580        self.update_flags(clear, set);
581    }
582
583    pub fn set_spawned(&mut self) {
584        self.set_flags(TaskFlags::SPAWNED, true);
585    }
586
587    pub fn set_exit_status(&mut self, status: ExitStatus) {
588        self.set_flags(TaskFlags::EXITED, true);
589        self.exit_status = Some(status);
590    }
591
592    pub fn set_exit_status_if_not_already(&mut self, status: ExitStatus) {
593        self.set_flags(TaskFlags::EXITED, true);
594        self.exit_status.get_or_insert(status);
595    }
596
597    /// Transitions the task out of any stop state, notifies signal waiters, and thaws it so it can
598    /// wind down after being marked [`TaskFlags::EXITED`].
599    pub(crate) fn force_wake_for_exit(&mut self) {
600        self.set_stopped(
601            StopState::ForceWaking,
602            /* siginfo = */ None,
603            /* current_task = */ None,
604            /* event = */ None,
605        );
606        self.notify_signal_waiters(&SIGKILL);
607        self.thaw();
608    }
609
610    /// The set of pending signals for the task, including the signals pending for the thread
611    /// group.
612    pub fn pending_signals(&self) -> SigSet {
613        self.signals.pending() | self.base.thread_group().get_pending_signals()
614    }
615
616    /// The set of pending signals for the task specifically, not including the signals pending
617    /// for the thread group.
618    pub fn task_specific_pending_signals(&self) -> SigSet {
619        self.signals.pending()
620    }
621
622    /// Returns true if any currently pending signal is allowed by `mask`.
623    pub fn is_any_signal_allowed_by_mask(&self, mask: SigSet) -> bool {
624        self.signals.is_any_allowed_by_mask(mask)
625            || self.base.thread_group().is_any_signal_allowed_by_mask(mask)
626    }
627
628    /// Returns whether or not a signal is pending for this task, taking the current
629    /// signal mask into account.
630    pub fn is_any_signal_pending(&self) -> bool {
631        let mask = self.signal_mask();
632        self.signals.is_any_pending()
633            || self.base.thread_group().is_any_signal_allowed_by_mask(mask)
634    }
635
636    /// Returns whether a deliverable signal or a task/thread-group stop is pending for this task.
637    pub fn is_interrupt_pending(&self) -> bool {
638        self.is_any_signal_pending()
639            || self.base.load_stopped().is_stopping_or_stopped()
640            || self.base.thread_group().load_stopped().is_stopping_or_stopped()
641    }
642
643    /// Returns the next pending signal that passes `predicate`.
644    fn take_next_signal_where<F>(&mut self, predicate: F) -> Option<SignalInfo>
645    where
646        F: Fn(&SignalInfo) -> bool,
647    {
648        if let Some(signal) = self.signals.take_next_where(&predicate) {
649            self.set_flags(TaskFlags::SIGNALS_AVAILABLE, self.signals.is_any_pending());
650            Some(signal)
651        } else {
652            self.base.thread_group().take_next_signal_where(&predicate)
653        }
654    }
655
656    /// Removes and returns the next pending `signal` for this task.
657    ///
658    /// Returns `None` if `siginfo` is a blocked signal, or no such signal is pending.
659    pub fn take_specific_signal(&mut self, siginfo: SignalInfo) -> Option<SignalInfo> {
660        let signal_mask = self.signal_mask();
661        if signal_mask.has_signal(siginfo.signal) {
662            return None;
663        }
664
665        let predicate = |s: &SignalInfo| s.signal == siginfo.signal;
666        self.take_next_signal_where(predicate)
667    }
668
669    /// Removes and returns a pending signal that is unblocked by the current signal mask or forced.
670    ///
671    /// Returns `None` if there are no deliverable signals pending.
672    pub fn take_any_signal(&mut self) -> Option<SignalInfo> {
673        let signal_mask = self.signal_mask();
674        let predicate = |s: &SignalInfo| !signal_mask.has_signal(s.signal) || s.force;
675        self.take_next_signal_where(predicate)
676    }
677
678    /// Removes and returns a pending signal that is unblocked by `signal_mask`.
679    ///
680    /// Returns `None` if there are no signals pending that are unblocked by `signal_mask`.
681    pub fn take_signal_with_mask(&mut self, signal_mask: SigSet) -> Option<SignalInfo> {
682        let predicate = |s: &SignalInfo| !signal_mask.has_signal(s.signal);
683        self.take_next_signal_where(predicate)
684    }
685
686    /// Enqueues an internal signal at the back of the task's kernel signal queue.
687    pub fn enqueue_kernel_signal(&mut self, signal: KernelSignal) {
688        self.kernel_signals.push_back(signal);
689        self.set_flags(TaskFlags::KERNEL_SIGNALS_AVAILABLE, true);
690    }
691
692    /// Removes and returns a pending internal signal.
693    ///
694    /// Returns `None` if there are no signals pending.
695    pub fn take_kernel_signal(&mut self) -> Option<KernelSignal> {
696        let signal = self.kernel_signals.pop_front();
697        if self.kernel_signals.is_empty() {
698            self.set_flags(TaskFlags::KERNEL_SIGNALS_AVAILABLE, false);
699        }
700        signal
701    }
702
703    #[cfg(test)]
704    pub fn queued_signal_count(&self, signal: Signal) -> usize {
705        self.signals.queued_count(signal)
706            + self.base.thread_group().pending_signals.lock().queued_count(signal)
707    }
708}
709
710#[derive(Debug, Clone, Copy, PartialEq, Eq)]
711pub enum TaskStateCode {
712    // Task is being executed.
713    Running,
714
715    // Task is waiting for an event.
716    Sleeping,
717
718    // Tracing stop
719    TracingStop,
720
721    // Task has exited.
722    Zombie,
723}
724
725impl TaskStateCode {
726    pub fn code_char(&self) -> char {
727        match self {
728            TaskStateCode::Running => 'R',
729            TaskStateCode::Sleeping => 'S',
730            TaskStateCode::TracingStop => 't',
731            TaskStateCode::Zombie => 'Z',
732        }
733    }
734
735    pub fn name(&self) -> &'static str {
736        match self {
737            TaskStateCode::Running => "running",
738            TaskStateCode::Sleeping => "sleeping",
739            TaskStateCode::TracingStop => "tracing stop",
740            TaskStateCode::Zombie => "zombie",
741        }
742    }
743}
744
745/// The information of the task that needs to be available to the `ThreadGroup` while computing
746/// which process a wait can target. It is necessary to shared this data with the `ThreadGroup` so
747/// that it is available while the task is being dropped and so is not accessible from a weak
748/// pointer.
749#[derive(Debug, RcuDroppable)]
750pub struct TaskPersistentInfoState {
751    /// Immutable information about the task
752    pub tid: Pid,
753    pub pid: Pid,
754
755    /// The command of this task.
756    command: LockDepMutex<TaskCommand, TaskCommandLevel>,
757
758    /// The security credentials for this task. These are only set when the task is the CurrentTask,
759    /// or on task creation.
760    creds: RcuDroppableArc<Credentials>,
761
762    // A lock for the security credentials. Writers must take the lock, readers that need to ensure
763    // that the task state does not change may take the lock.
764    creds_lock: LockDepRwLock<(), TaskCredsLock>,
765}
766
767/// Guard for reading locked credentials.
768pub struct CredentialsReadGuard<'a> {
769    _lock: LockDepReadGuard<'a, ()>,
770    creds: RcuReadGuard<Credentials>,
771}
772
773impl<'a> Deref for CredentialsReadGuard<'a> {
774    type Target = Credentials;
775
776    fn deref(&self) -> &Self::Target {
777        self.creds.deref()
778    }
779}
780
781/// Guard for writing credentials. No `CredentialsReadGuard` to the same task can concurrently
782///  exist.
783pub struct CredentialsWriteGuard<'a> {
784    _lock: LockDepWriteGuard<'a, ()>,
785    creds: &'a RcuDroppableArc<Credentials>,
786}
787
788impl<'a> CredentialsWriteGuard<'a> {
789    pub fn update(&mut self, creds: Arc<Credentials>) {
790        self.creds.update(creds);
791    }
792}
793
794impl TaskPersistentInfoState {
795    fn new(
796        tid: Pid,
797        pid: Pid,
798        command: TaskCommand,
799        creds: Arc<Credentials>,
800    ) -> TaskPersistentInfo {
801        Arc::new(Self {
802            tid,
803            pid,
804            command: command.into(),
805            creds: RcuDroppableArc::new(creds),
806            creds_lock: Default::default(),
807        })
808    }
809
810    pub fn command_guard(&self) -> LockDepGuard<'_, TaskCommand> {
811        self.command.lock()
812    }
813
814    /// Snapshots the credentials, returning a short-lived RCU-guarded reference.
815    pub fn real_creds(&self) -> RcuReadGuard<Credentials> {
816        self.creds.read()
817    }
818
819    /// Snapshots the credentials, returning a new reference. Use this if you need to stash the
820    /// credentials somewhere.
821    pub fn clone_creds(&self) -> Arc<Credentials> {
822        self.creds.to_arc()
823    }
824
825    /// Returns a read lock on the credentials. This is appropriate if you need to guarantee that
826    ///  the Task's credentials will not change during a security-sensitive operation.
827    pub fn lock_creds(&self) -> CredentialsReadGuard<'_> {
828        let lock = self.creds_lock.read();
829        CredentialsReadGuard { _lock: lock, creds: self.creds.read() }
830    }
831
832    /// Locks the credentials for writing, returning a guard that the `CurrentTask` can use to
833    /// update both the objective `Task` credentials, and its own subjective cached copy.
834    pub(in crate::task) fn write_current_task_creds(
835        self: &Arc<Self>,
836    ) -> CurrentTaskCredentialsWriteGuard {
837        let persistent_info = self.clone();
838        // SAFETY: `creds_lock` remains live via the `persistent_info` reference to `Self`.
839        let lock = unsafe {
840            let raw_lock = self.creds_lock.write();
841            std::mem::transmute::<LockDepWriteGuard<'_, ()>, LockDepWriteGuard<'static, ()>>(
842                raw_lock,
843            )
844        };
845        CurrentTaskCredentialsWriteGuard { _lock: lock, persistent_info }
846    }
847}
848
849impl std::borrow::Borrow<Pid> for TaskPersistentInfoState {
850    fn borrow(&self) -> &Pid {
851        &self.tid
852    }
853}
854
855impl PartialEq for TaskPersistentInfoState {
856    fn eq(&self, other: &Self) -> bool {
857        self.tid == other.tid
858    }
859}
860
861impl Eq for TaskPersistentInfoState {}
862
863impl PartialOrd for TaskPersistentInfoState {
864    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
865        Some(self.cmp(other))
866    }
867}
868
869impl Ord for TaskPersistentInfoState {
870    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
871        self.tid.cmp(&other.tid)
872    }
873}
874
875impl std::hash::Hash for TaskPersistentInfoState {
876    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
877        self.tid.hash(state);
878    }
879}
880
881pub type TaskPersistentInfo = Arc<TaskPersistentInfoState>;
882
883pub struct CurrentTaskCredentialsWriteGuard {
884    // Drop order is critical: the lock must be dropped BEFORE the persistent_info Arc.
885    // Rust drops fields in declaration order (top-to-bottom).
886    // So _lock is dropped first, then persistent_info.
887    _lock: LockDepWriteGuard<'static, ()>,
888    pub persistent_info: TaskPersistentInfo,
889}
890
891impl CurrentTaskCredentialsWriteGuard {
892    pub fn update(self, current_task: &CurrentTask, creds: Arc<Credentials>) {
893        self.persistent_info.creds.update(creds.clone());
894        *current_task.current_creds.borrow_mut() = CurrentCreds::Cached(creds);
895
896        // The /proc/pid directory's ownership is updated when the task's euid
897        // or egid changes. See proc(5).
898        let maybe_node = current_task.running_state().proc_pid_directory_cache.get();
899        if let Some(node) = maybe_node {
900            let creds = current_task.real_creds().euid_as_fscred();
901            // SAFETY: The /proc/pid directory held by `proc_pid_directory_cache` represents the
902            // current task. It's owner and group are supposed to track the current task's euid and
903            // egid.
904            unsafe {
905                node.force_chown(creds);
906            }
907        }
908    }
909}
910
911/// A unit of execution.
912///
913/// A task is the primary unit of execution in the Starnix kernel. Most tasks are *user* tasks,
914/// which have an associated Zircon thread. The Zircon thread switches between restricted mode,
915/// in which the thread runs userspace code, and normal mode, in which the thread runs Starnix
916/// code.
917///
918/// Tasks track the resources used by userspace by referencing various objects, such as an
919/// `FdTable`, a `MemoryManager`, and an `FsContext`. Many tasks can share references to these
920/// objects. In principle, which objects are shared between which tasks can be largely arbitrary,
921/// but there are common patterns of sharing. For example, tasks created with `pthread_create`
922/// will share the `FdTable`, `MemoryManager`, and `FsContext` and are often called "threads" by
923/// userspace programmers. Tasks created by `posix_spawn` do not share these objects and are often
924/// called "processes" by userspace programmers. However, inside the kernel, there is no clear
925/// definition of a "thread" or a "process".
926///
927/// During boot, the kernel creates the first task, often called `init`. The vast majority of other
928/// tasks are created as transitive clones (e.g., using `clone(2)`) of that task. Sometimes, the
929/// kernel will create new tasks from whole cloth, either with a corresponding userspace component
930/// or to represent some background work inside the kernel.
931///
932/// See also `CurrentTask`, which represents the task corresponding to the thread that is currently
933/// executing.
934pub struct Task {
935    /// Weak reference to this `Task`. This allows us to retrieve an `Arc` from a raw `Task`.
936    pub weak_self: Weak<Self>,
937
938    /// A unique identifier for this task.
939    ///
940    /// This value can be read in userspace using `gettid(2)`. In general, this value
941    /// is different from the value return by `getpid(2)`, which returns the `id` of the leader
942    /// of the `thread_group`.
943    pub tid: Pid,
944
945    /// The process key of this task.
946    pub pid: Pid,
947
948    /// The kernel to which this thread group belongs.
949    pub kernel: Arc<Kernel>,
950
951    /// The thread group to which this task belongs.
952    ///
953    /// The group of tasks in a thread group roughly corresponds to the userspace notion of a
954    /// process.
955    pub thread_group: Arc<ThreadGroup>,
956
957    /// The running state of the task.
958    ///
959    /// This is `None` for exited tasks.
960    pub running_state: RcuArc<TaskRunningState>,
961
962    /// The stop state of the task, distinct from the stop state of the thread group.
963    ///
964    /// Must only be set when the `mutable_state` write lock is held.
965    stop_state: AtomicStopState,
966
967    /// The flags for the task.
968    ///
969    /// Must only be set the then `mutable_state` write lock is held.
970    flags: AtomicTaskFlags,
971
972    /// The mutable state of the Task.
973    mutable_state:
974        starnix_sync::LockDepRwLock<TaskMutableState, starnix_sync::TaskMutableStateLock>,
975
976    /// Desired scheduler state for the task. This may not reflect the actual committed Zircon
977    /// priority, which is not applied until [`SchedulerManager::commit_thread_role`] is invoked.
978    pub scheduler_state:
979        starnix_sync::LockDepMutex<SchedulerState, starnix_sync::TaskSchedulerStateLock>,
980
981    /// The information of the task that needs to be available to the `ThreadGroup` while computing
982    /// which process a wait can target.
983    /// Contains the command line, the task credentials and the exit signal.
984    /// See `TaskPersistentInfo` for more information.
985    pub persistent_info: TaskPersistentInfo,
986
987    /// For vfork and clone() with CLONE_VFORK, this is set when the task exits or calls execve().
988    /// It allows the calling task to block until the fork has been completed. Only populated
989    /// when created with the CLONE_VFORK flag.
990    vfork_event: Option<Arc<zx::Event>>,
991
992    /// Variable that can tell you whether there are currently seccomp
993    /// filters without holding a lock
994    pub seccomp_filter_state: SeccompState,
995
996    /// Tell you whether you are tracing syscall entry / exit without a lock.
997    pub trace_syscalls: AtomicBool,
998}
999
1000/// The decoded cross-platform parts we care about for page fault exception reports.
1001#[derive(Debug)]
1002pub struct PageFaultExceptionReport {
1003    pub faulting_address: u64,
1004    pub not_present: bool, // Set when the page fault was due to a not-present page.
1005    pub is_write: bool,    // Set when the triggering memory operation was a write.
1006    pub is_execute: bool,  // Set when the triggering memory operation was an execute.
1007}
1008
1009impl Task {
1010    pub fn kernel(&self) -> &Arc<Kernel> {
1011        &self.kernel
1012    }
1013
1014    pub fn thread_group(&self) -> &Arc<ThreadGroup> {
1015        &self.thread_group
1016    }
1017
1018    pub fn has_same_address_space(&self, other: Option<&Arc<MemoryManager>>) -> bool {
1019        match (self.mm(), other) {
1020            (Ok(this), Some(other)) => Arc::ptr_eq(&this, other),
1021            (Err(_), None) => true,
1022            _ => false,
1023        }
1024    }
1025
1026    pub fn flags(&self) -> TaskFlags {
1027        self.flags.load(Ordering::Relaxed)
1028    }
1029
1030    pub fn is_spawned(&self) -> bool {
1031        self.flags().contains(TaskFlags::SPAWNED)
1032    }
1033
1034    /// When the task exits, if there is a notification that needs to propagate
1035    /// to a ptracer, make sure it will propagate.
1036    pub fn set_ptrace_zombie(&self, pids: &mut crate::task::PidTableGuard<'_>) {
1037        if !self.is_spawned() {
1038            // A task that has not fully spawned cannot become a zombie.
1039            return;
1040        }
1041
1042        let exit_signal = self.thread_group().read().exit_signal.clone();
1043        let mut state = self.write();
1044        state.set_stopped(StopState::ForceAwake, None, None, None);
1045        if let Some(ptrace) = &mut state.ptrace {
1046            // Add a zombie that the ptracer will notice.
1047            ptrace.last_signal_waitable = true;
1048            let tracer_tg = ptrace.core_state.thread_group.upgrade();
1049            if let Some(tracer_tg) = tracer_tg {
1050                drop(state);
1051                let mut tracer_state = tracer_tg.write();
1052                if tracer_state.is_exited() {
1053                    // An exited tracer has already detached its ptracees and cannot accept new
1054                    // zombies.
1055                    return;
1056                }
1057
1058                let exit_status = self.exit_status().unwrap_or_else(|| {
1059                    starnix_logging::log_error!("Exiting without an exit code.");
1060                    ExitStatus::Exit(u8::MAX)
1061                });
1062                let zombie = ZombieProcess {
1063                    task: self
1064                        .weak_self
1065                        .upgrade()
1066                        .expect("Task strong reference must exist while &self is held"),
1067                    state: ZombieState {
1068                        exit_status,
1069                        // ptrace doesn't need this.
1070                        time_stats: TaskTimeStats::default(),
1071                    },
1072                    exit_signal,
1073                    is_canonical: false,
1074                };
1075
1076                tracer_state.zombie_ptracees.add(pids, self.tid.clone(), zombie);
1077            };
1078        }
1079    }
1080
1081    /// Disconnects this task from the tracer.
1082    pub fn ptrace_disconnect(&self) {
1083        // Get a reference to the ptracer thread group through the weak reference in PtraceCoreState
1084        // to avoid acquiring a PidTable lock.
1085        let tracer_tg = self
1086            .read()
1087            .ptrace
1088            .as_ref()
1089            .map(|p| p.core_state.thread_group.clone())
1090            .and_then(|tg| tg.upgrade());
1091        if let Some(tg) = tracer_tg {
1092            tg.ptracees.lock().remove(&self.persistent_info);
1093        }
1094    }
1095
1096    pub fn exit_status(&self) -> Option<ExitStatus> {
1097        self.is_exitted().then(|| self.read().exit_status.clone()).flatten()
1098    }
1099
1100    pub fn is_exitted(&self) -> bool {
1101        self.flags().contains(TaskFlags::EXITED)
1102    }
1103
1104    pub fn load_stopped(&self) -> StopState {
1105        self.stop_state.load(Ordering::Relaxed)
1106    }
1107
1108    /// Upgrade a [`Weak<Task>`], returning [`Err(ESRCH)`] if the reference cannot be borrowed.
1109    pub fn from_weak(weak: &Weak<Task>) -> Result<Arc<Task>, Errno> {
1110        weak.upgrade().ok_or_else(|| errno!(ESRCH))
1111    }
1112
1113    /// Internal function for creating a Task object. Useful when you need to specify the value of
1114    /// every field. create_process and create_thread are more likely to be what you want.
1115    ///
1116    /// Any fields that should be initialized fresh for every task, even if the task was created
1117    /// with fork, are initialized to their defaults inside this function. All other fields are
1118    /// passed as parameters.
1119    #[allow(clippy::let_and_return)]
1120    pub fn new(
1121        tid: Pid,
1122        command: TaskCommand,
1123        thread_group: Arc<ThreadGroup>,
1124        files: SharedFdTable,
1125        mm: Option<Arc<MemoryManager>>,
1126        // The only case where fs should be None if when building the initial task that is the
1127        // used to build the initial FsContext.
1128        fs: Arc<FsContext>,
1129        creds: Arc<Credentials>,
1130        abstract_socket_namespace: Arc<AbstractUnixSocketNamespace>,
1131        abstract_vsock_namespace: Arc<AbstractVsockSocketNamespace>,
1132        signal_mask: SigSet,
1133        kernel_signals: VecDeque<KernelSignal>,
1134        vfork_event: Option<Arc<zx::Event>>,
1135        scheduler_state: SchedulerState,
1136        uts_ns: UtsNamespaceHandle,
1137        no_new_privs: bool,
1138        seccomp_filter_state: SeccompState,
1139        seccomp_filters: SeccompFilterContainer,
1140        robust_list_head: RobustListHeadPtr,
1141        timerslack_ns: u64,
1142    ) -> Arc<Self> {
1143        let pid = thread_group.leader.clone();
1144        Arc::new_cyclic(|weak_self| {
1145            let task = Task {
1146                weak_self: weak_self.clone(),
1147                tid: tid.clone(),
1148                pid: pid.clone(),
1149                kernel: Arc::clone(&thread_group.kernel),
1150                thread_group,
1151                running_state: RcuArc::new(Some(Arc::new(TaskRunningState {
1152                    thread: Default::default(),
1153                    files: Some(files).into(),
1154                    mm: RcuArc::new(mm),
1155                    fs: SharedFsContext::new(fs),
1156                    abstract_socket_namespace,
1157                    abstract_vsock_namespace,
1158                    proc_pid_directory_cache: Default::default(),
1159                }))),
1160                vfork_event,
1161                stop_state: AtomicStopState::new(StopState::Awake),
1162                flags: AtomicTaskFlags::new(TaskFlags::empty()),
1163                mutable_state: TaskMutableState {
1164                    clear_child_tid: UserRef::default(),
1165                    signals: SignalState::with_mask(signal_mask),
1166                    run_state: RunState::default(),
1167                    kernel_signals,
1168                    exit_status: None,
1169                    uts_ns,
1170                    no_new_privs,
1171                    oom_score_adj: Default::default(),
1172                    seccomp_filters,
1173                    robust_list_head,
1174                    timerslack_ns,
1175                    // The default timerslack is set to the current timerslack of the creating thread.
1176                    default_timerslack_ns: timerslack_ns,
1177                    ptrace: None,
1178                    captured_thread_state: None,
1179                    cpuset_path: "/".to_string(),
1180                }
1181                .into(),
1182                scheduler_state: LockDepMutex::new(scheduler_state),
1183                persistent_info: TaskPersistentInfoState::new(tid, pid, command, creds),
1184                seccomp_filter_state,
1185                trace_syscalls: AtomicBool::new(false),
1186            };
1187
1188            #[cfg(any(test, debug_assertions))]
1189            {
1190                // Note that `Kernel::pids` is already locked by the caller of `Task::new()`.
1191                let _l1 = task.persistent_info.lock_creds();
1192                let _l2 = task.scheduler_state.lock();
1193                let _l3 = task.read();
1194                let _l4 = task.persistent_info.command_guard();
1195            }
1196            task
1197        })
1198    }
1199
1200    state_accessor!(Task, mutable_state);
1201
1202    /// Returns the real credentials of the task as a short-lived RCU-guarded reference. These
1203    /// credentials are used to check permissions for actions performed on the task. If the task
1204    /// itself is performing an action, use `CurrentTask::current_creds` instead. This does not
1205    /// lock the credentials.
1206    pub fn real_creds(&self) -> RcuReadGuard<Credentials> {
1207        self.persistent_info.real_creds()
1208    }
1209
1210    /// Returns a new long-lived reference to the real credentials of the task.  These credentials
1211    /// are used to check permissions for actions performed on the task. If the task itself is
1212    /// performing an action, use `CurrentTask::current_creds` instead. This does not lock the
1213    /// credentials.
1214    pub fn clone_creds(&self) -> Arc<Credentials> {
1215        self.persistent_info.clone_creds()
1216    }
1217
1218    pub fn ptracer_task(&self) -> Option<Arc<Task>> {
1219        self.read().ptrace.as_ref().and_then(|p| p.core_state.task.upgrade())
1220    }
1221
1222    /// Determine whether the task is running.
1223    ///
1224    /// # Thread Safety
1225    ///
1226    /// The task may exit immediately after `is_running()` returns `true`.
1227    pub fn is_running(&self) -> bool {
1228        self.running_state.is_some()
1229    }
1230
1231    /// Returns the running state of the task, if it exists.
1232    ///
1233    /// # Errors
1234    ///
1235    /// Returns [`Err(ESRCH)`] if the task has already transitioned to a zombie state and its running
1236    /// resources have been dropped.
1237    #[track_caller]
1238    pub fn running_state(&self) -> Result<Arc<TaskRunningState>, Errno> {
1239        self.running_state.upgrade().ok_or_else(|| errno!(ESRCH))
1240    }
1241
1242    /// Returns the file descriptor table of the task, if it exists.
1243    ///
1244    /// # Errors
1245    ///
1246    /// Returns [`Err(errno)`] where `errno` is:
1247    ///
1248    ///   - `ESRCH`: the task is dead and its live resources have been dropped.
1249    #[track_caller]
1250    pub fn files(&self) -> Result<Arc<FdTable>, Errno> {
1251        self.running_state()?.files()
1252    }
1253
1254    /// Returns the file system context of the task, if it exists.
1255    ///
1256    /// # Errors
1257    ///
1258    /// Returns [`Err(errno)`] where `errno` is:
1259    ///
1260    ///   - `ESRCH`: the task is dead and its live resources have been dropped.
1261    #[track_caller]
1262    pub fn fs(&self) -> Result<Arc<FsContext>, Errno> {
1263        self.running_state()?.fs()
1264    }
1265
1266    /// Returns the memory manager of the task, if it exists.
1267    ///
1268    /// # Errors
1269    ///
1270    /// Returns [`Err(errno)`] where `errno` is:
1271    ///
1272    ///   - `ESRCH`: the task is dead and its live resources have been dropped.
1273    ///   - `EINVAL`: the task does not have a memory manager.
1274    #[track_caller]
1275    pub fn mm(&self) -> Result<Arc<MemoryManager>, Errno> {
1276        // Retain an RCU read scope for the entire operation. This allows self.running_state() and
1277        // mm.upgrade() to use cheaper nested RCU read locks.
1278        let _scope = RcuReadScope::new();
1279        self.running_state()?.mm.upgrade().ok_or_else(|| errno!(EINVAL))
1280    }
1281
1282    /// Modify the given elements of the scheduler state with new values and update the
1283    /// task's thread's role.
1284    pub(crate) fn set_scheduler_policy_priority_and_reset_on_fork(
1285        &self,
1286        policy: SchedulingPolicy,
1287        priority: RealtimePriority,
1288        reset_on_fork: bool,
1289    ) -> Result<(), Errno> {
1290        self.update_scheduler_state_then_role(|scheduler_state| {
1291            scheduler_state.policy = policy;
1292            scheduler_state.realtime_priority = priority;
1293            scheduler_state.reset_on_fork = reset_on_fork;
1294        })
1295    }
1296
1297    /// Modify the scheduler state's priority and update the task's thread's role.
1298    pub(crate) fn set_scheduler_priority(&self, priority: RealtimePriority) -> Result<(), Errno> {
1299        self.update_scheduler_state_then_role(|scheduler_state| {
1300            scheduler_state.realtime_priority = priority;
1301        })
1302    }
1303
1304    /// Modify the scheduler state's nice and update the task's thread's role.
1305    pub(crate) fn set_scheduler_nice(&self, nice: NormalPriority) -> Result<(), Errno> {
1306        self.update_scheduler_state_then_role(|scheduler_state| {
1307            scheduler_state.normal_priority = nice;
1308        })
1309    }
1310
1311    /// Update the task's thread's role based on its current scheduler state without making any
1312    /// changes to the state.
1313    ///
1314    /// This should be called on tasks that have newly created threads, e.g. after cloning.
1315    pub fn sync_scheduler_state_to_role(&self) -> Result<(), Errno> {
1316        self.update_scheduler_state_then_role(|_| {})
1317    }
1318
1319    fn update_scheduler_state_then_role(
1320        &self,
1321        updater: impl FnOnce(&mut SchedulerState),
1322    ) -> Result<(), Errno> {
1323        let mut scheduler_state = self.scheduler_state.lock();
1324        let prev = (
1325            scheduler_state.policy,
1326            scheduler_state.normal_priority,
1327            scheduler_state.realtime_priority,
1328            scheduler_state.reset_on_fork,
1329        );
1330        updater(&mut scheduler_state);
1331        let result = if !scheduler_state.policy.is_valid_priority(scheduler_state.realtime_priority)
1332        {
1333            error!(EINVAL)
1334        } else {
1335            self.thread_group().kernel.scheduler.commit_thread_role(self, &mut scheduler_state)
1336        };
1337        result.inspect_err(|_| {
1338            (
1339                scheduler_state.policy,
1340                scheduler_state.normal_priority,
1341                scheduler_state.realtime_priority,
1342                scheduler_state.reset_on_fork,
1343            ) = prev;
1344        })
1345    }
1346
1347    /// Signals the vfork event, if any, to unblock waiters.
1348    pub fn signal_vfork(&self) {
1349        if let Some(event) = &self.vfork_event {
1350            if let Err(status) = event.signal(Signals::NONE, Signals::USER_0) {
1351                log_warn!("Failed to set vfork signal {status}");
1352            }
1353        };
1354    }
1355
1356    /// Blocks the caller until the task has exited or executed execve(). This is used to implement
1357    /// vfork() and clone(... CLONE_VFORK, ...). The task must have created with CLONE_EXECVE.
1358    pub fn wait_for_execve(&self, task_to_wait: Weak<Task>) -> Result<(), Errno> {
1359        let event = task_to_wait.upgrade().and_then(|t| t.vfork_event.clone());
1360        if let Some(event) = event {
1361            event
1362                .wait_one(zx::Signals::USER_0, zx::MonotonicInstant::INFINITE)
1363                .map_err(|status| from_status_like_fdio!(status))?;
1364        }
1365        Ok(())
1366    }
1367
1368    /// If needed, clear the child tid for this task.
1369    ///
1370    /// Userspace can ask us to clear the child tid and issue a futex wake at
1371    /// the child tid address when we tear down a task. For example, bionic
1372    /// uses this mechanism to implement pthread_join. The thread that calls
1373    /// pthread_join sleeps using FUTEX_WAIT on the child tid address. We wake
1374    /// them up here to let them know the thread is done.
1375    pub fn clear_child_tid_if_needed(&self) -> Result<(), Errno> {
1376        let mut state = self.write();
1377        let user_tid = state.clear_child_tid;
1378        if !user_tid.is_null() {
1379            let zero: tid_t = 0;
1380            self.write_object(user_tid, &zero)?;
1381            self.kernel().shared_futexes.wake::<crate::mm::SharedFutexKey>(
1382                self,
1383                user_tid.addr(),
1384                usize::MAX,
1385                FUTEX_BITSET_MATCH_ANY,
1386            )?;
1387            state.clear_child_tid = UserRef::default();
1388        }
1389        Ok(())
1390    }
1391
1392    pub fn get_task(&self, tid: tid_t) -> Result<Arc<Task>, Errno> {
1393        self.kernel().pids.get(tid)?.get_task()
1394    }
1395
1396    pub fn get_pid(&self) -> pid_t {
1397        self.pid.id
1398    }
1399
1400    pub fn get_tid(&self) -> tid_t {
1401        self.tid.id
1402    }
1403
1404    pub fn is_leader(&self) -> bool {
1405        self.get_pid() == self.get_tid()
1406    }
1407
1408    pub fn read_argv(&self, max_len: usize) -> Result<Vec<FsString>, Errno> {
1409        // argv is empty for kthreads
1410        let Ok(mm) = self.mm() else {
1411            return Ok(vec![]);
1412        };
1413        let (argv_start, argv_end) = {
1414            let mm_state = mm.state.read();
1415            (mm_state.argv_start, mm_state.argv_end)
1416        };
1417
1418        let len_to_read = std::cmp::min(argv_end - argv_start, max_len);
1419        self.read_nul_delimited_c_string_list(argv_start, len_to_read)
1420    }
1421
1422    pub fn read_argv0(&self) -> Result<FsString, Errno> {
1423        // argv is empty for kthreads
1424        let Ok(mm) = self.mm() else {
1425            return Ok(FsString::default());
1426        };
1427        let argv_start = {
1428            let mm_state = mm.state.read();
1429            mm_state.argv_start
1430        };
1431        // Assuming a 64-bit arch width is fine for a type that's just u8's on all arches.
1432        let argv_start = UserCString::new(&ArchWidth::Arch64, argv_start);
1433        self.read_path(argv_start)
1434    }
1435
1436    pub fn read_env(&self, max_len: usize) -> Result<Vec<FsString>, Errno> {
1437        // environment is empty for kthreads
1438        let Ok(mm) = self.mm() else { return Ok(vec![]) };
1439        let (env_start, env_end) = {
1440            let mm_state = mm.state.read();
1441            (mm_state.environ_start, mm_state.environ_end)
1442        };
1443
1444        let len_to_read = std::cmp::min(env_end - env_start, max_len);
1445        self.read_nul_delimited_c_string_list(env_start, len_to_read)
1446    }
1447
1448    pub fn thread_runtime_info(&self) -> Result<zx::TaskRuntimeInfo, Errno> {
1449        self.running_state()?
1450            .thread
1451            .get()
1452            .ok_or_else(|| errno!(EINVAL))?
1453            .get_runtime_info()
1454            .map_err(|status| from_status_like_fdio!(status))
1455    }
1456
1457    pub fn real_fscred(&self) -> FsCred {
1458        self.real_creds().as_fscred()
1459    }
1460
1461    /// Interrupts the current task.
1462    ///
1463    /// This will interrupt any blocking syscalls if the task is blocked on one.
1464    /// The signal_state of the task must not be locked.
1465    pub fn interrupt(&self) {
1466        let Ok(running_state) = self.running_state() else {
1467            log_warn!("Cannot interrupt dead task {}", self.get_tid());
1468            return;
1469        };
1470
1471        self.read().wake();
1472        if let Some(thread) = running_state.thread.get() {
1473            #[allow(
1474                clippy::undocumented_unsafe_blocks,
1475                reason = "Force documented unsafe blocks in Starnix"
1476            )]
1477            let status = unsafe { zx::sys::zx_restricted_kick(thread.raw_handle(), 0) };
1478            if status != zx::sys::ZX_OK {
1479                // zx_restricted_kick() could return ZX_ERR_BAD_STATE if the target thread is already in the
1480                // DYING or DEAD states. That's fine since it means that the task is in the process of
1481                // tearing down, so allow it.
1482                assert_eq!(status, zx::sys::ZX_ERR_BAD_STATE);
1483            }
1484        }
1485    }
1486
1487    pub fn command(&self) -> TaskCommand {
1488        self.persistent_info.command.lock().clone()
1489    }
1490
1491    pub fn set_command_name(&self, mut new_name: TaskCommand) {
1492        let Ok(running_state) = self.running_state() else {
1493            log_warn!("Cannot set command name for dead task {}", self.get_tid());
1494            return;
1495        };
1496
1497        let is_leader = self.is_leader();
1498
1499        // If we're going to update the process name, see if we can get a longer one than normally
1500        // provided in the Linux uapi. Only choose the argv0-based name if it's a superset of the
1501        // uapi-provided name to avoid clobbering the name provided by the user.
1502        if is_leader {
1503            if let Ok(argv0) = self.read_argv0() {
1504                let argv0 = TaskCommand::from_path_bytes(&argv0);
1505                if let Some(embedded_name) = argv0.try_embed(&new_name) {
1506                    new_name = embedded_name;
1507                }
1508            }
1509        }
1510
1511        // Acquire this before modifying Zircon state to ensure consistency under concurrent access.
1512        // Ideally this would also guard the logic above to read argv[0] but we can't due to lock
1513        // cycles with SELinux checks.
1514        let mut command_guard = self.persistent_info.command_guard();
1515
1516        // Set the name on the Linux thread. If the thread has already exited concurrently in
1517        // Zircon, `set_zx_name` safely ignores `ZX_ERR_BAD_STATE`.
1518        if let Some(thread) = running_state.thread.get() {
1519            set_zx_name(thread.thread.as_ref(), new_name.as_bytes());
1520        }
1521
1522        // If this is the thread group leader, use this name for the process too.
1523        if is_leader {
1524            set_zx_name(&*self.thread_group().process, new_name.as_bytes());
1525            let _ = zx::Thread::raise_user_exception(
1526                zx::RaiseExceptionOptions::TARGET_JOB_DEBUGGER,
1527                zx::sys::ZX_EXCP_USER_CODE_PROCESS_NAME_CHANGED,
1528                0,
1529            );
1530        }
1531
1532        // Avoid a lock cycle by dropping the guard before notifying memory attribution of the
1533        // change.
1534        *command_guard = new_name;
1535        drop(command_guard);
1536
1537        if is_leader {
1538            let tasks = {
1539                let thread_group = self.thread_group().read();
1540                if let Some(notifier) = &thread_group.notifier {
1541                    let _ =
1542                        notifier.send(MemoryAttributionLifecycleEvent::name_change(self.tid.id));
1543                }
1544                thread_group.tasks()
1545            };
1546            for task in tasks {
1547                if let Err(err) = task.sync_scheduler_state_to_role() {
1548                    log_warn!(err:?; "Failed to update scheduler role after process name change.");
1549                }
1550            }
1551        } else if let Err(err) = self.sync_scheduler_state_to_role() {
1552            log_warn!(err:?; "Failed to update scheduler role after thread name change.");
1553        }
1554    }
1555
1556    pub fn set_seccomp_state(&self, state: SeccompStateValue) -> Result<(), Errno> {
1557        self.seccomp_filter_state.set(&state)
1558    }
1559
1560    pub fn state_code(&self) -> TaskStateCode {
1561        let status = self.read();
1562        if status.exit_status.is_some() {
1563            TaskStateCode::Zombie
1564        } else {
1565            status.run_state.state_code()
1566        }
1567    }
1568
1569    pub fn time_stats(&self) -> TaskTimeStats {
1570        use zx::Task;
1571        // TODO(https://fxbug.dev/297440106): Return time stats for zombie tasks.
1572        let running_state = match self.running_state() {
1573            Ok(running_state) => running_state,
1574            Err(_) => return TaskTimeStats::default(),
1575        };
1576        let info = match running_state.thread.get() {
1577            Some(thread) => thread.get_runtime_info().expect("Failed to get thread stats"),
1578            None => return TaskTimeStats::default(),
1579        };
1580
1581        TaskTimeStats {
1582            user_time: zx::MonotonicDuration::from_nanos(info.cpu_time),
1583            // TODO(https://fxbug.dev/42078242): How can we calculate system time?
1584            system_time: zx::MonotonicDuration::default(),
1585        }
1586    }
1587
1588    pub fn get_signal_action(&self, signal: Signal) -> sigaction_t {
1589        self.thread_group().signal_actions.get(signal)
1590    }
1591
1592    pub fn should_check_for_pending_signals(&self) -> bool {
1593        self.flags().intersects(
1594            TaskFlags::KERNEL_SIGNALS_AVAILABLE
1595                | TaskFlags::SIGNALS_AVAILABLE
1596                | TaskFlags::TEMPORARY_SIGNAL_MASK,
1597        ) || self.thread_group.has_pending_signals.load(Ordering::Relaxed)
1598    }
1599
1600    /// Returns the process and thread KOIDs for this task if both are available.
1601    ///
1602    /// The thread handle is always attached before task startup; a task without a valid
1603    /// backing process (a Starnix kernel thread) is intentionally excluded.
1604    pub fn get_zircon_identity(&self) -> Option<ZirconIdentity> {
1605        let process = self.thread_group().get_process_koid().ok()?;
1606        let thread = self.running_state().ok()?.thread.get()?.koid;
1607        Some(ZirconIdentity { process, thread })
1608    }
1609
1610    /// Record the pid - koid mapping for tracing and profiling tools.
1611    pub fn record_pid_koid_mapping(&self) {
1612        if !self.kernel().trace_event_manager.is_recording() {
1613            return;
1614        }
1615        if let Some(identity) = self.get_zircon_identity() {
1616            self.kernel().trace_event_manager.record(self.get_pid(), self.get_tid(), identity);
1617        }
1618    }
1619}
1620
1621impl Drop for Task {
1622    fn drop(&mut self) {
1623        debug_assert!(self.running_state.is_none());
1624    }
1625}
1626
1627impl MemoryAccessor for Task {
1628    fn read_memory<'a>(
1629        &self,
1630        addr: UserAddress,
1631        bytes: &'a mut [MaybeUninit<u8>],
1632    ) -> Result<&'a mut [u8], Errno> {
1633        // Using a `Task` to read memory generally indicates that the memory
1634        // is being read from a task different than the `CurrentTask`. When
1635        // this `Task` is not current, its address space is not mapped
1636        // so access must go through the VMO.
1637        self.mm()?.syscall_read_memory(addr, bytes)
1638    }
1639
1640    fn read_memory_partial_until_null_byte<'a>(
1641        &self,
1642        addr: UserAddress,
1643        bytes: &'a mut [MaybeUninit<u8>],
1644    ) -> Result<&'a mut [u8], Errno> {
1645        // Using a `Task` to read memory generally indicates that the memory
1646        // is being read from a task different than the `CurrentTask`. When
1647        // this `Task` is not current, its address space is not mapped
1648        // so access must go through the VMO.
1649        self.mm()?.syscall_read_memory_partial_until_null_byte(addr, bytes)
1650    }
1651
1652    fn read_memory_partial<'a>(
1653        &self,
1654        addr: UserAddress,
1655        bytes: &'a mut [MaybeUninit<u8>],
1656    ) -> Result<&'a mut [u8], Errno> {
1657        // Using a `Task` to read memory generally indicates that the memory
1658        // is being read from a task different than the `CurrentTask`. When
1659        // this `Task` is not current, its address space is not mapped
1660        // so access must go through the VMO.
1661        self.mm()?.syscall_read_memory_partial(addr, bytes)
1662    }
1663
1664    fn write_memory(&self, addr: UserAddress, bytes: &[u8]) -> Result<usize, Errno> {
1665        // Using a `Task` to write memory generally indicates that the memory
1666        // is being written to a task different than the `CurrentTask`. When
1667        // this `Task` is not current, its address space is not mapped
1668        // so access must go through the VMO.
1669        self.mm()?.syscall_write_memory(addr, bytes)
1670    }
1671
1672    fn write_memory_partial(&self, addr: UserAddress, bytes: &[u8]) -> Result<usize, Errno> {
1673        // Using a `Task` to write memory generally indicates that the memory
1674        // is being written to a task different than the `CurrentTask`. When
1675        // this `Task` is not current, its address space is not mapped
1676        // so access must go through the VMO.
1677        self.mm()?.syscall_write_memory_partial(addr, bytes)
1678    }
1679
1680    fn zero(&self, addr: UserAddress, length: usize) -> Result<usize, Errno> {
1681        // Using a `Task` to zero memory generally indicates that the memory
1682        // is being zeroed from a task different than the `CurrentTask`. When
1683        // this `Task` is not current, its address space is not mapped
1684        // so access must go through the VMO.
1685        self.mm()?.syscall_zero(addr, length)
1686    }
1687}
1688
1689impl TaskMemoryAccessor for Task {
1690    fn maximum_valid_address(&self) -> Option<UserAddress> {
1691        self.mm().map(|mm| mm.maximum_valid_user_address).ok()
1692    }
1693
1694    fn ensure_buffers_mapped_in_user_vmar(
1695        &self,
1696        _buffers: &[UserBuffer],
1697        _access: MappingAccess,
1698    ) -> Result<(), Errno> {
1699        // Using `Task` rather than `CurrentTask` indicates that the target address space is not
1700        // mapped in the current thread, so buffers cannot be mapped for direct user-VMAR access.
1701        // Returning `ENOTSUP` lets callers of `peek_each_segment` (like `with_iovec_segments`)
1702        // fall back to `InputBuffer` / `OutputBuffer` read/write methods.
1703        error!(ENOTSUP)
1704    }
1705}
1706
1707impl fmt::Debug for Task {
1708    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1709        write!(f, "{}:{}[{}]", self.pid, self.tid, *self.persistent_info.command.lock())
1710    }
1711}
1712
1713impl cmp::PartialEq for Task {
1714    fn eq(&self, other: &Self) -> bool {
1715        let ptr: *const Task = self;
1716        let other_ptr: *const Task = other;
1717        ptr == other_ptr
1718    }
1719}
1720
1721impl cmp::Eq for Task {}
1722
1723#[cfg(test)]
1724mod test {
1725    use super::*;
1726    use crate::mm::PAGE_SIZE;
1727    use crate::security;
1728    use crate::testing::*;
1729    use starnix_uapi::auth::{CAP_SYS_ADMIN, Capabilities};
1730    use starnix_uapi::resource_limits::Resource;
1731    use starnix_uapi::signals::{SIGCHLD, SIGUSR1};
1732    use starnix_uapi::{CLONE_SIGHAND, CLONE_THREAD, CLONE_VM, rlimit};
1733
1734    #[::fuchsia::test]
1735    async fn test_tid_allocation() {
1736        spawn_kernel_and_run(async |current_task| {
1737            let kernel = current_task.kernel();
1738            assert_eq!(current_task.get_tid(), 1);
1739            let another_current = create_task(&kernel, "another-task");
1740            let another_tid = another_current.get_tid();
1741            assert!(another_tid >= 2);
1742
1743            let pids = &kernel.pids;
1744            assert_eq!(pids.get(1).unwrap().get_task().unwrap().get_tid(), 1);
1745            assert_eq!(pids.get(another_tid).unwrap().get_task().unwrap().get_tid(), another_tid);
1746        })
1747        .await;
1748    }
1749
1750    #[::fuchsia::test]
1751    async fn test_clone_pid_and_parent_pid() {
1752        spawn_kernel_and_run(async |current_task| {
1753            let thread = current_task.clone_task_for_test(
1754                (CLONE_THREAD | CLONE_VM | CLONE_SIGHAND) as u64,
1755                Some(SIGCHLD),
1756            );
1757            assert_eq!(current_task.get_pid(), thread.get_pid());
1758            assert_ne!(current_task.get_tid(), thread.get_tid());
1759            assert_eq!(current_task.pid, thread.thread_group().leader);
1760
1761            let child_task = current_task.clone_task_for_test(0, Some(SIGCHLD));
1762            assert_ne!(current_task.get_pid(), child_task.get_pid());
1763            assert_ne!(current_task.get_tid(), child_task.get_tid());
1764            assert_eq!(current_task.get_pid(), child_task.thread_group().read().get_ppid());
1765        })
1766        .await;
1767    }
1768
1769    #[::fuchsia::test]
1770    async fn test_root_capabilities() {
1771        spawn_kernel_and_run(async |current_task| {
1772            assert!(security::is_task_capable_noaudit(current_task, CAP_SYS_ADMIN));
1773            assert_eq!(current_task.real_creds().cap_inheritable, Capabilities::empty());
1774
1775            current_task.set_creds(Credentials::with_ids(1, 1));
1776            assert!(!security::is_task_capable_noaudit(current_task, CAP_SYS_ADMIN));
1777        })
1778        .await;
1779    }
1780
1781    #[::fuchsia::test]
1782    async fn test_is_spawned() {
1783        spawn_kernel_and_run(async |current_task| {
1784            // The init task should be marked as spawned, because it is executing.
1785            assert!(current_task.is_spawned());
1786
1787            // A cloned task should not be marked as spawned, because it has not yet been executed.
1788            let child = current_task
1789                .clone_task(
1790                    0,
1791                    Some(SIGCHLD),
1792                    UserRef::default(),
1793                    UserRef::default(),
1794                    UserRef::default(),
1795                )
1796                .expect("failed to create task in test");
1797            assert!(!child.is_spawned());
1798            child.release(());
1799
1800            // A cloned task for a test should be marked as spawned, because we intentionally avoid
1801            // spawning threads for test tasks but want them to behave as normal tasks.
1802            let test_child = current_task.clone_task_for_test(0, Some(SIGCHLD));
1803            assert!(test_child.is_spawned());
1804        })
1805        .await;
1806    }
1807
1808    #[::fuchsia::test]
1809    async fn test_clone_rlimit() {
1810        spawn_kernel_and_run(async |current_task| {
1811            let prev_fsize = current_task.thread_group().get_rlimit(Resource::FSIZE);
1812            assert_ne!(prev_fsize, 10);
1813            current_task
1814                .thread_group()
1815                .limits
1816                .lock()
1817                .set(Resource::FSIZE, rlimit { rlim_cur: 10, rlim_max: 100 });
1818            let current_fsize = current_task.thread_group().get_rlimit(Resource::FSIZE);
1819            assert_eq!(current_fsize, 10);
1820
1821            let child_task = current_task.clone_task_for_test(0, Some(SIGCHLD));
1822            let child_fsize = child_task.thread_group().get_rlimit(Resource::FSIZE);
1823            assert_eq!(child_fsize, 10)
1824        })
1825        .await;
1826    }
1827
1828    #[::fuchsia::test]
1829    async fn test_set_command_name_syncs_scheduler_role() {
1830        use crate::task::{RoleOverrides, SchedulerManager};
1831
1832        let mut builder = RoleOverrides::new();
1833        builder.add("renamed-thread", "renamed-thread", None, "test-role");
1834        let overrides = builder.build().unwrap();
1835
1836        let scheduler_manager = SchedulerManager::new_for_tests(None, overrides);
1837
1838        spawn_kernel_with_scheduler_and_run_sync(scheduler_manager, |current_task| {
1839            // Set did_exec = true so custom role overrides are applied.
1840            current_task.thread_group().write().did_exec = true;
1841
1842            let scheduler = &current_task.thread_group().kernel.scheduler;
1843
1844            // Before rename, check task's role name.
1845            let initial_state = current_task.scheduler_state.lock().clone();
1846            let initial_role = scheduler.role_name(current_task, &initial_state).unwrap();
1847            assert_ne!(initial_role, "test-role");
1848
1849            // Rename the task's thread to renamed-thread.
1850            current_task
1851                .set_command_name(starnix_task_command::TaskCommand::new(b"renamed-thread"));
1852
1853            let renamed_state = current_task.scheduler_state.lock().clone();
1854            let renamed_role = scheduler.role_name(current_task, &renamed_state).unwrap();
1855            assert_eq!(renamed_role, "test-role");
1856        })
1857        .await;
1858    }
1859
1860    #[::fuchsia::test]
1861    async fn test_set_command_name_on_leader_syncs_sibling_scheduler_roles() {
1862        use crate::task::{RoleOverrides, SchedulerManager};
1863        use fidl_fuchsia_scheduler::{
1864            RoleManagerMarker, RoleManagerRequest, RoleManagerSetRoleResponse,
1865        };
1866        use futures::StreamExt as _;
1867        use starnix_sync::Mutex;
1868
1869        let (role_manager, server_end) = fidl::endpoints::create_sync_proxy::<RoleManagerMarker>();
1870        let committed_roles = Arc::new(Mutex::new(Vec::<String>::new()));
1871        let committed_roles_server = committed_roles.clone();
1872        std::thread::spawn(move || {
1873            let mut executor = fuchsia_async::LocalExecutor::default();
1874            executor.run_singlethreaded(async move {
1875                let mut stream = server_end.into_stream();
1876                while let Some(Ok(request)) = stream.next().await {
1877                    match request {
1878                        RoleManagerRequest::GetProfileForRole { responder, .. } => {
1879                            let _ = responder.send(Err(zx::Status::NOT_SUPPORTED.into_raw()));
1880                        }
1881                        RoleManagerRequest::SetRole { payload, responder } => {
1882                            committed_roles_server.lock().push(payload.role.unwrap().role);
1883                            let _ = responder.send(Ok(RoleManagerSetRoleResponse::default()));
1884                        }
1885                        _ => unreachable!(),
1886                    }
1887                }
1888            });
1889        });
1890
1891        let mut builder = RoleOverrides::new();
1892        builder.add("my-app", "my-app", None, "leader-role");
1893        builder.add("my-app", "RenderThread", None, "render-role");
1894        let overrides = builder.build().unwrap();
1895        let scheduler_manager = SchedulerManager::new_for_tests(Some(role_manager), overrides);
1896
1897        spawn_kernel_with_scheduler_and_run_sync(scheduler_manager, move |current_task| {
1898            let sibling = current_task.clone_task_for_test(
1899                (CLONE_THREAD | CLONE_VM | CLONE_SIGHAND) as u64,
1900                Some(SIGCHLD),
1901            );
1902            assert!(!sibling.is_leader());
1903            let leader_thread = current_task.running_state().thread.get().unwrap().clone();
1904            sibling.running_state().thread.set(leader_thread).unwrap();
1905
1906            // Rename the sibling thread before the leader renames the process. Because the leader's
1907            // command name is still "test-task", the sibling does not match "my-app" yet.
1908            sibling.set_command_name(TaskCommand::new(b"RenderThread"));
1909            assert!(!committed_roles.lock().contains(&"render-role".to_string()));
1910
1911            committed_roles.lock().clear();
1912
1913            // Renaming the thread group leader updates the process name and re-evaluates scheduler
1914            // roles for all sibling threads in the thread group.
1915            current_task.set_command_name(TaskCommand::new(b"my-app"));
1916            let roles = committed_roles.lock().clone();
1917            assert!(roles.contains(&"leader-role".to_string()), "roles: {roles:?}");
1918            assert!(roles.contains(&"render-role".to_string()), "roles: {roles:?}");
1919        })
1920        .await;
1921    }
1922
1923    #[::fuchsia::test]
1924    async fn test_fork_does_not_inherit_custom_role() {
1925        use crate::task::{RoleOverrides, SchedulerManager};
1926
1927        let mut builder = RoleOverrides::new();
1928        builder.add("renamed-thread", "renamed-thread", None, "test-role");
1929        let overrides = builder.build().unwrap();
1930
1931        let scheduler_manager = SchedulerManager::new_for_tests(None, overrides);
1932
1933        spawn_kernel_with_scheduler_and_run_sync(scheduler_manager, |current_task| {
1934            // Fork a child process (which sets did_exec = false on the child's thread group)
1935            let child = current_task.clone_task_for_test(0, None);
1936
1937            let scheduler = &current_task.thread_group().kernel.scheduler;
1938
1939            // Before rename, check child's role name.
1940            let initial_state = child.scheduler_state.lock().clone();
1941            let initial_role = scheduler.role_name(&child, &initial_state).unwrap();
1942            assert_ne!(initial_role, "test-role");
1943
1944            // Rename the child's thread to renamed-thread. Since did_exec is false on the child,
1945            // this should NOT map to "test-role" from the overrides.
1946            child.set_command_name(starnix_task_command::TaskCommand::new(b"renamed-thread"));
1947
1948            let renamed_state = child.scheduler_state.lock().clone();
1949            let renamed_role = scheduler.role_name(&child, &renamed_state).unwrap();
1950            assert_ne!(renamed_role, "test-role");
1951        })
1952        .await;
1953    }
1954
1955    #[::fuchsia::test]
1956    async fn test_set_command_name_only_embeds_argv0_on_leader() {
1957        spawn_kernel_and_run(async |current_task| {
1958            let argv0_bytes = b"/bin/my_long_command_name\0";
1959            let addr = map_memory(current_task, UserAddress::default(), *PAGE_SIZE);
1960            current_task.write_memory(addr, argv0_bytes).expect("write argv0");
1961            {
1962                let mm = current_task.mm().expect("mm");
1963                let mut mm_state = mm.state.write();
1964                mm_state.argv_start = addr;
1965                mm_state.argv_end = (addr + argv0_bytes.len()).expect("argv_end");
1966            }
1967
1968            // Updating the leader task's command name embeds argv[0] when the truncated name is a
1969            // substring of argv[0].
1970            current_task.set_command_name(TaskCommand::new(b"my_long_command"));
1971            let cmd = current_task.command();
1972            assert_eq!(cmd.as_bytes(), b"my_long_command_name");
1973            assert_eq!(cmd.comm_name(), b"my_long_command");
1974
1975            // Updating a non-leader thread's command name does not embed the process-wide argv[0].
1976            let thread = current_task.clone_task_for_test(
1977                (CLONE_THREAD | CLONE_VM | CLONE_SIGHAND) as u64,
1978                Some(SIGCHLD),
1979            );
1980            assert!(!thread.is_leader());
1981            thread.set_command_name(TaskCommand::new(b"my_long_command"));
1982            let cmd = thread.command();
1983            assert_eq!(cmd.as_bytes(), b"my_long_command");
1984            assert_eq!(cmd.comm_name(), b"my_long_command");
1985        })
1986        .await;
1987    }
1988
1989    #[::fuchsia::test]
1990    async fn test_set_scheduler_priority_validates_policy() {
1991        spawn_kernel_and_run(async |current_task| {
1992            let non_realtime = SchedulingPolicy::Normal.realtime_priority_from(0).unwrap();
1993            let realtime_10 = SchedulingPolicy::Fifo.realtime_priority_from(10).unwrap();
1994            let realtime_20 = SchedulingPolicy::Fifo.realtime_priority_from(20).unwrap();
1995
1996            assert!(SchedulingPolicy::Normal.is_valid_priority(non_realtime));
1997            assert!(!SchedulingPolicy::Normal.is_valid_priority(realtime_10));
1998            assert!(SchedulingPolicy::Fifo.is_valid_priority(realtime_10));
1999            assert!(!SchedulingPolicy::Fifo.is_valid_priority(non_realtime));
2000
2001            assert_eq!(current_task.scheduler_state.lock().policy, SchedulingPolicy::Normal);
2002            assert_eq!(current_task.scheduler_state.lock().realtime_priority, non_realtime);
2003
2004            // Passing a non-zero real-time priority while `SchedulingPolicy::Normal` returns
2005            // `EINVAL` without mutating `realtime_priority`.
2006            assert_eq!(current_task.set_scheduler_priority(realtime_10), error!(EINVAL));
2007            assert_eq!(current_task.scheduler_state.lock().realtime_priority, non_realtime);
2008
2009            current_task
2010                .set_scheduler_policy_priority_and_reset_on_fork(
2011                    SchedulingPolicy::Fifo,
2012                    realtime_10,
2013                    false,
2014                )
2015                .expect("set_scheduler_policy_priority_and_reset_on_fork");
2016            assert_eq!(current_task.scheduler_state.lock().policy, SchedulingPolicy::Fifo);
2017            assert_eq!(current_task.scheduler_state.lock().realtime_priority, realtime_10);
2018
2019            current_task.set_scheduler_priority(realtime_20).expect("set_scheduler_priority");
2020            assert_eq!(current_task.scheduler_state.lock().realtime_priority, realtime_20);
2021
2022            // Passing `NON_REAL_TIME` while `SchedulingPolicy::Fifo` returns `EINVAL` without
2023            // mutating `realtime_priority`.
2024            assert_eq!(current_task.set_scheduler_priority(non_realtime), error!(EINVAL));
2025            assert_eq!(current_task.scheduler_state.lock().realtime_priority, realtime_20);
2026
2027            // Setting policy and priority together also validates their combination and rolls back
2028            // on mismatch.
2029            assert_eq!(
2030                current_task.set_scheduler_policy_priority_and_reset_on_fork(
2031                    SchedulingPolicy::Normal,
2032                    realtime_10,
2033                    true,
2034                ),
2035                error!(EINVAL)
2036            );
2037            assert_eq!(current_task.scheduler_state.lock().policy, SchedulingPolicy::Fifo);
2038            assert_eq!(current_task.scheduler_state.lock().realtime_priority, realtime_20);
2039            assert!(!current_task.scheduler_state.lock().reset_on_fork);
2040        })
2041        .await;
2042    }
2043
2044    #[::fuchsia::test]
2045    async fn test_update_scheduler_state_rolls_back_on_commit_error() {
2046        use crate::task::{RoleOverrides, SchedulerManager};
2047        use fidl_fuchsia_scheduler::RoleManagerMarker;
2048
2049        let (role_manager, server_end) = fidl::endpoints::create_sync_proxy::<RoleManagerMarker>();
2050        // Drop the server endpoint so RoleManager FIDL calls fail and `commit_thread_role`
2051        // returns `Err(EINVAL)`.
2052        drop(server_end);
2053
2054        let overrides = RoleOverrides::new().build().unwrap();
2055        let scheduler_manager = SchedulerManager::new_for_tests(Some(role_manager), overrides);
2056
2057        spawn_kernel_with_scheduler_and_run_sync(scheduler_manager, |current_task| {
2058            let initial_state = current_task.scheduler_state.lock().clone();
2059            let realtime_10 = SchedulingPolicy::Fifo.realtime_priority_from(10).unwrap();
2060
2061            assert_eq!(
2062                current_task.set_scheduler_policy_priority_and_reset_on_fork(
2063                    SchedulingPolicy::Fifo,
2064                    realtime_10,
2065                    true,
2066                ),
2067                error!(EINVAL)
2068            );
2069            assert_eq!(*current_task.scheduler_state.lock(), initial_state);
2070
2071            let nicer = NormalPriority::from_setpriority_syscall(-5);
2072            assert_eq!(current_task.set_scheduler_nice(nicer), error!(EINVAL));
2073            assert_eq!(*current_task.scheduler_state.lock(), initial_state);
2074        })
2075        .await;
2076    }
2077
2078    #[::fuchsia::test]
2079    async fn test_copy_state_from_preserves_dirty_snapshot() {
2080        spawn_kernel_and_run(async |current_task| {
2081            let mut state = current_task.write();
2082            assert!(state.captured_thread_state.is_none());
2083
2084            state.copy_state_from(current_task);
2085            assert!(state.captured_thread_state.is_some());
2086            assert!(!state.captured_thread_state.as_ref().unwrap().dirty);
2087
2088            // Mark the captured state as dirty to simulate a tracer poking a register.
2089            state.captured_thread_state.as_mut().unwrap().dirty = true;
2090
2091            // Consecutive calls to copy_state_from must preserve the existing snapshot.
2092            state.copy_state_from(current_task);
2093            assert!(state.captured_thread_state.as_ref().unwrap().dirty);
2094        })
2095        .await;
2096    }
2097
2098    #[::fuchsia::test]
2099    async fn test_temporary_signal_mask_without_pending_signals() {
2100        spawn_kernel_and_run(async |current_task| {
2101            assert!(!current_task.flags().contains(TaskFlags::TEMPORARY_SIGNAL_MASK));
2102            assert!(!current_task.flags().contains(TaskFlags::SIGNALS_AVAILABLE));
2103
2104            current_task.write().set_temporary_signal_mask(SigSet::from(SIGUSR1));
2105            assert!(current_task.flags().contains(TaskFlags::TEMPORARY_SIGNAL_MASK));
2106            assert!(!current_task.flags().contains(TaskFlags::SIGNALS_AVAILABLE));
2107
2108            current_task.write().restore_signal_mask();
2109            assert!(!current_task.flags().contains(TaskFlags::TEMPORARY_SIGNAL_MASK));
2110            assert!(!current_task.flags().contains(TaskFlags::SIGNALS_AVAILABLE));
2111        })
2112        .await;
2113    }
2114
2115    #[::fuchsia::test]
2116    async fn test_temporary_signal_mask_masks_pending_signal() {
2117        spawn_kernel_and_run(async |current_task| {
2118            current_task.write().enqueue_signal(SignalInfo::kernel(SIGUSR1));
2119            assert!(current_task.flags().contains(TaskFlags::SIGNALS_AVAILABLE));
2120            assert!(!current_task.flags().contains(TaskFlags::TEMPORARY_SIGNAL_MASK));
2121
2122            current_task.write().set_temporary_signal_mask(SigSet::from(SIGUSR1));
2123            assert!(current_task.flags().contains(TaskFlags::TEMPORARY_SIGNAL_MASK));
2124            assert!(!current_task.flags().contains(TaskFlags::SIGNALS_AVAILABLE));
2125
2126            current_task.write().restore_signal_mask();
2127            assert!(!current_task.flags().contains(TaskFlags::TEMPORARY_SIGNAL_MASK));
2128            assert!(current_task.flags().contains(TaskFlags::SIGNALS_AVAILABLE));
2129        })
2130        .await;
2131    }
2132
2133    #[::fuchsia::test]
2134    async fn test_temporary_signal_mask_unmasks_pending_signal() {
2135        spawn_kernel_and_run(async |current_task| {
2136            current_task.write().set_signal_mask(SigSet::from(SIGUSR1));
2137            current_task.write().enqueue_signal(SignalInfo::kernel(SIGUSR1));
2138            assert!(!current_task.flags().contains(TaskFlags::SIGNALS_AVAILABLE));
2139            assert!(!current_task.flags().contains(TaskFlags::TEMPORARY_SIGNAL_MASK));
2140
2141            current_task.write().set_temporary_signal_mask(SigSet::default());
2142            assert!(current_task.flags().contains(TaskFlags::TEMPORARY_SIGNAL_MASK));
2143            assert!(current_task.flags().contains(TaskFlags::SIGNALS_AVAILABLE));
2144
2145            current_task.write().restore_signal_mask();
2146            assert!(!current_task.flags().contains(TaskFlags::TEMPORARY_SIGNAL_MASK));
2147            assert!(!current_task.flags().contains(TaskFlags::SIGNALS_AVAILABLE));
2148        })
2149        .await;
2150    }
2151}