From f1919952f800f703a19d387eca4504ec261c6cec Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 18 Mar 2019 17:34:54 +0100 Subject: [PATCH] Add README for tutorial 0F --- 0F_global_println/README.md | 28 -- 0F_global_println/kernel8.img | Bin 12117 -> 0 bytes .../.cargo/config | 0 .../Cargo.lock | 2 + .../Cargo.toml | 0 .../Makefile | 0 0F_globals_synchronization_println/README.md | 438 ++++++++++++++++++ .../kernel8 | Bin 90232 -> 89792 bytes .../kernel8.img | Bin 0 -> 11797 bytes .../link.ld | 0 .../raspi3_boot/Cargo.toml | 0 .../raspi3_boot/src/lib.rs | 0 .../src/delays.rs | 0 .../src/devices.rs | 0 .../src/devices/hw.rs | 0 .../src/devices/hw/gpio.rs | 0 .../src/devices/hw/uart.rs | 0 .../src/devices/hw/videocore_mbox.rs | 0 .../src/devices/virt.rs | 0 .../src/devices/virt/console.rs | 0 .../src/macros.rs | 0 .../src/main.rs | 0 .../src/memory.rs | 0 .../src/memory/mmu.rs | 0 .../src/sync.rs | 15 +- 10_DMA_memory/src/sync.rs | 15 +- 11_exceptions_groundwork/src/sync.rs | 15 +- 27 files changed, 446 insertions(+), 67 deletions(-) delete mode 100644 0F_global_println/README.md delete mode 100755 0F_global_println/kernel8.img rename {0F_global_println => 0F_globals_synchronization_println}/.cargo/config (100%) rename {0F_global_println => 0F_globals_synchronization_println}/Cargo.lock (95%) rename {0F_global_println => 0F_globals_synchronization_println}/Cargo.toml (100%) rename {0F_global_println => 0F_globals_synchronization_println}/Makefile (100%) create mode 100644 0F_globals_synchronization_println/README.md rename {0F_global_println => 0F_globals_synchronization_println}/kernel8 (77%) create mode 100755 0F_globals_synchronization_println/kernel8.img rename {0F_global_println => 0F_globals_synchronization_println}/link.ld (100%) rename {0F_global_println => 0F_globals_synchronization_println}/raspi3_boot/Cargo.toml (100%) rename {0F_global_println => 0F_globals_synchronization_println}/raspi3_boot/src/lib.rs (100%) rename {0F_global_println => 0F_globals_synchronization_println}/src/delays.rs (100%) rename {0F_global_println => 0F_globals_synchronization_println}/src/devices.rs (100%) rename {0F_global_println => 0F_globals_synchronization_println}/src/devices/hw.rs (100%) rename {0F_global_println => 0F_globals_synchronization_println}/src/devices/hw/gpio.rs (100%) rename {0F_global_println => 0F_globals_synchronization_println}/src/devices/hw/uart.rs (100%) rename {0F_global_println => 0F_globals_synchronization_println}/src/devices/hw/videocore_mbox.rs (100%) rename {0F_global_println => 0F_globals_synchronization_println}/src/devices/virt.rs (100%) rename {0F_global_println => 0F_globals_synchronization_println}/src/devices/virt/console.rs (100%) rename {0F_global_println => 0F_globals_synchronization_println}/src/macros.rs (100%) rename {0F_global_println => 0F_globals_synchronization_println}/src/main.rs (100%) rename {0F_global_println => 0F_globals_synchronization_println}/src/memory.rs (100%) rename {0F_global_println => 0F_globals_synchronization_println}/src/memory/mmu.rs (100%) rename {0F_global_println => 0F_globals_synchronization_println}/src/sync.rs (73%) diff --git a/0F_global_println/README.md b/0F_global_println/README.md deleted file mode 100644 index 36ca1832..00000000 --- a/0F_global_println/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# Tutorial 0F - Global `println!` - -Coming soon! - -This lesson will teach about: -- Restructuring the current codebase. -- Realizing global println! and print! macros by reusing macros from the Rust - standard library. -- The NullLock, a wrapper that allows using global static variables without - explicit need for `unsafe {}` code. It is a teaching concept that is only - valid in single-threaded IRQ-disabled environments. However, it already lays - the groundwork for the introduction of proper locking mechanisms, e.g. real - Spinlocks. - -```console -ferris@box:~$ make raspboot - -[0] UART is live! -[1] Press a key to continue booting... Greetings fellow Rustacean! -[2] MMU online. -[i] Kernel memory layout: - 0x00000000 - 0x0007FFFF | 512 KiB | C RW PXN | Kernel stack - 0x00080000 - 0x00082FFF | 12 KiB | C RO PX | Kernel code and RO data - 0x00083000 - 0x0008500F | 8 KiB | C RW PXN | Kernel data and BSS - 0x3F000000 - 0x3FFFFFFF | 16 MiB | Dev RW PXN | Device MMIO - -$> -``` diff --git a/0F_global_println/kernel8.img b/0F_global_println/kernel8.img deleted file mode 100755 index f3f884fb82a22c0270c9a0533009235327e3e7b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12117 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 JjA=gozX6Nx8YKV# diff --git a/0F_global_println/.cargo/config b/0F_globals_synchronization_println/.cargo/config similarity index 100% rename from 0F_global_println/.cargo/config rename to 0F_globals_synchronization_println/.cargo/config diff --git a/0F_global_println/Cargo.lock b/0F_globals_synchronization_println/Cargo.lock similarity index 95% rename from 0F_global_println/Cargo.lock rename to 0F_globals_synchronization_println/Cargo.lock index db059c6f..df3c7389 100644 --- a/0F_global_println/Cargo.lock +++ b/0F_globals_synchronization_println/Cargo.lock @@ -1,3 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. [[package]] name = "cortex-a" version = "2.4.0" diff --git a/0F_global_println/Cargo.toml b/0F_globals_synchronization_println/Cargo.toml similarity index 100% rename from 0F_global_println/Cargo.toml rename to 0F_globals_synchronization_println/Cargo.toml diff --git a/0F_global_println/Makefile b/0F_globals_synchronization_println/Makefile similarity index 100% rename from 0F_global_println/Makefile rename to 0F_globals_synchronization_println/Makefile diff --git a/0F_globals_synchronization_println/README.md b/0F_globals_synchronization_println/README.md new file mode 100644 index 00000000..24793117 --- /dev/null +++ b/0F_globals_synchronization_println/README.md @@ -0,0 +1,438 @@ +# Tutorial 0F - Globals, Synchronization and `println!` + +Until now, we use a rather inelegant way of printing messages: We are directly +calling the `UART` device driver's functions for putting and receiving +characters on the serial line, e.g. `uart.puts()`. Also, we have only very +bare-bones implementations for printing hex or decimal integers. This both looks +ugly in the code, and is not very flexible. For example, if at some point we +decide to replace the `UART` as the output device, we have to manually find and +replace all the respective calls, and need to take care that we do not use the +device before it was probed or after it was shut down. + +Hence, it is time to get some elegant format-string-based printing going, like +we know it from other languages, e.g. `C`'s `printf()`, and introduce an +abstraction layer that allows us to decouple printing functions from the actual +output device. + +On this occasion, we will also learn important lessons about about **mutable +global variables**, which are called **static variables** in Rust, get to know +**trait objects** and hear about Rust's concept of **interior mutability**. + +## The Virtual Console + +First, we introduce a `Console` type in `src/devics/virt/console.rs`: + +```rust +pub struct Console { + output: Output, +} +``` + +When everything is finished, this type will be used as a `virtual device` that +forwards calls to printing functions to the currently active output device. + +### Code Restructuring + +In case you wonder about the path: The introduction of the first `virtual +device` in our code was a good opportunity to introduce a better structure for +our modules. Basically, we differentiate between real (HW) and virtual devices +now: + +```console +src +├── devices +│   ├── hw +│   │   ├── gpio.rs +│   │   ├── uart.rs +│   │   └── videocore_mbox.rs +│   ├── hw.rs +│   ├── virt +│   │   └── console.rs +│   └── virt.rs +├── devices.rs +``` + +### Console Implementation + +The `Console` type has a single field of type `Output`: + +```rust +/// Possible outputs which the console can store. +pub enum Output { + None(NullConsole), + Uart(hw::Uart), +} +``` + +How will it be used? Let us have a look: + +```rust +impl Console { + pub const fn new() -> Console { + Console { + output: Output::None(NullConsole {}), + } + } + + #[inline(always)] + fn current_ptr(&self) -> &dyn ConsoleOps { + match &self.output { + Output::None(i) => i, + Output::Uart(i) => i, + } + } + + /// Overwrite the current output. The old output will go out of scope and + /// it's Drop function will be called. + pub fn replace_with(&mut self, x: Output) { + self.current_ptr().flush(); + + self.output = x; + } +``` + +Basically two things can be done. + +1. `output` can be replaced during runtime. +2. Using `current_ptr()`, a reference to the current `output` is returned as a + [trait object](https://doc.rust-lang.org/edition-guide/rust-2018/trait-system/dyn-trait-for-trait-objects.html) + that implements the `ConsoleOps` trait. Hence, for the first time in the + tutorials, Rust's [dynamic dispatch](https://doc.rust-lang.org/book/ch17-02-trait-objects.html#trait-objects-perform-dynamic-dispatch) + is used. + +So what does the `ConsoleOps` trait define? + +```rust +pub trait ConsoleOps: Drop { + fn putc(&self, c: char) {} + fn puts(&self, string: &str) {} + fn getc(&self) -> char { + ' ' + } + fn flush(&self) {} +} +``` + +All in all, it is basically the same that is already present in the `UART` +driver: Reading and writing a single character, and writing a whole string. What +is new is the `flush` function, which is meant for devices that implement output +FIFOs. + +So any device that can be stored into `output` must implement this trait, +otherwise a compile-time error would occur. + +### Dispatching to the Current Output + +In order to use the `Console` as a HW-agnostic device for printing, some +dispatching code is needed. Therefore, it implements the `ConsoleOps` trait +itself, and forwards the trait calls during run-time to whatever is stored in +`output`. + +```rust +/// Dispatch the respective function to the currently stored output device. +impl ConsoleOps for Console { + fn putc(&self, c: char) { + self.current_ptr().putc(c); + } + + fn puts(&self, string: &str) { + self.current_ptr().puts(string); + } + + fn getc(&self) -> char { + self.current_ptr().getc() + } + + fn flush(&self) { + self.current_ptr().flush() + } +} +``` + +Congratulations :tada:. + +This is not much code, but enough so that you've implemented your first, very +basic kind of [Hardware Abstraction Layer (HAL)](https://en.wikipedia.org/wiki/Hardware_abstraction). + +## Making it Static (and Mutable) + +Now we need an instance of the virtual console in form of a _static variable_ +(remember, this is Rust speak for global) to make our life easier and our code +less bloated. Doing so enables calls to printing functions from every place in +the code, without dragging along references to the console everywhere. + +At times, we also want to replace the `output` field of our console variable, so we +need a `mutable` static. + +In system programming languages like `C` or `C++`, this would be quite easy. For +example, the declaration below is enough to allow mutation of `console`, since +the language does not have a built-in concept of mutable and immutable types: + +```C++ +Console console = Console::Console(); + +int kernel_entry() { + console.replace_with(...) +} +``` + +However, in Rust, if you do + +```rust +static mut CONSOLE: devices::virt::Console = + devices::virt::Console::new(); + +fn kernel_entry() -> ! { + CONSOLE.replace_with(...) // <-- Compiler: "Where's my unsafe{}?!!" +} +``` + +the compiler will shout angrily at you whenever you try to use `CONSOLE` that +this is unsafe code, and frankly, that is a good thing. + +In contrast to the C-family of languages, Rust is from the ground up designed +with multi-core and multi-threading in mind. Thanks to the **borrow-checker**, +Rust ensures that in safe code, there can ever only exist a single mutable +reference to a variable. + +This way, it is ensured at compile time that no situations are created where +code that might execute concurrently (that is, for example, code running at the +same time on different physical processor cores) fiddles with the same data +or resources in an unsychronized way. + +By instantiating a **mutable** static variable, we allow all code from every +source-code file to easily operate on this mutable reference. Since the variable +is not instantiated at runtime and explicitly passed on in function calls, it is +not possible for the borrow-checker to draw any conclusions about the number of +mutable references in use. As a result, access to mutable statics needs to be +marked with `unsafe{}` in any case in Rust. + +So how can we make this safe again? What we need in this case is a +**synchronization primitive**. You've probably heard of them +before. **Spinlocks** and **mutexes** are two examples. What they do is to +ensure _at runtime_ that there is no concurrent access to the data they protect. + +### How to Build a Synchronization Primitive in Rust + +In contrast to mutable statics, **immutable statics** are considered safe by +Rust as long as they are marked +[Sync](https://doc.rust-lang.org/std/marker/trait.Sync.html). It is perfectly +fine to share an infinite number of references to them. So here is the strategy: + +1. Build a wrapper type that can be instantiated as an **immutable static** and + that encapsulates the actual mutable data. +2. Provide a function that returns a mutable reference to the wrapped type. +3. This function will need to be marked `unsafe`. In order to consider it safe + nonetheless, it must feature code that ensures at runtime that only a + single reference is given out at times. + +This is the basic concept of all synchronization primitives in Rust. For +educational purposes, in the tutorials, we will roll our own, and not reuse +stuff from the core library or popular crates like [spin](https://crates.io/crates/spin). + +### The `NullLock` + +The first implementation will actually be very easy. We do not yet have to worry +that a situation arises where (i) code tries to take the lock while it is +already locked or (ii) where there is contention for the lock. This is because +the kernel is still in a state where everything is executed linearly from start +to finish: + +1. Asynchronous exceptions like Interrupts are not enabled yet, so there never is + any interruption in the program flow. +2. We know that we currently do not have any code yet that raises synchronous exceptions. +2. Only a single core is active, all others are parked. Therefore, no concurrent + execution of code is happening. + +> Hint: You will learn about asynchronous and synchronous exceptions in the +> tutorial after the next. + +So all that needs be done is wrapping the data and giving back the mutable +reference. Introducing the `NullLock` in `sync.rs`: + +```rust +use core::cell::UnsafeCell; + +pub struct NullLock { + data: UnsafeCell, +} + +unsafe impl Sync for NullLock {} + +impl NullLock { + pub const fn new(data: T) -> NullLock { + NullLock { + data: UnsafeCell::new(data), + } + } +} + +impl NullLock { + pub fn lock(&self, f: F) -> R + where + F: FnOnce(&mut T) -> R, + { + // In a real lock, there would be code around this line that ensures + // that this mutable reference will ever only be given out one at a + // time. + f(unsafe { &mut *self.data.get() }) + } +} +``` + +First, the lock type is marked with the `Sync` [marker trait](https://doc.rust-lang.org/std/marker/trait.Sync.html) to tell the +compiler that it is safe to share references to it between threads. More +literature on this topic in [[1]](https://doc.rust-lang.org/beta/nomicon/send-and-sync.html)[[2]](https://doc.rust-lang.org/book/ch16-04-extensible-concurrency-sync-and-send.html). + +Second, a `lock()` function is provided which returns mutable references to the +wrapped data in the +[UnsafeCell](https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html). Quoting +from the UnsafeCell documentation: + + +> The core primitive for interior mutability in Rust. +> +> UnsafeCell is a type that wraps some T and indicates unsafe interior operations on the wrapped type. Types with an UnsafeCell field are considered to have an 'unsafe interior'. The UnsafeCell type is the only legal way to obtain aliasable data that is considered mutable. In general, transmuting an &T type into an &mut T is considered undefined behavior. +> +> [...] +> +> The UnsafeCell API itself is technically very simple: it gives you a raw pointer *mut T to its contents. It is up to you as the abstraction designer to use that raw pointer correctly. + +In upcoming tutorials, when the need arises, the `NullLock` will be gradually +extended to provide proper locking using architectural features the RPi3 +provides for this case. + +### Closures + +The Rust standard library and some popular crates for synchronization primitives +use the concept of returning +[RAII](https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization) +type [guards](https://doc.rust-lang.org/std/sync/struct.Mutex.html#method.lock) +that allow usage of the locked data until the guard goes out of scope. + +In the author's opinion, RAII guards have the disadvantage that the user must +explicitly scope their lifetime with braces `{}`, which is prone to being +forgotten. This in turn would lead to the lock being held much longer than +needed. For educational purposes, the `lock()` functions in the tutorials will +therefore take [closures](https://doc.rust-lang.org/book/ch13-01-closures.html) +as arguments. They give better visual cues about the parts of the code during +which the lock is held. + +Example: + +```rust +static CONSOLE: sync::NullLock = + sync::NullLock::new(devices::virt::Console::new()); + +fn kernel_entry() -> ! { + + ... + + CONSOLE.lock(|c| { // + c.getc(); // Unlocked only inside here + }); // + + ... +} +``` + +> Disclaimer: No investigations have been made if using closures results in +> poorer performance. If so, the hit is taken willingly for said educational +> purposes. + +## `print!` and `println!` + +In `macros.rs`, printing macros from the Rust core library are reused to empower +the kernel with [all the format-string beauty Rust provides](https://doc.rust-lang.org/std/fmt/). The macros eventually call the +function `_print()`, which redirects to the global `CONSOLE` of the kernel (will +be introduced in a minute): + +```rust +pub fn _print(args: fmt::Arguments) { + use core::fmt::Write; + + crate::CONSOLE.lock(|c| { + c.write_fmt(args).unwrap(); + }) +} +``` + +To make this work, the virtual console needs to provide an implementation of +`core::fmt::Write`. In this case, it is as easy as forwarding the +macro-formatted string via `self.current_ptr().puts(s)`. + +## Stitching it All Together + +In `main.rs`, a static `CONSOLE` is defined: + +```rust +/// The global console. Output of the print! and println! macros. +static CONSOLE: sync::NullLock = + sync::NullLock::new(devices::virt::Console::new()); +``` + +By default, it encapsulates a `NullConsole` output, which, well, does +nothing. This is just a safety measure to ensure that the print macros can be +called any time, even before a real physical output is available. In `main.rs`, +a respective call is made that will never appear as an output anywhere: + +```rust +// This will be invisible, because CONSOLE is dispatching to the NullConsole +// at this point in time. +println!("Is there anybody out there?"); +``` + +After initializing the `GPIO` and `VidecoreMbox` drivers, the `UART` is +initialized and replaces the `NullConsole` as the static output: + +```rust +match uart.init(&mut v_mbox, &gpio) { + Ok(_) => { + CONSOLE.lock(|c| { + // Moves uart into the global CONSOLE. It is not accessible + // anymore for the remaining parts of kernel_entry(). + c.replace_with(uart.into()); + }); + println!("\n[0] UART is live!"); + } +``` + +Here it becomes clear why the virtual console is designed such that it stores an +output _by value_. It is not possible to safely store a reference to something +that is generated at runtime in a static data structure. This is because the +static has `static` lifetime, aka lives forever. Whereas a reference to +something generated during runtime might become invalid at some point in the +future. + +Hence, `move semantics` are used to achieve our goal. Once `uart` has moved into +`CONSOLE`, it will live there until it is replaces again. That is also why the +`ConsoleOps` trait demands that its implementors also implement the `Drop` +trait. When calling `CONSOLE.replace()`, the old output will go out of scope, +and hence its drop function will be called. The drop function can then take care +of gracefully shutting down or disabling the device it belongs to. + +While the print macros implicitly call the lock function, there are some places +where it is done explicitly. For example, when querying a keystroke from the +user: + +```rust + print!("[1] Press a key to continue booting... "); + CONSOLE.lock(|c| { + c.getc(); + }); + println!("Greetings fellow Rustacean!"); + +``` + +## Summary + +Lots of things happened in this tutorial: +1. The kernel's code was restructured. +2. The virtual console was introduced as a **Hardware Abstraction Layer**. + 1. **Trait objects** and **dynamic dispatch** were used for the first time. +3. The peculiarities of **mutable static variables** were discussed and what role the **Sync marker trait** plays for them. +4. **Synchronization primitives** were introduced and (a special) one was built. + 1. You learned about **UnsafeCell** and its role in providing **interior mutability**. + 2. You read about **Closures** vs. **RAII guards**. +5. And finally, the `print!` and `println!` macros from the core library are now + usable in the kernel! diff --git a/0F_global_println/kernel8 b/0F_globals_synchronization_println/kernel8 similarity index 77% rename from 0F_global_println/kernel8 rename to 0F_globals_synchronization_println/kernel8 index c078e488cfa2c1249ba39839bc02eff6e5c0369c..a9e375fade3fc846e743b52d30fb0b4c7493d489 100755 GIT binary patch literal 89792 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 literal 90232 zcmeHveRNdUb?><|5}J{~NLT{Qhcy^nBoPlYcfOrC8VPU!6GMdj(NI^+CzAC&l8gw> zLbl@;TO?&1(l|IR*iLJ%9Jjp2evR6uhWPcZCN!-v#r0b4dltBPOF|?z9|nnn^?v)@ zbA&XWA$HQ0zs_9?-Fx@lXPy)5Kssx1QY@a0fm4hapb$_9Cy)5Kssx1QY@a0fm4hapb$_9Cy)5Kssx1QY@a0fm4hapb$_9Cy)5Kssx1QY@a z0fm4hapb$_9Cy) z5Kssx1QY@a0fm4hapb$_9Cy)5Kssx1QY@a0fm4ha zpb$_9Cy)5Kssx1QY@a0fm4hapb$_9Cy)5Kssx1QY@a0fm4>fH$H`b76RNoOkf9ZjIdsh;2IjAtnXa_3*A_xn(c-Uuv+&xc6GhFyftRgp{3(sSy24s`ta{cxqtOCZ|IjS^%MP5^ z&$9P_c?nBbXtsX4vF?N&d{3gE2JMzn#|&0a&#qYu2k6(SQ7CqJFq2JTC87;r@c< z=KjXVe}AkzpPkb*R^Md#{V|f!V`&(32pNWDZogl%9cy}_A=vnMLvO|6jvu^R7e0UF z@MGd56ww@@O=AByh3Wh8{7!-O=NLOY4&A>De0KuZeW{}KcX3VQ8L{3n z@DTb96|nR$#^wK6_vEI-3aJM3QA{P3jRkA0*2nH8{mBe#1YY`^fQuUi+5u7$m?SQig08K0=P!S8GuORxLh zAG~E7-1UsjG5@4J@5p&uLGYyAzV!#|aQ|+#^`xyhc+y~x*V#0Cm95yModPx&@h=bh zJa6f%v(OoSJ!CB%xVG~P@cp}uOAo9u#u`=|SGKJ(uC~`2m^0}k)`quj%fiNKt2QuX zwGEuI+6VR(u+oV)wBv;1&>u2m4+8>#N(X9XbEH&IZ@9Bj>9fY;d69V9M`c#s%no z(P|l}tk8_W+VJ?;g7Dz~wXl8Vk3QJU;HTw?6OHS`U(6ChE6?)@WI* z58uWH2`kBG1K+$Iw{HF!cqc5Zxdyz{-ll~I?X%b%TkE1Z)rdh%+x(TsFfSTsga=2g znqIEio1e$r+HDDs|71>IU15HB@TYT2J%#yfu>4zWuri-@QXfYl&;Fh8U{(Gco%4NX z`m-Txc~v=RgxTwNv%w|}aiw6PzG7=%-J#!MgGLp`?qq{60}Ij{^I5;JbCvPo=33+O zmKtNMVD%WcDX=Vevq8H4aP!|ArMSPaQzN{pb_1ibvi!~aFviz0#v%AI=_cvl5Ol)n zn-(^BVP_5G|M(Eex-xs=*mz7sUl!1;#)X}E#tTL4)r+vh1uGlyF-!mdgw7A(-!Od7 zUUnoHT+HUIvy25U!oSK_u+F}G^tWnt=a8M%?*LvB|B8j-!3EH(4gEJ*8Mjl=$_5Wu z%0{2RHc`Kd?4*^AZnXgC8R5{rLY6KpgH3K`bIPBvcCG@Qcp2nBH8&ir#Ito}3q0j- zSUatt(X*{MKaFSW@eKK*^bGL6i1;97SYXq_k_DbIYhe}Xdi2UfeeV<`-fr$7+l#1#7t7FV4PojO=_f>@9U_guP2k@;1+h zP6uFbvTLIyJh%=vBHP+vpK>4TbZEO5Tr8;Na>&*b*8JliZk}Tdud<}cf39vRfxU0$ zbM9M(;qil(>bEc5gLsPPmkJoaAKn-qw`+5c4HvQT705kJ*XmCgjJ;Y&@uPt0>mwy; z*Vdn?*4R1zthFS)=dqHst!(%Hr?sc|H)&7p?|&g28hKeWhUc;IU3S(< zzPbxJXbI*v#T%L@m9L-;Wb%9TQTcpHn&P1O9QUu4q@Vuta0var`SpQti27|lT9O`F zYBlx@mZTdnH~Y2z{Y0lWz+K<-lalo78tbe)S&|-Ik!MtBd-ku(e|rBJ#KcoiAdVsK zfp_olDweK1{`vHf_2z*y%k9P)9uo`c+2P71;Cq6l&nz!8d1HuuZ-5{1^NdwXkGwb& z*y8;1EaMC?962!?vGyi2o-Ub_9{EFt9E=#Xe1@QvLYB=KUS41+e3=GpW!+nGL!G1x1aQB=c1WXme(1D!rtUxWUUW7g-h*l$j&^Te*a_Vbk0##BLk+eheR<0a!-IZ5++1K#{+QThMGmm= zv2dT14LJN)G|u%i4hhWqcpR~?1SN4e#~O5~H8#p%mS8T^p#oeSFV zy9|Am>t(nm+565fPLq$k9bJODfa$NDHf3M@cg+}zY3Z@0c?QY<5H^1tvcmYlgY+9g-Xj^q|7PJbM&7j=oupqr3ry;F^j4lD$Dkv8nddx`MeWBn zn>t*=*trhKf0vi%8Hi*1nAMcQ^?0m&x*qSDW8@g2f6{|=AfF>SBQIKwjgWyk5xB5( zEqvh%hzEBYV=KbrunG4EhA~A@2e5Eey6B^cZ}VFDjXccj62lAIT-Z5>eDlql@$YJE zHn-E|EyV_MLwaHt`ob70BTLg=FDy-8g#U6~tX9k&%{UD`F2JTv!eSQlm7yk?*kw1$ z{_~~O#4ek0Xh!(>#I6Ek=nV^G%`i@Ze_~g@F+9NxTk*H+Y(vBcyDTNT)u8?+s9xC2 z#y{M`#>cNse0wWn-Udx75yqx1Gkx$qOM3VH40Vt-eetCt=s43D)7ZYPGfY33 z*k!i6unY6^)Uvd+?GV~se6fhP8`;LjN73d;9`li|Q+2bI3B5>%sj{BGJ*TX9sDBId z{p9MzxBD1-jeN~kvpj7@Y~$C@{|@&#>Ywx>xnv*Gk@TXmkWT-bbOMf3ePK7SC0{6+ zpffv+XX!o6tjT&g&GD}kH*8bth>vEMk1^a=U)4Hcr$OLbe;WOs^03hD(5d=rd1nRU z@^HZd9d){1Q8B|)S;{=8F;7twhDHJ`MC+o8M~gS_)|hX&Xd&l2L%g4x>8bjR$xpne z5y#Jff8?_)bQ5ngXR~eAqDlTywBdZ#TlK2dGd(LrTWT|kHY3$6ME0gULw2aFsZ6i0 zsYuiMWi9dwbWYn!Oq)>6^-)0$&wCSA?Kq8j=sm>13aX1)`Xj`QiqF&0bRn$ZS)KU#=6XVv(elQ@x$NCzAGu0-F3&;z;VT!prKf405}Z~8Z6U8u`z zI$z%MBg}2hxQP1d!cL1p{!jDZZOnnom;<~2z?=iamOtK4@sR2;lKC26Vw==wBp zBA+~kT8HKbUyscSkDs!#Dxwpu5p@n-6GkLU`Yh2Ut-OMD)}TfjMGXSkeC_>?@E5|7 z^rd`I1Pq5!6VlrDqg8DD3~+2i{rrBxBE9w6>J#m=nCIC4VI}WYvd#^fz5kc){spL! zk&|W(eB+uHdgY^u*BqK9U7lw-_ha}Jwg0)*erz3h(eL49cvgG1Dh>Vh_uyZ&c6p2J zuOEz{_9%f9GeO{#xBDxBmS6H)i(Ly}y*D5C8qal>1Uu`aIT5 zm0vyf+-a?_zw+8WCmcVS`P}*vcD%t-JgQx-J+b7`pFOt(XGh;n&n@{%q}TD4t-Uoa zOK*6SrMCiDuKyF3u1;&`1~8uxhfB|3y+ij!sAtcjXzCroKE(H%s(Pz$XXnmBCeQWYkCT2! zS;g}R_I+_IfOokUqUWGKei># z^u&Z_jQ$|cI1?zU9GbikLxufVe$?`*F;zy;NgS{csApjl7&^V7?z7 zK`zI$!QXa1fhoKwq z@2Edrxx|~MI+?GJAs_3=^e}WAe#v6|yO>kTZ~y!J_NVZtsd0M3YCV2=iybx2mcP1x zSuJ90p>YOz=ROK$RMcZyKcYoVXcvG;#-j;;U7XHl2LY^b-{_ylY>RA4bK zt*{!GU~}4E^v!0kuA3Pihwtvagt_w9x3Tn>tuxaKX-yw=!_eKXB|^iU<@F>=~C?Oi!aSm2Nz9vpsv4IVlj4h=(xLw?+E#{G<1gW~ZJ z?QhIt=V-lKZfEC?B3=wHUu9q~VstCwnjN+N2x6Tb^-s07VDu>VCu~}HoYr5bmxsq2 zm^NBD8*P?`$L%Frf2H7i400;ZK6=8|)HJ4nAO5YQrbRth!~0!==acPceY`#Gfywq1 z&*0w!Q`ef8UK*Ru3wTszJe_?JRv z8SEIqzkjo^SHFdSLrZIo#|p#7v*5GAhSY{>EO6wuqlZWq-M?1Lj$g*Vi`MxA;g1UZ zW3Y2EWbK3P4_Iy z*m)29cRlL=b=VJBYh3v()gxB91~|-yK9~LrQU9aXL%nxr`q`=XeV47}sLu=l^#f{iUx8@IAvRVhOY_ni5fMI`ehH+G5{>HlSU=!9F zg>Ish z<<^DGM_|{jx78Y_tn;g6&DXbx1$OVUY#v5UZa$kgaN0U|K>AMKLKZOTWuVjk?cLbF zU4#AG)!4sXh5g%F?BCWHR`>$;Y13O-Iri|WHfB2Y*?2$p4Wn8pTi*xg-?;CC^Vr8Q z-ikSbdD=My8(apKjrWHK5&H(quW6lYVWUeFAC|JvH-S05$G8F>sxQ}JkACe$&50|> z%~g2+!P{ZofE+$fZFd8kacYZt|MTE4zhU0)*aa~Y*7p#(Mq!s7#$ z(*73gk;c5c=ivv4SyjKpySxLBSv!{^pT3J&a|HBbh(YbxyB@XPG;rXk zwetngZh`Dqupj<1_QQXP`1T5(Q@bc)80|N|FJ*!M4e^Yysp7S1UR@H%;)tyJ+6LuSW^$z5NcCGAKgH|-^0FC-OYn?stFVKHB^nV}vbGg8} zBR?E!v$OO$=vh3M&6$8c?;-YATM9?Rc<#g={9EYvm)4Sj3Fu|TvpI7Yc zwV!PKJYwR%VxNiZMmd~v5WQc-8Xd9F%tKEh579ODTL%tV?ET-zT>AyqjNd>W`Xl6_ z_mNZn8UNlzURhuE^!^E)o6Gw5zasL`!&s9Yu-JJXGT<*ouvs(scM1M#&BpT(-bIZ+ zWx;!6+@FRnrKn9vFAd|TzUh6g1A0xJFPZNVcurYm<`il}dGu-MPuGNjVJYl?1^Sb3 z{w4H34E-sG(io)PGN1ml&>z@C|3a=m`TJ*}{~quk5aVn>ey2RzgxvnHR(k9~yx*=y zjvq$-Ksg?Bndcv>7bo)%@(9mAc*gS&Vm{@D%c!r$pr_0=#AAnSitlTIL)Q2%a?3Kb zwgaAy z-RY=_$5V-}E=N~7g{M{m&I;P>9q)7IS9zP;^^mZr9z z-aEFn^{i}Zims$)bnZ&U_%*)(A=aKstb~1fTDqO7E-3Y;z@t?t_;Vj-2F^?dAE`Z7=;OS9?jP{^^kY$+LVe&nDM( zJ>|VaTu46I9`AMeA?f0F@+9ewNs4(P+mr3-kbLId$L}5Df#j3zrTrycwwGr~m+d88 zwnvS^56LH=XWl!+14+Lpk!nk{IJ&wcv1V}{YmX-!k+!&_Zlfa}>5d38U2<~m=FRZx zrdY!9#V@YgDCF6en|@5bLC0Pcc3BV2)VNge&l5~7x%kEN6@nl8KKxjli(kn9yx_;4 z6hB-!_$`88hTry{Zby64k&3i!OE|YQJ>(FhZ%wqer*=46B0IowXCb@2!W-wfD5d zd9v$DbUS)F;7<2B9W~MR6z|Q{vsbjop3bxba){s2-i834a26gBeAxTq$D^}MJ*5}Q z^Q$+RS9`?s4sqX?gMW3t$-h^eT?OWSuQ&$9 zB@uUQt>Zc7&O3YBwx=Q;6_r~tLfG1|6`*Z(JQ8W?Nw|7lE|=S-yF4zh%jfdD0_-yLuV-67qjyLDan=w98Y`}Kex)I%PZ$L-NQ9*@`K^Y}dhPtX(c zy1Z_$?)7-RUZ2B^o9H`zuT|-J$|p>=lA;q{-8e; za0T1}J>Us=1HOPi5C{YVp`a`14(dTq&>Qpx{lP#m7z~A=VhG)bAUcF*A&>yo_e!$k zb|`~xqI&&rQ(HXI%bg#yHQL_O7Vo-~=7FOn(MGQBh??`lVKRbZwmq`K>`&aXA#soO zEI*{(#O<#g&!rqWZ*$3WhzFAIw^7G*wIFz}Y;BLDl#zPo(ogCopJ(bT+skt%f98E= zd#;Nx5&}o6yUP*jHm#R{P3eYrz55Q+Zdm{F<4?ss_Tu^R>}Sm99pXNPqMmZHoL3t= zx|`bDGUt_J>%Hx52{EsJ8_>6NHGuoD&|k*2o1LcqvYz~109q!-LZ{z`a>>?i;T2dQ z34Pjx4sH}k6}Zl%-vv7M${3I7f;ZcV{3DN@o5*}NpA#&s4=+rn9*YJ2FEZ%23HpCz z(9L`VZ*xtT^BK+$IyNPz9&RD0IAdLdy+|Ay#yXwbr0 z*FRE@iL-@;#rj0jrT)Dc`hOOM8Q~-8jiSK^IA_z}1_#PUcjTZ4bI>>Cpl<`6?2df~ zp^15F5%kGCFP?S^x~vamqelc?)(eupQ_yAoAnARAF6#+NUxdI$_{e@`UHzn>OFbXt z?HPMr(4`!?o|%D7B9bHfT`M|xQqZOT8w5RXw#hH`KPcosiE}pmzssLnSSrKrF9>>1 z2K|tr%XP0D?_UVIT>nb?tAZ}qxsv`jf-cv$l72+ccW3mAZ`E*EnCHk|Z=+gfiGw3qTG-uHNN$As>K|e0&Z5i~p1-&DKF6Y;yq8^nvJR$5T=_Zbh z{X68`$c~%Dx=G5Bb}Y_V*GN0cb&%wjb_{3mOFPQ-kmQ$kd@zGw+Oao-F7cG>O({p> zDc6;fF7cG>M@g4>%5|coOFT2zi|0B18p~XF%D9oaewA?}a~&+>!}sjd{qQp6TNvi4 zpqufU@fYz#m;Ejiine0Igy^zgNk1g$vR|1O-bFp6;boPy?-3zq8}bOzrF~`1@ejyj z6gQ-vhxzy!n~!8q{L(IAA!m!AOS_9S$o@poGwuGapi8?ugq-)F|Bd{!QLOU>JCpt? z*NKuY{qs-;zw}SJUX=XOKi|yYH{%16_onIglJVh(8U88b!#f#t86V`jTlVYb7Z`L# zztW%OdRy{Ke-38wOMjN@ZOJeFxxQ$+{?ebj#kyDWUlINz`5m~Y;}#?!&2k+FY2ONv zve`?{>!A!i<-9Jgny!zG&zmyn_$>?$3yWvOJ*mH3=MxtlYdAlgHDf(~kD%ve(B=G< z>wi-UV{-n=eF90Bd0*}uNV=TYa(_Y6W!{(j0FvG(;)&cBkn}GJJ>@=uq~9;-llunZ z!4}Xd4oDni-rpF2@xV^q&a2)Kgk>HWpnZ zM~)Y4{J2lh<#;9iIYF1>lJv*9zgd{{AD58RgoQefSHe%if<7SV(tjlV1JEgsNxMHQ z`0v8T7ty7k$bSC{bdoRqP0~+8&uo4^o`YVD4c%<~G7jv`@N?2Kf5pw|d| zq#U`9Tq4FR|Uken!7*a`68y-@vx8zs(p|gP{K?gP!1YyeQ9* z-z?~Bi=~F9!J6lqc9HT$SYodTdZzpjGU)#(?A{6a+3fNMLeKePA3?CQuM7Hau}>uF z-xPGYpCswu5p=n)BE#nGUWUjr)%u*GWNS(7WBM1({cD8f*#MHPx?uQ92sXa z_tX9wa%i4Px~vl{1twkY%SrzafSwIEnO~mG(5Eg3|2EL62f1HEcXYH0x=rkhm{i8P z1YPd`Ncs*zm-|4HzDv*#XUKU{(BI6U_j9_&4rb_|20hz&|2zl%Z*$Q9B?tYz9Q4be z6Fzc(NRI28pv!$CNjI0P*gp~bHIi=UZey9;uaR_fx>=ZG<#fL)6a2vp`a(h9ltEv@ z=^Fbz`o++c!(2XStb5*cx(U0+_AZ)E_Xs(AOo5Ys`h^^H`f+MD z{e3y;_vfI?d3`YhPnoAGGWOqOzQ7j*lQyJ_PROS?Bl+=vF!1A5L6`Eqf=)lQm@~z` zavju${UV~vxF`7!2)eYpKq7O0au%nP^GQw24n~p3sb5*2%cl<_P!nD9 zR|tLLf-d8*nLhUCi0F zqqRE{#ksMoJ7r#(XV%PLiwB*7M_QBa_O|#Pv28t07h4v0y6KNje?0WZOMiUy$Iq7a zf~Dch_Xb33zxmSG)7skOc5S$SgWgbIQ@de}JJ1+N1U&&g?)N4pA#6Iq2RTbYFHlK@|@L zWN*Ylcbk^rrf_pxxJ^2@hMSwi4ST>^0s71T1nDZ2T`KR}O-At2mp-2Mj;>&`r!7YB zjQn@EZETArLi8r7p&eJSpEsD$W6>Didb-@cc+kh~_sN<@b$2wGj0O|QxUR<{iBHiq z=87iK*d2)lT=96s{VAHpqn>2KjaRt|Z&Hs0Tsb_)H`Nc_y6MLaiMH<44vab!@+3m> zsLPd1x;?=}D2EUec);E3BtzjZw=XAzu4CNMopJ|LiAYOBJk{RO(A3t@(Si>L(2vLO z3;F!9NGP6&29h4Q`J`cTH}d+TQI9VePX^-=mmc--Mm|@=vJLgimet+8thJ|mS&!~o z_5lAI>Eb6cw$q9CUQXu&siyA4vM&Ok6 zV$m6-CR|>BG8&3Td{NyW3YkOv4WuG|L8>e64R}00mpc;o`Jp$*Kt`iLoPV^_<$a_n z)g8dc9bN4$3AbyNd9ksh%eyVn9fK5KBJK;u@X0_h68GcVfln!=qlZh02SNc~T=%*# zb7C={>8zhz7f9)XE_wuCG$j1)AfUp>46#qAi!a&I)7418M0^Pt5T7FG`2HaQV6q1I z95E-Dojb(3@l|F+DzUAp3*Q`eITM|(mQd0g5y^r(m%BOG6MeWhcs+pxLOc-hkmKin z1Ag{#Ubh+DTs+hT&EUo3SjfDF6hu#+bac>h9i(aE@pF%_|G1aqgCVE0rfmoJaW`z; z(7mH0(a;npd|ZfV32y|GO;7ql2oIlN#vzp8D-&-Z?g>UBF&}1JN2IMO))1jDc$|7N z(&Tdmk~zU}^I+}cqw(|b?Kkr%j~{+MRzD9K2&Na+V7OSHHflBxDqTgVKrp(7McUfioF1Rsg^#DAL4>Ce3OwBxz$^?T;|WYHTsyrt?$N9B84qv! z_?+jNZFN%@GAp0=9y9y+gGmn}tIr#AyM2*B(46kx$y}KwdgPGggD7v*7xcJeaTKLO z68XH}{94-WF~4MMKsdk$Zh#?@NJQOn4?ZS~xC7D9lqx2~<3}^TCN!@aOl`fsfHx9| z=*dLD7mI~}8-kP1!?oqJ%S_<>3zS?CB%(drDDX)D-1zv-7x%d%iBK@+<_U!Gueno_$trym#|PUe3ECNGm9=lK2D;U$zB=W!Yvj-*Cj2qok53e{ zw#-@eOx6fKS3E)=Df)c6$L$Z8YqF4;PCv~^Kh8@9m(wXKE~oQ)#l^=jsxE-*qY3YE zVP&Da&GG*hx)xQEwy~kNQ2KxLLV+f1QYg z+3Jh<;j2Mk%omDaE>4y*nA)DUo>reJwyCwFg?s3f7$QR@EfkXNWUax2L6L1C|A}?5wBx&F47%d<$@UQ0fnfT^hmI`T6NoP3e_}1|T|KD;uH!_A zFN0O_@qGdbJrKc$1#(wVREXKKIQ$}D2wanLNGvWd?crkbY7$Aa7)4S6C79gFLT$4r;z z7TB*Tzh|0!)Bq7|0l9sNNE`z(3y&lK0gETU#4 zj{T|b#I{tV1qR1%P$GeiDwG|l+1*pN@O=Dpc3tNuG{J8a8roBFEMKVnr3jG3W=0^C z2>Anvq*s@fqRSgi1Y8Mk-0O=6Tp|1>BZi+xRg2`CS6V-J;f(2%7(k$n> zVXrs!@s@-a(C|e)Zas=0vIJvhRW#`Z*KOp1iNGF+1Y+@s9*tpRUH2z5*xjz0)V7{h ztS9exyIoz4?b{o8awn5|V)z|RJn2I508kT?t31@>D5p{0%`x|Ww!RW-feR3lO2gBneG2SBX|Hg diff --git a/0F_globals_synchronization_println/kernel8.img b/0F_globals_synchronization_println/kernel8.img new file mode 100755 index 0000000000000000000000000000000000000000..94bf5f5b05398a0d5eb2977d549851a2b04a65b7 GIT binary patch literal 11797 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 V7&{U8bMbxsd@<(H=V6+!`){D{7OVgO literal 0 HcmV?d00001 diff --git a/0F_global_println/link.ld b/0F_globals_synchronization_println/link.ld similarity index 100% rename from 0F_global_println/link.ld rename to 0F_globals_synchronization_println/link.ld diff --git a/0F_global_println/raspi3_boot/Cargo.toml b/0F_globals_synchronization_println/raspi3_boot/Cargo.toml similarity index 100% rename from 0F_global_println/raspi3_boot/Cargo.toml rename to 0F_globals_synchronization_println/raspi3_boot/Cargo.toml diff --git a/0F_global_println/raspi3_boot/src/lib.rs b/0F_globals_synchronization_println/raspi3_boot/src/lib.rs similarity index 100% rename from 0F_global_println/raspi3_boot/src/lib.rs rename to 0F_globals_synchronization_println/raspi3_boot/src/lib.rs diff --git a/0F_global_println/src/delays.rs b/0F_globals_synchronization_println/src/delays.rs similarity index 100% rename from 0F_global_println/src/delays.rs rename to 0F_globals_synchronization_println/src/delays.rs diff --git a/0F_global_println/src/devices.rs b/0F_globals_synchronization_println/src/devices.rs similarity index 100% rename from 0F_global_println/src/devices.rs rename to 0F_globals_synchronization_println/src/devices.rs diff --git a/0F_global_println/src/devices/hw.rs b/0F_globals_synchronization_println/src/devices/hw.rs similarity index 100% rename from 0F_global_println/src/devices/hw.rs rename to 0F_globals_synchronization_println/src/devices/hw.rs diff --git a/0F_global_println/src/devices/hw/gpio.rs b/0F_globals_synchronization_println/src/devices/hw/gpio.rs similarity index 100% rename from 0F_global_println/src/devices/hw/gpio.rs rename to 0F_globals_synchronization_println/src/devices/hw/gpio.rs diff --git a/0F_global_println/src/devices/hw/uart.rs b/0F_globals_synchronization_println/src/devices/hw/uart.rs similarity index 100% rename from 0F_global_println/src/devices/hw/uart.rs rename to 0F_globals_synchronization_println/src/devices/hw/uart.rs diff --git a/0F_global_println/src/devices/hw/videocore_mbox.rs b/0F_globals_synchronization_println/src/devices/hw/videocore_mbox.rs similarity index 100% rename from 0F_global_println/src/devices/hw/videocore_mbox.rs rename to 0F_globals_synchronization_println/src/devices/hw/videocore_mbox.rs diff --git a/0F_global_println/src/devices/virt.rs b/0F_globals_synchronization_println/src/devices/virt.rs similarity index 100% rename from 0F_global_println/src/devices/virt.rs rename to 0F_globals_synchronization_println/src/devices/virt.rs diff --git a/0F_global_println/src/devices/virt/console.rs b/0F_globals_synchronization_println/src/devices/virt/console.rs similarity index 100% rename from 0F_global_println/src/devices/virt/console.rs rename to 0F_globals_synchronization_println/src/devices/virt/console.rs diff --git a/0F_global_println/src/macros.rs b/0F_globals_synchronization_println/src/macros.rs similarity index 100% rename from 0F_global_println/src/macros.rs rename to 0F_globals_synchronization_println/src/macros.rs diff --git a/0F_global_println/src/main.rs b/0F_globals_synchronization_println/src/main.rs similarity index 100% rename from 0F_global_println/src/main.rs rename to 0F_globals_synchronization_println/src/main.rs diff --git a/0F_global_println/src/memory.rs b/0F_globals_synchronization_println/src/memory.rs similarity index 100% rename from 0F_global_println/src/memory.rs rename to 0F_globals_synchronization_println/src/memory.rs diff --git a/0F_global_println/src/memory/mmu.rs b/0F_globals_synchronization_println/src/memory/mmu.rs similarity index 100% rename from 0F_global_println/src/memory/mmu.rs rename to 0F_globals_synchronization_println/src/memory/mmu.rs diff --git a/0F_global_println/src/sync.rs b/0F_globals_synchronization_println/src/sync.rs similarity index 73% rename from 0F_global_println/src/sync.rs rename to 0F_globals_synchronization_println/src/sync.rs index 55a45e31..3cbc1714 100644 --- a/0F_global_println/src/sync.rs +++ b/0F_globals_synchronization_println/src/sync.rs @@ -28,17 +28,6 @@ pub struct NullLock { data: UnsafeCell, } -// Since we are instantiating this struct as a static variable, which could -// potentially be shared between different threads, we need to tell the compiler -// that sharing of this struct is safe by marking it with the Sync trait. -// -// At this point in time, we can do so without worrying, because the kernel -// anyways runs on a single core and interrupts are disabled. In short, multiple -// threads don't exist yet in our code. -// -// Literature: -// https://doc.rust-lang.org/beta/nomicon/send-and-sync.html -// https://doc.rust-lang.org/book/ch16-04-extensible-concurrency-sync-and-send.html unsafe impl Sync for NullLock {} impl NullLock { @@ -55,8 +44,8 @@ impl NullLock { F: FnOnce(&mut T) -> R, { // In a real lock, there would be code around this line that ensures - // that this mutable reference will ever only be given out to one thread - // at a time. + // that this mutable reference will ever only be given out one at a + // time. f(unsafe { &mut *self.data.get() }) } } diff --git a/10_DMA_memory/src/sync.rs b/10_DMA_memory/src/sync.rs index 55a45e31..3cbc1714 100644 --- a/10_DMA_memory/src/sync.rs +++ b/10_DMA_memory/src/sync.rs @@ -28,17 +28,6 @@ pub struct NullLock { data: UnsafeCell, } -// Since we are instantiating this struct as a static variable, which could -// potentially be shared between different threads, we need to tell the compiler -// that sharing of this struct is safe by marking it with the Sync trait. -// -// At this point in time, we can do so without worrying, because the kernel -// anyways runs on a single core and interrupts are disabled. In short, multiple -// threads don't exist yet in our code. -// -// Literature: -// https://doc.rust-lang.org/beta/nomicon/send-and-sync.html -// https://doc.rust-lang.org/book/ch16-04-extensible-concurrency-sync-and-send.html unsafe impl Sync for NullLock {} impl NullLock { @@ -55,8 +44,8 @@ impl NullLock { F: FnOnce(&mut T) -> R, { // In a real lock, there would be code around this line that ensures - // that this mutable reference will ever only be given out to one thread - // at a time. + // that this mutable reference will ever only be given out one at a + // time. f(unsafe { &mut *self.data.get() }) } } diff --git a/11_exceptions_groundwork/src/sync.rs b/11_exceptions_groundwork/src/sync.rs index 55a45e31..3cbc1714 100644 --- a/11_exceptions_groundwork/src/sync.rs +++ b/11_exceptions_groundwork/src/sync.rs @@ -28,17 +28,6 @@ pub struct NullLock { data: UnsafeCell, } -// Since we are instantiating this struct as a static variable, which could -// potentially be shared between different threads, we need to tell the compiler -// that sharing of this struct is safe by marking it with the Sync trait. -// -// At this point in time, we can do so without worrying, because the kernel -// anyways runs on a single core and interrupts are disabled. In short, multiple -// threads don't exist yet in our code. -// -// Literature: -// https://doc.rust-lang.org/beta/nomicon/send-and-sync.html -// https://doc.rust-lang.org/book/ch16-04-extensible-concurrency-sync-and-send.html unsafe impl Sync for NullLock {} impl NullLock { @@ -55,8 +44,8 @@ impl NullLock { F: FnOnce(&mut T) -> R, { // In a real lock, there would be code around this line that ensures - // that this mutable reference will ever only be given out to one thread - // at a time. + // that this mutable reference will ever only be given out one at a + // time. f(unsafe { &mut *self.data.get() }) } }