1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
//! This crate contains the basic [`Task`] structure, which holds contextual execution states
//! needed to support safe multithreading.
//! 
//! To create new `Task`s, use the [`spawn`](../spawn/index.html) crate.
//! For more advanced task-related types, see the [`task`](../task/index.html) crate.

#![no_std]
#![feature(panic_info_message)]
#![feature(negative_impls)]
#![allow(clippy::type_complexity)]

extern crate alloc;

use core::{
    any::Any,
    fmt,
    hash::{Hash, Hasher},
    ops::Deref,
    panic::PanicInfo,
    sync::atomic::{AtomicBool, AtomicUsize, Ordering},
    task::Waker,
};
use alloc::{
    boxed::Box,
    format,
    string::String,
    sync::Arc,
};
use cpu::{CpuId, OptionalCpuId};
use crossbeam_utils::atomic::AtomicCell;
use sync_irq::IrqSafeMutex;
use log::{warn, trace};
use memory::MmiRef;
use stack::Stack;
use kernel_config::memory::KERNEL_STACK_SIZE_IN_PAGES;
use mod_mgmt::{AppCrateRef, CrateNamespace, TlsDataImage};
use environment::Environment;
use spin::Mutex;

/// The function signature of the callback that will be invoked when a `Task`
/// panics or otherwise fails, e.g., a machine exception occurs.
pub type KillHandler = Box<dyn Fn(&KillReason) + Send>;

/// Just like `core::panic::PanicInfo`, but with owned String types instead of &str references.
#[derive(Debug, Default)]
pub struct PanicInfoOwned {
    pub payload:  Option<Box<dyn Any + Send>>,
    pub msg:      String,
    pub file:     String,
    pub line:     u32, 
    pub column:   u32,
}
impl fmt::Display for PanicInfoOwned {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{}:{}:{} -- {:?}", self.file, self.line, self.column, self.msg)
    }
}
impl<'p> From<&PanicInfo<'p>> for PanicInfoOwned {
    fn from(info: &PanicInfo) -> PanicInfoOwned {
        let msg = info.message()
            .map(|m| format!("{m}"))
            .unwrap_or_default();
        let (file, line, column) = if let Some(loc) = info.location() {
            (String::from(loc.file()), loc.line(), loc.column())
        } else {
            (String::new(), 0, 0)
        };

        PanicInfoOwned { payload: None, msg, file, line, column }
    }
}
impl PanicInfoOwned {
    /// Constructs a new `PanicInfoOwned` object containing only the given `payload`
    /// without any location or message info.
    /// 
    /// Useful for forwarding panic payloads through a catch and resume unwinding sequence.
    pub fn from_payload(payload: Box<dyn Any + Send>) -> PanicInfoOwned {
        PanicInfoOwned {
            payload: Some(payload),
            ..Default::default()
        }
    }
}


/// The list of possible reasons that a given `Task` was killed prematurely.
#[derive(Debug)]
pub enum KillReason {
    /// The user or another task requested that this `Task` be killed. 
    /// For example, the user pressed `Ctrl + C` on the shell window that started a `Task`.
    Requested,
    /// A Rust-level panic occurred while running this `Task`.
    Panic(PanicInfoOwned),
    /// A non-language-level problem, such as a Page Fault or some other machine exception.
    /// The number of the exception is included, e.g., 15 (0xE) for a Page Fault.
    Exception(u8),
}
impl fmt::Display for KillReason {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self {
            Self::Requested         => write!(f, "Requested"),
            Self::Panic(panic_info) => write!(f, "Panicked at {panic_info}"),
            Self::Exception(num)    => write!(f, "Exception {num:#X}({num})"),
        }
    }
}


/// The two ways a `Task` can exit, including possible return values and conditions.
#[derive(Debug)]
pub enum ExitValue {
    /// The `Task` ran to completion
    /// and returned the enclosed [`Any`] value from its entry point function.
    ///
    /// The caller of this task's entry point function should know which concrete type
    /// this Task returned, and is thus able to downcast it appropriately.
    Completed(Box<dyn Any + Send>),
    /// The `Task` did NOT run to completion but was instead killed for the enclosed reason.
    Killed(KillReason),
}


/// The set of possible runstates that a `Task` can be in.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum RunState {
    /// This task is in the midst of being initialized/spawned.
    Initing,
    /// This task is able to be scheduled in, but not necessarily currently running.
    /// To check whether it is currently running, use [`Task::is_running()`].
    Runnable,
    /// This task is blocked on something and is *not* able to be scheduled in.
    Blocked,
    /// This `Task` has exited and can no longer be run.
    /// This covers both the case when a task ran to completion or was killed;
    /// see [`ExitValue`] for more details.
    Exited,
    /// This `Task` had already exited, and now its [`ExitValue`] has been taken
    /// (either by another task that `join`ed it, or by the system).
    /// Because a task's exit value can only be taken once, a repaed task
    /// is useless and will be cleaned up and removed from the system.
    Reaped,
}


#[cfg(simd_personality)]
/// The supported levels of SIMD extensions that a `Task` can use.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum SimdExt {
    /// AVX (and below) instructions and registers will be used.
    AVX,
    /// SSE instructions and registers will be used.
    SSE,
    /// The regular case: no SIMD instructions or registers of any kind will be used.
    None,
}

/// A struct holding data items needed to restart a `Task`.
pub struct RestartInfo {
    /// Stores the argument of the task for restartable tasks
    pub argument: Box<dyn Any + Send>,
    /// Stores the function of the task for restartable tasks
    pub func: Box<dyn Any + Send>,
}


/// The parts of a `Task` that may be modified after its creation.
///
/// This includes only the parts that cannot be modified atomically.
/// As such, they are protected by a lock in the containing `Task` struct.
///
/// In general, other crates cannot obtain a mutable reference to a Task (`&mut Task`),
/// which means they cannot access this struct's contents directly at all 
/// (except through the specific get/set methods exposed by `Task`).
///
/// Therefore, it is safe to expose all members of this struct as public, 
/// though not strictly necessary. 
/// Currently, we only publicize the fields here that need to be modified externally,
/// primarily by the `spawn` and `task` crates for creating and running new tasks. 
pub struct TaskInner {
    /// the saved stack pointer value, used for task switching.
    pub saved_sp: usize,
    /// The kernel stack, which all `Task`s must have in order to execute.
    pub kstack: Stack,
    /// Whether or not this task is pinned to a certain CPU.
    /// The idle tasks are always pinned to their respective CPU.
    pub pinned_cpu: Option<CpuId>,
    /// The function that will be called when this `Task` panics or fails due to a machine exception.
    /// It will be invoked before the task is cleaned up via stack unwinding.
    /// This is similar to Rust's built-in panic hook, but is also called upon a machine exception, not just a panic.
    pub kill_handler: Option<KillHandler>,
    /// The environment variables for this task, which are shared among child and parent tasks by default.
    env: Arc<Mutex<Environment>>,
    /// Stores the restartable information of the task. 
    /// `Some(RestartInfo)` indicates that the task is restartable.
    pub restart_info: Option<RestartInfo>,
    /// The waker that is awoken when this task completes.
    pub waker: Option<Waker>,
}


/// A structure that contains contextual information for a thread of execution. 
///
/// # Implementation note
/// Only fields that do not permit interior mutability can safely be exposed as public
/// because we allow foreign crates to directly access task struct fields.
pub struct Task {
    /// The mutable parts of a `Task` struct that can be modified after task creation,
    /// excluding private items that can be modified atomically.
    ///
    /// We use this inner structure to reduce contention when accessing task struct fields,
    /// because the other fields aside from this one are primarily read, not written.
    ///
    /// This must not be public because it permits interior mutability of key task states.
    inner: IrqSafeMutex<TaskInner>,

    /// The unique identifier of this Task.
    pub id: usize,
    /// The simple name of this Task.
    pub name: String,
    /// Which cpu core this Task is currently running on;
    /// `None` if not currently running.
    /// We use `OptionalCpuId` instead of `Option<CpuId>` to ensure that 
    /// this field is accessed using lock-free native atomic instructions.
    ///
    /// This is not public because it permits interior mutability.
    running_on_cpu: AtomicCell<OptionalCpuId>,
    /// The runnability of this task, i.e., whether it's eligible to be scheduled in.
    ///
    /// This is not public because it permits interior mutability.
    runstate: AtomicCell<RunState>,
    /// Whether the task is suspended.
    ///
    /// This is only triggered by a Ctrl + Z in the terminal.
    ///
    /// This is not public because it permits interior mutability.
    suspended: AtomicBool,
    /// Memory management details: page tables, mappings, allocators, etc.
    /// This is shared among all other tasks in the same address space.
    pub mmi: MmiRef, 
    /// Whether this Task is an idle task, the task that runs by default when no other task is running.
    /// There exists one idle task per core, so this is `false` for most tasks.
    pub is_an_idle_task: bool,
    /// For application `Task`s, this is effectively a reference to the [`mod_mgmt::LoadedCrate`]
    /// that contains the entry function for this `Task`.
    pub app_crate: Option<Arc<AppCrateRef>>,
    /// This `Task` is linked into and runs within the context of this [`CrateNamespace`].
    pub namespace: Arc<CrateNamespace>,
    /// The Thread-Local Storage (TLS) area for this task.
    ///
    /// Upon each task switch, we must set the value of the TLS base register 
    /// (e.g., FsBase on x86_64) to the value of this TLS area's self pointer.
    tls_area: TlsDataImage,
    
    #[cfg(simd_personality)]
    /// Whether this Task is SIMD enabled and what level of SIMD extensions it uses.
    pub simd: SimdExt,
}

// Ensure that atomic fields in the `Tast` struct are actually lock-free atomics.
const _: () = assert!(AtomicCell::<OptionalCpuId>::is_lock_free());
const _: () = assert!(AtomicCell::<RunState>::is_lock_free());

impl fmt::Debug for Task {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut ds = f.debug_struct("Task");
        ds.field("name", &self.name)
            .field("id", &self.id)
            .field("running_on", &self.running_on_cpu())
            .field("runstate", &self.runstate());
        if let Some(inner) = self.inner.try_lock() {
            ds.field("pinned", &inner.pinned_cpu);
        } else {
            ds.field("pinned", &"<Locked>");
        }
        ds.finish()
    }
}
impl fmt::Display for Task {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}{{{}}}", self.name, self.id)
    }
}
impl Hash for Task {
    fn hash<H: Hasher>(&self, h: &mut H) {
        self.id.hash(h);
    }
}

impl Task {
    /// Creates a new `Task` and initializes it to be non-`Runnable`.
    ///
    /// # Arguments
    /// * `stack`: the optional `Stack` for this new `Task` to use.
    ///    * If `None`, a stack of the default size will be allocated and used.
    /// * `inherited states`: the set of states used to initialize this new `Task`.
    ///    * Typically, a caller will pass in [`InheritedStates::FromTask`] with the
    ///      enclosed task being a reference to the current task.
    ///      In this way, the enclosed task acts as a sort of "parent" template
    ///      for this new `Task`.
    ///      Theseus doesn't have a true parent-child relationship between tasks;
    ///      the new `Task` merely inherits select states from it.
    ///
    /// # Usage Notes
    /// * This does not run the task, schedule it in, or switch to it.
    /// * If you want to create a new task, you should use the `spawn` crate instead.
    pub fn new(
        stack: Option<Stack>,
        states_to_inherit: InheritedStates,
    ) -> Result<Task, &'static str> {
        /// The counter of task IDs. We start at `1` such that `0` can be used 
        /// as a task ID that indicates the absence of a task, e.g., in sync primitives. 
        static TASKID_COUNTER: AtomicUsize = AtomicUsize::new(1);

        let (mmi, namespace, env, app_crate) = states_to_inherit.into_tuple();
        let kstack = stack
            .or_else(|| stack::alloc_stack(KERNEL_STACK_SIZE_IN_PAGES, &mut mmi.lock().page_table))
            .ok_or("couldn't allocate stack for new Task!")?;

        // TODO: re-use old task IDs again, instead of simply blindly counting up.
        let task_id = TASKID_COUNTER.fetch_add(1, Ordering::Relaxed);

        // Obtain a new copied instance of the TLS data image for this task.
        let tls_area = namespace.get_tls_initializer_data();

        Ok(Task {
            inner: IrqSafeMutex::new(TaskInner {
                saved_sp: 0,
                kstack,
                pinned_cpu: None,
                kill_handler: None,
                env,
                restart_info: None,
                waker: None,
            }),
            id: task_id,
            name: format!("task_{task_id}"),
            running_on_cpu: AtomicCell::new(None.into()),
            runstate: AtomicCell::new(RunState::Initing),
            suspended: AtomicBool::new(false),
            mmi,
            is_an_idle_task: false,
            app_crate,
            namespace,
            tls_area,

            #[cfg(simd_personality)]
            simd: SimdExt::None,
        })
    }

    /// Sets the `Environment` of this Task.
    ///
    /// # Locking / Deadlock
    /// Obtains the lock on this `Task`'s inner state in order to mutate it.
    pub fn set_env(&self, new_env: Arc<Mutex<Environment>>) {
        self.inner.lock().env = new_env;
    }

    /// Gets a reference to this task's `Environment`.
    ///
    /// # Locking / Deadlock
    /// Obtains the lock on this `Task`'s inner state in order to access it.
    pub fn get_env(&self) -> Arc<Mutex<Environment>> {
        Arc::clone(&self.inner.lock().env)
    }

    /// Returns `true` if this `Task` is currently running.
    pub fn is_running(&self) -> bool {
        self.running_on_cpu().is_some()
    }

    /// Returns the ID of the CPU this `Task` is currently running on.
    pub fn running_on_cpu(&self) -> Option<CpuId> {
        self.running_on_cpu.load().into()
    }

    /// Returns the ID of the CPU this `Task` is pinned on,
    /// or `None` if it is not pinned.
    pub fn pinned_cpu(&self) -> Option<CpuId> {
        self.inner.lock().pinned_cpu
    }

    /// Returns the current [`RunState`] of this `Task`.
    pub fn runstate(&self) -> RunState {
        self.runstate.load()
    }

    /// Returns whether this `Task` is runnable, i.e., able to be scheduled in.
    ///
    /// For this to return `true`, this `Task`'s runstate must be [`Runnable`]
    /// and it must not be [suspended].
    ///
    /// # Note
    /// This does *NOT* mean that this `Task` is actually currently [running],
    /// just that it is *able* to be run.
    ///
    /// [`Runnable`]: RunState::Runnable
    /// [suspended]: Task::is_suspended
    /// [running]: Task::is_running
    pub fn is_runnable(&self) -> bool {
        self.runstate() == RunState::Runnable && !self.is_suspended()
    }

    /// Returns the namespace that this `Task` is loaded/linked into and runs within.
    pub fn get_namespace(&self) -> &Arc<CrateNamespace> {
        &self.namespace
    }

    /// Exposes read-only access to this `Task`'s [`Stack`] by invoking
    /// the given `func` with a reference to its kernel stack.
    ///
    /// # Locking / Deadlock
    /// Obtains the lock on this `Task`'s inner state for the duration of `func`
    /// in order to access its stack.
    /// The given `func` **must not** attempt to obtain that same inner lock.
    pub fn with_kstack<R, F>(&self, func: F) -> R 
        where F: FnOnce(&Stack) -> R
    {
        func(&self.inner.lock().kstack)
    }

    /// Returns a mutable reference to this `Task`'s inner state. 
    ///
    /// # Note about mutability
    /// This function requires the caller to have a mutable reference to this `Task`
    /// in order to protect the inner state from foreign crates accessing it
    /// through a `TaskRef` auto-dereferencing into a `Task`.
    /// This is because you can only obtain a mutable reference to a `Task`
    /// *before* you enclose it in a `TaskRef` wrapper type.
    ///
    /// Because this function requires a mutable reference to this `Task`,
    /// no locks must be obtained. 
    pub fn inner_mut(&mut self) -> &mut TaskInner {
        self.inner.get_mut()
    }

    /// Invokes `func` with immutable access to this `Task`'s [`RestartInfo`].
    ///
    /// # Locking / Deadlock
    /// Obtains the lock on this `Task`'s inner state for the duration of `func`
    /// in order to access its stack.
    /// The given `func` **must not** attempt to obtain that same inner lock.
    pub fn with_restart_info<R, F>(&self, func: F) -> R 
        where F: FnOnce(Option<&RestartInfo>) -> R
    {
        func(self.inner.lock().restart_info.as_ref())
    }

    /// Returns `true` if this `Task` has been exited, i.e.,
    /// if its `RunState` is either `Exited` or `Reaped`.
    pub fn has_exited(&self) -> bool {
        matches!(self.runstate(), RunState::Exited | RunState::Reaped)
    }

    /// Returns `true` if this is an application `Task`.
    ///
    /// This will also return `true` if this task was spawned by an application task,
    /// since a task inherits the "application crate" field from its "parent" that spawned it.
    pub fn is_application(&self) -> bool {
        self.app_crate.is_some()
    }

    /// Returns `true` if this `Task` was spawned as a restartable task.
    ///
    /// # Locking / Deadlock
    /// Obtains the lock on this `Task`'s inner state in order to access it.
    pub fn is_restartable(&self) -> bool {
        self.inner.lock().restart_info.is_some()
    }

    /// Blocks this `Task` by setting its runstate to [`RunState::Blocked`].
    ///
    /// Returns the previous runstate on success, and the current runstate on error.
    /// This will only succeed if the task is runnable or already blocked.
    pub fn block(&self) -> Result<RunState, RunState> {
        use RunState::{Blocked, Runnable};

        if self.runstate.compare_exchange(Runnable, Blocked).is_ok() {
            Ok(Runnable)
        } else if self.runstate.compare_exchange(Blocked, Blocked).is_ok() {
            // warn!("Blocked an already blocked task: {:?}", self);
            Ok(Blocked)
        } else {
            Err(self.runstate.load())
        }
    }

    /// Blocks this `Task` if it is a newly-spawned task currently being initialized.
    ///
    /// This is a special case only to be used when spawning a new task that
    /// should not be immediately scheduled in; it will fail for all other cases.
    ///
    /// Returns the previous runstate (i.e. `RunState::Initing`) on success,
    /// or the current runstate on error.
    pub fn block_initing_task(&self) -> Result<RunState, RunState> {
        if self.runstate.compare_exchange(RunState::Initing, RunState::Blocked).is_ok() {
            Ok(RunState::Initing)
        } else {
            Err(self.runstate.load())
        }
    }

    /// Unblocks this `Task` by setting its runstate to [`RunState::Runnable`].
    ///
    /// Returns the previous runstate on success, and the current runstate on
    /// error. Will only succed if the task is blocked or already runnable.
    pub fn unblock(&self) -> Result<RunState, RunState> {
        use RunState::{Blocked, Runnable};

        if self.runstate.compare_exchange(Blocked, Runnable).is_ok() {
            Ok(Blocked)
        } else if self.runstate.compare_exchange(Runnable, Runnable).is_ok() {
            // warn!("Unblocked an already runnable task: {:?}", self);
            Ok(Runnable)
        } else {
            Err(self.runstate.load())
        }
    }
    
    /// Makes this `Task` `Runnable` if it is a newly-spawned and fully initialized task.
    ///
    /// This is a special case only to be used when spawning a new task that
    /// is ready to be scheduled in; it will fail for all other cases.
    ///
    /// Returns the previous runstate (i.e. `RunState::Initing`) on success, and
    /// the current runstate on error.
    pub fn make_inited_task_runnable(&self) -> Result<RunState, RunState> {
        if self.runstate.compare_exchange(RunState::Initing, RunState::Runnable).is_ok() {
            Ok(RunState::Initing)
        } else {
            Err(self.runstate.load())
        }
    }

    /// Suspends this `Task`.
    pub fn suspend(&self) {
        self.suspended.store(true, Ordering::Release);
    }

    /// Unsuspends this `Task`.
    pub fn unsuspend(&self) {
        self.suspended.store(false, Ordering::Release);
    }

    /// Returns `true` if this `Task` is suspended.
    ///
    /// Note that a task being suspended is independent from its [`RunState`].
    pub fn is_suspended(&self) -> bool {
        self.suspended.load(Ordering::Acquire)
    }
}

impl Drop for Task {
    fn drop(&mut self) {
        #[cfg(not(rq_eval))]
        trace!("[CPU {}] Task::drop(): {}", cpu::current_cpu(), self);

        // We must consume/drop the Task's kill handler BEFORE a Task can possibly be dropped.
        // This is because if an application task sets a kill handler that is a closure/function in the text section of the app crate itself,
        // then after the app crate is released, the kill handler will be dropped AFTER the app crate has been freed.
        // When it tries to drop the task's kill handler, a page fault will occur because the text section of the app crate has been unmapped.
        if let Some(kill_handler) = self.inner.lock().kill_handler.take() {
            warn!("While dropping task {:?}, its kill handler callback was still present. Removing it now.", self);
            drop(kill_handler);
        }
    }
}


/// A type wrapper that exposes public access to all inner fields of a task.
///
/// This is intended for use by the `task` crate, specifically within a `TaskRef`.
/// This can only be obtained by consuming a fully-initialized [`Task`],
/// which makes it completely safe to be public because there is nowhere else
/// besides within the `TaskRef::create()` constructor that one can obtain access
/// to an owned `Task` value that is already registered/spawned (actually usable).
///
/// If another crate instantiates a bare `Task` (not a `Taskref`) and then converts
/// it into this `ExposedTask` type, then there's nothing they can do with that task
/// because it cannot become a spawnable/schedulable/runnable task until it is
/// passed into `TaskRef::create()`, so that'd be completely harmless.
#[doc(hidden)]
pub struct ExposedTask {
    pub task: Task,
}
impl From<Task> for ExposedTask {
    fn from(task: Task) -> Self {
        Self { task }
    }
}
impl Deref for ExposedTask {
    type Target = Task;
    fn deref(&self) -> &Self::Target {
        &self.task
    }
}
// Here we simply expose accessors for all private fields of `Task`.
impl ExposedTask {
    #[inline(always)]
    pub fn inner(&self) -> &IrqSafeMutex<TaskInner> {
        &self.inner
    }
    #[inline(always)]
    pub fn tls_area(&self) -> &TlsDataImage {
        &self.tls_area
    }
    #[inline(always)]
    pub fn running_on_cpu(&self) -> &AtomicCell<OptionalCpuId> {
        &self.running_on_cpu
    }
    #[inline(always)]
    pub fn runstate(&self) -> &AtomicCell<RunState> {
        &self.runstate
    }
}


/// The states used to initialize a new `Task` when creating it; see [`Task::new()`].
///
/// Currently, this includes the states given in the [`InheritedStates::Custom`] variant.
pub enum InheritedStates<'t> {
    /// The new `Task` will inherit its states from the enclosed `Task`.
    FromTask(&'t Task),
    /// The new `Task` will be initialized with the enclosed custom states.
    Custom {
        mmi: MmiRef,
        namespace: Arc<CrateNamespace>,
        env: Arc<Mutex<Environment>>,
        app_crate: Option<Arc<AppCrateRef>>,
    }
}
impl<'t> From<&'t Task> for InheritedStates<'t> {
    fn from(task: &'t Task) -> Self {
        Self::FromTask(task)
    }
}
impl<'t> InheritedStates<'t> {
    fn into_tuple(self) -> (
        MmiRef,
        Arc<CrateNamespace>,
        Arc<Mutex<Environment>>,
        Option<Arc<AppCrateRef>>,
    ) {
        match self {
            Self::FromTask(task) => (
                task.mmi.clone(),
                task.namespace.clone(),
                task.inner.lock().env.clone(),
                task.app_crate.clone(),
            ),
            Self::Custom { mmi, namespace, env, app_crate } => (
                mmi,
                namespace,
                env,
                app_crate,
            )
        }
    }
}