mirror of
https://github.com/phil-opp/blog_os.git
synced 2025-12-16 06:17:49 +00:00
[Fix][Translation][Portuguese pt-BR] fix broken anchors (edition-2)
This commit is contained in:
@@ -215,7 +215,7 @@ A convenção de chamada `x86-interrupt` é uma abstração poderosa que esconde
|
|||||||
Se você estiver interessado em mais detalhes, também temos uma série de postagens que explica a manipulação de exceção usando [funções nuas] vinculadas [no final desta postagem][too-much-magic].
|
Se você estiver interessado em mais detalhes, também temos uma série de postagens que explica a manipulação de exceção usando [funções nuas] vinculadas [no final desta postagem][too-much-magic].
|
||||||
|
|
||||||
[funções nuas]: https://github.com/rust-lang/rfcs/blob/master/text/1201-naked-fns.md
|
[funções nuas]: https://github.com/rust-lang/rfcs/blob/master/text/1201-naked-fns.md
|
||||||
[too-much-magic]: #muita-magia
|
[too-much-magic]: #muita-magica
|
||||||
|
|
||||||
## Implementação
|
## Implementação
|
||||||
Agora que entendemos a teoria, é hora de manipular exceções de CPU em nosso kernel. Começaremos criando um novo módulo interrupts em `src/interrupts.rs`, que primeiro cria uma função `init_idt` que cria uma nova `InterruptDescriptorTable`:
|
Agora que entendemos a teoria, é hora de manipular exceções de CPU em nosso kernel. Começaremos criando um novo módulo interrupts em `src/interrupts.rs`, que primeiro cria uma função `init_idt` que cria uma nova `InterruptDescriptorTable`:
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ Escolhemos criar uma função `init` separada em vez de realizar a inicializaç
|
|||||||
|
|
||||||
Como [explicado no post anterior][global-alloc], todos os alocadores heap precisam implementar a trait [`GlobalAlloc`], que é definida assim:
|
Como [explicado no post anterior][global-alloc], todos os alocadores heap precisam implementar a trait [`GlobalAlloc`], que é definida assim:
|
||||||
|
|
||||||
[global-alloc]: @/edition-2/posts/10-heap-allocation/index.md#the-allocator-interface
|
[global-alloc]: @/edition-2/posts/10-heap-allocation/index.pt-BR.md#a-interface-do-alocador
|
||||||
[`GlobalAlloc`]: https://doc.rust-lang.org/alloc/alloc/trait.GlobalAlloc.html
|
[`GlobalAlloc`]: https://doc.rust-lang.org/alloc/alloc/trait.GlobalAlloc.html
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
@@ -912,7 +912,7 @@ struct ListNode {
|
|||||||
|
|
||||||
Este tipo é similar ao tipo `ListNode` de nossa [implementação de alocador de lista encadeada], com a diferença de que não temos um campo `size`. Ele não é necessário porque cada bloco em uma lista tem o mesmo tamanho com o design de alocador de bloco de tamanho fixo.
|
Este tipo é similar ao tipo `ListNode` de nossa [implementação de alocador de lista encadeada], com a diferença de que não temos um campo `size`. Ele não é necessário porque cada bloco em uma lista tem o mesmo tamanho com o design de alocador de bloco de tamanho fixo.
|
||||||
|
|
||||||
[implementação de alocador de lista encadeada]: #the-allocator-type
|
[implementação de alocador de lista encadeada]: #o-tipo-alocador
|
||||||
|
|
||||||
#### Tamanhos de Bloco
|
#### Tamanhos de Bloco
|
||||||
|
|
||||||
@@ -947,7 +947,7 @@ pub struct FixedSizeBlockAllocator {
|
|||||||
|
|
||||||
O campo `list_heads` é um array de ponteiros `head`, um para cada tamanho de bloco. Isso é implementado usando o `len()` da slice `BLOCK_SIZES` como o comprimento do array. Como um alocador de fallback para alocações maiores que o maior tamanho de bloco, usamos o alocador fornecido pela crate `linked_list_allocator`. Também poderíamos usar o `LinkedListAllocator` que implementamos nós mesmos em vez disso, mas ele tem a desvantagem de que não [mescla blocos liberados].
|
O campo `list_heads` é um array de ponteiros `head`, um para cada tamanho de bloco. Isso é implementado usando o `len()` da slice `BLOCK_SIZES` como o comprimento do array. Como um alocador de fallback para alocações maiores que o maior tamanho de bloco, usamos o alocador fornecido pela crate `linked_list_allocator`. Também poderíamos usar o `LinkedListAllocator` que implementamos nós mesmos em vez disso, mas ele tem a desvantagem de que não [mescla blocos liberados].
|
||||||
|
|
||||||
[mescla blocos liberados]: #merging-freed-blocks
|
[mescla blocos liberados]: #mesclando-blocos-liberados
|
||||||
|
|
||||||
Para construir um `FixedSizeBlockAllocator`, fornecemos as mesmas funções `new` e `init` que implementamos para os outros tipos de alocadores também:
|
Para construir um `FixedSizeBlockAllocator`, fornecemos as mesmas funções `new` e `init` que implementamos para os outros tipos de alocadores também:
|
||||||
|
|
||||||
@@ -1005,7 +1005,7 @@ impl FixedSizeBlockAllocator {
|
|||||||
O tipo [`Heap`] da crate `linked_list_allocator` não implementa [`GlobalAlloc`] (já que [não é possível sem bloqueio]). Em vez disso, ele fornece um método [`allocate_first_fit`] que tem uma interface ligeiramente diferente. Em vez de retornar um `*mut u8` e usar um ponteiro nulo para sinalizar um erro, ele retorna um `Result<NonNull<u8>, ()>`. O tipo [`NonNull`] é uma abstração para um ponteiro bruto que é garantido de não ser um ponteiro nulo. Ao mapear o caso `Ok` para o método [`NonNull::as_ptr`] e o caso `Err` para um ponteiro nulo, podemos facilmente traduzir isso de volta para um tipo `*mut u8`.
|
O tipo [`Heap`] da crate `linked_list_allocator` não implementa [`GlobalAlloc`] (já que [não é possível sem bloqueio]). Em vez disso, ele fornece um método [`allocate_first_fit`] que tem uma interface ligeiramente diferente. Em vez de retornar um `*mut u8` e usar um ponteiro nulo para sinalizar um erro, ele retorna um `Result<NonNull<u8>, ()>`. O tipo [`NonNull`] é uma abstração para um ponteiro bruto que é garantido de não ser um ponteiro nulo. Ao mapear o caso `Ok` para o método [`NonNull::as_ptr`] e o caso `Err` para um ponteiro nulo, podemos facilmente traduzir isso de volta para um tipo `*mut u8`.
|
||||||
|
|
||||||
[`Heap`]: https://docs.rs/linked_list_allocator/0.9.0/linked_list_allocator/struct.Heap.html
|
[`Heap`]: https://docs.rs/linked_list_allocator/0.9.0/linked_list_allocator/struct.Heap.html
|
||||||
[não é possível sem bloqueio]: #globalalloc-and-mutability
|
[não é possível sem bloqueio]: #globalalloc-e-mutabilidade
|
||||||
[`allocate_first_fit`]: https://docs.rs/linked_list_allocator/0.9.0/linked_list_allocator/struct.Heap.html#method.allocate_first_fit
|
[`allocate_first_fit`]: https://docs.rs/linked_list_allocator/0.9.0/linked_list_allocator/struct.Heap.html#method.allocate_first_fit
|
||||||
[`NonNull`]: https://doc.rust-lang.org/nightly/core/ptr/struct.NonNull.html
|
[`NonNull`]: https://doc.rust-lang.org/nightly/core/ptr/struct.NonNull.html
|
||||||
[`NonNull::as_ptr`]: https://doc.rust-lang.org/nightly/core/ptr/struct.NonNull.html#method.as_ptr
|
[`NonNull::as_ptr`]: https://doc.rust-lang.org/nightly/core/ptr/struct.NonNull.html#method.as_ptr
|
||||||
@@ -1099,7 +1099,7 @@ Se o índice da lista for `Some`, tentamos remover o primeiro nó na lista corre
|
|||||||
|
|
||||||
[`Option::take`]: https://doc.rust-lang.org/core/option/enum.Option.html#method.take
|
[`Option::take`]: https://doc.rust-lang.org/core/option/enum.Option.html#method.take
|
||||||
|
|
||||||
Se o head da lista for `None`, indica que a lista de blocos está vazia. Isso significa que precisamos construir um novo bloco como [descrito acima](#creating-new-blocks). Para isso, primeiro obtemos o tamanho do bloco atual da slice `BLOCK_SIZES` e o usamos como tanto o tamanho quanto o alinhamento para o novo bloco. Então criamos um novo `Layout` a partir dele e chamamos o método `fallback_alloc` para realizar a alocação. A razão para ajustar o layout e alinhamento é que o bloco será adicionado à lista de blocos na desalocação.
|
Se o head da lista for `None`, indica que a lista de blocos está vazia. Isso significa que precisamos construir um novo bloco como [descrito acima](#criando-novos-blocos). Para isso, primeiro obtemos o tamanho do bloco atual da slice `BLOCK_SIZES` e o usamos como tanto o tamanho quanto o alinhamento para o novo bloco. Então criamos um novo `Layout` a partir dele e chamamos o método `fallback_alloc` para realizar a alocação. A razão para ajustar o layout e alinhamento é que o bloco será adicionado à lista de blocos na desalocação.
|
||||||
|
|
||||||
#### `dealloc`
|
#### `dealloc`
|
||||||
|
|
||||||
|
|||||||
@@ -702,7 +702,8 @@ fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output>
|
|||||||
|
|
||||||
A razão pela qual este método recebe `self: Pin<&mut Self>` em vez do `&mut self` normal é que instâncias de future criadas a partir de async/await são frequentemente auto-referenciais, como vimos [acima][self-ref-async-await]. Ao encapsular `Self` em `Pin` e deixar o compilador desistir de `Unpin` para futures auto-referenciais gerados de async/await, é garantido que as futures não sejam movidas na memória entre chamadas `poll`. Isso garante que todas as referências internas ainda são válidas.
|
A razão pela qual este método recebe `self: Pin<&mut Self>` em vez do `&mut self` normal é que instâncias de future criadas a partir de async/await são frequentemente auto-referenciais, como vimos [acima][self-ref-async-await]. Ao encapsular `Self` em `Pin` e deixar o compilador desistir de `Unpin` para futures auto-referenciais gerados de async/await, é garantido que as futures não sejam movidas na memória entre chamadas `poll`. Isso garante que todas as referências internas ainda são válidas.
|
||||||
|
|
||||||
[self-ref-async-await]: @/edition-2/posts/12-async-await/index.md#structs-auto-referenciais
|
[self-ref-async-await]: @/edition-2/posts/12-async-await/index.md#o-problema-com-structs-auto-referenciais
|
||||||
|
|
||||||
|
|
||||||
Vale notar que mover futures antes da primeira chamada `poll` é aceitável. Isso é resultado do fato de que futures são preguiçosas e não fazem nada até serem consultadas pela primeira vez. O estado `start` das máquinas de estados geradas, portanto, contém apenas os argumentos da função mas nenhuma referência interna. Para chamar `poll`, o chamador deve encapsular a future em `Pin` primeiro, o que garante que a future não pode ser movida na memória mais. Como fixar em pilha é mais difícil de acertar, recomendo sempre usar [`Box::pin`] combinado com [`Pin::as_mut`] para isso.
|
Vale notar que mover futures antes da primeira chamada `poll` é aceitável. Isso é resultado do fato de que futures são preguiçosas e não fazem nada até serem consultadas pela primeira vez. O estado `start` das máquinas de estados geradas, portanto, contém apenas os argumentos da função mas nenhuma referência interna. Para chamar `poll`, o chamador deve encapsular a future em `Pin` primeiro, o que garante que a future não pode ser movida na memória mais. Como fixar em pilha é mais difícil de acertar, recomendo sempre usar [`Box::pin`] combinado com [`Pin::as_mut`] para isso.
|
||||||
|
|
||||||
@@ -1373,7 +1374,7 @@ pub async fn print_keypresses() {
|
|||||||
|
|
||||||
O código é muito similar ao código que tínhamos em nosso [manipulador de interrupção de teclado] antes de modificá-lo neste post. A única diferença é que, em vez de ler o scancode de uma porta de E/S, nós o pegamos do `ScancodeStream`. Para isso, primeiro criamos um novo `Scancode` stream e então usamos repetidamente o método [`next`] fornecido pela trait [`StreamExt`] para obter uma `Future` que resolve para o próximo elemento no stream. Usando o operador `await` nele, aguardamos assincronamente o resultado da future.
|
O código é muito similar ao código que tínhamos em nosso [manipulador de interrupção de teclado] antes de modificá-lo neste post. A única diferença é que, em vez de ler o scancode de uma porta de E/S, nós o pegamos do `ScancodeStream`. Para isso, primeiro criamos um novo `Scancode` stream e então usamos repetidamente o método [`next`] fornecido pela trait [`StreamExt`] para obter uma `Future` que resolve para o próximo elemento no stream. Usando o operador `await` nele, aguardamos assincronamente o resultado da future.
|
||||||
|
|
||||||
[manipulador de interrupção de teclado]: @/edition-2/posts/07-hardware-interrupts/index.md#interpretando-os-scancodes
|
[manipulador de interrupção de teclado]: @/edition-2/posts/07-hardware-interrupts/index.pt-BR.md#interpretando-os-scancodes
|
||||||
[`next`]: https://docs.rs/futures-util/0.3.4/futures_util/stream/trait.StreamExt.html#method.next
|
[`next`]: https://docs.rs/futures-util/0.3.4/futures_util/stream/trait.StreamExt.html#method.next
|
||||||
[`StreamExt`]: https://docs.rs/futures-util/0.3.4/futures_util/stream/trait.StreamExt.html
|
[`StreamExt`]: https://docs.rs/futures-util/0.3.4/futures_util/stream/trait.StreamExt.html
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user