diff --git a/blog/content/edition-2/posts/04-testing/index.es.md b/blog/content/edition-2/posts/04-testing/index.es.md index 5722aab2..12a06ea1 100644 --- a/blog/content/edition-2/posts/04-testing/index.es.md +++ b/blog/content/edition-2/posts/04-testing/index.es.md @@ -269,13 +269,13 @@ Para ver la salida de las pruebas en la consola, necesitamos enviar los datos de Una forma simple de enviar los datos es usar el [puerto serial], un estándar de interfaz antiguo que ya no se encuentra en computadoras modernas. Es fácil de programar y QEMU puede redirigir los bytes enviados a través del serial a la salida estándar del host o a un archivo. -[puerto serial]: https://es.wikipedia.org/wiki/Puerto_serial +[puerto serial]: https://en.wikipedia.org/wiki/Serial_port Los chips que implementan una interfaz serial se llaman [UARTs]. Hay [muchos modelos de UART] en x86, pero afortunadamente las únicas diferencias entre ellos son algunas características avanzadas que no necesitamos. Los UART comunes hoy en día son todos compatibles con el [UART 16550], así que utilizaremos ese modelo para nuestro framework de pruebas. -[UARTs]: https://es.wikipedia.org/wiki/Transmisor-receptor_asíncrono_universal -[muchos modelos de UART]: https://es.wikipedia.org/wiki/Transmisor-receptor_asíncrono_universal#Modelos_UART -[UART 16550]: https://es.wikipedia.org/wiki/16550_UART +[UARTs]: https://en.wikipedia.org/wiki/Universal_asynchronous_receiver-transmitter +[muchos modelos de UART]: https://en.wikipedia.org/wiki/Universal_asynchronous_receiver-transmitter#UART_models +[UART 16550]: https://en.wikipedia.org/wiki/16550_UART Usaremos la crate [`uart_16550`] para inicializar el UART y enviar datos a través del puerto serial. Para añadirlo como dependencia, actualizamos nuestro `Cargo.toml` y `main.rs`: @@ -545,7 +545,7 @@ where Implementamos la función `run` imprimiendo primero el nombre de la función utilizando la función [`any::type_name`] . Esta función se implementa directamente en el compilador y devuelve una descripción de cadena de cada tipo. Para las funciones, el tipo es su nombre, así que esto es exactamente lo que queremos en este caso. El carácter `\t` es el [carácter de tabulación], que añade algo de alineación a los mensajes `[ok]`. [`any::type_name`]: https://doc.rust-lang.org/stable/core/any/fn.type_name.html -[carácter de tabulación]: https://es.wikipedia.org/wiki/Tecla_tabulador#Caracteres_de_tabulación +[carácter de tabulación]: https://en.wikipedia.org/wiki/Tab_key#Tab_characters Después de imprimir el nombre de la función, invocamos la función de prueba a través de `self()`. Esto solo funciona porque requerimos que `self` implemente el trait `Fn()`. Después de que la función de prueba retorna, imprimimos `[ok]` para indicar que la función no provocó un pánico. diff --git a/blog/content/edition-2/posts/11-allocator-designs/index.es.md b/blog/content/edition-2/posts/11-allocator-designs/index.es.md index 2a785432..2cdd7a97 100644 --- a/blog/content/edition-2/posts/11-allocator-designs/index.es.md +++ b/blog/content/edition-2/posts/11-allocator-designs/index.es.md @@ -38,7 +38,7 @@ La responsabilidad de un allocador es gestionar la memoria heap disponible. Nece Aparte de la corrección, hay muchos objetivos secundarios de diseño. Por ejemplo, el allocador debería utilizar de manera efectiva la memoria disponible y mantener baja la [_fragmentación_]. Además, debería funcionar bien para aplicaciones concurrentes y escalar a cualquier número de procesadores. Para un rendimiento máximo, podría incluso optimizar el diseño de la memoria con respecto a los cachés de CPU para mejorar la [localidad de caché] y evitar [compartición falsa]. [localidad de caché]: https://www.geeksforgeeks.org/locality-of-reference-and-cache-operation-in-cache-memory/ -[_fragmentación_]: https://es.wikipedia.org/wiki/Fragmentaci%C3%B3n_(computaci%C3%B3n) +[_fragmentación_]: https://en.wikipedia.org/wiki/Fragmentation_(computing) [compartición falsa]: https://mechanical-sympathy.blogspot.de/2011/07/false-sharing.html Estos requisitos pueden hacer que los buenos allocadores sean muy complejos. Por ejemplo, [jemalloc] tiene más de 30.000 líneas de código. Esta complejidad a menudo es indeseable en el código del kernel, donde un solo error puede conducir a vulnerabilidades de seguridad graves. Afortunadamente, los patrones de asignación del código del kernel son a menudo mucho más simples en comparación con el código de espacio de usuario, de manera que diseños de allocadores relativamente simples suelen ser suficientes. @@ -194,7 +194,7 @@ Afortunadamente, hay una manera de obtener una referencia `&mut self` de una ref [mutabilidad interna]: https://doc.rust-lang.org/book/ch15-05-interior-mutability.html [vga-mutex]: @/edition-2/posts/03-vga-text-buffer/index.md#spinlocks [`spin::Mutex`]: https://docs.rs/spin/0.5.0/spin/struct.Mutex.html -[exclusión mutua]: https://es.wikipedia.org/wiki/Exclusi%C3%B3n_mutua +[exclusión mutua]: https://en.wikipedia.org/wiki/Mutual_exclusion #### Un Tipo Wrapper `Locked` @@ -314,7 +314,7 @@ fn align_up(addr: usize, align: usize) -> usize { La función primero calcula el [resto] de la división de `addr` entre `align`. Si el resto es `0`, la dirección ya está alineada con la alineación dada. De lo contrario, alineamos la dirección restando el resto (para que el nuevo resto sea 0) y luego sumando la alineación (para que la dirección no se vuelva más pequeña que la dirección original). -[resto]: https://es.wikipedia.org/wiki/Divisi%C3%B3n_euclidiana +[resto]: https://en.wikipedia.org/wiki/Euclidean_division Ten en cuenta que esta no es la forma más eficiente de implementar esta función. Una implementación mucho más rápida se ve así: @@ -330,16 +330,16 @@ fn align_up(addr: usize, align: usize) -> usize { Este método requiere que `align` sea una potencia de dos, lo que puede ser garantizado utilizando el trait `GlobalAlloc` (y su parámetro [`Layout`]). Esto hace posible crear una [máscara de bits] para alinear la dirección de manera muy eficiente. Para entender cómo funciona, repasemos el proceso paso a paso, comenzando por el lado derecho: [`Layout`]: https://doc.rust-lang.org/alloc/alloc/struct.Layout.html -[máscara de bits]: https://es.wikipedia.org/wiki/M%C3%A1scara_(computaci%C3%B3n) +[máscara de bits]: https://en.wikipedia.org/wiki/Mask_(computing) - Dado que `align` es una potencia de dos, su [representación binaria] tiene solo un solo bit establecido (por ejemplo, `0b000100000`). Esto significa que `align - 1` tiene todos los bits inferiores establecidos (por ejemplo, `0b00011111`). - Al crear el [NO bit a bit] a través del operador `!`, obtenemos un número que tiene todos los bits establecidos excepto los bits inferiores a `align` (por ejemplo, `0b…111111111100000`). - Al realizar un [Y bit a bit] en una dirección y `!(align - 1)`, alineamos la dirección _hacia abajo_. Esto funciona borrando todos los bits que están por debajo de `align`. - Dado que queremos alinear hacia arriba en lugar de hacia abajo, incrementamos `addr` en `align - 1` antes de realizar el Y bit a bit. De esta manera, las direcciones ya alineadas permanecen iguales mientras que las direcciones no alineadas se redondean al siguiente límite de alineación. -[representación binaria]: https://es.wikipedia.org/wiki/N%C3%BAmero_binario#Representaci%C3%B3n -[NO bit a bit]: https://es.wikipedia.org/wiki/Operaci%C3%B3n_bit_a_bit#NO -[Y bit a bit]: https://es.wikipedia.org/wiki/Operaci%C3%B3n_bit_a_bit#Y +[representación binaria]: https://en.wikipedia.org/wiki/Binary_number#Representation +[NO bit a bit]: https://en.wikipedia.org/wiki/Bitwise_operation#NOT +[Y bit a bit]: https://en.wikipedia.org/wiki/Bitwise_operation#AND Qué variante elijas depende de ti. Ambas calculan el mismo resultado, solo que utilizan diferentes métodos. @@ -455,7 +455,7 @@ El enfoque de implementación más común es construir una lista enlazada simple Cada nodo de la lista contiene dos campos: el tamaño de la región de memoria y un puntero a la siguiente región de memoria no utilizada. Con este enfoque, solo necesitamos un puntero a la primera región no utilizada (llamada `head`) para llevar un registro de todas las regiones no utilizadas, independientemente de su número. La estructura de datos resultante se denomina a menudo [_lista libre_]. -[_lista libre_]: https://es.wikipedia.org/wiki/Free_list +[_lista libre_]: https://en.wikipedia.org/wiki/Free_list Como puedes adivinar por el nombre, esta es la técnica que utiliza el crate `linked_list_allocator`. Los allocadores que utilizan esta técnica a menudo se llaman también _allocadores de piscina_. diff --git a/blog/content/edition-2/posts/12-async-await/index.es.md b/blog/content/edition-2/posts/12-async-await/index.es.md index f79fc3ff..adfeb552 100644 --- a/blog/content/edition-2/posts/12-async-await/index.es.md +++ b/blog/content/edition-2/posts/12-async-await/index.es.md @@ -906,7 +906,7 @@ La función `from_raw` es insegura porque se puede producir un comportamiento in El tipo [`RawWaker`] requiere que el programador defina explícitamente un [_tabla de métodos virtuales_] (_vtable_) que especifica las funciones que deben ser llamadas cuando `RawWaker` se clona, se despierta o se elimina. La disposición de esta vtable es definida por el tipo [`RawWakerVTable`]. Cada función recibe un argumento `*const ()`, que es un puntero _sin tipo_ a algún valor. La razón por la que se utiliza un puntero `*const ()` en lugar de una referencia apropiada es que el tipo `RawWaker` debería ser no genérico pero aún así soportar tipos arbitrarios. El puntero se proporciona colocando `data` en la llamada a [`RawWaker::new`], que simplemente inicializa un `RawWaker`. Luego, el `Waker` utiliza este `RawWaker` para llamar a las funciones de la vtable con `data`. -[_tabla de métodos virtuales_]: https://es.wikipedia.org/wiki/Tabla_de_metodos_virtuales +[_tabla de métodos virtuales_]: https://en.wikipedia.org/wiki/Virtual_method_table [`RawWakerVTable`]: https://doc.rust-lang.org/stable/core/task/struct.RawWakerVTable.html [`RawWaker::new`]: https://doc.rust-lang.org/stable/core/task/struct.RawWaker.html#method.new