├── .gitignore
├── templates
└── .gitignore
├── content
├── _index.md
├── hello-world.md
├── en
│ └── understanding-atomics.md
└── entendendo-atomicos.md
├── static
├── favicon.ico
├── apple-icon.png
├── favicon-16x16.png
├── favicon-32x32.png
├── favicon-96x96.png
├── ms-icon-70x70.png
├── apple-icon-57x57.png
├── apple-icon-60x60.png
├── apple-icon-72x72.png
├── apple-icon-76x76.png
├── imgs
│ └── common
│ │ ├── logo.png
│ │ └── base_og_image.png
├── ms-icon-144x144.png
├── ms-icon-150x150.png
├── ms-icon-310x310.png
├── android-icon-36x36.png
├── android-icon-48x48.png
├── android-icon-72x72.png
├── android-icon-96x96.png
├── apple-icon-114x114.png
├── apple-icon-120x120.png
├── apple-icon-144x144.png
├── apple-icon-152x152.png
├── apple-icon-180x180.png
├── android-icon-144x144.png
├── android-icon-192x192.png
├── apple-icon-precomposed.png
├── browserconfig.xml
└── manifest.json
├── .gitmodules
├── README.md
├── .travis.yml
└── config.toml
/.gitignore:
--------------------------------------------------------------------------------
1 | public
--------------------------------------------------------------------------------
/templates/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/content/_index.md:
--------------------------------------------------------------------------------
1 | +++
2 | paginate_by = 5
3 | +++
--------------------------------------------------------------------------------
/static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/favicon.ico
--------------------------------------------------------------------------------
/static/apple-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/apple-icon.png
--------------------------------------------------------------------------------
/static/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/favicon-16x16.png
--------------------------------------------------------------------------------
/static/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/favicon-32x32.png
--------------------------------------------------------------------------------
/static/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/favicon-96x96.png
--------------------------------------------------------------------------------
/static/ms-icon-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/ms-icon-70x70.png
--------------------------------------------------------------------------------
/static/apple-icon-57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/apple-icon-57x57.png
--------------------------------------------------------------------------------
/static/apple-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/apple-icon-60x60.png
--------------------------------------------------------------------------------
/static/apple-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/apple-icon-72x72.png
--------------------------------------------------------------------------------
/static/apple-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/apple-icon-76x76.png
--------------------------------------------------------------------------------
/static/imgs/common/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/imgs/common/logo.png
--------------------------------------------------------------------------------
/static/ms-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/ms-icon-144x144.png
--------------------------------------------------------------------------------
/static/ms-icon-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/ms-icon-150x150.png
--------------------------------------------------------------------------------
/static/ms-icon-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/ms-icon-310x310.png
--------------------------------------------------------------------------------
/static/android-icon-36x36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/android-icon-36x36.png
--------------------------------------------------------------------------------
/static/android-icon-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/android-icon-48x48.png
--------------------------------------------------------------------------------
/static/android-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/android-icon-72x72.png
--------------------------------------------------------------------------------
/static/android-icon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/android-icon-96x96.png
--------------------------------------------------------------------------------
/static/apple-icon-114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/apple-icon-114x114.png
--------------------------------------------------------------------------------
/static/apple-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/apple-icon-120x120.png
--------------------------------------------------------------------------------
/static/apple-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/apple-icon-144x144.png
--------------------------------------------------------------------------------
/static/apple-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/apple-icon-152x152.png
--------------------------------------------------------------------------------
/static/apple-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/apple-icon-180x180.png
--------------------------------------------------------------------------------
/static/android-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/android-icon-144x144.png
--------------------------------------------------------------------------------
/static/android-icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/android-icon-192x192.png
--------------------------------------------------------------------------------
/static/apple-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/apple-icon-precomposed.png
--------------------------------------------------------------------------------
/static/imgs/common/base_og_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-br/blog/HEAD/static/imgs/common/base_og_image.png
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "themes/dinkleberg"]
2 | path = themes/dinkleberg
3 | url = https://github.com/rust-br/dinkleberg.git
4 |
--------------------------------------------------------------------------------
/static/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 | #ffffff
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RustBR Blog
2 | Repositório oficial do Blog da Comudidade Rust BR :D
3 |
4 | ## Contribuindo
5 | Se deseja contribuir como o layout, o tema utilizado foi desenvolvido pela própria comunidade e pode ser acessado [clicando aqui](https://github.com/rust-br/dinkleberg)
6 |
7 | Caso deseje escrever uma publicação sugerimos que leia o [essa postagem](https://rust-br.github.io/blog/hello-world/) no nosso blog.
8 |
--------------------------------------------------------------------------------
/static/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "App",
3 | "icons": [
4 | {
5 | "src": "\/android-icon-36x36.png",
6 | "sizes": "36x36",
7 | "type": "image\/png",
8 | "density": "0.75"
9 | },
10 | {
11 | "src": "\/android-icon-48x48.png",
12 | "sizes": "48x48",
13 | "type": "image\/png",
14 | "density": "1.0"
15 | },
16 | {
17 | "src": "\/android-icon-72x72.png",
18 | "sizes": "72x72",
19 | "type": "image\/png",
20 | "density": "1.5"
21 | },
22 | {
23 | "src": "\/android-icon-96x96.png",
24 | "sizes": "96x96",
25 | "type": "image\/png",
26 | "density": "2.0"
27 | },
28 | {
29 | "src": "\/android-icon-144x144.png",
30 | "sizes": "144x144",
31 | "type": "image\/png",
32 | "density": "3.0"
33 | },
34 | {
35 | "src": "\/android-icon-192x192.png",
36 | "sizes": "192x192",
37 | "type": "image\/png",
38 | "density": "4.0"
39 | }
40 | ]
41 | }
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | before_script:
2 | - curl -s -L https://github.com/Keats/gutenberg/releases/download/v0.3.1/gutenberg-v0.3.1-x86_64-unknown-linux-gnu.tar.gz | sudo tar xvzf - -C /usr/local/bin
3 | script:
4 | - gutenberg build
5 | deploy:
6 | provider: pages
7 | skip-cleanup: true
8 | github-token:
9 | secure: Oufj4oNvtFr98ny/dpoar4+ObCTjYGbh2smZ5EUMz4dL9qodCsg2+IIbcMwwWGGydAH5XjG4syEzeyxsquRlD0B0E75NTPzKUyqAZ8hom0wnyPDuwPcGOxOgYvPW7Dxo9kJO6kreyXZKmGg9rMOyEGKGyYcSJqk5EXHkFpuc79Jx+99A3zvarB+QAUvAADevTNYb5nFpUV3DCV1E5X3dVy0fNv7gyBU83GzrXAxlwfFXCwbf9PIEEhxSnyzD6EPt/EgUn9RLJyazwgY1uu1VsQ5/Q4hov3EiKRYtWpjAcgvLM1O4phTngXogQg+BYwXaSvaqSwh6FwlkXar2z47sqi3ej8it99v1NawCGP3Z233OeqdISKawhFjUwh1p6iuDy1hma1qGwLgCh0aapfgi09Obbp1XqhJGD2U0CCDIvxOKk+Hy0om1w74PpD2XJWv3vWddGBwLCz/F7gtuaIZCbohWaozW21gPvNGwCPH1oIvE+gH3GPac7/jzz2MCaAGsJZGgeFhY9YWIgET+g7QtlHeDLFlvQfNNWgnbbROHQkJg1I0P36Nbec5T6kQcMyAIaHGEBW/wNtxrdYnreT038do7LF4er8Oz9KrIf9vKNDFF7UV/yKbosff6rJZapXipleX/icjgMsNL//Gt5W2scpk02p6x3FvL1zy5Yn4GTa0=
10 | keep-history: true
11 | local-dir: public
12 | on:
13 | branch: master
14 |
--------------------------------------------------------------------------------
/config.toml:
--------------------------------------------------------------------------------
1 | base_url = "https://rust-br.github.io/blog"
2 |
3 | # RSS
4 | title = "Rust Brasil: Dividindo conhecimento sobre a linguagem Rust"
5 | description = "Um blog com conteúdo focado no público brasileiro escrito, grande parte, em português sobre a linguagem de programção Rust"
6 | default_language = "pt"
7 |
8 | theme = "dinkleberg"
9 | compile_sass = true
10 |
11 | highlight_code = true
12 | highlight_theme = "gruvbox-dark"
13 |
14 | generate_tags_pages = true
15 | generate_categories_pages = true
16 |
17 | [extra]
18 | blog_logo = "/imgs/common/logo.png"
19 | blog_title="rust::brasil::Blog"
20 | label_tags = "Tags"
21 | label_tag = "Tag"
22 | label_categories = "Categorias"
23 | label_category = "Categoria"
24 | label_relative_posts = "Postagens Relacionadas"
25 | label_next = "Próxima"
26 | label_previous = "Anterior"
27 | label_page = "Página"
28 | label_of = "de"
29 |
30 | og_image="https://rust-br.github.io/blog/imgs/common/base_og_image.png"
31 | og_alt_image="Rust Brasil Blog"
32 | og_site_name="Rust Brasil Blog"
33 | keywords="Rust, Lang, Language, Linguagem de Programação, Desenvolvimento, Brazil, Brasil"
34 |
35 | educational_use="knowledge share"
36 | copyright_year="2018"
37 |
38 | sidebar = [
39 | {name = "Social", urls=[
40 | {name="Telegram", url="https://t.me/rustlangbr"},
41 | {name="Github", url="https://github.com/rust-br"},
42 | ]},
43 | {name = "Divida Conhecimento!", urls=[
44 | {name="Contribuir!", url="https://rust-br.github.io/blog/hello-world"}
45 | ]}
46 | ]
47 |
--------------------------------------------------------------------------------
/content/hello-world.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "println!(\"Hello World!\")"
3 | description = "Blog, como nasceu, onde está, como vive. Hoje no Rust Brasil"
4 | date=2018-05-28
5 | category = "Apresentação"
6 | tags = ["amigavel a iniciantes", "introdução", "gutenberg"]
7 |
8 | [extra]
9 | author="Guilherme Diego"
10 | +++
11 |
12 | Olá, me chamo Guilherme Diego e sou muitas coisas nessa vida e uma delas é ser entusiasta de coisas que em meu ponto de vista são boas, e esse foi o meu caso com RUST. Desde que comecei minha jornada pelo maravilhoso mundo de rust, eu tenho recebido ajuda da incrível comunidade que é a Rust Brasil pelo [telegram](https://t.me/rustlangbr), e já não é recente o assunto de: *"Devíamos criar um blog"*. Eu sou *front-end* já fazem quase 6 anos, e me responsabilizei por erguer os templates e tomar a frente de organizar o blog junto com outras pessoas que queriam dividir conhecimentos. O que nos faz chegar ao motivo dessa postagem: Introduzir como o Blog foi feito e como contribuir para ele.
13 |
14 | ## Gutenberg (ou Dinkleberg)
15 | Quando iniciamos nossas discussões para o que usaríamos para erguer o blog estático no Github, e optamos pelo [**Gutenberg**](https://www.getgutenberg.io/), uma alternativa a grandes nomes como Hugo, Jenkyll e Cobalt, porem, escrito em Rust <3. Gutenberg tem uma mecânica muito simples, ele é composto por 4 pastas:
16 |
17 | - **content**: Onde fica as páginas
18 | - **templates**: Onde fica os *templates* a serem rendenizados
19 | - **sass**: Onde fica os estilos em `scss`
20 | - **themes** Onde fica os temas
21 |
22 | Por incrível que pareça, um tema nada mais é que um site Gutenberg sobrescrito por informações de outro site Gutenberg! Bruxaria? Talvez! Logo foi dado início a um tema do zero para o nosso Blog. Logo a primeira vez que ouvi o nome da ferramenta, eu um amante de padrinhos mágicos, já cerrei meus olhos e disse lentamente: "Dinkleberg", acabamos aderindo em `alias`, até que eu batizei o tema que escrevemos como:
23 |
24 | 
25 |
26 | Logo, caso sinta vontade de contribuir com o tema você pode achar ele [aqui](https://github.com/rust-br/dinkleberg). Se você deseja publicar algo irei agora explicar como publicar.
27 |
28 | ## Contribuindo
29 | Existem dois jeitos de contribuir: MANUALMENTE pelo seu computador, ou direto pelo Github. Irei mostrar ambas!
30 |
31 | ### Manualmente
32 | - Faça um fork do repositório do blog: [https://github.com/rust-br/blog](https://github.com/rust-br/blog)
33 | - Clone ele na sua maquina
34 | - Entre na pasta
35 | - `git submodule init`
36 | - `git submodule update`
37 | - Crie um arquivo na raiz do `/content` com o `slug` do seu artigo, exemplo: `borrow-checker-para-iniciantes.md`
38 | - Escreva / commit / push
39 | - Abra um pull request para o master go rust-br/blog
40 |
41 | OBS: Caso queira rodar local, instale o [gutenberg]() e rode `gutenberg --config config.toml serve`
42 |
43 | ### Pelo Github
44 | - Faça um fork do repositório do blog: [https://github.com/rust-br/blog](https://github.com/rust-br/blog)
45 | - Crie um branch
46 | -
47 | - Pelo próprio github acesse a pasta content, e clique em (Create new file / Criar novo arquivo no canto superior direito)
48 | -
49 | - Escreva seu post e commit
50 | -
51 | - abra um pull request para o master go rust-br/blog
52 |
53 | OBS: É possível editar os arquivos pelo github! Uma vez que eles estejam na pasta `/content`, basta clicar no arquivo que deseja editar e posteriormente no lápis no canto superior direito
54 |
55 |
56 | ## Boas Práticas
57 | É necessário que se siga boas práticas para que o post tenha o resultado necessário, algumas informações são obrigatórias quando criar o post!
58 |
59 | ### Cabeçalho
60 |
61 | ```markdown
62 | +++
63 | title = "println!(\"Hello World!\")" # TITULO DO POST
64 | description = "Blog, como nasceu, onde está, como vive. Hoje no Rust Brasil" # DESCRIÇÃO DO POST
65 | date=2018-05-28 # DATA DE PUBLICAÇÃO
66 | category = "Apresentação" # Categoria da publicação
67 | tags = ["amigável a iniciantes", "introdução", "gutenberg"] # Tags relacionadas
68 |
69 | [extra]
70 | author="Guilherme Diego" # Nome do autor (mantenha o padrão entre suas postagens :D)
71 | updated_date=2018-05-29 # Data que você editou o post
72 | +++
73 | ```
74 |
75 | O **updated_date** é o único parâmetro NÃO OBRIGATÓRIO do header! Posts sem os requisitos serão negados. Você pode pedir ajuda a qualquer momento para encaixar seu post em uma **Categoria** e colocar as **Tags** nela, estaremos sempre dispostos a ajudar.
76 |
77 | ### Branch
78 | É recomendado que use a nomenclatura `post/nome-do-meu-post` quando for inserir um novo post no blog e `repost/nome-do-meu-post` quando for atualizar um post. Em caso de atualização de tema ou ajuste em templates ou outras coisas use a nomenclatura `fix/resumo-do-que-fez`
79 |
80 | ### Português Por Favor
81 | Somos um blog brasileiro, logo, é **OBRIGATÓRIO** que o post seja em português, caso queira postar uma versão em inglês você pode estar traduzindo e postando seu post dentro da pasta `/en/nome-do-seu-post-em-inglês`, e adicionando ele nos `relative_posts` do seu cabeçalho:
82 |
83 | ```markdown
84 | +++
85 | relative_posts=[
86 | {label="Postagem em Inglês", url="/en/nome-do-seu-post-em-inglês"}
87 | ]
88 | +++
89 | ```
90 |
91 | ## Conclusão
92 | Dividir conhecimento é uma das melhores maneiras de aprender e/ou aprimorar um conhecimento enquanto ajuda pessoas que ainda não portam o mesmo. Um blog, dentro de uma comunidade, é um passo importante para o fortalecimento e difusão de conhecimento dentro dela. Não esqueça de entrar no grupo de telegrama, opinar em posts abrindo ***issues*** no Github. Leia também os códigos de consulta, seguiremos ele dentro da comunidade e consecutivamente no blog:
93 |
94 | [https://www.rust-lang.org/pt-BR/conduct.html](https://www.rust-lang.org/pt-BR/conduct.html)
95 |
96 | Abraços e até a próxima!
97 |
--------------------------------------------------------------------------------
/content/en/understanding-atomics.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Understanding Atomics"
3 | description = "Explains the basic of atomics in Rust. Comes with a bonus: spinlock implementation."
4 | date = 2018-05-30
5 | tags = ["atomics"]
6 | category = "concurrency"
7 | [extra]
8 | relative_posts = [ {label="Post em português", url="/entendendo-atomicos"} ]
9 | author = "Bruno Corrêa Zimmermann"
10 | +++
11 |
12 | # Abstract
13 |
14 | In this post I will explain what are atomics and how to use them in rust.
15 |
16 |
17 | # "What is an 'atomic' anyway?"
18 |
19 | Atomics are data types on which operations are indivisible,
20 | or the indivisible operations by themselves. Indivisible here means that
21 | the side effects of the operations are only observable when the operation
22 | is done. Generally, machines provide read and write operations over its
23 | native integer both indivisible and divisible.
24 |
25 | If you have ever heard of "data races", divisible read and write causes them.
26 | Suppose we are on a 64-bit word machine. Threads `A`, `B` and `C` have
27 | access to address `p`. If `A` does a "divisible" write on `p` with `x`,
28 | at the same time `C` does a "divisible" read, `C` might get half of previous
29 | bits of `p` and half bits of `x`. Or a quarter of bits. Or the previous state.
30 | Or the new state. It's actualy hard to predict. If thread `A` writes
31 | "divisibily" again on `p` with `y` at the same time thread `B` writes
32 | "divisibily" `z`, the resulting value of `p` might be a mix of both states or
33 | something similar.
34 |
35 | Because the behavior might vary between different machines, programming
36 | languages such as Rust and C++ defines data races as undefined behavior. The
37 | actual behavior might not be "leaving an intermediate value", but it could
38 | be anything, from throwing an exception to setting the processor on fire.
39 | You probably noticed that the problem here are the "divisible" operations.
40 | If `A` had atomically written `x` on `p`, and `C` had atomically read from
41 | `p`, `C` would see the bits of `p` either before of `A`'s write or after the
42 | write, but not in the middle. The same apply for `A` and `B` writing
43 | atomically; the final state would be either `y` or `z`, but not anything else.
44 |
45 | There is also race condition. Race condition is similar to data race, but it
46 | can happen even with atomics. Race condition is about dependency between the
47 | order of asynchronous events, but it does not corrupt data. Race condition
48 | is what generally makes atomic data structures hard to be written. One should
49 | think carefully when writing atomic code.
50 |
51 | # Atomics in Rust
52 |
53 | Currently (rust nightly 1.28 and stable 1.26) these atomic data types were
54 | stabilized: `AtomicPtr`, `AtomicUsize`, `AtomicIsize` and `AtomicBool`.
55 | They are all located in `core::sync::atomic` (or `std::sync::atomic`).
56 | To explain, I will pick the simplest one: `AtomicBool`.
57 |
58 | ## `AtomicBool`
59 |
60 | It is very simple to create one:
61 |
62 | ```rust
63 | let atomic_bool = AtomicBool::new(true);
64 | ```
65 |
66 | Now let's make an atomic read. But wait... uh oh... `AtomicBool::load`
67 | accepts two arguments: an immutable reference to `self` and another
68 | argument of type `Ordering`. The reference to `self` is easily understandable
69 | but what about `Ordering`? `Ordering` is a type which determinates the...
70 | the... order? Yes, the order related to other operations and other threads.
71 | Let's see the definition of `Ordering`:
72 |
73 | ```rust
74 | pub enum Ordering {
75 | Relaxed,
76 | Release,
77 | Acquire,
78 | AcqRel,
79 | SeqCst,
80 | // some variants omitted
81 | }
82 | ```
83 |
84 | There are, roughly speaking, two kinds of CPUs related to orderings: the weak
85 | and the strong. The weak processors have naturally weak guarantees on the
86 | orderings, while the strong processors have naturally strong guarantees on the
87 | orderings. It is generally low-cost for strong-processors to perform `Acquire`,
88 | `Relase` and `AcqRel`, while they are high-cost for weak-processors. For all
89 | of them `Relaxed` is low-cost and `SeqCst` is high-cost. Examples of weak-
90 | processors are ARM-archs, and examples of strong-processors are the ones
91 | x86/x86_64-archs.
92 |
93 | The only valid variants for `load` to be called with are: `Relaxed`, `Acquire`
94 | and `SeqCst`. Don't worry, the other variants will be explained later. `Relaxed`
95 | is somewhat like "the order does not matter at all". This allows both
96 | the compiler and the CPU to reorder the operation. `SeqCst` means "sequentially
97 | consistent"; it should not be reordered at all! Everything before it happens
98 | before it, and everything after it happens after it.
99 |
100 | `Acquire` is a bit more complex. It is the "complement" of `Release`.
101 | Everything (generally `store`-like operations) that happens after the `Acquire`
102 | stays after it. But the compiler and the CPU are free to reorder anything that
103 | happens before it. It is designed to be used with `load`-like operations when
104 | acquiring locks.
105 |
106 | Let's see an example with `AtomicBool::load`:
107 |
108 | ```rust
109 | use std::sync::atomic::{
110 | AtomicBool,
111 | Ordering::*,
112 | };
113 |
114 | fn print_if_it_is(atomic: &AtomicBool) {
115 | if atomic.load(Acquire) {
116 | println!("It is!");
117 | }
118 | }
119 | ```
120 |
121 | Let's jump into the next operation: `store`. `store` accepts a reference to
122 | `self`, the new value (of type `bool`), and an `Ordering`. The valid
123 | `Ordering`s are `Relaxed`, `Release` and `SeqCst`. `Release`, as said before,
124 | is used as a pair with `Acquire`. Everything before `Release` happens before
125 | it, but the compiler and the CPU are free to reorder anything that happens
126 | after it. It is intended to be used when releasing a lock.
127 |
128 | Let's see an example:
129 |
130 | ```rust
131 | use std::sync::atomic::{
132 | AtomicBool,
133 | Ordering::*,
134 | };
135 |
136 | fn store_something(atomic: &AtomicBool) {
137 | atomic.store(false, Release);
138 | }
139 | ```
140 |
141 | You may have noticed two things. If you did not notice them, do it now. First:
142 | `store` just needs an immutable reference. This means that it does not need
143 | "outer" mutability, but it has inner mutability. Second: atomics are only
144 | useful with shared references. They don't have anything like "`clone`"; to
145 | clone you can do somewhat `let copied = AtomicBool::new(src.load(Acquire));`.
146 | But this does not share the atomic. Therefore, it is a common pattern to
147 | encapsulate the atomic (or the struct which keeps the atomic) into an `Arc`.
148 |
149 | There are at least three more important operations `swap`, `compare_and_swap`,
150 | `compare_exchange_*`. Swap is pretty simple: it swaps its argument (of type
151 | `bool`) with the stored value, and returns the stored value. `Ordering` on
152 | swap accepts any of the `Ordering`s. `compare_and_swap` takes a `bool`, say,
153 | "current", another `bool`, say "new", and the `Ordering` (which can be any).
154 | `compare_and_swap` is a really important atomic operation. It compares the
155 | argument "current" with the stored value. If they are the same, the operation
156 | swaps the stored value with "new". In any case, the stored value is returned.
157 | The operation succeeds if the return value is equal to the "current" argument.
158 |
159 | There is also `compare_exchange_strong` (just `compare_exchange` in Rust), and
160 | `compare_exchange_weak` (which may fail more often). They are similar to
161 | `compare_and_swap`, except that they take two orderings: one for success, and
162 | one for failure. Also, in Rust they return a `Result`. The fact that these
163 | operations return a `Result` allows `compare_exchange_weak` to fail even if
164 | the comparison succeed. Important: success `Ordering` accepts the same
165 | `Ordering`s as a `swap`, but failure `Ordering` has to be weaker than success
166 | or equivalent, but valid for `load`.
167 |
168 | Wait! I did not explain `Ordering::AcqRel`. It is what it seems: it combines
169 | `Acquire` when loading and `Release` when storing for operations that
170 | load/store atomically. Although I explained all of these using `AtomicBool`,
171 | they are pretty much common primitive operations for all primitive atomic data
172 | types. All atomic data types in Rust have at least these operations: `load`,
173 | `store`, `swap`, `compare_and_swap`, `compare_exchange`,
174 | `compare_exchange_weak`. Enough of talk, let's act!
175 |
176 | ## Lock-free logical AND
177 |
178 | The function below receives an atomic boolean, an ordinary boolean, stores the
179 | logical AND of them and returns the previous value.
180 |
181 | ```rust
182 | use std::sync::atomic::{AtomicBool, Ordering::{*, self}};
183 |
184 | fn lockfree_and(x: &AtomicBool, y: bool, ord: Ordering) -> bool {
185 | let mut stored = x.load(match ord {
186 | AcqRel => Acquire,
187 | Release => Relaxed,
188 | o => o,
189 | });
190 | loop {
191 | let inner = x.compare_and_swap(stored, stored & y, ord);
192 | if inner == stored {
193 | break inner;
194 | }
195 | stored = inner;
196 | }
197 | }
198 | ```
199 |
200 | Note that side-effects are only visible after we're done. This is, in some way,
201 | "atomic". Generally, this kind of operation is called "lock-free" because it
202 | does not use any kind of lock. Although we have a loop, we do not depend on
203 | any thread "free-ing" the resource. This is not a lock.
204 |
205 | And, well... Rust already provides us a method `AtomicBool::fetch_and`, which
206 | probably is translated into a single native instruction. I just wanted to show
207 | you that with the primitives `load` and `compare_and_swap`, the operation can
208 | be implemented via software.
209 | [Take a look here](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicBool.html#method.fetch_and),
210 | we have other methods on `AtomicBool`, such as `nand`, `or`, and `xor`.
211 |
212 | As you may suspect, `AtomicUsize` and `AtomicIsize` have their own methods with
213 | basic arithmetic (add and sub) and bitwise. And all of them are implementable
214 | via software, but probably are implemented in such a way they are translated
215 | into a single native instruction. Although the API does not provide `mul` and
216 | `div`, it is not hard to implement them.
217 |
218 | ## A note on `AtomicPtr`
219 |
220 | `AtomicPtr` can be confusing. The methods `load` and `store` read and write
221 | the address or its content? The answer is: the address. They operate on `*mut T`.
222 | To load the contents is pretty much another operation, but it is not atomic and
223 | and it is very unsafe.
224 |
225 | ## `Send` and `Sync`
226 |
227 | You may have heard of the auto traits `Send` and `Sync`. They matter a lot in a
228 | concurrent environment. `T: Send` means `T` is safe to be sent to another
229 | thread. `T: Sync` means `&T` is safe to be shared between threads. Atomic data
230 | types implement both `Send` and `Sync`, so it is safe to share and send them
231 | among threads.
232 |
233 |
234 | ## Bonus: Implementing a spinlock
235 |
236 | ```rust
237 | pub mod spinlock {
238 | use std::{
239 | cell::UnsafeCell,
240 | fmt,
241 | ops::{Deref, DerefMut},
242 | sync::atomic::{
243 | AtomicBool,
244 | Ordering::*,
245 | },
246 | };
247 |
248 | #[derive(Debug)]
249 | pub struct Mutex {
250 | locked: AtomicBool,
251 | inner: UnsafeCell,
252 | }
253 |
254 | #[derive(Debug, Clone, Copy)]
255 | pub struct MutexErr;
256 |
257 | pub struct MutexGuard<'a, T>
258 | where
259 | T: 'a
260 | {
261 | mutex: &'a Mutex,
262 | }
263 |
264 | impl Mutex {
265 | pub fn new(data: T) -> Self {
266 | Self {
267 | locked: AtomicBool::new(false),
268 | inner: UnsafeCell::new(data),
269 | }
270 | }
271 |
272 | pub fn try_lock<'a>(&'a self) -> Result, MutexErr> {
273 | if self.locked.swap(true, Acquire) {
274 | Err(MutexErr)
275 | } else {
276 | Ok(MutexGuard {
277 | mutex: self,
278 | })
279 | }
280 | }
281 |
282 | pub fn lock<'a>(&'a self) -> MutexGuard<'a, T> {
283 | loop {
284 | if let Ok(m) = self.try_lock() {
285 | break m;
286 | }
287 | }
288 | }
289 | }
290 |
291 | unsafe impl Send for Mutex
292 | where
293 | T: Send,
294 | {
295 | }
296 |
297 | unsafe impl Sync for Mutex
298 | where
299 | T: Send,
300 | {
301 | }
302 |
303 | impl Drop for Mutex {
304 | fn drop(&mut self) {
305 | unsafe {
306 | self.inner.get().drop_in_place()
307 | }
308 | }
309 | }
310 |
311 | impl<'a, T> Deref for MutexGuard<'a, T> {
312 | type Target = T;
313 |
314 | fn deref(&self) -> &T {
315 | unsafe {
316 | &*self.mutex.inner.get()
317 | }
318 | }
319 | }
320 |
321 | impl<'a, T> DerefMut for MutexGuard<'a, T> {
322 | fn deref_mut(&mut self) -> &mut T {
323 | unsafe {
324 | &mut *self.mutex.inner.get()
325 | }
326 | }
327 | }
328 |
329 | impl<'a, T> fmt::Debug for MutexGuard<'a, T>
330 | where
331 | T: fmt::Debug,
332 | {
333 | fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
334 | write!(fmtr, "{:?}", &**self)
335 | }
336 | }
337 |
338 | impl<'a, T> Drop for MutexGuard<'a, T> {
339 | fn drop(&mut self) {
340 | let _prev = self.mutex.locked.swap(false, Release);
341 | debug_assert!(_prev);
342 | }
343 | }
344 |
345 | }
346 | ```
347 |
--------------------------------------------------------------------------------
/content/entendendo-atomicos.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Entendendo Atômicos"
3 | description = "Explica o básico de atômicos em Rust. Vem com um bônus: implementação de spinlock."
4 | date = 2018-05-30
5 | tags = ["atômicos"]
6 | category = "concorrência"
7 | [extra]
8 | relative_posts = [ {label="English post", url="/en/understanding-atomics"} ]
9 | author = "Bruno Corrêa Zimmermann"
10 | +++
11 |
12 | # Resumão
13 |
14 | Neste post, explicarei o que são atômicos e como usá-los em Rust.
15 |
16 | # "De qualquer forma, o que seria um 'atômico'?"
17 |
18 | Atômicos são tipos de dados com operações indivisíveis ou as próprias
19 | operações indivisíveis. Aqui, indivisível significa que os efeitos dessas
20 | operações só são observáveis quando a operação já acabou. Normalmente, as
21 | máquinas fornecem leitura e escrita tanto divisíveis quanto indivisíveis
22 | sobre os inteiros nativos.
23 |
24 | Se você já ouviu falar de "_data races_" (corrida de dados em tradução
25 | literal), saiba que leitura e escrita divisíveis causam-nas. Suponha uma
26 | máquina com palavra de 64 bits. Suponha _threads_ `A`, `B` e `C`, todas com
27 | acesso ao endereço `p`. Se `A` faz uma escrita "divisível" de `x` em `p` ao
28 | mesmo tempo em que `C` faz uma leitura "divisível", `C` pode ficar com metade
29 | dos bits anteriores de `p` e metade dos bits de `x`. Ou um quarto desses bits.
30 | Ou o estado anterior. Ou o novo estado. Na verdade, é difícil prever. Se
31 | a thread `A` escreve "divisivelmente" `y`, de novo em `p`, ao mesmo tempo em
32 | que a thread `B` escreve "divisivelmente" `z`, o resultado de `p` pode ser uma
33 | mistura de `y` e `z` ou algo similar.
34 |
35 | Pelo fato do comportamento variar em diferentes máquinas, as linguagens de
36 | programação como Rust e C++ definem _data races_ como comportamento indefinido
37 | (_undefined behavior_). O comportamento real pode não ser "deixar um estado
38 | intermediário", mas qualquer coisa, de "lançar uma exceção" até "incendiar o
39 | processador". Você provavelmente deve ter notado que o problema aqui são as
40 | operações "divisíveis". Se `A` tivesse escrito `x` em `p` atomicamente, e `C`
41 | tivesse lido de `p` também atomicamente, `C` veria os bits de `p` ou antes
42 | ou depois da escrita de `A`, mas nunca no meio. O mesmo se aplica à `A` e `B`
43 | escreverem atomicamente; o estado final seria ou `y` ou `z`, mas nada além disso.
44 |
45 | Há ainda a chamada "_race condition_" (condição de corrida). Condição de
46 | corrida é similar a _data race_, mas pode ocorrer até mesmo com atômicos.
47 | Race condition é sobre dependência da ordem de eventos assíncronos, mas
48 | não necessariamente corrompe dados. Condição de corrida é o que costuma
49 | tornar estruturas de dados atômicas difíceis de serem escritas. Você
50 | deve pensar com cuidado ao escrever código atômico.
51 |
52 | # Atômicos em Rust
53 |
54 | Atualmente (rust nightly 1.28 e stable 1.26) estes tipos de dados atômics
55 | foram estabilizados: `AtomicPtr`, `AtomicUsize`, `AtomicIsize` and
56 | `AtomicBool`. Eles se localizam em `core::sync::atomic` (ou
57 | `std::sync::atomic`). Para explicar, escolhi o mais simples: `AtomicBool`.
58 |
59 | ## `AtomicBool`
60 |
61 | É bastante simples criar um `AtomicBool`:
62 |
63 | ```rust
64 | let atomic_bool = AtomicBool::new(true);
65 | ```
66 |
67 | Agora, vamos fazer leitura atômica! Mas espere... opa... `AtomicBool::load`
68 | (carregar) aceita dois argumentos: uma referência imutável para `self` e um
69 | argumento do tipo `Ordering`. A referência para `self` acredito ser fácil de
70 | entender, mas e o `Ordering`? `Ordering` é um tipo que determina a... a...
71 | ordem? Sim, a ordem relacionada às outras operações e às outras _threads_.
72 | Veja abaixo a definição de `Ordering`:
73 |
74 | ```rust
75 | pub enum Ordering {
76 | Relaxed,
77 | Release,
78 | Acquire,
79 | AcqRel,
80 | SeqCst,
81 | // some variants omitted
82 | }
83 | ```
84 |
85 | Há, de modo ríspido, dois tipos de CPUs relacionados às ordens: os "fracos"
86 | e os "fortes". Os processadores "fracos" tem garantias naturalmente fracas a
87 | respeito das ordens, enquanto os processadores "fortes" tem garantias
88 | naturalmente fortes. Geralmente é de baixo custo para processadores "fortes"
89 | executarem `Acquire`, `Release` e `AcqRel`. Enquanto isso, é de alto custo para
90 | processadores "fracos" executarem estas ordens. Para todos eles, `Relaxed` é de
91 | baixo custo, e `SeqCst` é de alto custo. Exemplos de processadores "fracos" são
92 | os das arquiteturas ARM em geral e exemplos de "fortes" são os de arquiteturas
93 | x86/x86-64.
94 |
95 | As únicas variantes válidas para se passar a `load` são: `Relaxed`. `Acquire` e
96 | `SeqCst`. Não se preocupe, as outras variantes serão explicadas já já. `Relaxed`
97 | é algo como "a ordem não importa mesmo". Isso permite tanto o CPU quanto o
98 | compilador reordenarem a operação. `SeqCst` significa "sequencialmente
99 | consistente"; e não será reordenada de jeito nenhum: tudo antes da operação
100 | acontence antes, e tudo depois da operação acontece depois.
101 |
102 | `Acquire` é um pouco mais complexo. É o complementar de `Release`. Tudo
103 | (geralmente operações no estilo `store`) que acontecem depois de
104 | `Acquire` ficam depois de `Acquire`. Mas o compilador e o CPU são livres para
105 | reordenar tudo que ocorre antes de `Acquire`. Ele foi projetado para ser usado
106 | em operações do estilo `load` (carregar) ao adquir travas.
107 |
108 | Vejamos um exemplo com `AtomicBool::load`:
109 |
110 | ```rust
111 | use std::sync::atomic::{
112 | AtomicBool,
113 | Ordering::*,
114 | };
115 |
116 | fn print_if_it_is(atomic: &AtomicBool) {
117 | if atomic.load(Acquire) {
118 | println!("It is!");
119 | }
120 | }
121 | ```
122 |
123 | Agora vamos para a próxima operação: `store` (armazenar). `store` aceita uma
124 | referência para `self`, o novo valor (do tipo `bool`) e um `Ordering`. Os
125 | `Orderings`s válidos são `Relaxed`, `Release` e `SeqCst`. `Release`, como já
126 | mencionado, é usado junto a `Acquire` como um par. Tudo antes de um `Release`
127 | acontece antes dele, mas o CPU e o compilador são livres para reordenar tudo
128 | que há depois. A intenção é usá-lo ao soltar uma trava.
129 |
130 | Vejamos um exemplo:
131 |
132 | ```rust
133 | use std::sync::atomic::{
134 | AtomicBool,
135 | Ordering::*,
136 | };
137 |
138 | fn store_something(atomic: &AtomicBool) {
139 | atomic.store(false, Release);
140 | }
141 | ```
142 |
143 | Você pode ter percebido duas coisas. Se não as percebeu, perceba agora.
144 | Primeiro: `store` precisa de uma referencia apenas imutável. Isso significa que
145 | ele não precisa de uma mutabilidade "externa", mas o atômico tem mutabilidade
146 | interna. Segundo: atômicos só são úteis em referências compartilhadas. Eles não
147 | tem nada como `clone`; para clonar você pode fazer algo como
148 | `let copied = AtomicBool::new(src.load(Acquire));`. Mas isso não compartilha o
149 | atômico. Desse modo, é comum encapsular o atômico (ou a estrutura que mantém
150 | um) em um `Arc`.
151 |
152 | Há, pelo menos, outras três operações importantes: `swap`, `compare_and_swap`,
153 | `compare_exchange_*`. `swap` (troca) é bastante simples: troca o argumento
154 | (do tipo `bool`) com o valor armazenado, e retorna o valor armazenado. `swap`
155 | aceita qualquer `Ordering`. `compare_and_swap` aceita um `bool`, dito "atual",
156 | outro `bool`, dito "novo", e o `Ordering` (qualquer um é válido).
157 | `compare_and_swap` é uma operação atômica bastante importante. Ela compara o
158 | argumento "atual" com o valor armazenado. Caso eles sejam iguais, a operação
159 | troca o valor armazenado com o argumento "novo". De qualquer forma, o valor
160 | armazenado é retornado. A operação obteve sucesso se o valor retornado é
161 | igual ao argumento "atual".
162 |
163 | Há ainda `compare_exchange_strong` (apenas `compare_exchange` em Rust) e
164 | `compare_exchange_weak` (que pode falhar espontaneamente). Estas são similares
165 | a `compare_and_swap`, exceto pelo fato de que aceitam duas ordens: uma para
166 | o caso de sucesso e uma para o caso de falha. Além disso, em Rust elas retornam
167 | um `Result`. O fato delas retornarem um `Result` possibilita
168 | `compare_exchange_weak` falhar mesmo que a comparação seja um sucesso.
169 | Importante: a ordem de sucesso aceita as mesmas variantes que `swap`, mas a de
170 | falha tem de ser igual ou mais fraca do que a de sucesso, além de ser válida
171 | para um `load`.
172 |
173 | Calma aí! Eu não expliquei ainda `Ordering::AcqRel`. Ele é o que parece:
174 | combina `Acquire` ao carregar e `Release` ao armazenar, para operações que
175 | carregam e armazenam atomicamente. Apesar de eu ter explicado tudo isso
176 | usando `AtomicBool`, essas operações são bastante comuns entre tipos de
177 | dados atômicos primitivos. Todos os tipos de dados atômicos do Rust têm
178 | pelo menos estas operações: `load`, `store`, `swap`, `compare_and_swap`,
179 | `compare_exchange` e `compare_exchange_weak`. Enfim, chega de conversa.
180 | Vamos agir.
181 |
182 | ## "E" lógico livre de travas (lock-free)
183 |
184 | A função abaixo recebe um booleano atômico, um booleano normal, armazena
185 | o resultado de um "E" lógico entre eles, e retorna o valor anterior.
186 |
187 | ```rust
188 | use std::sync::atomic::{AtomicBool, Ordering::{*, self}};
189 |
190 | fn lockfree_and(x: &AtomicBool, y: bool, ord: Ordering) -> bool {
191 | let mut stored = x.load(match ord {
192 | AcqRel => Acquire,
193 | Release => Relaxed,
194 | o => o,
195 | });
196 | loop {
197 | let inner = x.compare_and_swap(stored, stored && y, ord);
198 | if inner == stored {
199 | break inner;
200 | }
201 | stored = inner;
202 | }
203 | }
204 | ```
205 |
206 | Note que os efeitos da operação só são visíveis após acabarmos. Ela é, de
207 | algum modo, "atômica". Geralmente, esse tipo de operação é chamada "lock-free"
208 | (livre de travas) porque ela não usa nenhuma forma de trava. Por mais que
209 | tenhamos um loop de tentativas, nós não dependemos de nenhuma _thread_
210 | liberando o recurso. Não é uma trava!
211 |
212 | E, bem... é... Rust já fornece um método `AtomicBool::fetch_and`
213 | ("buscar 'e'"), que provavelmente é compilado para uma única instrução nativa.
214 | Eu quis apenas mostrar que você pode implementá-lo com os primitivos `load` e
215 | `compare_and_swap` via _software_.
216 | [Dê uma olhada aqui](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicBool.html#method.fetch_and),
217 | temos outras operações em `AtomicBool`, tais como `nand` ("não 'e'"), `or`
218 | ("ou") e `xor` ("ou exclusivo").
219 |
220 | Como você deve suspeitar, `AtomicUsize` e `AtomicIsize` tem seus próprios
221 | métodos com aritmética básica (adição e subtração) e bits. Todos eles são
222 | implementáveis via software, mas provavelmente são implementados para compilar
223 | para uma única instrução nativa. Apesar de a API não fornecer multiplicação e
224 | divisão, não é difícil de implementá-las.
225 |
226 | ## Nota sobre `AtomicPtr`
227 |
228 | `AtomicPtr` pode ser confuso. Os métodos `load` e `store` leem e escrevem
229 | o endereço ou o conteúdo do endereço? A resposta é: o endereço. Eles operam
230 | sobre um `*mut T`. Carregar o conteúdo é outra operação, que não é atômica e
231 | é bastante _unsafe_.
232 |
233 | ## `Send` e `Sync`
234 |
235 | Você talves tenha ouvido falar das _auto trait_s `Send` e `Sync`. Elas são
236 | bastante importantes em ambientes concorrentes. `T: Send` significa que `T` é
237 | seguro de ser mandado para outra _thread_. `T: Sync` significa que `&T` é
238 | seguro de ser compartilhado entre _threads_. Tipos de dados atômicos
239 | implementam tanto `Send` quanto `Sync`, então é seguro mandar e compartilhar
240 | esses tipos com _threads_.
241 |
242 | ## Bônus: implementação de spinlock
243 |
244 | ```rust
245 | pub mod spinlock {
246 | use std::{
247 | cell::UnsafeCell,
248 | fmt,
249 | ops::{Deref, DerefMut},
250 | sync::atomic::{
251 | AtomicBool,
252 | Ordering::*,
253 | },
254 | };
255 |
256 | #[derive(Debug)]
257 | pub struct Mutex {
258 | locked: AtomicBool,
259 | inner: UnsafeCell,
260 | }
261 |
262 | #[derive(Debug, Clone, Copy)]
263 | pub struct MutexErr;
264 |
265 | pub struct MutexGuard<'a, T>
266 | where
267 | T: 'a
268 | {
269 | mutex: &'a Mutex,
270 | }
271 |
272 | impl Mutex {
273 | pub fn new(data: T) -> Self {
274 | Self {
275 | locked: AtomicBool::new(false),
276 | inner: UnsafeCell::new(data),
277 | }
278 | }
279 |
280 | pub fn try_lock<'a>(&'a self) -> Result, MutexErr> {
281 | if self.locked.swap(true, Acquire) {
282 | Err(MutexErr)
283 | } else {
284 | Ok(MutexGuard {
285 | mutex: self,
286 | })
287 | }
288 | }
289 |
290 | pub fn lock<'a>(&'a self) -> MutexGuard<'a, T> {
291 | loop {
292 | if let Ok(m) = self.try_lock() {
293 | break m;
294 | }
295 | }
296 | }
297 | }
298 |
299 | unsafe impl Send for Mutex
300 | where
301 | T: Send,
302 | {
303 | }
304 |
305 | unsafe impl Sync for Mutex
306 | where
307 | T: Send,
308 | {
309 | }
310 |
311 | impl Drop for Mutex {
312 | fn drop(&mut self) {
313 | unsafe {
314 | self.inner.get().drop_in_place()
315 | }
316 | }
317 | }
318 |
319 | impl<'a, T> Deref for MutexGuard<'a, T> {
320 | type Target = T;
321 |
322 | fn deref(&self) -> &T {
323 | unsafe {
324 | &*self.mutex.inner.get()
325 | }
326 | }
327 | }
328 |
329 | impl<'a, T> DerefMut for MutexGuard<'a, T> {
330 | fn deref_mut(&mut self) -> &mut T {
331 | unsafe {
332 | &mut *self.mutex.inner.get()
333 | }
334 | }
335 | }
336 |
337 | impl<'a, T> fmt::Debug for MutexGuard<'a, T>
338 | where
339 | T: fmt::Debug,
340 | {
341 | fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
342 | write!(fmtr, "{:?}", &**self)
343 | }
344 | }
345 |
346 | impl<'a, T> Drop for MutexGuard<'a, T> {
347 | fn drop(&mut self) {
348 | let _prev = self.mutex.locked.swap(false, Release);
349 | debug_assert!(_prev);
350 | }
351 | }
352 |
353 | }
354 | ```
355 |
--------------------------------------------------------------------------------