Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update some wording making reference to issues/RFCs #271

Merged
merged 2 commits into from
Jun 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# The Rustonomicon

#### The Dark Arts of Unsafe Rust
## The Dark Arts of Unsafe Rust

> THE KNOWLEDGE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF UNLEASHING INDESCRIBABLE HORRORS THAT
Expand Down
100 changes: 50 additions & 50 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,64 +3,64 @@
[Introduction](README.md)

* [Meet Safe and Unsafe](meet-safe-and-unsafe.md)
* [How Safe and Unsafe Interact](safe-unsafe-meaning.md)
* [What Unsafe Can Do](what-unsafe-does.md)
* [Working with Unsafe](working-with-unsafe.md)
* [How Safe and Unsafe Interact](safe-unsafe-meaning.md)
* [What Unsafe Can Do](what-unsafe-does.md)
* [Working with Unsafe](working-with-unsafe.md)
* [Data Layout](data.md)
* [repr(Rust)](repr-rust.md)
* [Exotically Sized Types](exotic-sizes.md)
* [Other reprs](other-reprs.md)
* [repr(Rust)](repr-rust.md)
* [Exotically Sized Types](exotic-sizes.md)
* [Other reprs](other-reprs.md)
* [Ownership](ownership.md)
* [References](references.md)
* [Aliasing](aliasing.md)
* [Lifetimes](lifetimes.md)
* [Limits of Lifetimes](lifetime-mismatch.md)
* [Lifetime Elision](lifetime-elision.md)
* [Unbounded Lifetimes](unbounded-lifetimes.md)
* [Higher-Rank Trait Bounds](hrtb.md)
* [Subtyping and Variance](subtyping.md)
* [Drop Check](dropck.md)
* [PhantomData](phantom-data.md)
* [Splitting Borrows](borrow-splitting.md)
* [References](references.md)
* [Aliasing](aliasing.md)
* [Lifetimes](lifetimes.md)
* [Limits of Lifetimes](lifetime-mismatch.md)
* [Lifetime Elision](lifetime-elision.md)
* [Unbounded Lifetimes](unbounded-lifetimes.md)
* [Higher-Rank Trait Bounds](hrtb.md)
* [Subtyping and Variance](subtyping.md)
* [Drop Check](dropck.md)
* [PhantomData](phantom-data.md)
* [Splitting Borrows](borrow-splitting.md)
* [Type Conversions](conversions.md)
* [Coercions](coercions.md)
* [The Dot Operator](dot-operator.md)
* [Casts](casts.md)
* [Transmutes](transmutes.md)
* [Coercions](coercions.md)
* [The Dot Operator](dot-operator.md)
* [Casts](casts.md)
* [Transmutes](transmutes.md)
* [Uninitialized Memory](uninitialized.md)
* [Checked](checked-uninit.md)
* [Drop Flags](drop-flags.md)
* [Unchecked](unchecked-uninit.md)
* [Checked](checked-uninit.md)
* [Drop Flags](drop-flags.md)
* [Unchecked](unchecked-uninit.md)
* [Ownership Based Resource Management](obrm.md)
* [Constructors](constructors.md)
* [Destructors](destructors.md)
* [Leaking](leaking.md)
* [Constructors](constructors.md)
* [Destructors](destructors.md)
* [Leaking](leaking.md)
* [Unwinding](unwinding.md)
* [Exception Safety](exception-safety.md)
* [Poisoning](poisoning.md)
* [Exception Safety](exception-safety.md)
* [Poisoning](poisoning.md)
* [Concurrency](concurrency.md)
* [Races](races.md)
* [Send and Sync](send-and-sync.md)
* [Atomics](atomics.md)
* [Races](races.md)
* [Send and Sync](send-and-sync.md)
* [Atomics](atomics.md)
* [Implementing Vec](vec.md)
* [Layout](vec-layout.md)
* [Allocating](vec-alloc.md)
* [Push and Pop](vec-push-pop.md)
* [Deallocating](vec-dealloc.md)
* [Deref](vec-deref.md)
* [Insert and Remove](vec-insert-remove.md)
* [IntoIter](vec-into-iter.md)
* [RawVec](vec-raw.md)
* [Drain](vec-drain.md)
* [Handling Zero-Sized Types](vec-zsts.md)
* [Final Code](vec-final.md)
* [Layout](vec-layout.md)
* [Allocating](vec-alloc.md)
* [Push and Pop](vec-push-pop.md)
* [Deallocating](vec-dealloc.md)
* [Deref](vec-deref.md)
* [Insert and Remove](vec-insert-remove.md)
* [IntoIter](vec-into-iter.md)
* [RawVec](vec-raw.md)
* [Drain](vec-drain.md)
* [Handling Zero-Sized Types](vec-zsts.md)
* [Final Code](vec-final.md)
* [Implementing Arc and Mutex](arc-and-mutex.md)
* [Arc](arc.md)
* [Layout](arc-layout.md)
* [Base Code](arc-base.md)
* [Cloning](arc-clone.md)
* [Dropping](arc-drop.md)
* [Final Code](arc-final.md)
* [Arc](arc.md)
* [Layout](arc-layout.md)
* [Base Code](arc-base.md)
* [Cloning](arc-clone.md)
* [Dropping](arc-drop.md)
* [Final Code](arc-final.md)
* [FFI](ffi.md)
* [Beneath `std`](beneath-std.md)
* [#[panic_handler]](panic-handler.md)
* [#[panic_handler]](panic-handler.md)
8 changes: 1 addition & 7 deletions src/aliasing.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@ don't happen unless you tell it otherwise. For more details, see the
With that said, here's our working definition: variables and pointers *alias*
if they refer to overlapping regions of memory.




# Why Aliasing Matters
## Why Aliasing Matters

So why should we care about aliasing?

Expand Down Expand Up @@ -130,6 +127,3 @@ Of course, a full aliasing model for Rust must also take into consideration thin
function calls (which may mutate things we don't see), raw pointers (which have
no aliasing requirements on their own), and UnsafeCell (which lets the referent
of an `&` be mutated).



10 changes: 9 additions & 1 deletion src/arc-clone.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@
Now that we've got some basic code set up, we'll need a way to clone the `Arc`.

Basically, we need to:

1. Increment the atomic reference count
2. Construct a new instance of the `Arc` from the inner pointer

First, we need to get access to the `ArcInner`:

```rust,ignore
let inner = unsafe { self.ptr.as_ref() };
```

We can update the atomic reference count as follows:

```rust,ignore
let old_rc = inner.rc.fetch_add(1, Ordering::???);
```
Expand All @@ -26,11 +29,13 @@ is described more in [the section on the `Drop` implementation for
ordering, see [the section on atomics](atomics.md).

Thus, the code becomes this:

```rust,ignore
let old_rc = inner.rc.fetch_add(1, Ordering::Relaxed);
```

We'll need to add another import to use `Ordering`:

```rust,ignore
use std::sync::atomic::Ordering;
```
Expand All @@ -54,14 +59,16 @@ probably incredibly degenerate) if the reference count reaches `isize::MAX`
probably not about 2 billion threads (or about **9 quintillion** on some 64-bit
machines) incrementing the reference count at once. This is what we'll do.

It's pretty simple to implement this behaviour:
It's pretty simple to implement this behavior:

```rust,ignore
if old_rc >= isize::MAX as usize {
std::process::abort();
}
```

Then, we need to return a new instance of the `Arc`:

```rust,ignore
Self {
ptr: self.ptr,
Expand All @@ -70,6 +77,7 @@ Self {
```

Now, let's wrap this all up inside the `Clone` implementation:

```rust,ignore
use std::sync::atomic::Ordering;

Expand Down
10 changes: 8 additions & 2 deletions src/arc-drop.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ low enough, otherwise the data will live forever on the heap.
To do this, we can implement `Drop`.

Basically, we need to:

1. Decrement the reference count
2. If there is only one reference remaining to the data, then:
3. Atomically fence the data to prevent reordering of the use and deletion of
the data
4. Drop the inner data
4. Drop the inner data

First, we'll need to get access to the `ArcInner`:

```rust,ignore
let inner = unsafe { self.ptr.as_ref() };
```
Expand All @@ -21,6 +23,7 @@ Now, we need to decrement the reference count. To streamline our code, we can
also return if the returned value from `fetch_sub` (the value of the reference
count before decrementing it) is not equal to `1` (which happens when we are not
the last reference to the data).

```rust,ignore
if inner.rc.fetch_sub(1, Ordering::Relaxed) != 1 {
return;
Expand Down Expand Up @@ -53,17 +56,19 @@ implementation of `Arc`][3]:
> Also note that the Acquire fence here could probably be replaced with an
> Acquire load, which could improve performance in highly-contended situations.
> See [2].
>
>
> [1]: https://www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html
> [2]: https://github.com/rust-lang/rust/pull/41714
[3]: https://github.com/rust-lang/rust/blob/e1884a8e3c3e813aada8254edfa120e85bf5ffca/library/alloc/src/sync.rs#L1440-L1467

To do this, we do the following:

```rust,ignore
atomic::fence(Ordering::Acquire);
```

We'll need to import `std::sync::atomic` itself:

```rust,ignore
use std::sync::atomic;
```
Expand All @@ -80,6 +85,7 @@ This is safe as we know we have the last pointer to the `ArcInner` and that its
pointer is valid.

Now, let's wrap this all up inside the `Drop` implementation:

```rust,ignore
impl<T> Drop for Arc<T> {
fn drop(&mut self) {
Expand Down
1 change: 1 addition & 0 deletions src/arc-final.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Final Code

Here's the final code, with some added comments and re-ordered imports:

```rust
use std::marker::PhantomData;
use std::ops::Deref;
Expand Down
3 changes: 3 additions & 0 deletions src/arc-layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pointer to the T's allocation, we might as well put the reference count in that
same allocation.

Naively, it would look something like this:

```rust,ignore
use std::sync::atomic;

Expand All @@ -45,6 +46,7 @@ all the details on variance and drop check.

To fix the first problem, we can use `NonNull<T>`. Note that `NonNull<T>` is a
wrapper around a raw pointer that declares that:

* We are variant over `T`
* Our pointer is never null

Expand All @@ -53,6 +55,7 @@ To fix the second problem, we can include a `PhantomData` marker containing an
ownership of a value of `ArcInner<T>` (which itself contains some `T`).

With these changes we get our final structure:

```rust,ignore
use std::marker::PhantomData;
use std::ptr::NonNull;
Expand Down
38 changes: 8 additions & 30 deletions src/atomics.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,7 @@ semantics we want, the optimizations compilers want, and the inconsistent chaos
our hardware wants. *We* would like to just write programs and have them do
exactly what we said but, you know, fast. Wouldn't that be great?




# Compiler Reordering
## Compiler Reordering

Compilers fundamentally want to be able to do all sorts of complicated
transformations to reduce data dependencies and eliminate dead code. In
Expand Down Expand Up @@ -54,10 +51,7 @@ able to make these kinds of optimizations, because they can seriously improve
performance. On the other hand, we'd also like to be able to depend on our
program *doing the thing we said*.




# Hardware Reordering
## Hardware Reordering

On the other hand, even if the compiler totally understood what we wanted and
respected our wishes, our hardware might instead get us in trouble. Trouble
Expand Down Expand Up @@ -110,11 +104,7 @@ programming:
incorrect. If possible, concurrent algorithms should be tested on
weakly-ordered hardware.





# Data Accesses
## Data Accesses

The C++ memory model attempts to bridge the gap by allowing us to talk about the
*causality* of our program. Generally, this is by establishing a *happens
Expand Down Expand Up @@ -156,9 +146,7 @@ propagated to other threads. The set of orderings Rust exposes are:
TODO: negative reasoning vs positive reasoning? TODO: "can't forget to
synchronize"



# Sequentially Consistent
## Sequentially Consistent

Sequentially Consistent is the most powerful of all, implying the restrictions
of all other orderings. Intuitively, a sequentially consistent operation
Expand All @@ -182,10 +170,7 @@ mechanically trivial to downgrade atomic operations to have a weaker
consistency later on. Just change `SeqCst` to `Relaxed` and you're done! Of
course, proving that this transformation is *correct* is a whole other matter.




# Acquire-Release
## Acquire-Release

Acquire and Release are largely intended to be paired. Their names hint at their
use case: they're perfectly suited for acquiring and releasing locks, and
Expand All @@ -200,8 +185,8 @@ reordered to occur before it.
When thread A releases a location in memory and then thread B subsequently
acquires *the same* location in memory, causality is established. Every write
(including non-atomic and relaxed atomic writes) that happened before A's
release will be observed by B after its acquisition. However no causality is
established with any other threads. Similarly, no causality is established
release will be observed by B after its acquisition. However no causality is
established with any other threads. Similarly, no causality is established
if A and B access *different* locations in memory.

Basic use of release-acquire is therefore simple: you acquire a location of
Expand Down Expand Up @@ -233,10 +218,7 @@ On strongly-ordered platforms most accesses have release or acquire semantics,
making release and acquire often totally free. This is not the case on
weakly-ordered platforms.




# Relaxed
## Relaxed

Relaxed accesses are the absolute weakest. They can be freely re-ordered and
provide no happens-before relationship. Still, relaxed operations are still
Expand All @@ -251,9 +233,5 @@ There's rarely a benefit in making an operation relaxed on strongly-ordered
platforms, since they usually provide release-acquire semantics anyway. However
relaxed operations can be cheaper on weakly-ordered platforms.





[C11-busted]: http://plv.mpi-sws.org/c11comp/popl15.pdf
[C++-model]: https://en.cppreference.com/w/cpp/atomic/memory_order
8 changes: 4 additions & 4 deletions src/beneath-std.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This section documents (or will document) features that are provided by the stan
that `#![no_std]` developers have to deal with (i.e. provide) to build `#![no_std]` binary crates. A
(likely incomplete) list of such features is shown below:

- #[lang = "eh_personality"]
- #[lang = "start"]
- #[lang = "termination"]
- #[panic_implementation]
- `#[lang = "eh_personality"]`
- `#[lang = "start"]`
- `#[lang = "termination"]`
- `#[panic_implementation]`
Loading