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