Skip to content

Commit

Permalink
Improve task docs and book chapter; fix typos/links (theseus-os#950)
Browse files Browse the repository at this point in the history
Co-authored-by: Kevin Boos <[email protected]> 21f653f
  • Loading branch information
Ramla-I committed May 31, 2023
1 parent ac3c9a0 commit eeea98f
Show file tree
Hide file tree
Showing 848 changed files with 11,110 additions and 8,099 deletions.
51 changes: 35 additions & 16 deletions book/print.html
Original file line number Diff line number Diff line change
Expand Up @@ -1007,7 +1007,7 @@ <h3 id="how-to-use-mappedpages"><a class="header" href="#how-to-use-mappedpages"
<li>The same is true for functions and executable memory regions.</li>
</ul>
</li>
<li>These methods all return <em>references</em> to the requested type or slice, in which the lifetime of the returned reference (<code>&amp;T</code>, `in order to prevent use-after-free errors.
<li>These methods all return <em>references</em> to the requested type or slice, in which the lifetime of the returned reference (<code>&amp;T</code>) is dependent upon the lifetime of the <code>MappedPages</code> object, in order to statically prevent use-after-free errors.
<ul>
<li>One cannot obtain an owned instance of a type <code>T</code> from an underlying <code>MappedPages</code> memory region, because that would remove the semantic connection between the type <code>T</code> and the existence of the underlying memory mapping.</li>
</ul>
Expand Down Expand Up @@ -1046,7 +1046,7 @@ <h2 id="deallocating-frames"><a class="header" href="#deallocating-frames">Deall
</li>
<li>Using strong type safety, the <a href="https://theseus-os.github.io/Theseus/doc/frame_allocator/index.html"><code>frame_allocator</code></a> is able to accept a set of <code>UnmappedFrames</code> as a trusted &quot;token&quot; stating that the included frames cannot possibly still be mapped by any pages. It can therefore safely deallocate them.
<ul>
<li>Deallocation occurs seamlessly because an <code>UnmappedFrames</code> object can be converted into an <code>AllocatedFrames</code> object, <a href="https://theseus-os.github.io/Theseus/doc/src/frame_allocator/lib.rs.html#393">see here for details</a>.</li>
<li>Deallocation occurs seamlessly because an <code>UnmappedFrames</code> object can be converted into an <code>AllocatedFrames</code> object, <a href="https://www.theseus-os.com/Theseus/doc/frame_allocator/fn.init.html#return">see here for details and source</a>.</li>
</ul>
</li>
</ol>
Expand All @@ -1057,8 +1057,7 @@ <h2 id="deallocating-frames"><a class="header" href="#deallocating-frames">Deall
<p>Note: One can request a large allocation from the heap, but in Theseus it will be backed by an individually-created <code>MappedPages</code> object of newly-allocated pages and frames that are mapped to one another, so it's generally less efficient to use the heap for large allocations.</p>
</blockquote>
<p>In Theseus, the primary purpose of the heap is to enable the usage of Rust's <a href="https://doc.rust-lang.org/alloc/"><code>alloc</code></a> types, e.g., <code>Box</code>, <code>Arc</code>, <code>Vec</code>, and other dynamically-allocated collections types.
Heap allocators must implement Rust's <a href="https://doc.rust-lang.org/alloc/alloc/trait.GlobalAlloc.html"><code>GlobalAlloc</code></a> trait in order to be used as the backing allocator behind these <code>alloc</code> types.
how we integrate that with Rust's (old) requirement of a single global allocator.</p>
Heap allocators must implement Rust's <a href="https://doc.rust-lang.org/alloc/alloc/trait.GlobalAlloc.html"><code>GlobalAlloc</code></a> trait in order to be used as the backing allocator behind these <code>alloc</code> types.</p>
<h2 id="overview-of-relevant-crates"><a class="header" href="#overview-of-relevant-crates">Overview of Relevant Crates</a></h2>
<ul>
<li><a href="https://theseus-os.github.io/Theseus/doc/heap/index.html"><code>heap</code></a>: the default heap implementation that offers a static singleton fixed-size block allocator.
Expand All @@ -1080,8 +1079,8 @@ <h2 id="overview-of-relevant-crates"><a class="header" href="#overview-of-releva
</ul>
</li>
</ul>
<p>One unique aspect of Theseus's &quot;combination&quot; heap design is that the early heap, fully-featured heap, and per-core dedicated heaps are all combined into a single heap abstraction that can be accessed via singleton global heap instance.
It starts out with the simple block allocator described above, and then once more key system functionality has been initialized during OS boot, the <a href="https://theseus-os.github.io/Theseus/doc/multiple_heaps/fn.switch_to_multiple_heaps.html"><code>switch_to_multiple_heaps()</code></a> function is invoked to transparently activate the more complex, per-core heap allocators.</p>
<p>One unique aspect of Theseus's &quot;combination&quot; heap design is that the early heap, fully-featured heap, and per-core dedicated heaps are all combined into a single heap abstraction that can be accessed via a singleton global heap instance.
It starts out with the simple block allocator described above, and then, once more key system functionality has been initialized during OS boot, the <a href="https://theseus-os.github.io/Theseus/doc/multiple_heaps/fn.switch_to_multiple_heaps.html"><code>switch_to_multiple_heaps()</code></a> function is invoked to transparently activate the more complex, per-core heap allocators.</p>
<p>Another unique aspect of heaps in Theseus is that all entities across the system use and share the same set of global heaps. This allows allocations to seamlessly flow and be passed among applications, libraries, and kernel entities without the need for inefficient and complex <a href="https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/EuroSys2007_SealedProcesses.pdf">exchange heaps</a> used in other SAS OSes. </p>
<blockquote>
<p>Note: Theseus's combination heap design was implemented before Rust's <code>alloc</code> types supported non-global allocators and placement constructors.</p>
Expand All @@ -1099,15 +1098,15 @@ <h2 id="overview-of-relevant-crates"><a class="header" href="#overview-of-releva
<ul>
<li>You can spawn (create) a new task with a function or a closure as the entry point.</li>
<li>You can customize a new task using a convenient builder pattern.</li>
<li>You can wait on a task to exit by <em>joining</em> it.</li>
<li>You can wait on a task to exit by <a href="https://www.theseus-os.com/Theseus/doc/task/struct.JoinableTaskRef.html#method.join"><code>join</code></a>ing it.</li>
<li>You can use any standard synchronization types for inter-task communication, e.g., shared memory or channels.</li>
<li>You can catch the action of stack unwinding after a panic or exception occurs in a task.</li>
</ul>
<p>In this way, tasks in Theseus are effectively a combination of the concept of language-level green threads and OS-level native threads.</p>
<h2 id="the-task-struct"><a class="header" href="#the-task-struct">The <code>Task</code> struct</a></h2>
<p>There is one instance of the <code>Task</code> struct for each task that currently exists in the system.
A task is often thought of as an <em>execution context</em>, and the task struct includes key information about the execution of a given program's code.
Compare to that of other OSes, the <a href="https://theseus-os.github.io/Theseus/doc/task/struct.Task.html"><code>Task</code></a> struct in Theseus is quite minimal in size and scope,
Compared to that of other OSes, the <a href="https://theseus-os.github.io/Theseus/doc/task/struct.Task.html"><code>Task</code></a> struct in Theseus is quite minimal in size and scope,
because our state management philosophy strives to keep only states relevant to a given subsystem in that subsystem.
For example, scheduler-related states are not present in Theseus's task struct; rather, they are found in the relevant scheduler crate in which they are used.
In other words, Theseus's task struct is not monolithic and all-encompassing.</p>
Expand Down Expand Up @@ -1195,7 +1194,7 @@ <h2 id="context-switching"><a class="header" href="#context-switching">Context s
<p>Only number 1 above is what we consider to be a true context switch, and that is what we refer to here when we say &quot;context switch.&quot;
Number 2 above is an <em>address space switch</em>, e.g., switching page tables, a different action that could potentially occur when switching to a different task, if the next task is in a different process/address space than the current task.
Number 3 above is a <em>mode switch</em> that generally does not result in the full execution context being saved or restored; only some registers may be pushed or popped onto the stack, depending on the calling convention employed by a given platform's system calls.
Number 4 above is similar to number 3, but is trigger by the hardware rather than userspace software, so more execution context states may need to be saved/restored. </p>
Number 4 above is similar to number 3, but is triggered by the hardware rather than userspace software, so more execution context states may need to be saved/restored. </p>
<p>One key aspect of context switching is that it is transparent to the actual code that is currently executing, as the lower layers of the OS kernel will save and restore execution context as needed before resuming.
Thus, context switching (with preemption) allows for multiple untrusted and uncooperative tasks to transparently share the CPU, while maintaining the idealistic model that they each are the only task executing in the entire system and have exclusive access to the CPU.</p>
<h3 id="implementing-context-switching"><a class="header" href="#implementing-context-switching">Implementing context switching</a></h3>
Expand All @@ -1210,7 +1209,7 @@ <h3 id="implementing-context-switching"><a class="header" href="#implementing-co
Thus, disabling SIMD results in the simplest and fastest version of context switching, as only the basic set of general-purpose CPU registers must be saved and restored; all SIMD registers can be ignored.</p>
<p>Context switching is inherently an unsafe operation, hence why the standard <a href="https://theseus-os.github.io/Theseus/doc/context_switch_regular/fn.context_switch_regular.html"><code>context_switch()</code></a> function is marked unsafe.
It must be implemented in assembly in order to ensure that the compiler doesn't insert any instructions that modify register values in between our instructions that save/restore them.
It is only invoked by the <a href="https://theseus-os.github.io/Theseus/doc/task/struct.Task.html#method.task_switch"><code>task_switch()</code></a> function, as only that function has the proper information — saved register values and the destination for the restored register values — to correctly invoke it.</p>
It is only invoked by the <a href="https://theseus-os.github.io/Theseus/doc/task/fn.task_switch.html"><code>task_switch()</code></a> function, as only that function has the proper information — saved register values and the destination for the restored register values — to correctly invoke it.</p>
<h2 id="pre-emptive-vs-cooperative-multitasking"><a class="header" href="#pre-emptive-vs-cooperative-multitasking">Pre-emptive vs. Cooperative Multitasking</a></h2>
<p>Theseus implements full support for preemptive multitasking, in which a given task is interrupted at a certain periodic time interval in order to allow other tasks to take over execution.
This prevents one greedy task from hogging all system resources and/or starving other tasks from execution time.
Expand All @@ -1224,11 +1223,14 @@ <h2 id="pre-emptive-vs-cooperative-multitasking"><a class="header" href="#pre-em
<h2 id="the-task-lifecycle"><a class="header" href="#the-task-lifecycle">The Task lifecycle</a></h2>
<p>Theseus tasks follow a typical task lifecycle, which is in-part demonstrated by the possible variants of the <a href="https://theseus-os.github.io/Theseus/doc/task/enum.RunState.html"><code>RunState</code></a> enum. </p>
<ul>
<li><strong>Spawning</strong>: the task is being created.</li>
<li><strong>Running</strong>: the task is executing.
<li><strong>Initializing</strong>: the task is being created.
<ul>
<li>A runnable task may be <em>blocked</em> to temporarily prevent it from being scheduled in.</li>
<li>A blocked task may be <em>unblocked</em> to mark it as runnable again.</li>
<li>After the task is finished being created and is fully spawned, its runstate will be set to Runnable.</li>
</ul>
</li>
<li><strong>Runnable</strong>: the task is able to be scheduled in (but is not necessarily currently executing).
<ul>
<li>A runnable task may be <em>blocked</em> to prevent it from being scheduled in until it is subsequently unblocked.</li>
</ul>
<blockquote>
<p>Note: &quot;running&quot; and &quot;runnable&quot; are not the same thing.</p>
Expand All @@ -1238,10 +1240,27 @@ <h2 id="the-task-lifecycle"><a class="header" href="#the-task-lifecycle">The Tas
</ul>
</blockquote>
</li>
<li><strong>Blocked</strong>: the task is blocked on some other condition and is not able to be scheduled in.
<ul>
<li>A blocked task may be <em>unblocked</em> to mark it as runnable again.</li>
</ul>
</li>
<li><strong>Exited</strong>: the task is no longer executing and will never execute again.
<ul>
<li>Completed: the task ran to completion normally and finished as expected.</li>
<li>Failed: the task stopped executing prematurely as a result of a crash (language-level panic or machine-level exception) or as a result of a kill request.</li>
<li>An exited task has an <a href="https://theseus-os.github.io/Theseus/doc/task/enum.ExitValue.html"><code>ExitValue</code></a>, which is one of:
<ul>
<li>Completed -- the task ran to completion normally and finished as expected.</li>
<li>Killed -- the task stopped executing prematurely as a result of a crash (language-level panic or machine-level exception) or as a result of a kill request.</li>
</ul>
</li>
<li>An exited task must not cleaned up until ist has been &quot;reaped&quot; (see below).</li>
</ul>
</li>
<li><strong>Reaped</strong>: the task has exited and its <a href="https://theseus-os.github.io/Theseus/doc/task/enum.ExitValue.html"><code>ExitValue</code></a> has been taken by another <code>Task</code>.
<ul>
<li>A task is cleaned up and removed from the system once it has been reaped.</li>
<li>An exited task will be auto-reaped by the system if no other task is waiting on it to exit.
See <a href="https://www.theseus-os.com/Theseus/doc/task/struct.JoinableTaskRef.html"><code>JoinableTaskRef</code></a> for more info on how this works.</li>
</ul>
</li>
</ul>
Expand Down
2 changes: 1 addition & 1 deletion book/searchindex.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion book/searchindex.json

Large diffs are not rendered by default.

7 changes: 3 additions & 4 deletions book/subsystems/heap.html
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,7 @@ <h1 id="heap-dynamic-memory-allocation"><a class="header" href="#heap-dynamic-me
<p>Note: One can request a large allocation from the heap, but in Theseus it will be backed by an individually-created <code>MappedPages</code> object of newly-allocated pages and frames that are mapped to one another, so it's generally less efficient to use the heap for large allocations.</p>
</blockquote>
<p>In Theseus, the primary purpose of the heap is to enable the usage of Rust's <a href="https://doc.rust-lang.org/alloc/"><code>alloc</code></a> types, e.g., <code>Box</code>, <code>Arc</code>, <code>Vec</code>, and other dynamically-allocated collections types.
Heap allocators must implement Rust's <a href="https://doc.rust-lang.org/alloc/alloc/trait.GlobalAlloc.html"><code>GlobalAlloc</code></a> trait in order to be used as the backing allocator behind these <code>alloc</code> types.
how we integrate that with Rust's (old) requirement of a single global allocator.</p>
Heap allocators must implement Rust's <a href="https://doc.rust-lang.org/alloc/alloc/trait.GlobalAlloc.html"><code>GlobalAlloc</code></a> trait in order to be used as the backing allocator behind these <code>alloc</code> types.</p>
<h2 id="overview-of-relevant-crates"><a class="header" href="#overview-of-relevant-crates">Overview of Relevant Crates</a></h2>
<ul>
<li><a href="https://theseus-os.github.io/Theseus/doc/heap/index.html"><code>heap</code></a>: the default heap implementation that offers a static singleton fixed-size block allocator.
Expand All @@ -172,8 +171,8 @@ <h2 id="overview-of-relevant-crates"><a class="header" href="#overview-of-releva
</ul>
</li>
</ul>
<p>One unique aspect of Theseus's &quot;combination&quot; heap design is that the early heap, fully-featured heap, and per-core dedicated heaps are all combined into a single heap abstraction that can be accessed via singleton global heap instance.
It starts out with the simple block allocator described above, and then once more key system functionality has been initialized during OS boot, the <a href="https://theseus-os.github.io/Theseus/doc/multiple_heaps/fn.switch_to_multiple_heaps.html"><code>switch_to_multiple_heaps()</code></a> function is invoked to transparently activate the more complex, per-core heap allocators.</p>
<p>One unique aspect of Theseus's &quot;combination&quot; heap design is that the early heap, fully-featured heap, and per-core dedicated heaps are all combined into a single heap abstraction that can be accessed via a singleton global heap instance.
It starts out with the simple block allocator described above, and then, once more key system functionality has been initialized during OS boot, the <a href="https://theseus-os.github.io/Theseus/doc/multiple_heaps/fn.switch_to_multiple_heaps.html"><code>switch_to_multiple_heaps()</code></a> function is invoked to transparently activate the more complex, per-core heap allocators.</p>
<p>Another unique aspect of heaps in Theseus is that all entities across the system use and share the same set of global heaps. This allows allocations to seamlessly flow and be passed among applications, libraries, and kernel entities without the need for inefficient and complex <a href="https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/EuroSys2007_SealedProcesses.pdf">exchange heaps</a> used in other SAS OSes. </p>
<blockquote>
<p>Note: Theseus's combination heap design was implemented before Rust's <code>alloc</code> types supported non-global allocators and placement constructors.</p>
Expand Down
4 changes: 2 additions & 2 deletions book/subsystems/memory_mapping.html
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ <h3 id="how-to-use-mappedpages"><a class="header" href="#how-to-use-mappedpages"
<li>The same is true for functions and executable memory regions.</li>
</ul>
</li>
<li>These methods all return <em>references</em> to the requested type or slice, in which the lifetime of the returned reference (<code>&amp;T</code>, `in order to prevent use-after-free errors.
<li>These methods all return <em>references</em> to the requested type or slice, in which the lifetime of the returned reference (<code>&amp;T</code>) is dependent upon the lifetime of the <code>MappedPages</code> object, in order to statically prevent use-after-free errors.
<ul>
<li>One cannot obtain an owned instance of a type <code>T</code> from an underlying <code>MappedPages</code> memory region, because that would remove the semantic connection between the type <code>T</code> and the existence of the underlying memory mapping.</li>
</ul>
Expand Down Expand Up @@ -265,7 +265,7 @@ <h2 id="deallocating-frames"><a class="header" href="#deallocating-frames">Deall
</li>
<li>Using strong type safety, the <a href="https://theseus-os.github.io/Theseus/doc/frame_allocator/index.html"><code>frame_allocator</code></a> is able to accept a set of <code>UnmappedFrames</code> as a trusted &quot;token&quot; stating that the included frames cannot possibly still be mapped by any pages. It can therefore safely deallocate them.
<ul>
<li>Deallocation occurs seamlessly because an <code>UnmappedFrames</code> object can be converted into an <code>AllocatedFrames</code> object, <a href="https://theseus-os.github.io/Theseus/doc/src/frame_allocator/lib.rs.html#393">see here for details</a>.</li>
<li>Deallocation occurs seamlessly because an <code>UnmappedFrames</code> object can be converted into an <code>AllocatedFrames</code> object, <a href="https://www.theseus-os.com/Theseus/doc/frame_allocator/fn.init.html#return">see here for details and source</a>.</li>
</ul>
</li>
</ol>
Expand Down
Loading

0 comments on commit eeea98f

Please sign in to comment.