diff options
Diffstat (limited to 'Documentation/translations/sp_SP')
18 files changed, 8347 insertions, 0 deletions
diff --git a/Documentation/translations/sp_SP/disclaimer-sp.rst b/Documentation/translations/sp_SP/disclaimer-sp.rst new file mode 100644 index 0000000000..a400034e95 --- /dev/null +++ b/Documentation/translations/sp_SP/disclaimer-sp.rst @@ -0,0 +1,6 @@ +:orphan: + +.. warning:: + Si tiene alguna duda sobre la exactitud del contenido de esta + traducción, la única referencia válida es la documentación oficial en + inglés. diff --git a/Documentation/translations/sp_SP/howto.rst b/Documentation/translations/sp_SP/howto.rst new file mode 100644 index 0000000000..f1629738b4 --- /dev/null +++ b/Documentation/translations/sp_SP/howto.rst @@ -0,0 +1,617 @@ +.. include:: ./disclaimer-sp.rst + +:Original: :ref:`Documentation/process/howto.rst <process_howto>` +:Translator: Carlos Bilbao <carlos.bilbao@amd.com> + +.. _sp_process_howto: + +Cómo participar en el desarrollo del kernel de Linux +==================================================== + +Este documento es el principal punto de partida. Contiene instrucciones +sobre cómo convertirse en desarrollador del kernel de Linux y explica cómo +trabajar con el y en su desarrollo. El documento no tratará ningún aspecto +técnico relacionado con la programación del kernel, pero le ayudará +guiándole por el camino correcto. + +Si algo en este documento quedara obsoleto, envíe parches al maintainer de +este archivo, que se encuentra en la parte superior del documento. + +Introducción +------------ +¿De modo que quiere descubrir como convertirse en un/a desarrollador/a del +kernel de Linux? Tal vez su jefe le haya dicho, "Escriba un driver de +Linux para este dispositivo." El objetivo de este documento en enseñarle +todo cuanto necesita para conseguir esto, describiendo el proceso por el +que debe pasar, y con indicaciones de como trabajar con la comunidad. +También trata de explicar las razones por las cuales la comunidad trabaja +de la forma en que lo hace. + +El kernel esta principalmente escrito en C, con algunas partes que son +dependientes de la arquitectura en ensamblador. Un buen conocimiento de C +es necesario para desarrollar en el kernel. Lenguaje ensamblador (en +cualquier arquitectura) no es necesario excepto que planee realizar +desarrollo de bajo nivel para dicha arquitectura. Aunque no es un perfecto +sustituto para una educación sólida en C y/o años de experiencia, los +siguientes libros sirven, como mínimo, como referencia: + +- "The C Programming Language" de Kernighan e Ritchie [Prentice Hall] +- "Practical C Programming" de Steve Oualline [O'Reilly] +- "C: A Reference Manual" de Harbison and Steele [Prentice Hall] + +El kernel está escrito usando GNU C y la cadena de herramientas GNU. Si +bien se adhiere al estándar ISO C89, utiliza una serie de extensiones que +no aparecen en dicho estándar. El kernel usa un C independiente de entorno, +sin depender de la biblioteca C estándar, por lo que algunas partes del +estándar C no son compatibles. Divisiones de long long arbitrarios o +de coma flotante no son permitidas. En ocasiones, puede ser difícil de +entender las suposiciones que el kernel hace respecto a la cadena de +herramientas y las extensiones que usa, y desafortunadamente no hay +referencia definitiva para estas. Consulte las páginas de información de +gcc (`info gcc`) para obtener información al respecto. + +Recuerde que está tratando de aprender a trabajar con una comunidad de +desarrollo existente. Es un grupo diverso de personas, con altos estándares +de código, estilo y procedimiento. Estas normas han sido creadas a lo +largo del tiempo en función de lo que se ha encontrado que funciona mejor +para un equipo tan grande y geográficamente disperso. Trate de aprender +tanto como le sea posible acerca de estos estándares antes de tiempo, ya +que están bien documentados; no espere que la gente se adapte a usted o a +la forma de hacer las cosas en su empresa. + +Cuestiones legales +------------------ +El código fuente del kernel de Linux se publica bajo licencia GPL. Por +favor, revise el archivo COPYING, presente en la carpeta principal del +código fuente, para detalles de la licencia. Si tiene alguna otra pregunta +sobre licencias, contacte a un abogado, no pregunte en listas de discusión +del kernel de Linux. La gente en estas listas no son abogadas, y no debe +confiar en sus opiniones en materia legal. + +Para preguntas y respuestas más frecuentes sobre la licencia GPL, consulte: + + https://www.gnu.org/licenses/gpl-faq.html + +Documentación +-------------- +El código fuente del kernel de Linux tiene una gran variedad de documentos +que son increíblemente valiosos para aprender a interactuar con la +comunidad del kernel. Cuando se agregan nuevas funciones al kernel, se +recomienda que se incluyan nuevos archivos de documentación que expliquen +cómo usar la función. Cuando un cambio en el kernel hace que la interfaz +que el kernel expone espacio de usuario cambie, se recomienda que envíe la +información o un parche en las páginas del manual que expliquen el cambio +a mtk.manpages@gmail.com, y CC la lista linux-api@vger.kernel.org. + +Esta es la lista de archivos que están en el código fuente del kernel y son +de obligada lectura: + + :ref:`Documentation/admin-guide/README.rst <readme>` + Este archivo ofrece una breve descripción del kernel de Linux y + describe lo que es necesario hacer para configurar y compilar el + kernel. Quienes sean nuevos en el kernel deben comenzar aquí. + + :ref:`Documentation/process/changes.rst <changes>` + Este archivo proporciona una lista de los niveles mínimos de varios + paquetes que son necesarios para construir y ejecutar el kernel + exitosamente. + + :ref:`Documentation/process/coding-style.rst <codingstyle>` + Esto describe el estilo de código del kernel de Linux y algunas de los + razones detrás de esto. Se espera que todo el código nuevo siga las + directrices de este documento. La mayoría de los maintainers solo + aceptarán parches si se siguen estas reglas, y muchas personas solo + revisan el código si tiene el estilo adecuado. + + :ref:`Documentation/process/submitting-patches.rst <submittingpatches>` + Este archivo describe en gran detalle cómo crear con éxito y enviar un + parche, que incluye (pero no se limita a): + + - Contenidos del correo electrónico (email) + - Formato del email + - A quien se debe enviar + + Seguir estas reglas no garantiza el éxito (ya que todos los parches son + sujetos a escrutinio de contenido y estilo), pero en caso de no seguir + dichas reglas, el fracaso es prácticamente garantizado. + Otras excelentes descripciones de cómo crear parches correctamente son: + + "The Perfect Patch" + https://www.ozlabs.org/~akpm/stuff/tpp.txt + + "Linux kernel patch submission format" + https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html + + :ref:`Documentation/process/stable-api-nonsense.rst <stable_api_nonsense>` + Este archivo describe la lógica detrás de la decisión consciente de + no tener una API estable dentro del kernel, incluidas cosas como: + + - Capas intermedias del subsistema (por compatibilidad?) + - Portabilidad de drivers entre sistemas operativos + - Mitigar el cambio rápido dentro del árbol de fuentes del kernel (o + prevenir cambios rápidos) + + Este documento es crucial para comprender la filosofía del desarrollo + de Linux y es muy importante para las personas que se mudan a Linux + tras desarrollar otros sistemas operativos. + + :ref:`Documentation/process/security-bugs.rst <securitybugs>` + Si cree que ha encontrado un problema de seguridad en el kernel de + Linux, siga los pasos de este documento para ayudar a notificar a los + desarrolladores del kernel y ayudar a resolver el problema. + + :ref:`Documentation/process/management-style.rst <managementstyle>` + Este documento describe cómo operan los maintainers del kernel de Linux + y los valores compartidos detrás de sus metodologías. Esta es una + lectura importante para cualquier persona nueva en el desarrollo del + kernel (o cualquier persona que simplemente sienta curiosidad por + el campo IT), ya que clarifica muchos conceptos erróneos y confusiones + comunes sobre el comportamiento único de los maintainers del kernel. + + :ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>` + Este archivo describe las reglas sobre cómo se suceden las versiones + del kernel estable, y qué hacer si desea obtener un cambio en una de + estas publicaciones. + + :ref:`Documentation/process/kernel-docs.rst <kernel_docs>` + Una lista de documentación externa relativa al desarrollo del kernel. + Por favor consulte esta lista si no encuentra lo que están buscando + dentro de la documentación del kernel. + + :ref:`Documentation/process/applying-patches.rst <applying_patches>` + Una buena introducción que describe exactamente qué es un parche y cómo + aplicarlo a las diferentes ramas de desarrollo del kernel. + +El kernel también tiene una gran cantidad de documentos que pueden ser +generados automáticamente desde el propio código fuente o desde +ReStructuredText markups (ReST), como este. Esto incluye un descripción +completa de la API en el kernel y reglas sobre cómo manejar cerrojos +(locking) correctamente. + +Todos estos documentos se pueden generar como PDF o HTML ejecutando:: + + make pdfdocs + make htmldocs + +respectivamente desde el directorio fuente principal del kernel. + +Los documentos que utilizan el markup ReST se generarán en +Documentation/output. También se pueden generar en formatos LaTeX y ePub +con:: + + make latexdocs + make epubdocs + +Convertirse en un/a desarrollador/a de kernel +--------------------------------------------- + +Si no sabe nada sobre el desarrollo del kernel de Linux, debería consultar +el proyecto Linux KernelNewbies: + + https://kernelnewbies.org + +Consiste en una útil lista de correo donde puede preguntar casi cualquier +tipo de pregunta básica de desarrollo del kernel (asegúrese de buscar en +los archivos primero, antes de preguntar algo que ya ha sido respondido en +el pasado.) También tiene un canal IRC que puede usar para hacer preguntas +en tiempo real, y una gran cantidad de documentación útil para ir +aprendiendo sobre el desarrollo del kernel de Linux. + +El sitio web tiene información básica sobre la organización del código, +subsistemas, y proyectos actuales (tanto dentro como fuera del árbol). +También describe alguna información logística básica, como cómo compilar +un kernel y aplicar un parche. + +Si no sabe por dónde quiere empezar, pero quieres buscar alguna tarea que +comenzar a hacer para unirse a la comunidad de desarrollo del kernel, +acuda al proyecto Linux Kernel Janitor: + + https://kernelnewbies.org/KernelJanitors + +Es un gran lugar para comenzar. Describe una lista de problemas +relativamente simples que deben limpiarse y corregirse dentro del código +fuente del kernel de Linux árbol de fuentes. Trabajando con los +desarrolladores a cargo de este proyecto, aprenderá los conceptos básicos +para incluir su parche en el árbol del kernel de Linux, y posiblemente +descubrir en la dirección en que trabajar a continuación, si no tiene ya +una idea. + +Antes de realizar cualquier modificación real al código del kernel de +Linux, es imperativo entender cómo funciona el código en cuestión. Para +este propósito, nada es mejor que leerlo directamente (lo más complicado +está bien comentado), tal vez incluso con la ayuda de herramientas +especializadas. Una de esas herramientas que se recomienda especialmente +es el proyecto Linux Cross-Reference, que es capaz de presentar el código +fuente en un formato de página web indexada y autorreferencial. Una +excelente puesta al día del repositorio del código del kernel se puede +encontrar en: + + https://elixir.bootlin.com/ + +El proceso de desarrollo +------------------------ + +El proceso de desarrollo del kernel de Linux consiste actualmente de +diferentes "branches" (ramas) con muchos distintos subsistemas específicos +a cada una de ellas. Las diferentes ramas son: + + - El código principal de Linus (mainline tree) + - Varios árboles estables con múltiples major numbers + - Subsistemas específicos + - linux-next, para integración y testing + +Mainline tree (Árbol principal) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +El mainline tree es mantenido por Linus Torvalds, y puede encontrarse en +https://kernel.org o en su repo. El proceso de desarrollo es el siguiente: + + - Tan pronto como se lanza un nuevo kernel, se abre una ventana de dos + semanas, durante este período de tiempo, los maintainers pueden enviar + grandes modificaciones a Linus, por lo general los parches que ya se + han incluido en el linux-next durante unas semanas. La forma preferida + de enviar grandes cambios es usando git (la herramienta de + administración de código fuente del kernel, más información al respecto + en https://git-scm.com/), pero los parches simples también son validos. + - Después de dos semanas, se lanza un kernel -rc1 y la atención se centra + en hacer el kernel nuevo lo más estable ("solido") posible. La mayoría + de los parches en este punto deben arreglar una regresión. Los errores + que siempre han existido no son regresiones, por lo tanto, solo envíe + este tipo de correcciones si son importantes. Tenga en cuenta que se + podría aceptar un controlador (o sistema de archivos) completamente + nuevo después de -rc1 porque no hay riesgo de causar regresiones con + tal cambio, siempre y cuando el cambio sea autónomo y no afecte áreas + fuera del código que se está agregando. git se puede usar para enviar + parches a Linus después de que se lance -rc1, pero los parches también + deben ser enviado a una lista de correo pública para su revisión. + - Se lanza un nuevo -rc cada vez que Linus considera que el árbol git + actual esta en un estado razonablemente sano y adecuado para la prueba. + La meta es lanzar un nuevo kernel -rc cada semana. + - El proceso continúa hasta que el kernel se considera "listo", y esto + puede durar alrededor de 6 semanas. + +Vale la pena mencionar lo que Andrew Morton escribió en las listas de +correo del kernel de Linux, sobre lanzamientos del kernel (traducido): + + *"Nadie sabe cuándo se publicara un nuevo kernel, pues esto sucede + según el estado de los bugs, no de una cronología preconcebida."* + +Varios árboles estables con múltiples major numbers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Los kernels con versiones de 3 partes son kernels estables. Estos contienen +correcciones relativamente pequeñas y críticas para problemas de seguridad +o importantes regresiones descubiertas para una publicación de código. +Cada lanzamiento en una gran serie estable incrementa la tercera parte de +la versión número, manteniendo las dos primeras partes iguales. + +Esta es la rama recomendada para los usuarios que quieren la versión +estable más reciente del kernel, y no están interesados en ayudar a probar +versiones en desarrollo/experimentales. + +Los árboles estables son mantenidos por el equipo "estable" +<stable@vger.kernel.org>, y se liberan (publican) según lo dicten las +necesidades. El período de liberación normal es de aproximadamente dos +semanas, pero puede ser más largo si no hay problemas apremiantes. Un +problema relacionado con la seguridad, en cambio, puede causar un +lanzamiento casi instantáneamente. + +El archivo :ref:`Documentación/proceso/stable-kernel-rules.rst <stable_kernel_rules>` +en el árbol del kernel documenta qué tipos de cambios son aceptables para +el árbol estable y cómo funciona el proceso de lanzamiento. + +Subsistemas específicos +~~~~~~~~~~~~~~~~~~~~~~~~ +Los maintainers de los diversos subsistemas del kernel --- y también muchos +desarrolladores de subsistemas del kernel --- exponen su estado actual de +desarrollo en repositorios fuente. De esta manera, otros pueden ver lo que +está sucediendo en las diferentes áreas del kernel. En áreas donde el +desarrollo es rápido, se le puede pedir a un desarrollador que base sus +envíos en tal árbol del subsistema del kernel, para evitar conflictos entre +este y otros trabajos ya en curso. + +La mayoría de estos repositorios son árboles git, pero también hay otros +SCM en uso, o colas de parches que se publican como series quilt. Las +direcciones de estos repositorios de subsistemas se enumeran en el archivo +MAINTAINERS. Muchos de estos se pueden ver en https://git.kernel.org/. + +Antes de que un parche propuesto se incluya con dicho árbol de subsistemas, +es sujeto a revisión, que ocurre principalmente en las listas de correo +(ver la sección respectiva a continuación). Para varios subsistemas del +kernel, esta revisión se rastrea con la herramienta patchwork. Patchwork +ofrece una interfaz web que muestra publicaciones de parches, cualquier +comentario sobre un parche o revisiones a él, y los maintainers pueden +marcar los parches como en revisión, aceptado, o rechazado. La mayoría de +estos sitios de trabajo de parches se enumeran en + +https://patchwork.kernel.org/. + +linux-next, para integración y testing +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Antes de que las actualizaciones de los árboles de subsistemas se combinen +con el árbol principal, necesitan probar su integración. Para ello, existe +un repositorio especial de pruebas en el que se encuentran casi todos los +árboles de subsistema, actualizado casi a diario: + + https://git.kernel.org/?p=linux/kernel/git/next/linux-next.git + +De esta manera, linux-next ofrece una perspectiva resumida de lo que se +espera que entre en el kernel principal en el próximo período de "merge" +(fusión de código). Los testers aventureros son bienvenidos a probar +linux-next en ejecución. + +Reportar bugs +------------- + +El archivo 'Documentación/admin-guide/reporting-issues.rst' en el +directorio principal del kernel describe cómo informar un posible bug del +kernel y detalles sobre qué tipo de información necesitan los +desarrolladores del kernel para ayudar a rastrear la fuente del problema. + +Gestión de informes de bugs +------------------------------ + +Una de las mejores formas de poner en práctica sus habilidades de hacking +es arreglando errores reportados por otras personas. No solo ayudará a +hacer el kernel más estable, también aprenderá a solucionar problemas del +mundo real y mejora sus habilidades, y otros desarrolladores se darán +cuenta de tu presencia. La corrección de errores es una de las mejores +formas de ganar méritos entre desarrolladores, porque no a muchas personas +les gusta perder el tiempo arreglando los errores de otras personas. + +Para trabajar en informes de errores ya reportados, busque un subsistema +que le interese. Verifique el archivo MAINTAINERS donde se informan los +errores de ese subsistema; con frecuencia será una lista de correo, rara +vez un rastreador de errores (bugtracker). Busque en los archivos de dicho +lugar para informes recientes y ayude donde lo crea conveniente. También es +posible que desee revisar https://bugzilla.kernel.org para informes de +errores; solo un puñado de subsistemas del kernel lo emplean activamente +para informar o rastrear; sin embargo, todos los errores para todo el kernel +se archivan allí. + +Listas de correo +----------------- + +Como se explica en algunos de los documentos anteriores, la mayoría de +desarrolladores del kernel participan en la lista de correo del kernel de +Linux. Detalles sobre cómo para suscribirse y darse de baja de la lista se +pueden encontrar en: + + http://vger.kernel.org/vger-lists.html#linux-kernel + +Existen archivos de la lista de correo en la web en muchos lugares +distintos. Utilice un motor de búsqueda para encontrar estos archivos. Por +ejemplo: + + http://dir.gmane.org/gmane.linux.kernel + +Es muy recomendable que busque en los archivos sobre el tema que desea +tratar, antes de publicarlo en la lista. Un montón de cosas ya discutidas +en detalle solo se registran en los archivos de la lista de correo. + +La mayoría de los subsistemas individuales del kernel también tienen sus +propias lista de correo donde hacen sus esfuerzos de desarrollo. Revise el +archivo MAINTAINERS para obtener referencias de lo que estas listas para +los diferentes grupos. + +Muchas de las listas están alojadas en kernel.org. La información sobre +estas puede ser encontrada en: + + http://vger.kernel.org/vger-lists.html + +Recuerde mantener buenos hábitos de comportamiento al usar las listas. +Aunque un poco cursi, la siguiente URL tiene algunas pautas simples para +interactuar con la lista (o cualquier lista): + + http://www.albion.com/netiquette/ + +Si varias personas responden a su correo, el CC (lista de destinatarios) +puede hacerse bastante grande. No elimine a nadie de la lista CC: sin una +buena razón, o no responda solo a la dirección de la lista. Acostúmbrese +a recibir correos dos veces, una del remitente y otra de la lista, y no +intente ajustar esto agregando encabezados de correo astutos, a la gente no +le gustará. + +Recuerde mantener intacto el contexto y la atribución de sus respuestas, +mantenga las líneas "El hacker John Kernel escribió ...:" en la parte +superior de su respuesta, y agregue sus declaraciones entre las secciones +individuales citadas en lugar de escribiendo en la parte superior del +correo electrónico. + +Si incluye parches en su correo, asegúrese de que sean texto legible sin +formato como se indica en :ref:`Documentation/process/submitting-patches.rst <submittingpatches>`. +Los desarrolladores del kernel no quieren lidiar con archivos adjuntos o +parches comprimidos; y pueden querer comentar líneas individuales de su +parche, que funciona sólo de esa manera. Asegúrese de emplear un programa +de correo que no altere los espacios ni los tabuladores. Una buena primera +prueba es enviarse el correo a usted mismo, e intentar aplicar su +propio parche. Si eso no funciona, arregle su programa de correo o +reemplace hasta que funcione. + +Sobretodo, recuerde de ser respetuoso con otros subscriptores. + +Colaborando con la comunidad +---------------------------- + +El objetivo de la comunidad del kernel es proporcionar el mejor kernel +posible. Cuando envíe un parche para su aceptación, se revisará en sus +méritos técnicos solamente. Entonces, ¿qué deberías ser? + + - críticas + - comentarios + - peticiones de cambios + - peticiones de justificaciones + - silencio + +Recuerde, esto es parte de introducir su parche en el kernel. Tiene que ser +capaz de recibir críticas y comentarios sobre sus parches, evaluar +a nivel técnico y re-elaborar sus parches o proporcionar razonamiento claro +y conciso de por qué no se deben hacer tales cambios. Si no hay respuestas +a su publicación, espere unos días e intente de nuevo, a veces las cosas se +pierden dado el gran volumen. + +¿Qué no debería hacer? + + - esperar que su parche se acepte sin preguntas + - actuar de forma defensiva + - ignorar comentarios + - enviar el parche de nuevo, sin haber aplicados los cambios pertinentes + +En una comunidad que busca la mejor solución técnica posible, siempre habrá +diferentes opiniones sobre lo beneficioso que es un parche. Tiene que ser +cooperativo y estar dispuesto a adaptar su idea para que encaje dentro +del kernel, o al menos esté dispuesto a demostrar que su idea vale la pena. +Recuerde, estar equivocado es aceptable siempre y cuando estés dispuesto a +trabajar hacia una solución que sea correcta. + +Es normal que las respuestas a su primer parche sean simplemente una lista +de una docena de cosas que debe corregir. Esto **no** implica que su +parche no será aceptado, y **no** es personal. Simplemente corrija todos +los problemas planteados en su parche, y envié otra vez. + +Diferencias entre la comunidad kernel y las estructuras corporativas +-------------------------------------------------------------------- + +La comunidad del kernel funciona de manera diferente a la mayoría de los +entornos de desarrollo tradicionales en empresas. Aquí hay una lista de +cosas que puede intentar hacer para evitar problemas: + + Cosas buenas que decir respecto a los cambios propuestos: + + - "Esto arregla múltiples problemas." + - "Esto elimina 2000 lineas de código." + - "Aquí hay un parche que explica lo que intento describir." + - "Lo he testeado en 5 arquitecturas distintas..." + - "Aquí hay una serie de parches menores que..." + - "Esto mejora el rendimiento en maquinas típicas..." + + Cosas negativas que debe evitar decir: + + - "Lo hicimos así en AIX/ptx/Solaris, de modo que debe ser bueno..." + - "Llevo haciendo esto 20 años, de modo que..." + - "Esto lo necesita mi empresa para ganar dinero" + - "Esto es para la linea de nuestros productos Enterprise" + - "Aquí esta el documento de 1000 paginas describiendo mi idea" + - "Llevo 6 meses trabajando en esto..." + - "Aquí esta un parche de 5000 lineas que..." + - "He rescrito todo el desastre actual, y aquí esta..." + - "Tengo un deadline, y este parche debe aplicarse ahora." + +Otra forma en que la comunidad del kernel es diferente a la mayoría de los +entornos de trabajo tradicionales en ingeniería de software, es la +naturaleza sin rostro de interacción. Una de las ventajas de utilizar el +correo electrónico y el IRC como formas principales de comunicación es la +no discriminación por motivos de género o raza. El entorno de trabajo del +kernel de Linux acepta a mujeres y minorías porque todo lo que eres es una +dirección de correo electrónico. El aspecto internacional también ayuda a +nivelar el campo de juego porque no puede adivinar el género basado en +el nombre de una persona. Un hombre puede llamarse Andrea y una mujer puede +llamarse Pat. La mayoría de las mujeres que han trabajado en el kernel de +Linux y han expresado una opinión han tenido experiencias positivas. + +La barrera del idioma puede causar problemas a algunas personas que no se +sientes cómodas con el inglés. Un buen dominio del idioma puede ser +necesario para transmitir ideas correctamente en las listas de correo, por +lo que le recomendamos que revise sus correos electrónicos para asegurarse +de que tengan sentido en inglés antes de enviarlos. + +Divida sus cambios +--------------------- + +La comunidad del kernel de Linux no acepta con gusto grandes fragmentos de +código, sobretodo a la vez. Los cambios deben introducirse correctamente, +discutidos y divididos en pequeñas porciones individuales. Esto es casi +exactamente lo contrario de lo que las empresas están acostumbradas a hacer. +Su propuesta también debe introducirse muy temprano en el proceso de +desarrollo, de modo que pueda recibir comentarios sobre lo que está +haciendo. También deje que la comunidad sienta que está trabajando con +ellos, y no simplemente usándolos como un vertedero para su función. Sin +embargo, no envíe 50 correos electrónicos a una vez a una lista de correo, +su serie de parches debe casi siempre ser más pequeña que eso. + +Las razones para dividir las cosas son las siguientes: + +1) Los cambios pequeños aumentan la probabilidad de que sus parches sean + aplicados, ya que no requieren mucho tiempo o esfuerzo para verificar su + exactitud. Un parche de 5 líneas puede ser aplicado por un maintainer + con apenas una segunda mirada. Sin embargo, un parche de 500 líneas + puede tardar horas en ser revisado en términos de corrección (el tiempo + que toma es exponencialmente proporcional al tamaño del parche, o algo + así). + + Los parches pequeños también facilitan la depuración cuando algo falla. + Es mucho más fácil retirar los parches uno por uno que diseccionar un + parche muy grande después de haber sido aplicado (y roto alguna cosa). + +2) Es importante no solo enviar pequeños parches, sino también reescribir + y simplificar (o simplemente reordenar) los parches antes de enviarlos. + +Esta es una analogía del desarrollador del kernel Al Viro (traducida): + + *"Piense en un maestro que califica la tarea de un estudiante de + matemáticas. El maestro no quiere ver los intentos y errores del + estudiante antes de que se les ocurriera la solución. Quiere ver la + respuesta más limpia y elegante. Un buen estudiante lo sabe, y nunca + presentaría su trabajo intermedio antes de tener la solución final.* + + *Lo mismo ocurre con el desarrollo del kernel. Los maintainers y + revisores no quieren ver el proceso de pensamiento detrás de la solución + al problema que se está resolviendo. Quieren ver un solución simple y + elegante."* + +Puede resultar un reto mantener el equilibrio entre presentar una solución +elegante y trabajar junto a la comunidad, discutiendo su trabajo inacabado. +Por lo tanto, es bueno comenzar temprano en el proceso para obtener +"feedback" y mejorar su trabajo, pero también mantenga sus cambios en +pequeños trozos que pueden ser aceptados, incluso cuando toda su labor no +está listo para inclusión en un momento dado. + +También tenga en cuenta que no es aceptable enviar parches para su +inclusión que están sin terminar y serán "arreglados más tarde". + +Justifique sus cambios +---------------------- + +Además de dividir sus parches, es muy importante que deje a la comunidad de +Linux sabe por qué deberían agregar este cambio. Nuevas características +debe justificarse como necesarias y útiles. + +Documente sus cambios +--------------------- + +Cuando envíe sus parches, preste especial atención a lo que dice en el +texto de su correo electrónico. Esta información se convertirá en el +ChangeLog del parche, y se conservará para que todos la vean, todo el +tiempo. Debe describir el parche por completo y contener: + + - por qué los cambios son necesarios + - el diseño general de su propuesta + - detalles de implementación + - resultados de sus experimentos + +Para obtener más detalles sobre cómo debería quedar todo esto, consulte la +sección ChangeLog del documento: + + "The Perfect Patch" + https://www.ozlabs.org/~akpm/stuff/tpp.txt + +Todas estas cuestiones son a veces son muy difíciles de conseguir. Puede +llevar años perfeccionar estas prácticas (si es que lo hace). Es un proceso +continuo de mejora que requiere mucha paciencia y determinación. Pero no se +rinda, es posible. Muchos lo han hecho antes, y cada uno tuvo que comenzar +exactamente donde está usted ahora. + +---------- + +Gracias a Paolo Ciarrocchi que permitió que la sección "Development Process" +se basara en el texto que había escrito (https://lwn.net/Articles/94386/), +y a Randy Dunlap y Gerrit Huizenga por algunas de la lista de cosas que +debes y no debes decir. También gracias a Pat Mochel, Hanna Linder, Randy +Dunlap, Kay Sievers, Vojtech Pavlik, Jan Kara, Josh Boyer, Kees Cook, +Andrew Morton, Andi Kleen, Vadim Lobanov, Jesper Juhl, Adrian Bunk, +Keri Harris, Frans Pop, David A. Wheeler, Junio Hamano, Michael Kerrisk y +Alex Shepard por su revisión, comentarios y contribuciones. Sin su ayuda, +este documento no hubiera sido posible. + +Maintainer: Greg Kroah-Hartman <greg@kroah.com> diff --git a/Documentation/translations/sp_SP/index.rst b/Documentation/translations/sp_SP/index.rst new file mode 100644 index 0000000000..5c2a213152 --- /dev/null +++ b/Documentation/translations/sp_SP/index.rst @@ -0,0 +1,81 @@ + +===================== +Traducción al español +===================== + +.. raw:: latex + + \kerneldocCJKoff + +:maintainer: Carlos Bilbao <carlos.bilbao@amd.com> + +.. _sp_disclaimer: + +Advertencia +=========== + +El objetivo de esta traducción es facilitar la lectura y comprensión para +aquellos que no entiendan inglés o duden de sus interpretaciones, o +simplemente para aquellos que prefieran leer en el idioma español. Sin +embargo, tenga en cuenta que la *única* documentación oficial es la que +está en inglés: :ref:`linux_doc` + +La propagación simultánea de la traducción de una modificación en +:ref:`linux_doc` es altamente improbable. Los maintainers y colaboradores +de la traducción intentan mantener sus traducciones al día, en tanto les +es posible. Por tanto, no existe ninguna garantía de que una traducción +esté actualizada con las últimas modificaciones. Si lo que lee en una +traducción no se corresponde con lo que ve en el código fuente, informe +al maintainer de la traducción y, si puede, consulte la documentación en +inglés. + +Una traducción no es una * bifurcación * de la documentación oficial, por +lo que los usuarios no encontrarán aquí ninguna información que no sea la +versión oficial. Cualquier adición, supresión o modificación de los +contenidos deberá ser realizada anteriormente en los documentos en inglés. +Posteriormente, y cuando sea posible, dicho cambio debería aplicarse +también a las traducciones. Los maintainers de las traducciones aceptan +contribuciones que son puramente de interés relativo a la traducción (por +ejemplo, nuevas traducciones, actualizaciones, correcciones, etc.). + +Las traducciones tratan de ser lo más precisas posible pero no es posible +convertir directamente un idioma a otro. Cada idioma tiene su propia +gramática, y una cultura tras ella, por lo tanto, la traducción de una +oración al inglés se podría modificar para adaptarla al español. Por esta +razón, cuando lea esta traducción, puede encontrar algunas diferencias en +la forma, pero todavía transmiten el mensaje original. A pesar de la gran +difusión del inglés en el idioma hablado, cuando sea posible, expresiones +en inglés serán reemplazadas por las palabras correspondientes en español. + +Si necesita ayuda para comunicarse con la comunidad de Linux pero no se +siente cómodo escribiendo en inglés, puede pedir ayuda al maintainer para +obtener una traducción. + +Muchos países hablan español, cada uno con su propia cultura, expresiones, +y diferencias gramaticales en ocasiones significativas. Las traducciones de +los maintainers pueden utilizar el español con el que dichos maintainers se +sientan más cómodos. En principio, estas pequeñas diferencias no deberían +suponer una gran barrera para hablantes de distintas versiones del español, +pero en caso de duda se puede consultar a los maintainers. + +La documentación del kernel Linux +================================= + +Este es el nivel superior de la documentación del kernel en idioma español. +La traducción es incompleta, y podría encontrar advertencias que indiquen +la falta de una traducción o de un grupo de traducciones. + +En términos más generales, la documentación, como el kernel mismo, están en +constante desarrollo. Las mejoras en la documentación siempre son +bienvenidas; de modo que, si desea ayudar, únase a la lista de correo +linux-doc en vger.kernel.org. + +Traducciones al español +======================= + +.. toctree:: + :maxdepth: 1 + + howto + process/index + wrappers/memory-barriers diff --git a/Documentation/translations/sp_SP/memory-barriers.txt b/Documentation/translations/sp_SP/memory-barriers.txt new file mode 100644 index 0000000000..27097a808c --- /dev/null +++ b/Documentation/translations/sp_SP/memory-barriers.txt @@ -0,0 +1,3134 @@ +NOTE: +This is a version of Documentation/memory-barriers.txt translated into +Spanish by Carlos Bilbao <carlos.bilbao@amd.com>. If you find any +difference between this document and the original file or a problem with +the translation, please contact the maintainer of this file. Please also +note that the purpose of this file is to be easier to read for non English +(read: Spanish) speakers and is not intended as a fork. So if you have any +comments or updates for this file please update the original English file +first. The English version is definitive, and readers should look there if +they have any doubt. + + ====================================== + BARRERAS DE MEMORIA EN EL KERNEL LINUX + ====================================== + +Documento original: David Howells <dhowells@redhat.com> + Paul E. McKenney <paulmck@linux.ibm.com> + Will Deacon <will.deacon@arm.com> + Peter Zijlstra <peterz@infradead.org> + +Traducido por: Carlos Bilbao <carlos.bilbao@amd.com> +Nota: Si tiene alguna duda sobre la exactitud del contenido de esta +traducción, la única referencia válida es la documentación oficial en +inglés. + +=========== +ADVERTENCIA +=========== + +Este documento no es una especificación; es intencionalmente (por motivos +de brevedad) y sin querer (por ser humanos) incompleta. Este documento +pretende ser una guía para usar las diversas barreras de memoria +proporcionadas por Linux, pero ante cualquier duda (y hay muchas) por favor +pregunte. Algunas dudas pueden ser resueltas refiriéndose al modelo de +consistencia de memoria formal y documentación en tools/memory-model/. Sin +embargo, incluso este modelo debe ser visto como la opinión colectiva de +sus maintainers en lugar de que como un oráculo infalible. + +De nuevo, este documento no es una especificación de lo que Linux espera +del hardware. + +El propósito de este documento es doble: + + (1) especificar la funcionalidad mínima en la que se puede confiar para + cualquier barrera en concreto, y + + (2) proporcionar una guía sobre cómo utilizar las barreras disponibles. + +Tenga en cuenta que una arquitectura puede proporcionar más que el +requisito mínimo para cualquier barrera en particular, pero si la +arquitectura proporciona menos de eso, dicha arquitectura es incorrecta. + +Tenga en cuenta también que es posible que una barrera no valga (sea no-op) +para alguna arquitectura porque por la forma en que funcione dicha +arquitectura, la barrera explícita resulte innecesaria en ese caso. + +========== +CONTENIDOS +========== + + (*) Modelo abstracto de acceso a memoria. + + - Operaciones del dispositivo. + - Garantías. + + (*) ¿Qué son las barreras de memoria? + + - Variedades de barrera de memoria. + - ¿Qué no se puede asumir sobre las barreras de memoria? + - Barreras de dirección-dependencia (históricas). + - Dependencias de control. + - Emparejamiento de barreras smp. + - Ejemplos de secuencias de barrera de memoria. + - Barreras de memoria de lectura frente a especulación de carga. + - Atomicidad multicopia. + + (*) Barreras explícitas del kernel. + + - Barrera del compilador. + - Barreras de memoria de la CPU. + + (*) Barreras de memoria implícitas del kernel. + + - Funciones de adquisición de cerrojo. + - Funciones de desactivación de interrupciones. + - Funciones de dormir y despertar. + - Funciones varias. + + (*) Efectos de barrera adquiriendo intra-CPU. + + - Adquisición vs accesos a memoria. + + (*) ¿Dónde se necesitan barreras de memoria? + + - Interacción entre procesadores. + - Operaciones atómicas. + - Acceso a dispositivos. + - Interrupciones. + + (*) Efectos de barrera de E/S del kernel. + + (*) Modelo de orden mínimo de ejecución asumido. + + (*) Efectos de la memoria caché de la CPU. + + - Coherencia de caché. + - Coherencia de caché frente a DMA. + - Coherencia de caché frente a MMIO. + + (*) Cosas que hacen las CPU. + + - Y luego está el Alfa. + - Guests de máquinas virtuales. + + (*) Ejemplos de usos. + + - Buffers circulares. + + (*) Referencias. + + +==================================== +MODELO ABSTRACTO DE ACCESO A MEMORIA +==================================== + +Considere el siguiente modelo abstracto del sistema: + + : : + : : + : : + +-------+ : +--------+ : +-------+ + | | : | | : | | + | | : | | : | | + | CPU 1 |<----->| Memoria|<----->| CPU 2 | + | | : | | : | | + | | : | | : | | + +-------+ : +--------+ : +-------+ + ^ : ^ : ^ + | : | : | + | : | : | + | : v : | + | : +--------+ : | + | : | | : | + | : | Disposi| : | + +---------->| tivo |<----------+ + : | | : + : | | : + : +--------+ : + : : + +Cada CPU ejecuta un programa que genera operaciones de acceso a la memoria. +En la CPU abstracta, el orden de las operaciones de memoria es muy +relajado, y una CPU en realidad puede realizar las operaciones de memoria +en el orden que desee, siempre que la causalidad del programa parezca +mantenerse. De manera similar, el compilador también puede organizar las +instrucciones que emite en el orden que quiera, siempre que no afecte al +funcionamiento aparente del programa. + +Entonces, en el diagrama anterior, los efectos de las operaciones de +memoria realizadas por un CPU son percibidos por el resto del sistema a +medida que las operaciones cruzan la interfaz entre la CPU y el resto del +sistema (las líneas discontinuas a puntos). + +Por ejemplo, considere la siguiente secuencia de eventos: + + CPU 1 CPU 2 + =============== =============== + { A == 1; B == 2 } + A = 3; x = B; + B = 4; y = A; + +El conjunto de accesos visto por el sistema de memoria en el medio se puede +organizar en 24 combinaciones diferentes (donde LOAD es cargar y STORE es +guardar): + +STORE A=3, STORE B=4, y=LOAD A->3, x=LOAD B->4 +STORE A=3, STORE B=4, x=LOAD B->4, y=LOAD A->3 +STORE A=3, y=LOAD A->3, STORE B=4, x=LOAD B->4 +STORE A=3, y=LOAD A->3, x=LOAD B->2, STORE B=4 +STORE A=3, x=LOAD B->2, STORE B=4, y=LOAD A->3 +STORE A=3, x=LOAD B->2, y=LOAD A->3, STORE B=4 +STORE B=4, STORE A=3, y=LOAD A->3, x=LOAD B->4 +STORE B=4, ... +... + +y por lo tanto puede resultar en cuatro combinaciones diferentes de +valores: + +x == 2, y == 1 +x == 2, y == 3 +x == 4, y == 1 +x == 4, y == 3 + +Además, los stores asignados por una CPU al sistema de memoria pueden no +ser percibidos por los loads realizados por otra CPU en el mismo orden en +que fueron realizados. + +Como otro ejemplo, considere esta secuencia de eventos: + + CPU 1 CPU 2 + =============== =============== + { A == 1, B == 2, C == 3, P == &A, Q == &C } + B = 4; Q = P; + P = &B; D = *Q; + +Aquí hay una dependencia obvia de la dirección, ya que el valor cargado en +D depende en la dirección recuperada de P por la CPU 2. Al final de la +secuencia, cualquiera de los siguientes resultados son posibles: + + (Q == &A) y (D == 1) + (Q == &B) y (D == 2) + (Q == &B) y (D == 4) + +Tenga en cuenta que la CPU 2 nunca intentará cargar C en D porque la CPU +cargará P en Q antes de emitir la carga de *Q. + +OPERACIONES DEL DISPOSITIVO +--------------------------- + +Algunos dispositivos presentan sus interfaces de control como colecciones +de ubicaciones de memoria, pero el orden en que se accede a los registros +de control es muy importante. Por ejemplo, imagine una tarjeta ethernet con +un conjunto de registros a los que se accede a través de un registro de +puerto de dirección (A) y un registro de datos del puerto (D). Para leer el +registro interno 5, el siguiente código podría entonces ser usado: + + *A = 5; + x = *D; + +pero esto podría aparecer como cualquiera de las siguientes dos secuencias: + + STORE *A = 5, x = LOAD *D + x = LOAD *D, STORE *A = 5 + +el segundo de las cuales casi con certeza resultará en mal funcionamiento, +ya que se estableció la dirección _después_ de intentar leer el registro. + + +GARANTÍAS +--------- + +Hay algunas garantías mínimas que se pueden esperar de una CPU: + + (*) En cualquier CPU dada, los accesos a la memoria dependiente se + emitirán en orden, con respeto a sí mismo. Esto significa que para: + + Q = READ_ONCE(P); D = READ_ONCE(*Q); + + donde READ_ONCE() es LEER_UNA_VEZ(), la CPU emitirá las siguientes + operaciones de memoria: + + Q = LOAD P, D = LOAD *Q + + y siempre en ese orden. Sin embargo, en DEC Alpha, READ_ONCE() también + emite una instrucción de barrera de memoria, de modo que una CPU DEC + Alpha, sin embargo emite las siguientes operaciones de memoria: + + Q = LOAD P, MEMORY_BARRIER, D = LOAD *Q, MEMORY_BARRIER + + Ya sea en DEC Alpha o no, READ_ONCE() también evita que el compilador + haga cosas inapropiadas. + + (*) Los loads y stores superpuestos dentro de una CPU en particular + parecerán ser ordenados dentro de esa CPU. Esto significa que para: + + a = READ_ONCE(*X); WRITE_ONCE(*X, b); + + donde WRITE_ONCE() es ESCRIBIR_UNA_VEZ(), la CPU solo emitirá la + siguiente secuencia de operaciones de memoria: + + a = LOAD *X, STORE *X = b + + Y para: + + WRITE_ONCE(*X, c); d = READ_ONCE(*X); + + la CPU solo emitirá: + + STORE *X = c, d = LOAD *X + + (Los loads y stores se superponen si están destinados a piezas + superpuestas de memoria). + +Y hay una serie de cosas que _deben_ o _no_ deben asumirse: + + (*) _No_debe_ asumirse que el compilador hará lo que usted quiera + con referencias de memoria que no están protegidas por READ_ONCE() y + WRITE ONCE(). Sin ellos, el compilador tiene derecho a hacer todo tipo + de transformaciones "creativas", que se tratan en la sección BARRERA + DEL COMPILADOR. + + (*) _No_debe_ suponerse que se emitirán loads y stores independientes + en el orden dado. Esto significa que para: + + X = *A; Y = *B; *D = Z; + + podemos obtener cualquiera de las siguientes secuencias: + + X = LOAD *A, Y = LOAD *B, STORE *D = Z + X = LOAD *A, STORE *D = Z, Y = LOAD *B + Y = LOAD *B, X = LOAD *A, STORE *D = Z + Y = LOAD *B, STORE *D = Z, X = LOAD *A + STORE *D = Z, X = LOAD *A, Y = LOAD *B + STORE *D = Z, Y = LOAD *B, X = LOAD *A + + (*) Se _debe_ suponer que los accesos de memoria superpuestos pueden + fusionarse o ser descartados. Esto significa que para: + + X = *A; Y = *(A + 4); + + podemos obtener cualquiera de las siguientes secuencias: + +X = LOAD *A; Y = LOAD *(A + 4); +Y = LOAD *(A + 4); X = LOAD *A; +{X, Y} = LOAD {*A, *(A + 4) }; + + Y para: + +*A = X; *(A + 4) = Y; + + podemos obtener cualquiera de: + +STORE *A = X; STORE *(A + 4) = Y; +STORE *(A + 4) = Y; STORE *A = X; +STORE {*A, *(A + 4) } = {X, Y}; + +Y hay anti-garantías: + +(*) Estas garantías no se aplican a los campos de bits, porque los + compiladores a menudo generan código para modificarlos usando + secuencias de lectura-modificación-escritura no atómica. No intente + utilizar campos de bits para sincronizar algoritmos paralelos. + +(*) Incluso en los casos en que los campos de bits están protegidos por + cerrojos (o "cerrojos", o "locks"), todos los componentes en un campo + de bits dado deben estar protegidos por un candado. Si dos campos en un + campo de bits dado están protegidos por diferentes locks, las + secuencias de lectura-modificación-escritura no atómicas del lock + pueden causar una actualización a una campo para corromper el valor de + un campo adyacente. + +(*) Estas garantías se aplican solo a escalares correctamente alineados y + dimensionados. De "tamaño adecuado" significa actualmente variables que + son del mismo tamaño que "char", "short", "int" y "long". + "Adecuadamente alineado" significa la alineación natural, por lo tanto, + no hay restricciones para "char", alineación de dos bytes para "short", + alineación de cuatro bytes para "int", y alineación de cuatro u ocho + bytes para "long", en sistemas de 32 y 64 bits, respectivamente. Tenga + en cuenta que estos garantías se introdujeron en el estándar C11, así + que tenga cuidado cuando utilice compiladores anteriores a C11 (por + ejemplo, gcc 4.6). La parte de la norma que contiene esta garantía es + la Sección 3.14, que define "ubicación de memoria" de la siguiente + manera: + + ubicación de memoria + ya sea un objeto de tipo escalar, o una secuencia máxima + de campos de bits adyacentes, todos con ancho distinto de cero + + NOTE 1: Dos hilos de ejecución pueden actualizar y acceder + ubicaciones de memoria separadas sin interferir entre + ellos. + + NOTE 2: Un campo de bits y un miembro adyacente que no es un campo de + bits están en ubicaciones de memoria separadas. Lo mismo sucede con + dos campos de bits, si uno se declara dentro de un declaración de + estructura anidada y el otro no, o si las dos están separados por una + declaración de campo de bits de longitud cero, o si están separados por + un miembro no declarado como campo de bits. No es seguro actualizar + simultáneamente dos campos de bits en la misma estructura si entre + todos los miembros declarados también hay campos de bits, sin importar + cuál resulta ser el tamaño de estos campos de bits intermedios. + + +================================== +¿QUÉ SON LAS BARRERAS DE MEMORIA? +================================== + +Como se puede leer arriba, las operaciones independientes de memoria se +realizan de manera efectiva en orden aleatorio, pero esto puede ser un +problema para la interacción CPU-CPU y para la E/S ("I/O"). Lo que se +requiere es alguna forma de intervenir para instruir al compilador y al +CPU para restringir el orden. + +Las barreras de memoria son este tipo de intervenciones. Imponen una +percepción de orden parcial, sobre las operaciones de memoria a ambos lados +de la barrera. + +Tal cumplimiento es importante porque las CPUs y otros dispositivos en un +sistema pueden usar una variedad de trucos para mejorar el rendimiento, +incluido el reordenamiento, diferimiento y combinación de operaciones de +memoria; cargas especulativas; predicción de "branches" especulativos y +varios tipos de almacenamiento en caché. Las barreras de memoria se +utilizan para anular o suprimir estos trucos, permitiendo que el código +controle sensatamente la interacción de múltiples CPU y/o dispositivos. + + +VARIEDADES DE BARRERA DE MEMORIA +--------------------------------- + +Las barreras de memoria vienen en cuatro variedades básicas: + + (1) Barreras de memoria al escribir o almacenar (Write or store memory + barriers). + + Una barrera de memoria de escritura garantiza que todas las + operaciones de STORE especificadas antes de que la barrera aparezca + suceden antes de todas las operaciones STORE especificadas después + de la barrera, con respecto a los otros componentes del sistema. + + Una barrera de escritura es un orden parcial solo en los stores; No + es requerido que tenga ningún efecto sobre los loads. + + Se puede considerar que una CPU envía una secuencia de operaciones de + store al sistema de memoria a medida que pasa el tiempo. Todos los + stores _antes_ de una barrera de escritura ocurrirán _antes_ de todos + los stores después de la barrera de escritura. + + [!] Tenga en cuenta que las barreras de escritura normalmente deben + combinarse con read o barreras de address-dependency barriers + (dependencia de dirección); consulte la subsección + "Emparejamiento de barreras smp". + + + (2) Barrera de dependencia de dirección (histórico). + + Una barrera de dependencia de dirección es una forma más débil de + barrera de lectura. En el caso de que se realicen dos loads de manera + que la segunda dependa del resultado de la primera (por ejemplo: el + primer load recupera la dirección a la que se dirigirá el segundo + load), una barrera de dependencia de dirección sería necesaria para + asegurarse de que el objetivo de la segunda carga esté actualizado + después de acceder a la dirección obtenida por la primera carga. + + Una barrera de dependencia de direcciones es una ordenación parcial en + laods de direcciones interdependientes; no se requiere que tenga + ningún efecto en los stores, ya sean cargas de memoria o cargas + de memoria superpuestas. + + Como se mencionó en (1), las otras CPU en el sistema pueden verse como + secuencias de stores en el sistema de memoria que la considerada CPU + puede percibir. Una barrera de dependencia de dirección emitida por + la CPU en cuestión garantiza que para cualquier carga que la preceda, + si esa carga toca alguna secuencia de stores de otra CPU, entonces + en el momento en que la barrera se complete, los efectos de todos los + stores antes del cambio del load serán perceptibles por cualquier + carga emitida después la barrera de la dependencia de la dirección. + + Consulte la subsección "Ejemplos de secuencias de barrera de memoria" + para ver los diagramas mostrando las restricciones de orden. + + [!] Tenga en cuenta que la primera carga realmente tiene que tener una + dependencia de _dirección_ y no es una dependencia de control. Si la + dirección para la segunda carga depende de la primera carga, pero la + dependencia es a través de un condicional en lugar de -en realidad- + cargando la dirección en sí, entonces es una dependencia de _control_ + y se requiere una barrera de lectura completa o superior. Consulte la + subsección "Dependencias de control" para más información. + + [!] Tenga en cuenta que las barreras de dependencia de dirección + normalmente deben combinarse con barreras de escritura; consulte la + subsección "Emparejamiento de barreras smp". + + [!] Desde el kernel v5.9, se eliminó la API del kernel para barreras + de memoria de direcciones explícitas. Hoy en día, las APIs para marcar + cargas de variables compartidas, como READ_ONCE() y rcu_dereference(), + proporcionan barreras de dependencia de dirección implícitas. + + (3) Barreras de memoria al leer o cargar (Read or load memory + barriers). + + Una barrera de lectura es una barrera de dependencia de direcciones, + más una garantía de que todas las operaciones de LOAD especificadas + antes de la barrera parecerán ocurrir antes de todas las operaciones + de LOAD especificadas después de la barrera con respecto a los demás + componentes del sistema. + + Una barrera de lectura es un orden parcial solo en cargas; no es + necesario que tenga ningún efecto en los stores. + + Las barreras de memoria de lectura implican barreras de dependencia de + direcciones, y por tanto puede sustituirlas por estas. + + [!] Tenga en mente que las barreras de lectura normalmente deben + combinarse con barreras de escritura; consulte la subsección + "Emparejamiento de barreras smp". + + (4) Barreras de memoria generales + + Una barrera de memoria general proporciona la garantía de que todas + las operaciones LOAD y STORE especificadas antes de que la barrera + aparezca suceden antes de que todas las operaciones LOAD y STORE + especificadas después de la barrera con respecto a los demás + componentes del sistema. + + Una barrera de memoria general es un orden parcial tanto en + operaciones de carga como de almacenamiento. + + Las barreras de memoria generales implican barreras de memoria tanto + de lectura como de escritura, de modo que pueden sustituir a + cualquiera. + +Y un par de variedades implícitas: + + (5) ACQUIRE (de adquisición). + + Esto actúa como una barrera permeable unidireccional. Garantiza que + toda las operaciones de memoria después de la operación ACQUIRE + parezcan suceder después de la ACQUIRE con respecto a los demás + componentes del sistema. Las operaciones ACQUIRE incluyen operaciones + LOCK y smp_load_acquire(), y operaciones smp_cond_load_acquire(). + + Las operaciones de memoria que ocurren antes de una operación ACQUIRE + pueden parecer suceder después de que se complete. + + Una operación ACQUIRE casi siempre debe estar emparejada con una + operación RELEASE (de liberación). + + + (6) Operaciones RELEASE (de liberación). + + Esto también actúa como una barrera permeable unidireccional. + Garantiza que todas las operaciones de memoria antes de la operación + RELEASE parecerán ocurrir antes de la operación RELEASE con respecto a + los demás componentes del sistema. Las operaciones de RELEASE incluyen + operaciones de UNLOCK y operaciones smp_store_release(). + + Las operaciones de memoria que ocurren después de una operación + RELEASE pueden parecer suceder antes de que se complete. + + El uso de las operaciones ACQUIRE y RELEASE generalmente excluye la + necesidad de otros tipos de barrera de memoria. Además, un par + RELEASE+ACQUIRE NO garantiza actuar como una barrera de memoria + completa. Sin embargo, después de un ACQUIRE de una variable dada, + todos los accesos a la memoria que preceden a cualquier anterior + RELEASE en esa misma variable están garantizados como visibles. En + otras palabras, dentro de la sección crítica de una variable dada, + todos los accesos de todas las secciones críticas anteriores para esa + variable habrán terminado de forma garantizada. + + Esto significa que ACQUIRE actúa como una operación mínima de + "adquisición" y RELEASE actúa como una operación mínima de + "liberación". + +Un subconjunto de las operaciones atómicas descritas en atomic_t.txt +contiene variantes de ACQUIRE y RELEASE, además de definiciones +completamente ordenadas o relajadas (sin barrera semántica). Para +composiciones atómicas que realizan tanto un load como store, la semántica +ACQUIRE se aplica solo a la carga y la semántica RELEASE se aplica sólo a +la parte de la operación del store. + +Las barreras de memoria solo son necesarias cuando existe la posibilidad de +interacción entre dos CPU o entre una CPU y un dispositivo. Si se puede +garantizar que no habrá tal interacción en ninguna pieza de código en +particular, entonces las barreras de memoria son innecesarias en ese +fragmento de código. + +Tenga en cuenta que estas son las garantías _mínimas_. Diferentes +arquitecturas pueden proporcionar garantías más sustanciales, pero no se +puede confiar en estas fuera de esa arquitectura en específico. + + +¿QUÉ NO SE PUEDE ASUMIR SOBRE LAS BARRERAS DE LA MEMORIA? +--------------------------------------------------------- + +Hay ciertas cosas que las barreras de memoria del kernel Linux no +garantizan: + + (*) No hay garantía de que ninguno de los accesos a la memoria + especificados antes de una barrera de memoria estará _completo_ al + completarse una instrucción de barrera de memoria; se puede considerar + que la barrera dibuja una línea en la cola de acceso del CPU que no + pueden cruzar los accesos del tipo correspondiente. + + (*) No hay garantía de que la emisión de una barrera de memoria en una CPU + tenga cualquier efecto directo en otra CPU o cualquier otro hardware + en el sistema. El efecto indirecto será el orden en que la segunda CPU + ve los efectos de los primeros accesos que ocurren de la CPU, pero lea + el siguiente argumento: + + (*) No hay garantía de que una CPU vea el orden correcto de los efectos + de los accesos de una segunda CPU, incluso _si_ la segunda CPU usa una + barrera de memoria, a menos que la primera CPU _también_ use una + barrera de memoria coincidente (vea el subapartado "Emparejamiento de + barrera SMP"). + + (*) No hay garantía de que alguna pieza intermedia fuera del hardware[*] + del CPU no reordenará los accesos a la memoria. Los mecanismos de + coherencia de caché del CPU deben propagar los efectos indirectos de + una barrera de memoria entre las CPU, pero es posible que no lo hagan + en orden. + + [*] Para obtener información sobre bus mastering DMA y coherencia, lea: + + Documentation/driver-api/pci/pci.rst + Documentation/core-api/dma-api-howto.rst + Documentation/core-api/dma-api.rst + + +BARRERA DE DEPENDENCIA DE DIRECCIÓN (HISTÓRICO) +----------------------------------------------- + +A partir de la versión 4.15 del kernel Linux, se agregó un smp_mb() a +READ_ONCE() para DEC Alpha, lo que significa que las únicas personas que +necesitan prestar atención a esta sección son aquellas que trabajan en el +código específico de la arquitectura DEC Alpha y aquellas que trabajan en +READ_ONCE() por dentro. Para aquellos que lo necesitan, y para aquellos que +estén interesados desde un punto de vista histórico, aquí está la historia +de las barreras de dependencia de dirección. + +[!] Si bien las dependencias de direcciones se observan tanto en carga a +carga como en relaciones de carga a store, las barreras de dependencia de +dirección no son necesarias para situaciones de carga a store. + +El requisito de las barreras de dependencia de dirección es un poco sutil, +y no siempre es obvio que sean necesarias. Para ilustrar, considere la +siguiente secuencia de eventos: + + CPU 1 CPU 2 + =============== =============== + { A == 1, B == 2, C == 3, P == &A, Q == &C } + B = 4; + <barrera de escritura> + WRITE_ONCE(P, &B); + Q = READ_ONCE_OLD(P); + D = *Q; + +[!] READ_ONCE_OLD() corresponde a READ_ONCE() del kernel anterior a 4.15, +que no implica una barrera de dependencia de direcciones. + +Hay una clara dependencia de dirección aquí, y parecería que al final de +la secuencia, Q debe ser &A o &B, y que: + + (Q == &A) implica (D == 1) + (Q == &B) implica (D == 4) + +¡Pero! La percepción de la CPU 2 de P puede actualizarse _antes_ de su +percepción de B, por lo tanto dando lugar a la siguiente situación: + + (Q == &B) y (D == 2) ???? + +Si bien esto puede parecer una falla en el mantenimiento de la coherencia +o la causalidad, no lo es, y este comportamiento se puede observar en +ciertas CPU reales (como DEC Alfa). + +Para lidiar con esto, READ_ONCE() proporciona una barrera de dependencia +de dirección implícita desde el lanzamiento del kernel v4.15: + + CPU 1 CPU 2 + =============== =============== + { A == 1, B == 2, C == 3, P == &A, Q == &C } + B = 4; + <barrera de escritura> + WRITE_ONCE(P, &B); + Q = READ_ONCE(P); + <barrera de dependencia de dirección implícita> + D = *Q; + +Esto refuerza la ocurrencia de una de las dos implicaciones, y previene la +tercera posibilidad de surgir. + + +[!] Tenga en cuenta que esta situación extremadamente contraria a la +intuición surge más fácilmente en máquinas con cachés divididos, de modo +que, por ejemplo, un banco de caché procesa líneas de caché pares y el otro +banco procesa líneas impares de caché. El puntero P podría almacenarse en +una línea de caché impar y la variable B podría almacenarse en una línea de +caché con número par. Entonces, si el banco de números pares de la memoria +caché de la CPU de lectura está extremadamente ocupado mientras que el +banco impar está inactivo, uno podría ver el nuevo valor del puntero P +(&B), pero el antiguo valor de la variable B (2). + + +No se requiere una barrera de dependencia de dirección para ordenar +escrituras dependientes porque las CPU que admite el kernel Linux no +escriben hasta que están seguros (1) de que la escritura realmente +sucederá, (2) de la ubicación de la escritura, y (3) del valor a escribir. +Pero, por favor, lea atentamente la sección "DEPENDENCIAS DEL CONTROL" y el +archivo Documentation/RCU/rcu_dereference.rst: el compilador puede romperse +y romper dependencias en muchas formas altamente creativas. + + CPU 1 CPU 2 + =============== =============== + { A == 1, B == 2, C = 3, P == &A, Q == &C } + B = 4; + <barrera de escritura> + WRITE_ONCE(P, &B); + Q = READ_ONCE_OLD(P); + WRITE_ONCE(*Q, 5); + +Por lo tanto, no se requiere ninguna barrera de dependencia de direcciones +para ordenar la lectura en Q con el load en *Q. En otras palabras, este +resultado está prohibido, incluso sin una barrera de dependencia de +dirección implícita del READ_ONCE() moderno: + + (Q == &B) && (B == 4) + +Tenga en cuenta que este patrón debe ser raro. Después de todo, el objetivo +del orden de dependencia es -prevenir- escrituras en la estructura de +datos, junto con los costosos errores de caché asociados con tales +escrituras. Este patrón se puede utilizar para registrar raras condiciones +de error y similares, y el orden natural de las CPUs evita que se pierdan +tales registros. + + +Tenga en cuenta que el orden proporcionado por una dependencia de dirección +es local para la CPU que lo contiene. Lea la sección sobre "Atomicidad +multicopia" para más información. + + +La barrera de dependencia de dirección es muy importante para el sistema +RCU, por ejemplo. Vea rcu_assign_pointer() y rcu_dereference() en +include/linux/rcupdate.h. Esto permite que el objetivo actual de un puntero +RCU sea reemplazado con un nuevo objetivo modificado, sin que el objetivo +del reemplazo parezca estar inicializado de manera incompleta. + +Consulte también la subsección sobre "Coherencia de caché" para obtener un +ejemplo más completo. + +DEPENDENCIAS DE CONTROL +----------------------- + +Las dependencias de control pueden ser un poco complicadas porque los +compiladores actuales no las entienden. El propósito de esta sección es +ayudarle a prevenir que la ignorancia del compilador rompa su código. + +Una dependencia de control load-load (de carga a carga) requiere una +barrera de memoria de lectura completa, no simplemente una barrera +(implícita) de dependencia de direcciones para que funcione correctamente. +Considere el siguiente fragmento de código: + + q = READ_ONCE(a); + <barrera implícita de dependencia de direcciones> + if (q) { + /* BUG: No hay dependencia de dirección!!! */ + p = READ_ONCE(b); + } + +Esto no tendrá el efecto deseado porque no hay una dependencia de dirección +real, sino más bien una dependencia de control que la CPU puede +cortocircuitar al intentar predecir el resultado por adelantado, para que +otras CPU vean la carga de b como si hubiera ocurrido antes que la carga de +a. En cuyo caso lo que realmente se requiere es: + + q = READ_ONCE(a); + if (q) { + <barrera de lectura> + p = READ_ONCE(b); + } + +Sin embargo, los stores no se especulan. Esto significa que ordenar -es- +provisto para dependencias de control de load-store, como en el siguiente +ejemplo: + + q = READ_ONCE(a); + if (q) { + WRITE_ONCE(b, 1); + } + +Las dependencias de control se emparejan normalmente con otros tipos de +barreras. Dicho esto, tenga en cuenta que ni READ_ONCE() ni WRITE_ONCE() +son opcionales! Sin READ_ONCE(), el compilador podría combinar la carga de +'a' con otras cargas de 'a'. Sin WRITE_ONCE(), el compilador podría +combinar el store de 'b' con otros stores de 'b'. Cualquiera de estos casos +puede dar lugar a efectos en el orden muy contrarios a la intuición. + +Peor aún, si el compilador puede probar (decir) que el valor de la +variable 'a' siempre es distinta de cero, estaría dentro de sus derechos +para optimizar el ejemplo original eliminando la declaración "if", como: + + q = a; + b = 1; /* BUG: Compilador y CPU pueden ambos reordernar!!! */ + +Así que no deje de lado READ_ONCE(). + +Es tentador tratar de hacer cumplir el orden en stores idénticos en ambos +caminos del "if" de la siguiente manera: + + q = READ_ONCE(a); + if (q) { + barrier(); + WRITE_ONCE(b, 1); + hacer_algo(); + } else { + barrier(); + WRITE_ONCE(b, 1); + hacer_otra_cosa(); + } + +Desafortunadamente, los compiladores actuales transformarán esto de la +siguiente manera en casos de alto nivel de optimización: + + q = READ_ONCE(a); + barrier(); + WRITE_ONCE(b, 1); /* BUG: No hay orden en load de a!!! */ + if (q) { + /* WRITE_ONCE(b, 1); -- movido arriba, BUG!!! */ + hacer_algo(); + } else { + /* WRITE_ONCE(b, 1); -- movido arriba, BUG!!! */ + hacer_otra_cosa(); + } + +Ahora no hay condicional entre la carga de 'a' y el store de 'b', lo que +significa que la CPU está en su derecho de reordenarlos: El condicional es +absolutamente necesario y debe estar presente en el código ensamblador +incluso después de que se hayan aplicado todas las optimizaciones del +compilador. Por lo tanto, si necesita ordenar en este ejemplo, necesita +explícitamente barreras de memoria, por ejemplo, smp_store_release(): + + + q = READ_ONCE(a); + if (q) { + smp_store_release(&b, 1); + hacer_algo(); + } else { + smp_store_release(&b, 1); + hacer_otra_cosa(); + } + +Por el contrario, sin barreras de memoria explícita, el control de un if +con dos opciones está garantizado solo cuando los stores difieren, por +ejemplo: + + q = READ_ONCE(a); + if (q) { + WRITE_ONCE(b, 1); + hacer_algo(); + } else { + WRITE_ONCE(b, 2); + hacer_otra_cosa(); + } + +Aún se requiere el inicial READ_ONCE() para evitar que el compilador toque +el valor de 'a'. + +Además, debe tener cuidado con lo que hace con la variable local 'q', de lo +contrario, el compilador podría adivinar el valor y volver a eliminar el +necesario condicional. Por ejemplo: + + q = READ_ONCE(a); + if (q % MAX) { + WRITE_ONCE(b, 1); + hacer_algo(); + } else { + WRITE_ONCE(b, 2); + hacer_otra_cosa(); + } + +Si MAX se define como 1, entonces el compilador sabe que (q % MAX) es igual +a cero, en cuyo caso el compilador tiene derecho a transformar el código +anterior en el siguiente: + + q = READ_ONCE(a); + WRITE_ONCE(b, 2); + hacer_otra_cosa(); + +Dada esta transformación, la CPU no está obligada a respetar el orden entre +la carga de la variable 'a' y el store de la variable 'b'. Es tentador +agregar una barrier(), pero esto no ayuda. El condicional se ha ido, y la +barrera no lo traerá de vuelta. Por lo tanto, si confia en este orden, debe +asegurarse de que MAX sea mayor que uno, tal vez de la siguiente manera: + + q = READ_ONCE(a); + BUILD_BUG_ON(MAX <= 1); /* Orden de carga de a con store de b */ + if (q % MAX) { + WRITE_ONCE(b, 1); + hacer_algo(); + } else { + WRITE_ONCE(b, 2); + hacer_otra_cosa(); + } + +Tenga en cuenta una vez más que los stores de 'b' difieren. Si fueran +idénticos, como se señaló anteriormente, el compilador podría sacar ese +store fuera de la declaración 'if'. + +También debe tener cuidado de no confiar demasiado en el cortocircuito +de la evaluación booleana. Considere este ejemplo: + + q = READ_ONCE(a); + if (q || 1 > 0) + WRITE_ONCE(b, 1); + +Debido a que la primera condición no puede fallar y la segunda condición es +siempre cierta, el compilador puede transformar este ejemplo de la +siguiente manera, rompiendo la dependencia del control: + + q = READ_ONCE(a); + WRITE_ONCE(b, 1); + +Este ejemplo subraya la necesidad de asegurarse de que el compilador no +pueda adivinar su código. Más generalmente, aunque READ_ONCE() fuerza +al compilador para emitir código para una carga dada, no fuerza al +compilador para usar los resultados. + +Además, las dependencias de control se aplican solo a la cláusula then y +la cláusula else de la sentencia if en cuestión. En particular, no se +aplica necesariamente al código que sigue a la declaración if: + + q = READ_ONCE(a); + if (q) { + WRITE_ONCE(b, 1); + } else { + WRITE_ONCE(b, 2); + } + WRITE_ONCE(c, 1); /* BUG: No hay orden para la lectura de 'a'. */ + +Es tentador argumentar que, de hecho, existe un orden porque el compilador +no puede reordenar accesos volátiles y tampoco puede reordenar escrituras +en 'b' con la condición. Desafortunadamente para esta línea de +razonamiento, el compilador podría compilar las dos escrituras en 'b' como +instrucciones de movimiento condicional, como en este fantástico idioma +pseudo-ensamblador: + + ld r1,a + cmp r1,$0 + cmov,ne r4,$1 + cmov,eq r4,$2 + st r4,b + st $1,c + +Una CPU débilmente ordenada no tendría dependencia de ningún tipo entre la +carga de 'a' y el store de 'c'. Las dependencias de control se extenderían +solo al par de instrucciones cmov y el store dependiente de ellas. En +resumen, las dependencias de control se aplican solo a los stores en la +cláusula then y la cláusula else de la sentencia if en cuestión (incluidas +las funciones invocado por esas dos cláusulas), no al código que sigue a +esa declaración if. + + +Tenga muy en cuenta que el orden proporcionado por una dependencia de +control es local a la CPU que lo contiene. Vea el apartado de "Atomicidad +multicopia" para más información. + + +En resumen: + + (*) Las dependencias de control pueden ordenar cargas anteriores para + stores posteriores. Sin embargo, no garantizan ningún otro tipo de + orden: No cargas previas contra cargas posteriores, ni + almacenamientos previos y luego nada. Si necesita tales formas de + orden, use smp_rmb(), smp_wmb() o, en el caso de stores anteriores y + cargas posteriores, smp_mb(). + + (*) Si ambos caminos de la declaración "if" comienzan con stores + idénticos de la misma variable, entonces esos stores deben ser + ordenados, ya sea precediéndoles a ambos con smp_mb() o usando + smp_store_release() para realizar el store. Tenga en cuenta que -no- + es suficiente usar barrier() al comienzo de cada caso de la + declaración "if" porque, como se muestra en el ejemplo anterior, la + optimización de los compiladores puede destruir la dependencia de + control respetando al pie de la letra la ley de barrier(). + + (*) Las dependencias de control requieren al menos un condicional en + tiempo de ejecución entre la carga anterior y el almacenamiento + posterior, y este condicional debe implicar la carga previa. Si el + compilador es capaz de optimizar el condicional y quitarlo, también + habrá optimizado el ordenar. El uso cuidadoso de READ_ONCE() y + WRITE_ONCE() puede ayudar a preservar el necesario condicional. + + (*) Las dependencias de control requieren que el compilador evite + reordenar las dependencia hasta su inexistencia. El uso cuidadoso de + READ_ONCE() o atomic{,64}_read() puede ayudarle a preservar la + dependencia de control. Consulte la sección BARRERA DEL COMPILADOR + para obtener más información al respecto. + + (*) Las dependencias de control se aplican solo a la cláusula then y la + cláusula else de la sentencia "if" que contiene la dependencia de + control, incluyendo cualquier función a la que llamen dichas dos + cláusulas. Las dependencias de control no se aplican al código que + sigue a la instrucción if que contiene la dependencia de control. + + (*) Las dependencias de control se emparejan normalmente con otros tipos + de barreras. + + (*) Las dependencias de control no proporcionan atomicidad multicopia. Si + usted necesita todas las CPU para ver un store dado al mismo tiempo, + emplee smp_mb(). + + (*) Los compiladores no entienden las dependencias de control. Por lo + tanto es su trabajo asegurarse de que no rompan su código. + + +EMPAREJAMIENTO DE BARRERAS SMP +------------------------------ + +Cuando se trata de interacciones CPU-CPU, ciertos tipos de barrera de +memoria deben estar siempre emparejados. La falta del apropiado +emparejamiento es casi seguro un error. + +Las barreras generales se emparejan entre sí, aunque también se emparejan +con la mayoría de otro tipo de barreras, aunque sin atomicidad multicopia. +Una barrera de adquisición se empareja con una barrera de liberación, pero +ambas también pueden emparejarse con otras barreras, incluidas, por +supuesto, las barreras generales. Una barrera de escritura se empareja con +una barrera de dependencia de dirección, una dependencia de control, una +barrera de adquisición, una barrera de liberación, una barrera de lectura +o una barrera general. Del mismo modo, una barrera de lectura se empareja +con una de dependencia de control o barrera de dependencia de dirección con +una barrera de escritura, una barrera de adquisición, una barrera de +liberación o una barrera general: + + CPU 1 CPU 2 + =============== =============== + WRITE_ONCE(a, 1); + <barrera de escritura> + WRITE_ONCE(b, 2); x = READ_ONCE(b); + <barrera de lectura> + y = READ_ONCE(a); + +O bien: + + CPU 1 CPU 2 + =============== =============================== + a = 1; + <barrera de escritura> + WRITE_ONCE(b, &a); x = READ_ONCE(b); + <barrera de dependencia de dirección implícita> + y = *x; + +O incluso: + + CPU 1 CPU 2 + =============== =============================== + r1 = READ_ONCE(y); + <barrera general> + WRITE_ONCE(x, 1); if (r2 = READ_ONCE(x)) { + <barrera de control implícita> + WRITE_ONCE(y, 1); + } + + assert(r1 == 0 || r2 == 0); + +Básicamente, la barrera de lectura siempre tiene que estar ahí, aunque +puede ser del tipo "más débil". + +[!] Tenga en cuenta que normalmente se esperaría que los stores antes de la +barrera de escritura se hagan coincidir con los stores después de la +barrera de lectura o la barrera de dependencia de dirección, y viceversa: + + CPU 1 CPU 2 + =================== =================== + WRITE_ONCE(a, 1); }---- --->{ v = READ_ONCE(c); + WRITE_ONCE(b, 2); } \ / { w = READ_ONCE(d); + <barrera de escritura> \ <barrera de lectura> + WRITE_ONCE(c, 3); } / \ { x = READ_ONCE(a); + WRITE_ONCE(d, 4); }---- --->{ y = READ_ONCE(b); + + +EJEMPLOS DE SECUENCIAS DE BARRERA DE MEMORIA +-------------------------------------------- + +En primer lugar, las barreras de escritura actúan como orden parcial en las +operaciones de store. Considere la siguiente secuencia de eventos: + + CPU 1 + ======================= + STORE A = 1 + STORE B = 2 + STORE C = 3 + <barrera de escritura> + STORE D = 4 + STORE E = 5 + +Esta secuencia de eventos es finalizado para con el sistema de coherencia +de memoria en un orden que el resto del sistema podría percibir como el +conjunto desordenado { STORE A, STORE B, STORE C} todo ocurriendo antes del +conjunto desordenado { STORE D, STORE E}: + + + +-------+ : : + | | +------+ + | |------>| C=3 | } /\ + | | : +------+ }----- \ -----> Eventos perceptibles para + | | : | A=1 | } \/ el resto del sistema + | | : +------+ } + | CPU 1 | : | B=2 | } + | | +------+ } + | | wwwwwwwwwwwwwwww } <--- En este momento la barrera de + | | +------+ } escritura requiere que todos los + | | : | E=5 | } stores anteriores a la barrera + | | : +------+ } sean confirmados antes de que otros + | |------>| D=4 | } store puedan suceder + | | +------+ + +-------+ : : + | + | Secuencia por la cual los stores son confirmados al + | sistema de memoria por parte del CPU 1 + V + +En segundo lugar, las barreras de dependencia de dirección actúan como +órdenes parciales sobre la dirección de cargas dependientes. Considere la +siguiente secuencia de eventos: + + CPU 1 CPU 2 + ======================= ======================= + { B = 7; X = 9; Y = 8; C = &Y } + STORE A = 1 + STORE B = 2 + <barrera de escritura> + STORE C = &B LOAD X + STORE D = 4 LOAD C (consigue &B) + LOAD *C (lee B) + +Sin intervención, la CPU 2 puede percibir los eventos en la CPU 1 en orden +aleatorio a efectos prácticos, a pesar de la barrera de escritura emitida +por la CPU 1: + + +-------+ : : : : + | | +------+ +-------+ | Secuencia de + | |------>| B=2 |----- --->| Y->8 | | actualizado de + | | : +------+ \ +-------+ | percepción en CPU 2 + | CPU 1 | : | A=1 | \ --->| C->&Y | V + | | +------+ | +-------+ + | | wwwwwwwwwwwwwwww | : : + | | +------+ | : : + | | : | C=&B |--- | : : +-------+ + | | : +------+ \ | +-------+ | | + | |------>| D=4 | ----------->| C->&B |------>| | + | | +------+ | +-------+ | | + +-------+ : : | : : | | + | : : | | + | : : | CPU 2 | + | +-------+ | | + Percepción de B ---> | | B->7 |------>| | + aparentemente incorrecta! | +-------+ | | + | : : | | + | +-------+ | | + La carga de X frena ---> \ | X->9 |------>| | + el mantenimiento de \ +-------+ | | + la coherencia de B ----->| B->2 | +-------+ + +-------+ + : : + + +En el ejemplo anterior, la CPU 2 percibe que B es 7, a pesar de la carga de +*C (que sería B) viniendo después del LOAD de C. + +Sin embargo, si se colocara una barrera de dependencia de dirección entre +la carga de C y la carga de *C (es decir: B) en la CPU 2: + + CPU 1 CPU 2 + ======================= ======================= + { B = 7; X = 9; Y = 8; C = &Y } + STORE A = 1 + STORE B = 2 + <barrera de escritura> + STORE C = &B LOAD X + STORE D = 4 LOAD C (consigue &B) + <barrera de dependencia de dirección> + LOAD *C (reads B) + +entonces ocurrirá lo siguiente: + + +-------+ : : : : + | | +------+ +-------+ + | |------>| B=2 |----- --->| Y->8 | + | | : +------+ \ +-------+ + | CPU 1 | : | A=1 | \ --->| C->&Y | + | | +------+ | +-------+ + | | wwwwwwwwwwwwwwww | : : + | | +------+ | : : + | | : | C=&B |--- | : : +-------+ + | | : +------+ \ | +-------+ | | + | |------>| D=4 | ----------->| C->&B |------>| | + | | +------+ | +-------+ | | + +-------+ : : | : : | | + | : : | | + | : : | CPU 2 | + | +-------+ | | + | | X->9 |------>| | + | +-------+ | | + Se asegura de que ---> \ aaaaaaaaaaaaaaaaa | | + los efectos anteriores al \ +-------+ | | + store de C sean percibidos ----->| B->2 |------>| | + por los siguientes loads +-------+ | | + : : +-------+ + + +Y en tercer lugar, una barrera de lectura actúa como un orden parcial sobre +las cargas. Considere la siguiente secuencia de eventos: + + CPU 1 CPU 2 + ======================= ======================= + { A = 0, B = 9 } + STORE A=1 + <barrera de escritura> + STORE B=2 + LOAD B + LOAD A + +Sin intervención, la CPU 2 puede elegir percibir los eventos en la CPU 1 en +algún orden aleatorio a efectos prácticos, a pesar de la barrera de +escritura emitida por la CPU 1: + + +-------+ : : : : + | | +------+ +-------+ + | |------>| A=1 |------ --->| A->0 | + | | +------+ \ +-------+ + | CPU 1 | wwwwwwwwwwwwwwww \ --->| B->9 | + | | +------+ | +-------+ + | |------>| B=2 |--- | : : + | | +------+ \ | : : +-------+ + +-------+ : : \ | +-------+ | | + ---------->| B->2 |------>| | + | +-------+ | CPU 2 | + | | A->0 |------>| | + | +-------+ | | + | : : +-------+ + \ : : + \ +-------+ + ---->| A->1 | + +-------+ + : : + +Sin embargo, si se colocara una barrera de lectura entre la carga de B y la +carga de A en la CPU 2: + + CPU 1 CPU 2 + ======================= ======================= + { A = 0, B = 9 } + STORE A=1 + <barrera de escritura> + STORE B=2 + LOAD B + <barrera de lectura> + LOAD A + +entonces el orden parcial impuesto por la CPU 1 será percibido +correctamente por la CPU 2: + + +-------+ : : : : + | | +------+ +-------+ + | |------>| A=1 |------ --->| A->0 | + | | +------+ \ +-------+ + | CPU 1 | wwwwwwwwwwwwwwww \ --->| B->9 | + | | +------+ | +-------+ + | |------>| B=2 |--- | : : + | | +------+ \ | : : +-------+ + +-------+ : : \ | +-------+ | | + ---------->| B->2 |------>| | + | +-------+ | CPU 2 | + | : : | | + | : : | | + En este punto la barrera ----> \ rrrrrrrrrrrrrrrrr | | + de lectura consigue que \ +-------+ | | + todos los efectos anteriores ---->| A->1 |------>| | + al almacenamiento de B sean +-------+ | | + perceptibles por la CPU 2 : : +-------+ + + +Para ilustrar esto de manera más completa, considere lo que podría pasar si +el código contenía una carga de A a cada lado de la barrera de lectura: + + CPU 1 CPU 2 + ======================= ======================= + { A = 0, B = 9 } + STORE A=1 + <barrera de escritura> + STORE B=2 + LOAD B + LOAD A [primer load de A] + <rbarrera de lectura> + LOAD A [segundo load de A] + +Aunque las dos cargas de A ocurren después de la carga de B, ambas pueden +obtener diferentes valores: + + +-------+ : : : : + | | +------+ +-------+ + | |------>| A=1 |------ --->| A->0 | + | | +------+ \ +-------+ + | CPU 1 | wwwwwwwwwwwwwwww \ --->| B->9 | + | | +------+ | +-------+ + | |------>| B=2 |--- | : : + | | +------+ \ | : : +-------+ + +-------+ : : \ | +-------+ | | + ---------->| B->2 |------>| | + | +-------+ | CPU 2 | + | : : | | + | : : | | + | +-------+ | | + | | A->0 |------>| 1st | + | +-------+ | | + En este punto la barrera ----> \ rrrrrrrrrrrrrrrrr | | + de lectura consigue que \ +-------+ | | + todos los efectos anteriores ---->| A->1 |------>| | + al almacenamiento de B sean +-------+ | | + perceptibles por la CPU 2 : : +-------+ + +Pero puede ser que la actualización a A desde la CPU 1 se vuelva +perceptible para la CPU 2 antes de que la barrera de lectura se complete de +todos modos: + + +-------+ : : : : + | | +------+ +-------+ + | |------>| A=1 |------ --->| A->0 | + | | +------+ \ +-------+ + | CPU 1 | wwwwwwwwwwwwwwww \ --->| B->9 | + | | +------+ | +-------+ + | |------>| B=2 |--- | : : + | | +------+ \ | : : +-------+ + +-------+ : : \ | +-------+ | | + ---------->| B->2 |------>| | + | +-------+ | CPU 2 | + | : : | | + \ : : | | + \ +-------+ | | + ---->| A->1 |------>| 1st | + +-------+ | | + rrrrrrrrrrrrrrrrr | | + +-------+ | | + | A->1 |------>| 2nd | + +-------+ | | + : : +-------+ + +La garantía es que la segunda carga siempre dará como resultado A == 1 si +la carga de B resultó en B == 2. No existe tal garantía para la primera +carga de A; esto puede dar como resultado A == 0 o A == 1. + + +BARRERAS DE MEMORIA DE LECTURA FRENTE A ESPECULACIÓN DE CARGA +------------------------------------------------------------- + +Muchas CPU especulan con las cargas: es decir, ven que necesitarán cargar +un elemento de la memoria, y encuentran un momento en el que no están +usando el bus para ningún otra carga, y también en la carga por adelantado, +aunque en realidad no lo hayan llegado a ese punto en el flujo de ejecución +de instrucciones todavía. Esto permite que la instrucción de carga real +potencialmente complete de inmediato, porque la CPU ya tiene el valor a +mano. + +Puede resultar que la CPU en realidad no necesitara el valor, tal vez +porque una condición eludió la carga, en cuyo caso puede descartar el valor +o simplemente almacenar en caché para su uso posterior. + +Considere: + + CPU 1 CPU 2 + ======================= ======================= + LOAD B + DIVIDE } Instrucciones de división + DIVIDE } tardan mucho en terminar + LOAD A + +donde DIVIDE es DIVIDIR. Que podría aparecer como esto: + + : : +-------+ + +-------+ | | + --->| B->2 |------>| | + +-------+ | CPU 2 | + : :DIVIDE | | + +-------+ | | + La CPU ocupada con la división ---> --->| A->0 |~~~~ | | + especula sobre el LOAD de A +-------+ ~ | | + : : ~ | | + : :DIVIDE | | + : : ~ | | + Una vez completadas las divisiones --> : : ~-->| | + la CPU puede realizar el : : | | + LOAD con efecto inmediato : : +-------+ + + +Colocando una barrera de lectura o una barrera de dependencia de dirección +justo antes de la segundo carga: + + + + CPU 1 CPU 2 + ======================= ======================= + LOAD B + DIVIDE + DIVIDE + <rbarrera de lectura> + LOAD A + +obligará a reconsiderar cualquier valor obtenido especulativamente en una +medida dependiente del tipo de barrera utilizada. Si no se hizo ningún +cambio en la ubicación de memoria especulada, entonces el valor especulado +solo se usará: + + : : +-------+ + +-------+ | | + --->| B->2 |------>| | + +-------+ | CPU 2 | + : :DIVIDE | | + +-------+ | | + La CPU ocupada con la división ---> --->| A->0 |~~~~ | | + especula sobre el LOAD de A +-------+ ~ | | + : : ~ | | + : :DIVIDE | | + : : ~ | | + : : ~ | | + rrrrrrrrrrrrrrrr~ | | + : : ~ | | + : : ~-->| | + : : | | + : : +-------+ + + +pero si había una actualización o una invalidación de otra CPU pendiente, +entonces la especulación será cancelada y el valor recargado: + + : : +-------+ + +-------+ | | + --->| B->2 |------>| | + +-------+ | CPU 2 | + : :DIVIDE | | + +-------+ | | + La CPU ocupada con la división ---> --->| A->0 |~~~~ | | + especula sobre el LOAD de A +-------+ ~ | | + : : ~ | | + : :DIVIDE | | + : : ~ | | + : : ~ | | + rrrrrrrrrrrrrrrrr | | + +-------+ | | + La especulación es descartada ---> --->| A->1 |------>| | + y un valor actualizado +-------+ | | + es conseguido : : +-------+ + +ATOMICIDAD MULTICOPIA +--------------------- + +La atomicidad multicopia es una noción profundamente intuitiva sobre el +orden que no es siempre proporcionada por los sistemas informáticos reales, +a saber, que un determinada store se vuelve visible al mismo tiempo para +todos las CPU o, alternativamente, que todas las CPU acuerdan el orden en +que todos los stores se vuelven visibles. Sin embargo, el soporte para +atomicidad multicopia completa descartaría valiosas optimizaciones +hardware, por lo que una versión más débil conocida como ``otra atomicidad +multicopia'' en cambio, solo garantiza que un store dado se vuelva visible +al mismo tiempo en todas las -otras- CPUs. El resto de este documento +discute esta versión más débil, pero por brevedad lo llamaremos simplemente +``atomicidad multicopia''. + +El siguiente ejemplo demuestra la atomicidad multicopia: + + CPU 1 CPU 2 CPU 3 + ======================= ======================= ======================= + { X = 0, Y = 0 } + STORE X=1 r1=LOAD X (reads 1) LOAD Y (reads 1) + <barrera general> <barrera de lectura> + STORE Y=r1 LOAD X + +Suponga que la carga de la CPU 2 desde X devuelve 1, que luego almacena en +Y, y la carga de la CPU 3 desde Y devuelve 1. Esto indica que el store de +la CPU 1 a X precede a la carga de la CPU 2 desde X y el store de esa CPU 2 +a Y precede la carga de la CPU 3 desde Y. Además, las barreras de memoria +garantizan que la CPU 2 ejecuta su carga antes que su almacenamiento, y la +CPU 3 carga desde Y antes de cargar desde X. La pregunta entonces es +"¿Puede la carga de la CPU 3 desde X devolver 0?" + +Debido a que la carga de la CPU 3 desde X en cierto sentido viene después +de la carga de la CPU 2, es natural esperar que la carga de la CPU 3 desde +X deba devolver 1. Esta expectativa se deriva de la atomicidad multicopia: +si una carga que se ejecuta en la CPU B sigue una carga de la misma +variable que se ejecuta en la CPU A (y la CPU A no almacenó originalmente +el valor que leyó), entonces en sistemas atómicos multicopia, la carga de +la CPU B debe devolver el mismo valor que hizo la carga de la CPU A o algún +valor posterior. Sin embargo, el kernel Linux no requiere que los sistemas +sean atómicos multicopia. + +El uso de una barrera de memoria general en el ejemplo anterior compensa +cualquier falta de atomicidad multicopia. En el ejemplo, si la carga de la +CPU 2 de X devuelve 1 y la carga de la CPU 3 de Y devuelve 1, entonces la +carga de la CPU 3 desde X debe de hecho también devolver 1. + +Sin embargo, las dependencias, las barreras de lectura y las barreras de +escritura no siempre son capaces de compensar la atomicidad no multicopia. +Por ejemplo, supongamos que la barrera general de la CPU 2 se elimina del +ejemplo anterior, dejando solo la dependencia de datos que se muestra a +continuación: + + CPU 1 CPU 2 CPU 3 + ======================= ======================= ======================= + { X = 0, Y = 0 } + STORE X=1 r1=LOAD X (escribe 1) LOAD Y (lee 1) + <dependencia de datos> <barrera de lectura> + STORE Y=r1 LOAD X (lee 0) + +Esta sustitución permite que la atomicidad no multicopia se desenfrene: en +este ejemplo, es perfectamente legal que la carga de la CPU 2 desde X +devuelva 1, la carga de la CPU 3 desde Y devuelva 1, y su carga desde X +tenga valor 0. + +El punto clave es que aunque la dependencia de datos de la CPU 2 ordena su +carga y store, no garantiza ordenar el store de la CPU 1. De forma que, si +este ejemplo se ejecuta en un sistema atómico no multicopia donde las CPU 1 +y 2 comparten un buffer de almacenamiento o un nivel de caché, la CPU 2 +podría tener acceso anticipado de escritura a CPU 1. Por lo tanto, se +requieren barreras generales para garantizar que todas las CPU acurden el +orden combinado de accesos múltiples. + +Las barreras generales pueden compensar no solo la atomicidad no +multicopia, pero también pueden generar orden adicional que puede asegurar +que -todas- las CPU percibirán el mismo orden de -todas- las operaciones. +Por el contrario, una cadena de parejas de liberación-adquisición no +proporciona este orden adicional, lo que significa que solo se garantiza +que las CPU de la cadena estén de acuerdo en el orden combinado de los +accesos. Por ejemplo, cambiando a código C en deferencia al fantasma de +Herman Hollerith: + + int u, v, x, y, z; + + void cpu0(void) + { + r0 = smp_load_acquire(&x); + WRITE_ONCE(u, 1); + smp_store_release(&y, 1); + } + + void cpu1(void) + { + r1 = smp_load_acquire(&y); + r4 = READ_ONCE(v); + r5 = READ_ONCE(u); + smp_store_release(&z, 1); + } + + void cpu2(void) + { + r2 = smp_load_acquire(&z); + smp_store_release(&x, 1); + } + + void cpu3(void) + { + WRITE_ONCE(v, 1); + smp_mb(); + r3 = READ_ONCE(u); + } + +Dado que cpu0(), cpu1() y cpu2() participan en una cadena de parejas +smp_store_release()/smp_load_acquire(), el siguiente resultado estaría +prohibido: + + r0 == 1 && r1 == 1 && r2 == 1 + +Además, debido a la relación liberación-adquisición entre cpu0() y cpu1(), +cpu1() debe ver las escrituras de cpu0(), de modo que el siguiente +resultado estaría prohibido: + + r1 == 1 && r5 == 0 + +Sin embargo, el orden proporcionado por una cadena de +liberación-adquisición es local a las CPU que participan en esa cadena y no +se aplica a cpu3(), al menos aparte de los stores. Por lo tanto, es posible +el siguiente resultado: + + r0 == 0 && r1 == 1 && r2 == 1 && r3 == 0 && r4 == 0 + +Por otro lado, también el siguiente resultado es posible: + + r0 == 0 && r1 == 1 && r2 == 1 && r3 == 0 && r4 == 0 && r5 == 1 + +Aunque cpu0(), cpu1() y cpu2() verán sus respectivas lecturas y escrituras +en orden, las CPU que no participan en la cadena de liberación-adquisición +pueden estar en desacuerdo con el orden. Este desacuerdo se debe al hecho +de que las instrucciones de barrera de memoria débiles utilizadas para +implementar smp_load_acquire() y smp_store_release() no son necesarios para +ordenar stores anteriores contra cargas posteriores en todos los casos. +Esto significa que cpu3() puede ver el store de cpu0() suceder -después- de +la carga de cpu1() desde v, aunque tanto cpu0() como cpu1() están de +acuerdo en que estas dos operaciones ocurrieron en el orden previsto. + +Sin embargo, tenga en cuenta que smp_load_acquire() no es mágico. En +particular, simplemente lee de su argumento en orden. Es decir, -no- +asegura que se leerá cualquier valor en particular. Por lo tanto, los +siguiente resultados son posibles: + + r0 == 0 && r1 == 0 && r2 == 0 && r5 == 0 + +Tenga en cuenta que este resultado puede ocurrir incluso en un mítico +sistema, consistente en secuencia, donde nunca se reordena nada. + +Para reiterar, si su código requiere un orden completo de todas las +operaciones, utilice barreras generales en todo momento. + + +============================== +BARRERAS EXPLÍCITAS DEL KERNEL +============================== + +El kernel Linux tiene una variedad de diferentes barreras que actúan a +diferentes niveles: + + (*) Barrera del compilador. + + (*) Barreras de memoria de la CPU. + + +BARRERA DEL COMPILADOR +----------------------- + +El kernel de Linux tiene una función de barrera del compilador explícita +que evita que el el compilador mueva los accesos a la memoria de cualquier +lado al otro: + + barrier(); + +Esta es una barrera general: no hay variantes de barrier() para casos de +lectura-lectura o escritura-escritura. Sin embargo, READ_ONCE() y +WRITE_ONCE() pueden ser considerado como formas débiles de barrier() que +afectan solo específicos accesos marcados por READ_ONCE() o WRITE_ONCE(). + +La función barrier() produce los siguientes efectos: + + (*) Evita que el compilador reordene los accesos tras barrier() para + preceder a cualquier acceso que preceda a barrier(). Un ejemplo de uso + de esta propiedad es facilitar la comunicación entre código del + interrupt-handler (encargo de gestionar interrupciones) y el código + que fue interrumpido. + + (*) Dentro de un bucle ("loop"), obliga al compilador a cargar las + variables utilizadas en ese loop condicional en cada paso a través de + ese loop. + +Las funciones READ_ONCE() y WRITE_ONCE() pueden evitar cualquier cantidad +de optimizaciones que, si bien son perfectamente seguras en código de un +solo subproceso, pueden resultar fatales en código concurrente. Aquí hay +algunos ejemplos de tal tipo de optimizaciones: + +(*) El compilador está en su derecho de reordenar cargas y stores de la + misma variable, y en algunos casos, la CPU está dentro de su + derecho de reordenar cargas a la misma variable. Esto significa que + el siguiente código: + + a[0] = x; + a[1] = x; + + Podría resultar en un valor más antiguo de x almacenado en a[1] que en + a[0]. Evite que tanto el compilador como la CPU hagan esto de la + siguiente manera: + + a[0] = READ_ONCE(x); + a[1] = READ_ONCE(x); + + En resumen, READ_ONCE() y WRITE_ONCE() proporcionan coherencia de + caché para accesos desde múltiples CPUs a una sola variable. + + (*) El compilador tiene derecho a juntar cargas sucesivas de la misma + variable. Tal fusión puede hacer que el compilador "optimice" el + siguiente código: + + while (tmp = a) + hacer_algo_con(tmp); + + en el siguiente código, que, aunque en cierto sentido es legítimo + para un código de un solo subproceso, es casi seguro que no es lo + que el desarrollador pretendía: + + if (tmp = a) + for (;;) + hacer_algo_con(tmp); + + Use READ_ONCE() para evitar que el compilador le haga esto: + + while (tmp = READ_ONCE(a)) + hacer_algo_con(tmp); + + (*) El compilador tiene derecho a recargar una variable, por ejemplo, + en los casos en que la alta presión de los registros impida que el + compilador mantenga todos los datos de interés en registros. El + compilador podría por lo tanto, optimizar la variable 'tmp' de nuestro + ejemplo anterior: + + while (tmp = a) + hacer_algo_con(tmp); + + Esto podría resultar en el siguiente código, que es perfectamente + seguro en código de subproceso único, pero puede ser fatal en código + concurrente: + + while (a) + hacer_algo_con(a); + + Por ejemplo, la versión optimizada de este código podría resultar en + pasar un cero a hacer_algo_con() en el caso de que la variable a sea + modificada por alguna otra CPU, entre la instrucción "while" y la + llamada a hacer_algo_con(). + + De nuevo, use READ_ONCE() para evitar que el compilador haga esto: + + while (tmp = READ_ONCE(a)) + hacer_algo_con(tmp); + + Tenga en cuenta que si el compilador se queda sin registros, podría + guardar tmp en la pila ("stack"). El overhead (coste en eficiencia) de + este guardado y posterior restauración es por lo que los compiladores + recargan las variables. Hacerlo es perfectamente seguro para código de + subproceso único, por lo que debe informar al compilador sobre los + casos donde no sea seguro. + + (*) El compilador está en su derecho de omitir una carga por completo si + sabe cual será su valor. Por ejemplo, si el compilador puede probar + que el valor de la variable 'a' siempre es cero, puede optimizar este + código: + + while (tmp = a) + hacer_algo_con(tmp); + + En esto: + + do { } while (0); + + Esta transformación es una victoria para un código de un solo + subproceso, porque se deshace de una carga y un branch. El problema es + que el compilador llevará a cabo su prueba asumiendo que la CPU actual + es la única actualizando la variable 'a'. Si la variable 'a' es + compartida, entonces la prueba del compilador será errónea. Use + READ_ONCE() para decirle al compilador que no sabe tanto como cree: + + while (tmp = READ_ONCE(a)) + hacer_algo_con(tmp); + + Pero, por favor, tenga en cuenta que el compilador también está + observando de cerca lo que usted hace con el valor después de + READ_ONCE(). Por ejemplo, suponga que Ud. hace lo siguiente y MAX es + una macro de preprocesador con el valor 1: + + while ((tmp = READ_ONCE(a)) % MAX) + hacer_algo_con(tmp); + + Entonces el compilador sabe que el resultado del operador "%" aplicado + a MAX siempre será cero, nuevamente permitiendo que el compilador + optimice el código hasta su casi inexistencia. (Aún se cargará desde + la variable 'a'.) + + (*) De manera similar, el compilador tiene derecho a omitir un store por + completo si sabe que la variable ya tiene el valor almacenado. + Nuevamente, el compilador asume que la CPU actual es la única que + almacena la variable, lo que puede hacer que el compilador haga + algo incorrecto para las variables compartidas. Por ejemplo, suponga + que tiene lo siguiente: + + a = 0; + ... Código que no almacena la variable a ... + a = 0; + + El compilador observa que el valor de la variable 'a' ya es cero, por + lo que bien podría omitir el segundo store. Esto supondría una fatal + sorpresa, si alguna otra CPU hubiera almacenado la variable 'a' + mientras tanto. + + Use WRITE_ONCE() para evitar que el compilador haga este tipo de + suposición equivocada: + + WRITE_ONCE(a, 0); + ... Código que no almacena la variable a ... + WRITE_ONCE(a, 0); + + (*) El compilador tiene derecho a reordenar los accesos a memoria a menos + que le diga que no. Por ejemplo, considere la siguiente interacción + entre el código de nivel de proceso y un controlador de interrupción: + + void nivel_de_procesamiento(void) + { + msg = ACQUIRE_mensaje(); + flag = true; + } + + void controlador_interrupcion(void) + { + if (flag) + procesar_mensaje(msg); + } + + No hay nada que impida que el compilador transforme + nivel_de_procesamiento() a lo siguiente, que de hecho, bien podría ser + una victoria para código de un solo subproceso: + + void nivel_de_procesamiento(void) + { + flag = true; + msg = ACQUIRE_mensaje(); + } + + Si la interrupción ocurre entre estas dos declaraciones, entonces + controlador_interrupcion() podría recibir un mensaje ilegible. Use + READ_ONCE() para evitar esto de la siguiente manera: + + void nivel_de_procesamiento(void) + { + WRITE_ONCE(msg, ACQUIRE_mensaje()); + WRITE_ONCE(flag, true); + } + + void controlador_interrupcion(void) + { + if (READ_ONCE(flag)) + procesar_mensaje(READ_ONCE(msg)); + } + + Tenga en cuenta que los envoltorios ("wrappers") READ_ONCE() y + WRITE_ONCE() en controlador_interrupcion() son necesarios si este + controlador de interrupciones puede ser interrumpido por algo que + también accede a 'flag' y 'msg', por ejemplo, una interrupción anidada + o un NMI. De lo contrario, READ_ONCE() y WRITE_ONCE() no son + necesarios en controlador_interrupcion() aparte de con fines de + documentación. (Tenga también en cuenta que las interrupciones + anidadas no ocurren típicamente en los kernels Linux modernos, de + hecho, si un controlador de interrupciones regresa con interrupciones + habilitadas, obtendrá un WARN_ONCE().) + + Debe suponer que el compilador puede mover READ_ONCE() y WRITE_ONCE() + a código que no contiene READ_ONCE(), WRITE_ONCE(), barrier(), o + primitivas similares. + + Este efecto también podría lograrse usando barrier(), pero READ_ONCE() + y WRITE_ONCE() son más selectivos: Con READ_ONCE() y WRITE_ONCE(), el + compilador solo necesita olvidar el contenido de ubicaciones de + memoria indicadas, mientras que con barrier() el compilador debe + descartar el valor de todas las ubicaciones de memoria que tiene + actualmente almacenadas en caché, en cualquier registro de la máquina. + Por supuesto, el compilador también debe respetar el orden en que + ocurren READ_ONCE() y WRITE_ONCE(), aunque la CPU, efectivamente, no + necesita hacerlo. + + (*) El compilador tiene derecho a inventar stores para una variable, + como en el siguiente ejemplo: + + if (a) + b = a; + else + b = 42; + + El compilador podría ahorrar un branch al optimizar esto de la + siguiente manera: + + b = 42; + if (a) + b = a; + + En el código de un solo subproceso, esto no solo es seguro, sino que + también ahorra un branch. Desafortunadamente, en código concurrente, + esta optimización podría causar que alguna otra CPU vea un valor falso + de 42, incluso si la variable 'a' nunca fue cero, al cargar la + variable 'b'. Use WRITE_ONCE() para evitar esto de la siguiente + manera: + + if (a) + WRITE_ONCE(b, a); + else + WRITE_ONCE(b, 42); + + El compilador también puede inventar cargas. Estos casos suelen ser + menos perjudiciales, pero pueden dar como resultado "bouncing" de la + línea de caché y, por lo tanto, bajo rendimiento y escalabilidad. + Utilice READ_ONCE() para evitar cargas inventadas. + + (*) Para ubicaciones de memoria alineadas cuyo tamaño les permita + acceder con una sola instrucción de referencia de memoria, evite el + "desgarro de la carga" (load tearing) y "desgarro del store" (store + tearing), en el que un solo gran acceso es reemplazado por múltiples + accesos menores. Por ejemplo, dada una arquitectura que tiene + instrucciones de almacenamiento de 16 bits con campos inmediatos de 7 + bits, el compilador podría tener la tentación de usar dos + instrucciones inmediatas de almacenamiento de 16 bits para implementar + el siguiente store de 32 bits: + + p = 0x00010002; + + Tenga en cuenta que GCC realmente usa este tipo de optimización, lo + cual no es sorprendente dado que probablemente costaría más de dos + instrucciones el construir la constante y luego almacenarla. Por lo + tanto, esta optimización puede ser una victoria en un código de un + solo subproceso. De hecho, un error reciente (desde que se solucionó) + hizo que GCC usara incorrectamente esta optimización en un store + volátil. En ausencia de tales errores, el uso de WRITE_ONCE() evita el + desgarro del store en el siguiente ejemplo: + + struct __attribute__((__packed__)) foo { + short a; + int b; + short c; + }; + struct foo foo1, foo2; + ... + + foo2.a = foo1.a; + foo2.b = foo1.b; + foo2.c = foo1.c; + + Debido a que no hay envoltorios READ_ONCE() o WRITE_ONCE() y no + hay markings volátiles, el compilador estaría en su derecho de + implementar estas tres declaraciones de asignación como un par de + cargas de 32 bits, seguido de un par de stores de 32 bits. Esto + resultaría en una carga con desgarro en 'foo1.b' y store del desgarro + en 'foo2.b'. READ_ONCE() y WRITE_ONCE() nuevamente evitan el desgarro + en este ejemplo: + + foo2.a = foo1.a; + WRITE_ONCE(foo2.b, READ_ONCE(foo1.b)); + foo2.c = foo1.c; + +Aparte de esto, nunca es necesario usar READ_ONCE() y WRITE_ONCE() en una +variable que se ha marcado como volátil. Por ejemplo, dado que 'jiffies' +está marcado como volátil, nunca es necesario usar READ_ONCE(jiffies). La +razón de esto es que READ_ONCE() y WRITE_ONCE() se implementan como +conversiones volátiles, lo que no tiene efecto cuando su argumento ya está +marcado como volátil. + +Tenga en cuenta que estas barreras del compilador no tienen un efecto +directo en la CPU, que luego puede reordenar las cosas como quiera. + + +BARRERAS DE MEMORIA DE LA CPU +----------------------------- + +El kernel de Linux tiene siete barreras básicas de memoria de CPU: + +TIPO OBLIGATORIO SMP CONDICIONAL +======================= =============== =============== +GENERAL mb() smp_mb() +WRITE wmb() smp_wmb() +READ rmb() smp_rmb() +DEPEDENCIA DE DIRECCIÓN READ_ONCE() + + +Todas las barreras de memoria, excepto las barreras de dependencia de +direcciones, implican una barrera del compilador. Las dependencias de +direcciones no imponen ningún orden de compilación adicional. + +Además: en el caso de las dependencias de direcciones, se esperaría que el +compilador emita las cargas en el orden correcto (por ejemplo, `a[b]` +tendría que cargar el valor de b antes de cargar a[b]), sin embargo, no hay +garantía alguna en la especificación de C sobre que el compilador no puede +especular el valor de b (por ejemplo, es igual a 1) y carga a[b] antes que +b (ej. tmp = a[1]; if (b != 1) tmp = a[b]; ). También existe el problema de +que un compilador vuelva a cargar b después de haber cargado a[b], teniendo +así una copia más nueva de b que a[b]. Aún no se ha conseguido un consenso +acerca de estos problemas, sin embargo, el macro READ_ONCE() es un buen +lugar para empezar a buscar. + +Las barreras de memoria SMP se reducen a barreras de compilador cuando se +compila a monoprocesador, porque se supone que una CPU parecerá ser +auto-consistente, y ordenará correctamente los accesos superpuestos +respecto a sí misma. Sin embargo, consulte la subsección "Guests de +máquinas virtuales" mas adelante. + +[!] Tenga en cuenta que las barreras de memoria SMP _deben_ usarse para +controlar el orden de referencias a memoria compartida en sistemas SMP, +aunque el uso de bloqueo en su lugar sea suficiente. + +Las barreras obligatorias no deben usarse para controlar los efectos de +SMP, ya que dichas barreras imponen una sobrecarga innecesaria en los +sistemas SMP y UP. Se pueden, sin embargo, usar para controlar los efectos +MMIO en los accesos a través de ventanas E/S de memoria relajada. Estas +barreras son necesarias incluso en sistemas que no son SMP, ya que afectan +al orden en que las operaciones de memoria aparecen en un dispositivo, al +prohibir tanto al compilador como a la CPU que sean reordenados. + + +Hay algunas funciones de barrera más avanzadas: + + (*) smp_store_mb(var, valor) + + Asigna el valor a la variable y luego inserta una barrera de memoria + completa después de ella. No se garantiza insertar nada más que una + barrera del compilador en una compilación UP. + + + (*) smp_mb__before_atomic(); + (*) smp_mb__after_atomic(); + + Estos se pueden usar con funciones RMW atómicas que no implican + barreras de memoria, pero donde el código necesita una barrera de + memoria. Ejemplos de funciones RMW atómicas que no implican una + barrera de memoria son, por ejemplo, agregar, restar, operaciones + condicionales (fallidas), funciones _relaxed, pero no atomic_read o + atomic_set. Un ejemplo común donde se puede requerir una barrera es + cuando se usan operaciones atómicas como referencia de contador. + + Estos también se utilizan para funciones atómicas RMW bitop que no + implican una barrera de memoria (como set_bit y clear_bit). + + Como ejemplo, considere una pieza de código que marca un objeto como + muerto y luego disminuye el contador de referencias del objeto: + + obj->dead = 1; + smp_mb__before_atomic(); + atomic_dec(&obj->ref_count); + + Esto asegura que la marca de muerte en el objeto se perciba como + fijada *antes* de que disminuya el contador de referencia. + + Consulte Documentation/atomic_{t,bitops}.txt para obtener más + información. + + + (*) dma_wmb(); + (*) dma_rmb(); + (*) dma_mb(); + + Estos son usados con memoria consistente para garantizar el orden de + escrituras o lecturas de memoria compartida accesible tanto para la + CPU como para un dispositivo compatible con DMA. + + Por ejemplo, considere un controlador de dispositivo que comparte + memoria con otro dispositivo y usa un valor de estado del descriptor + para indicar si el descriptor pertenece al dispositivo o a la CPU, y + un "doorbell" (timbre, punto de acceso) para avisarle cuando haya + nuevos descriptores disponibles: + + if (desc->status != DEVICE_OWN) { + /* no leer los datos hasta que tengamos el descriptor */ + dma_rmb(); + + /* leer/modificar datos */ + read_data = desc->data; + desc->data = write_data; + + /* flush de modificaciones antes de la actualización de estado */ + dma_wmb(); + + /* asignar propiedad */ + desc->status = DEVICE_OWN; + + /* notificar al dispositivo de nuevos descriptores */ + writel(DESC_NOTIFY, doorbell); + } + + El dma_rmb() nos permite garantizar que el dispositivo ha liberado su + propiedad antes de que leamos los datos del descriptor, y el dma_wmb() + permite garantizar que los datos se escriben en el descriptor antes de + que el dispositivo pueda ver que ahora tiene la propiedad. El dma_mb() + implica tanto un dma_rmb() como un dma_wmb(). Tenga en cuenta que, al + usar writel(), no se necesita un wmb() anterior para garantizar que + las escrituras de la memoria caché coherente se hayan completado antes + escribiendo a la región MMIO. El writel_relaxed() más barato no + proporciona esta garantía y no debe utilizarse aquí. + + Consulte la subsección "Efectos de barrera de E/S del kernel" para + obtener más información sobre accesorios de E/S relajados y el archivo + Documentation/core-api/dma-api.rst para más información sobre memoria + consistente. + + (*) pmem_wmb(); + + Es es para uso con memoria persistente para garantizar que los stores + para los que las modificaciones se escriben en el almacenamiento + persistente llegaron a dominio de durabilidad de la plataforma. + + Por ejemplo, después de una escritura no temporal en la región pmem, + usamos pmem_wmb() para garantizar que los stores hayan alcanzado el + dominio de durabilidad de la plataforma. Esto garantiza que los stores + han actualizado el almacenamiento persistente antes de cualquier + acceso a datos o transferencia de datos causada por instrucciones + posteriores. Esto es además del orden realizado por wmb(). + + Para la carga desde memoria persistente, las barreras de memoria de + lectura existentes son suficientes para garantizar el orden de + lectura. + + (*) io_stop_wc(); + + Para accesos a memoria con atributos de combinación de escritura (por + ejemplo, los devueltos por ioremap_wc(), la CPU puede esperar a que + los accesos anteriores se junten con posteriores. io_stop_wc() se + puede utilizar para evitar la combinación de accesos a memoria de + de escritura antes de esta macro, con los posteriores, cuando dicha + espera tenga implicaciones en el rendimiento. + +========================================= +BARRERAS DE MEMORIA IMPLÍCITAS DEL KERNEL +========================================= + +Algunas de las otras funciones en el kernel Linux implican barreras de +memoria, entre estas encontramos funciones de bloqueo y planificación +("scheduling"). + +Esta especificación es una garantía _mínima_; cualquier arquitectura +particular puede proporcionar garantías más sustanciales, pero no se puede +confiar en estas fuera de código específico de arquitectura. + + +FUNCIONES DE ADQUISICIÓN DE CERROJO +----------------------------------- + +El kernel Linux tiene una serie de abstracciones de bloqueo: + + (*) spin locks (cerrojos en loop) + (*) R/W spin lock (cerrojos de escritura/lectura) + (*) mutex + (*) semáforos + (*) R/W semáforos + +En todos los casos existen variantes de las operaciones "ACQUIRE" y +"RELEASE" para cada uno de ellos. Todas estas operaciones implican ciertas +barreras: + + (1) Implicaciones de la operación ACQUIRE: + + Las operaciones de memoria emitidas después del ACQUIRE se completarán + después de que la operación ACQUIRE haya finalizado. + + Las operaciones de memoria emitidas antes de ACQUIRE pueden + completarse después que la operación ACQUIRE se ha completado. + + (2) Implicaciones de la operación RELEASE: + + Las operaciones de memoria emitidas antes de la RELEASE se + completarán antes de que la operación de RELEASE se haya completado. + + Las operaciones de memoria emitidas después de la RELEASE pueden + completarse antes de que la operación de RELEASE se haya completado. + + (3) Implicación de ACQUIRE vs ACQUIRE: + + Todas las operaciones ACQUIRE emitidas antes de otra operación + ACQUIRE serán completadas antes de esa operación ACQUIRE. + + (4) Implicación de ACQUIRE vs RELEASE: + + Todas las operaciones ACQUIRE emitidas antes de una operación RELEASE + serán completadas antes de la operación RELEASE. + + (5) Implicación de ACQUIRE condicional fallido: + + Ciertas variantes de bloqueo de la operación ACQUIRE pueden fallar, ya + sea debido a no poder obtener el bloqueo de inmediato, o debido a que + recibieron una señal de desbloqueo mientras dormían esperando que el + cerrojo estuviera disponible. Los fallos en cerrojos no implican + ningún tipo de barrera. + +[!] Nota: una de las consecuencias de que los cerrojos en ACQUIRE y RELEASE +sean barreras unidireccionales, es que los efectos de las instrucciones +fuera de una sección crítica pueden filtrarse al interior de la sección +crítica. + +No se puede suponer que un ACQUIRE seguido de una RELEASE sea una barrera +de memoria completa dado que es posible que un acceso anterior a ACQUIRE +suceda después del ACQUIRE, y un acceso posterior a la RELEASE suceda antes +del RELEASE, y los dos accesos puedan entonces cruzarse: + + *A = a; + ACQUIRE M + RELEASE M + *B = b; + +puede ocurrir como: + + ACQUIRE M, STORE *B, STORE *A, RELEASE M + +Cuando ACQUIRE y RELEASE son bloqueo de adquisición y liberación, +respectivamente, este mismo orden puede ocurrir si el cerrojo ACQUIRE y +RELEASE son para la misma variable de bloqueo, pero solo desde la +perspectiva de otra CPU que no tiene ese bloqueo. En resumen, un ACQUIRE +seguido de un RELEASE NO puede entenderse como una barrera de memoria +completa. + +De manera similar, el caso inverso de un RELEASE seguido de un ACQUIRE no +implica una barrera de memoria completa. Por lo tanto, la ejecución de la +CPU de los tramos críticos correspondientes a la RELEASE y la ACQUIRE +pueden cruzarse, de modo que: + + *A = a; + RELEASE M + ACQUIRE N + *B = b; + +puede ocurrir como: + + ACQUIRE N, STORE *B, STORE *A, RELEASE M + +Podría parecer que este nuevo orden podría introducir un punto muerto. +Sin embargo, esto no puede suceder porque si tal punto muerto amenazara +con suceder, el RELEASE simplemente se completaría, evitando así el +interbloqueo ("deadlock", punto muerto). + + ¿Por qué funciona esto? + + Un punto clave es que solo estamos hablando de la CPU re-haciendo el + orden, no el compilador. Si el compilador (o, ya puestos, el + desarrollador) cambió las operaciones, un deadlock -podría- ocurrir. + + Pero supongamos que la CPU reordenó las operaciones. En este caso, el + desbloqueo precede al bloqueo en el código ensamblador. La CPU + simplemente eligió intentar ejecutar primero la última operación de + bloqueo. Si hay un interbloqueo, esta operación de bloqueo simplemente + esperará (o tratará de dormir, pero hablaremos de eso más adelante). La + CPU eventualmente ejecutará la operación de desbloqueo (que precedió a la + operación de bloqueo en el código ensamblador), lo que desenmascará el + potencial punto muerto, permitiendo que la operación de bloqueo tenga + éxito. + + Pero, ¿y si el cerrojo es un cerrojo que duerme ("sleeplock")? En tal + caso, el código intentará entrar al scheduler, donde eventualmente + encontrará una barrera de memoria, que forzará la operación de desbloqueo + anterior para completar, nuevamente desentrañando el punto muerto. Podría + haber una carrera de desbloqueo del sueño ("sleep-unlock race"), pero la + primitiva de bloqueo necesita resolver tales carreras correctamente en + cualquier caso. + +Es posible que los cerrojos y los semáforos no proporcionen ninguna +garantía de orden en sistemas compilados en UP, por lo que no se puede +contar con tal situación para lograr realmente nada en absoluto, +especialmente con respecto a los accesos de E/S, a menos que se combinen +con operaciones de inhabilitación de interrupciones. + +Consulte también la sección "Efectos de barrera adquiriendo intra-CPU". + + +Como ejemplo, considere lo siguiente: + + *A = a; + *B = b; + ACQUIRE + *C = c; + *D = d; + RELEASE + *E = e; + *F = f; + +La siguiente secuencia de eventos es aceptable: + + ACQUIRE, {*F,*A}, *E, {*C,*D}, *B, RELEASE + + [+] Tenga en cuenta que {*F,*A} indica un acceso combinado. + +Pero ninguno de los siguientes lo son: + + {*F,*A}, *B, ACQUIRE, *C, *D, RELEASE, *E + *A, *B, *C, ACQUIRE, *D, RELEASE, *E, *F + *A, *B, ACQUIRE, *C, RELEASE, *D, *E, *F + *B, ACQUIRE, *C, *D, RELEASE, {*F,*A}, *E + + + +FUNCIONES DE DESACTIVACIÓN DE INTERRUPCIONES +-------------------------------------------- + +Las funciones que deshabilitan interrupciones (equivalentes a ACQUIRE) y +habilitan interrupciones (equivalentes a RELEASE) actuarán únicamente como +barrera del compilador. Por consiguiente, si la memoria o la E/S requieren +barreras en tal situación, deben ser provistas por algún otro medio. + + +FUNCIONES DE DORMIR Y DESPERTAR +------------------------------- + +Dormir y despertar son eventos marcados ("flagged") en los datos globales +que se pueden ver como una interacción entre dos piezas de datos: el estado +de la task (hilo, proceso, tarea) que espera el evento y los datos globales +utilizados para indicar el evento. Para asegurarse de que estos parezcan +suceder en el orden correcto, las primitivas para comenzar el proceso de ir +a dormir, y las primitivas para iniciar un despertar implican ciertas +barreras. + +En primer lugar, el agente durmiente normalmente sigue algo similar a esta +secuencia de eventos: + + for (;;) { + set_current_state(TASK_UNINTERRUPTIBLE); + if (evento_indicado) + break; + schedule(); // planificar + } + +Una barrera de memoria general se obtiene automáticamente mediante +set_current_state() después de haber alterado el estado de la tarea: + + CPU 1 + =============================== + set_current_state(); // hacer_estado_actual() + smp_store_mb(); + STORE current->state + <barrera general> + LOAD evento_indicado + +set_current_state() puede estar envuelto por: + + prepare_to_wait(); // preparese_para_esperar(); + prepare_to_wait_exclusive(); // prepararse_para_solo_esperar(); + +que por lo tanto también implican una barrera de memoria general después de +establecer el estado. Toda la secuencia anterior está disponible en varias +formas, todas las cuales obtienen la barrera de memoria en el lugar +correcto: + + wait_event(); + wait_event_interruptible(); + wait_event_interruptible_exclusive(); + wait_event_interruptible_timeout(); + wait_event_killable(); + wait_event_timeout(); + wait_on_bit(); + wait_on_bit_lock(); + + +En segundo lugar, el código que realiza una activación normalmente se +asemeja a algo como esto: + + evento_indicado = 1; + wake_up(&event_wait_queue); // despertar + +o: + + evento_indicado = 1; + wake_up_process(event_daemon); // despertar proceso + +wake_up() ejecuta una barrera de memoria general si despierta algo. Si no +despierta nada, entonces una barrera de memoria puede o no ser ejecutada; +no debe confiar en ello. La barrera se produce antes del acceso al estado +de la tarea. En particular, se encuentra entre el STORE para indicar el +evento y el STORE para configurar TASK_RUNNING (hilo ejecutando): + + CPU 1 (Durmiente) CPU 2 (Despertadora) + =============================== =============================== + set_current_state(); STORE evento_indicado + smp_store_mb(); wake_up(); + STORE current->state ... + <barrera general> <barrera general> + LOAD evento_indicado if ((LOAD task->state) & TASK_NORMAL) + STORE task->state + +donde "task" es el subproceso que se está despertando y es igual al +"current" (hilo actual) de la CPU 1. + +Para reiterar, se garantiza la ejecución de una barrera de memoria general +mediante wake_up() si algo está realmente despierto, pero de lo contrario +no existe tal garantía. Para entender esto, considere la siguiente +secuencia de eventos, donde X e Y son ambos cero inicialmente: + + CPU 1 CPU 2 + =============================== =============================== + X = 1; Y = 1; + smp_mb(); wake_up(); + LOAD Y LOAD X + +Si ocurre una reactivación ("wakeup"), una (al menos) de las dos cargas +debe ver 1. Si, por otro lado, no ocurre una reactivación, ambas cargas +pueden ver 0. + +wake_up_process() siempre ejecuta una barrera de memoria general. La +barrera, de nuevo, ocurre antes de que se acceda al estado del hilo. En +particular, si wake_up(), en el fragmento anterior, fuera reemplazado por +una llamada a wake_up_process(), las dos cargas verían 1, garantizado. + +Las funciones de activación disponibles incluyen: + + complete(); + wake_up(); + wake_up_all(); + wake_up_bit(); + wake_up_interruptible(); + wake_up_interruptible_all(); + wake_up_interruptible_nr(); + wake_up_interruptible_poll(); + wake_up_interruptible_sync(); + wake_up_interruptible_sync_poll(); + wake_up_locked(); + wake_up_locked_poll(); + wake_up_nr(); + wake_up_poll(); + wake_up_process(); + +En términos de orden de la memoria, todas estas funciones proporcionan las +mismas garantías que un wake_up() (o más fuertes). + +[!] Tenga en cuenta que las barreras de la memoria implicadas por el +durmiente y el despierto _no_ ordenan varios stores antes del despertar con +respecto a cargas de los valores guardados después de que el durmiente haya +llamado a set_current_state(). Por ejemplo, si el durmiente hace: + + set_current_state(TASK_INTERRUPTIBLE); + if (evento_indicado) + break; + __set_current_state(TASK_RUNNING); + hacer_algo(my_data); + +y el que despierta hace: + + my_data = valor; + evento_indicado = 1; + wake_up(&event_wait_queue); + +no existe garantía de que el cambio a event_indicated sea percibido por +el durmiente de manera que venga después del cambio a my_data. En tal +circunstancia, el código en ambos lados debe sacar sus propias barreras de +memoria entre los separados accesos a datos. Por lo tanto, el durmiente +anterior debería hacer: + + set_current_state(TASK_INTERRUPTIBLE); + if (evento_indicado) { + smp_rmb(); + hacer_algo(my_data); + } + +y el que despierta debería hacer: + + my_data = value; + smp_wmb(); + evento_indicado = 1; + wake_up(&event_wait_queue); + +FUNCIONES VARIAS +---------------- + +Otras funciones que implican barreras: + + (*) schedule() y similares implican barreras completas de memoria. + + +======================================== +EFECTOS DE BARRERA ADQUIRIENDO INTRA-CPU +======================================== + +En los sistemas SMP, las primitivas de bloqueo proveen una forma más +sustancial de barrera: una que afecta el orden de acceso a la memoria en +otras CPU, dentro del contexto de conflicto en cualquier bloqueo en +particular. + + +ADQUISICIÓN VS ACCESOS A MEMORIA +-------------------------------- + +Considere lo siguiente: el sistema tiene un par de spinlocks (M) y (Q), y +tres CPU; entonces la siguiente secuencia de eventos debería ocurrir: + + CPU 1 CPU 2 + =============================== =============================== + WRITE_ONCE(*A, a); WRITE_ONCE(*E, e); + ACQUIRE M ACQUIRE Q + WRITE_ONCE(*B, b); WRITE_ONCE(*F, f); + WRITE_ONCE(*C, c); WRITE_ONCE(*G, g); + RELEASE M RELEASE Q + WRITE_ONCE(*D, d); WRITE_ONCE(*H, h); + +Entonces no hay garantía sobre en qué orden verá la CPU 3 los accesos a *A +hasta que *H ocurra, además de las restricciones impuestas por los bloqueos +separados en las distintas CPUs. Podría, por ejemplo, ver: + + *E, ACQUIRE M, ACQUIRE Q, *G, *C, *F, *A, *B, RELEASE Q, *D, *H, RELEASE M + +Pero no verá ninguno de: + + *B, *C or *D preceding ACQUIRE M + *A, *B or *C following RELEASE M + *F, *G or *H preceding ACQUIRE Q + *E, *F or *G following RELEASE Q + +======================================== +¿DÓNDE SE NECESITAN BARRERAS DE MEMORIA? +======================================== + +Bajo operación normal, el re-ordenamiento de una operación de memoria +generalmente no va a suponer un problema, ya que para una pieza de código +lineal de un solo subproceso seguirá pareciendo que funciona correctamente, +incluso si está en un kernel SMP. Existen, sin embargo, cuatro +circunstancias en las que reordenar definitivamente _podría_ ser un +problema: + + (*) Interacción entre procesadores. + + (*) Operaciones atómicas. + + (*) Acceso a dispositivos. + + (*) Interrupciones. + + +INTERACCIÓN ENTRE PROCESADORES +------------------------------ + +Cuando se da un sistema con más de un procesador, más de una CPU en el +sistema puede estar trabajando en el mismo conjunto de datos al mismo +tiempo. Esto puede causar problemas de sincronización, y la forma habitual +de tratar con estos es utilizar cerrojos. Sin embargo, los cerrojos son +bastante caros, por lo que puede ser preferible operar sin el uso de un +cerrojo a ser posible. En cuyo caso, es posible que las operaciones que +afectan a ambas CPU deban ordenarse cuidadosamente para evitar un +funcionamiento incorrecto. + +Considere, por ejemplo, la ruta lenta del semáforo R/W. Aquí hay un proceso +de espera en cola del semáforo, en virtud de que tiene una parte de su pila +vinculada a la lista de procesos en espera del semáforo: + + struct rw_semaphore { + ... + spinlock_t lock; + struct list_head waiters; + }; + + struct rwsem_waiter { + struct list_head list; + struct task_struct *task; + }; + +Para despertar a un proceso que espera ("waiter") en particular, las +funciones up_read() o up_write() tienen que: + + (1) leer el siguiente puntero del registro de este proceso que espera, + para saber dónde está el registro del siguiente waiter; + + (2) leer el puntero a la estructura de tareas del waiter; + + (3) borrar el puntero de la tarea para decirle al waiter que se le ha dado + el semáforo; + + (4) llamar a wake_up_process() en la tarea; y + + (5) liberar la referencia retenida en la estructura de tareas del waiter. + +En otras palabras, tiene que realizar esta secuencia de eventos: + + LOAD waiter->list.next; + LOAD waiter->task; + STORE waiter->task; + CALL wakeup + RELEASE task + +y si alguno de estos pasos ocurre fuera de orden, entonces todo puede que +funcione defectuosamente. + +Una vez que se ha puesto en cola y soltado el bloqueo de semáforo, el +proceso que espera no consigue el candado de nuevo; en cambio, solo espera +a que se borre su puntero de tarea antes de continuar. Dado que el registro +está en la pila del proceso que espera, esto significa que si el puntero de +la tarea se borra _antes_ de que se lea el siguiente puntero de la lista, +otra CPU podría comenzar a procesar el proceso que espera y podría romper +el stack del proceso que espera antes de que la función up*() tenga la +oportunidad de leer el puntero que sigue. + +Considere entonces lo que podría suceder con la secuencia de eventos +anterior: + + CPU 1 CPU 2 + =============================== =============================== + down_xxx() + Poner waiter en la "queue" (cola) + Dormir + up_yyy() + LOAD waiter->task; + STORE waiter->task; + Despertado por otro evento + <preempt> + Reanudar el procesamiento + down_xxx() regresa + llamada a foo() + foo() estropea *waiter + </preempt> + LOAD waiter->list.next; + --- OOPS --- + +Esto podría solucionarse usando el bloqueo de semáforo, pero luego la +función down_xxx() tiene que obtener innecesariamente el spinlock +nuevamente, después de ser despertado el hilo. + +La forma de lidiar con esto es insertar una barrera de memoria SMP general: + + LOAD waiter->list.next; + LOAD waiter->task; + smp_mb(); + STORE waiter->task; + CALL wakeup + RELEASE task + +En este caso, la barrera garantiza que todos los accesos a memoria antes de +la barrera parecerán suceder antes de todos los accesos a memoria después +de dicha barrera con respecto a las demás CPU del sistema. _No_ garantiza +que todos los accesos a memoria antes de la barrera se completarán en el +momento en que la instrucción de la barrera en sí se complete. + +En un sistema UP, donde esto no sería un problema, la función smp_mb() es +solo una barrera del compilador, asegurándose así de que el compilador +emita las instrucciones en el orden correcto sin realmente intervenir en la +CPU. Como solo hay un CPU, la lógica de orden de dependencias de esa CPU se +encargará de todo lo demás. + + +OPERACIONES ATÓMICAS +-------------------- + +Si bien son, técnicamente, consideraciones de interacción entre +procesadores, las operaciones atómicas se destacan especialmente porque +algunas de ellas implican barreras de memoria completa y algunas otras no, +pero se confía mucho en ellos en su conjunto a lo largo del kernel. + +Consulte Documentation/atomic_t.txt para obtener más información. + + +ACCESO A DISPOSITIVOS +--------------------- + +Un driver puede ser interrumpido por su propia rutina de servicio de +interrupción y, por lo tanto, las dos partes del driver pueden interferir +con los intentos de controlar o acceder al dispositivo. + +Esto puede aliviarse, al menos en parte, desactivando las interrupciones +locales (una forma de bloqueo), de modo que las operaciones críticas sean +todas contenidas dentro la sección de interrupción desactivada en el +controlador. Mientras la interrupción del driver está ejecutando la rutina, +es posible que el "core" del controlador no se ejecute en la misma CPU y no +se permita que su interrupción vuelva a ocurrir hasta que la interrupción +actual haya sido resuelta, por lo tanto, el controlador de interrupción no +necesita bloquearse contra esto. + +Sin embargo, considere un driver que estaba hablando con una tarjeta +ethernet que tiene un registro de direcciones y un registro de datos. Si +el core de ese controlador habla con la tarjeta estando en desactivación de +interrupción y luego se invoca el controlador de interrupción del +controlador: + + IRQ LOCALES DESACTIVADAS + writew(ADDR, 3); + writew(DATA, y); + IRQ LOCALES ACTIVADAS + <interrupción> + writew(ADDR, 4); + q = readw(DATA); + </interrupción> + +El almacenamiento en el registro de datos puede ocurrir después del segundo +almacenamiento en el registro de direcciones si las reglas de orden son lo +suficientemente relajadas: + + STORE *ADDR = 3, STORE *ADDR = 4, STORE *DATA = y, q = LOAD *DATA + +Si se relajan las reglas de orden, se debe asumir que los accesos +realizados dentro de la sección con interrupción deshabilitada pueden +filtrarse fuera de esta y pueden intercalarse con accesos realizados en una +interrupción - y viceversa - a menos que se utilicenn barreras implícita o +explícitas. + +Normalmente, esto no será un problema porque los accesos de E/S realizados +dentro de tales secciones incluirán operaciones de carga síncronas en +registros E/S estrictamente ordenados, que forman barreras de E/S +implícitas. + + +Una situación similar puede ocurrir entre una rutina de interrupción y dos +rutinas ejecutándose en separadas CPU que se comunican entre sí. Si tal +caso es probable, entonces se deben usar bloqueos de desactivación de +interrupciones para garantizar el orden. + + +===================================== + Efectos de barrera de E/S del kernel +===================================== + +La interfaz con periféricos a través de accesos de E/S es profundamente +específica para cada arquitectura y dispositivo. Por lo tanto, los drivers +que son inherentemente no portátiles pueden depender de comportamientos +específicos de sus sistemas de destino, con el fin de lograr la +sincronización de la manera más ligera posible. Para drivers que deseen ser +portátiles entre múltiples arquitecturas e implementaciones de bus, el +kernel ofrece una serie de funciones de acceso que proporcionan varios +grados de garantías de orden: + + (*) readX(), writeX(): + + Las funciones de acceso MMIO readX() y writeX() usan un puntero al + periférico al que se accede como un parámetro __iomem *. para punteros + asignados los atributos de E/S predeterminados (por ejemplo, los + devueltos por ioremap()), las garantías de orden son las siguientes: + + 1. Se ordenan todos los accesos readX() y writeX() a un mismo periférico + entre estos. Esto asegura que los registros de acceso MMIO por el + mismo subproceso de la CPU a un dispositivo en particular llegarán en + el orden del programa. + + 2. Se ordena un writeX() emitido por un subproceso de CPU que contiene un + spinlock antes de un writeX() al mismo periférico desde otro + subproceso de CPU, si emitido después de una adquisición posterior del + mismo spinlock. Esto garantiza que ese registro MMIO escribe en un + dispositivo en particular, mientras que se obtiene un spinlock en un + orden consistente con las adquisiciones del cerrojo. + + 3. Un writeX() por un subproceso de la CPU al periférico primero esperará + a la finalización de todas las escrituras anteriores en la memoria + emitidas por, o bien propagadas por, el mismo subproceso. Esto asegura + que las escrituras de la CPU a un búfer DMA de salida asignadas por + dma_alloc_coherent() serán visibles para un motor ("engine") DMA + cuando la CPU escriba en sus registros de control MMIO, para activar + la transferencia. + + 4. Un readX() de un subproceso del CPU, desde el periférico, se + completará antes de que cualquier lectura subsiguiente de memoria por + el mismo subproceso pueda comenzar. Esto asegura que las lecturas de + la CPU desde un búfer DMA entrantes asignadas por + dma_alloc_coherent(), no verán datos obsoletos después de leer el + registro de estado MMIO del motor DMA, para establecer que la + transferencia DMA se haya completado. + + 5. Un readX() por un subproceso del CPU, desde el periférico, se + completará antes de que cualquier bucle delay() subsiguiente pueda + comenzar a ejecutarse en el mismo subproceso. Esto asegura que dos + escrituras del CPU a registros MMIO en un periférico llegarán al menos + con 1us de diferencia, si la primera escritura se lee inmediatamente + de vuelta con readX() y se llama a udelay(1) antes del segundo + writeX(): + + writel(42, DEVICE_REGISTER_0); // Llega al dispositivo ... + readl(DEVICE_REGISTER_0); + udelay(1); + writel(42, DEVICE_REGISTER_1); // al menos 1us antes de esto.... + +Las propiedades de orden de los punteros __iomem obtenidos con valores de +atributos que no sean los valores por defecto (por ejemplo, los devueltos +por ioremap_wc()) son específicos de la arquitectura subyacente y, por lo +tanto, las garantías enumeradas anteriormente no pueden por lo general ser +aseguradas para accesos a este tipo de "mappings" (asignaciones). + + (*) readX_relaxed(), writeX_relaxed(): + + Son similares a readX() y writeX(), pero proporcionan una garantía de + orden de memoria más débil. Específicamente, no garantizan orden con + respecto al bloqueo, los accesos normales a la memoria o los bucles + delay() (es decir, los puntos 2-5 arriba) pero todavía se garantiza que + se ordenarán con respecto a otros accesos desde el mismo hilo de la CPU, + al mismo periférico, cuando se opera en punteros __iomem asignados con el + valor predeterminado para los atributos de E/S. + + (*) readsX(), writesX(): + + Los puntos de entrada readsX() y writesX() MMIO están diseñados para + acceder FIFOs mapeados en memoria y basados en registros que residen en + periféricos, que no son capaces de realizar DMA. Por tanto, sólo + proporcionan garantías de orden readX_relaxed() y writeX_relaxed(), como + se documentó anteriormente. + + (*) inX(), outX(): + + Los puntos de entrada inX() y outX() están destinados a acceder a mapas + de puertos "legacy" (antiguos) de periféricos de E/S, que pueden requerir + instrucciones especiales en algunas arquitecturas (especialmente, en + x86). El número de puerto del periférico que se está accedido se pasa + como un argumento. + + Dado que muchas arquitecturas de CPU acceden finalmente a estos + periféricos a través de un mapeo interno de memoria virtual, las + garantías de orden portátiles proporcionadas por inX() y outX() son las + mismas que las proporcionadas por readX() y writeX(), respectivamente, al + acceder a una asignación con los valores de atributos de E/S + predeterminados (los que haya por defecto). + + Los drivers de dispositivos pueden esperar que outX() emita una + transacción de escritura no publicada, que espera una respuesta de + finalización del periférico de E/S antes de regresar. Esto no está + garantizado por todas las arquitecturas y por lo tanto no forma parte de + la semántica de orden portátil. + + (*) insX(), outsX(): + + Como arriba, los puntos de entrada insX() y outsX() proporcionan el mismo + orden garantizado por readsX() y writesX() respectivamente, al acceder a + un mapping con los atributos de E/S predeterminados. + + (*) ioreadX(), iowriteX(): + + Estos funcionarán adecuadamente para el tipo de acceso que realmente están + haciendo, ya sea inX()/outX() o readX()/writeX(). + +Con la excepción de los puntos de entrada (insX(), outsX(), readsX() y +writesX()), todo lo anterior supone que el periférico subyacente es +little-endian y, por lo tanto, realizará operaciones de intercambio de +bytes en arquitecturas big-endian. + + +=========================================== +MODELO DE ORDEN MÍNIMO DE EJECUCIÓN ASUMIDO +=========================================== + +Debe suponerse que la CPU conceptual está débilmente ordenada, pero que +mantiene la apariencia de causalidad del programa con respecto a sí misma. +Algunas CPU (como i386 o x86_64) están más limitadas que otras (como +powerpc o frv), por lo que el caso más relajado (es decir, DEC Alpha) se +debe asumir fuera de código específico de arquitectura. + +Esto significa que se debe considerar que la CPU ejecutará su flujo de +instrucciones en el orden que se quiera - o incluso en paralelo - siempre +que si una instrucción en el flujo depende de una instrucción anterior, +entonces dicha instrucción anterior debe ser lo suficientemente completa[*] +antes de que la posterior instrucción puede proceder; en otras palabras: +siempre que la apariencia de causalidad se mantenga. + + [*] Algunas instrucciones tienen más de un efecto, como cambiar el + código de condición, cambio de registros o cambio de memoria - y + distintas instrucciones pueden depender de diferentes efectos. + +Una CPU puede también descartar cualquier secuencia de instrucciones que +termine sin tener efecto final. Por ejemplo, si dos instrucciones +adyacentes cargan un valor inmediato en el mismo registro, la primera puede +descartarse. + + +De manera similar, se debe suponer que el compilador podría reordenar la +corriente de instrucciones de la manera que crea conveniente, nuevamente +siempre que la apariencia de causalidad se mantenga. + + +===================================== +EFECTOS DE LA MEMORIA CACHÉ DE LA CPU +===================================== + +La forma en que se perciben las operaciones de memoria caché en todo el +sistema se ve afectada, hasta cierto punto, por los cachés que se +encuentran entre las CPU y la memoria, y por el sistema de coherencia en +memoria que mantiene la consistencia de estado en el sistema. + +En cuanto a la forma en que una CPU interactúa con otra parte del sistema a +través del caché, el sistema de memoria tiene que incluir los cachés de la +CPU y barreras de memoria, que en su mayor parte actúan en la interfaz +entre la CPU y su caché (las barreras de memoria lógicamente actúan sobre +la línea de puntos en el siguiente diagrama): + + <--- CPU ---> : <----------- Memoria -----------> + : + +--------+ +--------+ : +--------+ +-----------+ + | Core | | Cola | : | Cache | | | +---------+ + | CPU | | de | : | CPU | | | | | + | |--->| acceso |----->| |<-->| | | | + | | | a | : | | | |--->| Memoria | + | | | memoria| : | | | | | | + +--------+ +--------+ : +--------+ | Mecanismo | | | + : | de | +---------+ + : | Coherencia| + : | de la | +--------+ + +--------+ +--------+ : +--------+ | cache | | | + | Core | | Cola | : | Cache | | | | | + | CPU | | de | : | CPU | | |--->| Dispos | + | |--->| acceso |----->| |<-->| | | itivo | + | | | a | : | | | | | | + | | | memoria| : | | | | +--------+ + +--------+ +--------+ : +--------+ +-----------+ + : + : + +Aunque es posible que una carga o store en particular no aparezca fuera de +la CPU que lo emitió, ya que puede haber sido satisfecha dentro del propio +caché de la CPU, seguirá pareciendo como si el acceso total a la memoria +hubiera tenido lugar para las otras CPUs, ya que los mecanismos de +coherencia de caché migrarán la cacheline sobre la CPU que accede y se +propagarán los efectos en caso de conflicto. + +El núcleo de la CPU puede ejecutar instrucciones en el orden que considere +adecuado, siempre que parezca mantenerse la causalidad esperada del +programa. Algunas de las instrucciones generan operaciones de carga y +almacenamiento que luego van a la cola de accesos a memoria a realizar. El +núcleo puede colocarlos en la cola en cualquier orden que desee, y +continuar su ejecución hasta que se vea obligado a esperar que una +instrucción sea completada. + +De lo que se ocupan las barreras de la memoria es de controlar el orden en +que los accesos cruzan, desde el lado de la CPU, hasta el lado de memoria, +y el orden en que los otros observadores perciben los efectos en el sistema +que sucedan por esto. + +[!] Las barreras de memoria _no_ son necesarias dentro de una CPU +determinada, ya que las CPU siempre ven sus propias cargas y stores como si +hubieran sucedido en el orden del programa. + +[!] Los accesos a MMIO u otros dispositivos pueden pasar por alto el +sistema de caché. Esto depende de las propiedades de la ventana de memoria +a través de la cual se accede a los dispositivos y/o el uso de +instrucciones especiales de comunicación con dispositivo que pueda tener la +CPU. + + +COHERENCIA DE CACHÉ FRENTE A DMA +--------------------------------- + +No todos los sistemas mantienen coherencia de caché con respecto a los +dispositivos que realizan DMA. En tales casos, un dispositivo que intente +DMA puede obtener datos obsoletos de la RAM, porque las líneas de caché +"sucias" pueden residir en los cachés de varias CPU, y es posible que no +se hayan vuelto a escribir en la RAM todavía. Para hacer frente a esto, la +parte apropiada del kernel debe vaciar los bits superpuestos de caché en +cada CPU (y tal vez también invalidarlos). + +Además, los datos enviados por DMA a RAM, por un dispositivo, pueden ser +sobrescritos por líneas de caché sucias que se escriben de nuevo en la RAM +desde el caché de una CPU, después de que el dispositivo haya puesto sus +propios datos, o las líneas de caché presentes en el caché de la CPU pueden +simplemente ocultar el hecho de que la memoria RAM se haya actualizado, +hasta el momento en que la caché se descarta de la memoria caché de la CPU +y se vuelve a cargar. Para hacer frente a esto, la parte apropiada del +kernel debe invalidar los bits superpuestos del caché en cada CPU. + +Consulte Documentation/core-api/cachetlb.rst para obtener más información +sobre administración de la memoria caché. + + +COHERENCIA DE CACHÉ FRENTE A MMIO +--------------------------------- + +La E/S mapeada en memoria generalmente se lleva a cabo a través de +ubicaciones de memoria que forman parte de una ventana del espacio de +memoria de la CPU, que tiene diferentes propiedades asignadas que la +ventana habitual dirigida a RAM. + +Entre dichas propiedades, suele existir el hecho de que tales accesos +eluden el almacenamiento en caché por completo e ir directamente a los +buses del dispositivo. Esto significa que los accesos MMIO pueden, en +efecto, superar los accesos a la memoria caché que se emitieron +anteriormente. Una barrera de memoria no es suficiente en tal caso, sino +que el caché debe ser vaciado entre la escritura de la memoria caché, y el +acceso MMIO, si los dos son de cualquier manera dependiente. + + +======================= +COSAS QUE HACEN LAS CPU +======================= + +Un programador podría dar por sentado que la CPU realizará las operaciones +de memoria exactamente en el orden especificado, de modo que si a la CPU se +entrega, por ejemplo, el siguiente fragmento de código a ejecutar: + + a = READ_ONCE(*A); + WRITE_ONCE(*B, b); + c = READ_ONCE(*C); + d = READ_ONCE(*D); + WRITE_ONCE(*E, e); + +esperarían entonces que la CPU complete la operación de memoria para cada +instrucción antes de pasar a la siguiente, lo que lleva a una definida +secuencia de operaciones vistas por observadores externos en el sistema: + + LOAD *A, STORE *B, LOAD *C, LOAD *D, STORE *E. + +La realidad es, por supuesto, mucho más intrincada. Para muchas CPU y +compiladores, la anterior suposición no se sostiene porque: + + (*) es más probable que las cargas deban completarse de inmediato para + permitir progreso en la ejecución, mientras que los stores a menudo se + pueden aplazar sin problema; + + (*) las cargas se pueden hacer especulativamente, y el resultado es + descartado si resulta innecesario; + + (*) las cargas se pueden hacer de forma especulativa, lo que lleva a que + se haya obtenido el resultado en el momento equivocado de la secuencia + de eventos esperada; + + (*) el orden de los accesos a memoria se puede reorganizar para promover + un mejor uso de los buses y cachés de la CPU; + + (*) las cargas y los stores se pueden combinar para mejorar el rendimiento + cuando se habla con memoria o hardware de E/S, que puede realizar + accesos por lotes a ubicaciones adyacentes, reduciendo así los costes + de configuración de transacciones (la memoria y los dispositivos PCI + pueden ambos pueden hacer esto); y + + (*) la caché de datos de la CPU puede afectar al orden, y mientras sus + mecanismos de coherencia pueden aliviar esto, una vez que el store + haya accedido al caché- no hay garantía de que la gestión de la + coherencia se propague en orden a otras CPU. + +Entonces, digamos que lo que otra CPU podría observar en el fragmento de +código anterior es: + + LOAD *A, ..., LOAD {*C,*D}, STORE *E, STORE *B + + (Donde "LOAD {*C,*D}" es una carga combinada) + + +Sin embargo, se garantiza que una CPU es autoconsistente: verá que sus + _propios_ accesos parecen estar correctamente ordenados, sin necesidad de +barrera de memoria. Por ejemplo con el siguiente código: + + U = READ_ONCE(*A); + WRITE_ONCE(*A, V); + WRITE_ONCE(*A, W); + X = READ_ONCE(*A); + WRITE_ONCE(*A, Y); + Z = READ_ONCE(*A); + +y asumiendo que no hay intervención de una influencia externa, se puede +suponer que el resultado final se parecerá a: + + U == el valor original de *A + X == W + Z == Y + *A == Y + +El código anterior puede hacer que la CPU genere la secuencia completa de +accesos de memoria: + + U=LOAD *A, STORE *A=V, STORE *A=W, X=LOAD *A, STORE *A=Y, Z=LOAD *A + +en ese orden, pero, sin intervención, la secuencia puede contener casi +cualquier combinación de elementos combinados o descartados, siempre que la +perspectiva del programa del mundo siga siendo consistente. Tenga en cuenta +que READ_ONCE() y WRITE_ONCE() -no- son opcionales en el ejemplo anterior, +ya que hay arquitecturas donde una CPU determinada podría reordenar cargas +sucesivas en la misma ubicación. En tales arquitecturas, READ_ONCE() y +WRITE_ONCE() hacen lo que sea necesario para evitar esto, por ejemplo, en +Itanium los casts volátiles utilizados por READ_ONCE() y WRITE_ONCE() hacen +que GCC emita las instrucciones especiales ld.acq y st.rel +(respectivamente) que impiden dicha reordenación. + +El compilador también puede combinar, descartar o diferir elementos de la +secuencia antes incluso de que la CPU los vea. + +Por ejemplo: + + *A = V; + *A = W; + +puede reducirse a: + + *A = W; + +ya que, sin una barrera de escritura o WRITE_ONCE(), puede que se asuma +que el efecto del almacenamiento de V a *A se pierde. Similarmente: + + *A = Y; + Z = *A; + +puede, sin una barrera de memoria o un READ_ONCE() y WRITE_ONCE(), esto +sea reducido a: + + *A = Y; + Z = Y; + +y la operación LOAD nunca aparezca fuera de la CPU. + + +Y LUEGO ESTÁ EL ALFA +-------------------- + +La CPU DEC Alpha es una de las CPU más relajadas que existen. No solo eso, +algunas versiones de la CPU Alpha tienen un caché de datos dividido, lo que +les permite tener dos líneas de caché relacionadas semánticamente, +actualizadas en momentos separados. Aquí es donde la barrera de dependencia +de dirección realmente se vuelve necesaria, ya que se sincronizan ambos +cachés con el sistema de coherencia de memoria, lo que hace que parezca un +cambio en el puntero, frente a que los nuevos datos se produzcan en el +orden correcto. + +Alpha define el modelo de memoria del kernel Linux, aunque a partir de +v4.15, la adición al kernel de Linux de smp_mb() a READ_ONCE() en Alpha +redujo en gran medida su impacto en el modelo de memoria. + + +GUESTS DE MÁQUINAS VIRTUALES +----------------------------- + +Los "guests" (invitados) que se ejecutan en máquinas virtuales pueden verse +afectados por los efectos de SMP incluso si el "host" (huésped) en sí se +compila sin compatibilidad con SMP. Este es un efecto de la interacción con +un host SMP mientras ejecuta un kernel UP. El uso obligatorio de barreras +para este caso de uso sería posible, pero a menudo no son óptimas. + +Para hacer frente a este caso de manera óptima, están disponibles macros de +bajo nivel virt_mb() etc. Estas tienen el mismo efecto que smp_mb(), etc. +cuando SMP está habilitado, pero generan código idéntico para sistemas SMP +y no SMP. Por ejemplo, los invitados de máquinas virtuales debería usar +virt_mb() en lugar de smp_mb() al sincronizar contra un (posiblemente SMP) +anfitrión. + +Estos son equivalentes a sus contrapartes smp_mb() etc. en todos los demás +aspectos, en particular, no controlan los efectos MMIO: para controlar los +efectos MMIO, utilice barreras obligatorias. + + +================ +EJEMPLOS DE USOS +================ + +BUFFERS CIRCULARES +------------------ + +Las barreras de memoria se pueden utilizar para implementar almacenamiento +en búfer circular, sin necesidad de un cerrojo para serializar al productor +con el consumidor. Vea: + + Documentation/core-api/circular-buffers.rst + +para más detalles. + + +=========== +REFERENCIAS +=========== + +Alpha AXP Architecture Reference Manual, Segunda Edición (por Sites & Witek, +Digital Press) + Capítulo 5.2: Physical Address Space Characteristics + Capítulo 5.4: Caches and Write Buffers + Capítulo 5.5: Data Sharing + Capítulo 5.6: Read/Write Ordering + +AMD64 Architecture Programmer's Manual Volumen 2: System Programming + Capítulo 7.1: Memory-Access Ordering + Capítulo 7.4: Buffering and Combining Memory Writes + +ARM Architecture Reference Manual (ARMv8, for ARMv8-A architecture profile) + Capítulo B2: The AArch64 Application Level Memory Model + +IA-32 Intel Architecture Software Developer's Manual, Volumen 3: +System Programming Guide + Capítulo 7.1: Locked Atomic Operations + Capítulo 7.2: Memory Ordering + Capítulo 7.4: Serializing Instructions + +The SPARC Architecture Manual, Version 9 + Capítulo 8: Memory Models + Appendix D: Formal Specification of the Memory Models + Appendix J: Programming with the Memory Models + +Storage in the PowerPC (por Stone and Fitzgerald) + +UltraSPARC Programmer Reference Manual + Capítulo 5: Memory Accesses and Cacheability + Capítulo 15: Sparc-V9 Memory Models + +UltraSPARC III Cu User's Manual + Capítulo 9: Memory Models + +UltraSPARC IIIi Processor User's Manual + Capítulo 8: Memory Models + +UltraSPARC Architecture 2005 + Capítulo 9: Memory + Appendix D: Formal Specifications of the Memory Models + +UltraSPARC T1 Supplement to the UltraSPARC Architecture 2005 + Capítulo 8: Memory Models + Appendix F: Caches and Cache Coherency + +Solaris Internals, Core Kernel Architecture, p63-68: + Capítulo 3.3: Hardware Considerations for Locks and + Synchronization + +Unix Systems for Modern Architectures, Symmetric Multiprocessing and Caching +for Kernel Programmers: + Capítulo 13: Other Memory Models + +Intel Itanium Architecture Software Developer's Manual: Volumen 1: + Sección 2.6: Speculation + Sección 4.4: Memory Access diff --git a/Documentation/translations/sp_SP/process/adding-syscalls.rst b/Documentation/translations/sp_SP/process/adding-syscalls.rst new file mode 100644 index 0000000000..f21504c612 --- /dev/null +++ b/Documentation/translations/sp_SP/process/adding-syscalls.rst @@ -0,0 +1,632 @@ +.. include:: ../disclaimer-sp.rst + +:Original: :ref:`Documentation/process/adding-syscalls.rst <addsyscalls>` +:Translator: Mauricio Fuentes <mauriciofb@gmail.com> + +.. _sp_addsyscalls: + +Agregando una Nueva Llamada del Sistema +======================================= + +Este documento describe qué involucra agregar una nueva llamada del sistema +al kernel Linux, más allá de la presentación y consejos normales en +:ref:`Documentation/process/submitting-patches.rst <submittingpatches>` que +también puede encontrar traducido a este idioma. + +Alternativas a Llamadas del Sistema +----------------------------------- + +La primera cosa a considerar cuando se agrega una llamada al sistema es si +alguna alternativa es adecuada en su lugar. Aunque las llamadas al sistema +son los puntos de interacción entre el userspace y el kernel más obvios y +tradicionales, existen otras posibilidades -- elija la que mejor se adecúe +a su interfaz. + + - Si se puede hacer que la operación se parezca a un objeto filesystem, + podría tener más sentido crear un nuevo sistema de ficheros o + dispositivo. Esto también hará más fácil encapsular la nueva + funcionalidad en un módulo del kernel en vez de requerir que sea + construido junto al kernel principal. + + - Si la nueva funcionalidad involucra operaciones donde el kernel + notifica al userspace que algo ha pasado, entonces retornar un nuevo + descriptor de archivo para el objeto relevante permite al userspace + usar ``poll``/``select``/``epoll`` para recibir esta notificación. + + - Sin embargo, operaciones que no mapean a operaciones similares a + :manpage:`read(2)`/:manpage:`write(2)` tienen que ser implementadas + como solicitudes :manpage:`ioctl(2)`, las cuales pueden llevar a un + API algo opaca. + + - Si sólo está exponiendo información del runtime, un nuevo nodo en sysfs + (mire ``Documentation/filesystems/sysfs.rst``) o el filesystem ``/proc`` + podría ser más adecuado. Sin embargo, acceder a estos mecanismos + requiere que el filesystem relevante esté montado, lo que podría no ser + siempre el caso (e.g. en un ambiente namespaced/sandboxed/chrooted). + Evite agregar cualquier API a debugfs, ya que no se considera una + interfaz (interface) de 'producción' para el userspace. + + - Si la operación es específica a un archivo o descriptor de archivo + específico, entonces la opción de comando adicional :manpage:`fcntl(2)` + podría ser más apropiada. Sin embargo, :manpage:`fcntl(2)` es una + llamada al sistema multiplexada que esconde mucha complejidad, así que + esta opción es mejor cuando la nueva funcion es analogamente cercana a + la funcionalidad existente :manpage:`fcntl(2)`, o la nueva funcionalidad + es muy simple (por ejemplo, definir/obtener un flag simple relacionado a + un descriptor de archivo). + + - Si la operación es específica a un proceso o tarea particular, entonces + un comando adicional :manpage:`prctl(2)` podría ser más apropiado. Tal + como con :manpage:`fcntl(2)`, esta llamada al sistema es un multiplexor + complicado así que está reservado para comandos análogamente cercanos + del existente ``prctl()`` u obtener/definir un flag simple relacionado a + un proceso. + +Diseñando el API: Planeando para extensiones +-------------------------------------------- + +Una nueva llamada del sistema forma parte del API del kernel, y tiene que +ser soportada indefinidamente. Como tal, es una muy buena idea discutir +explícitamente el interface en las listas de correo del kernel, y es +importante planear para futuras extensiones del interface. + +(La tabla syscall está poblada con ejemplos históricos donde esto no se +hizo, junto con los correspondientes seguimientos de los system calls -- +``eventfd``/``eventfd2``, ``dup2``/``dup3``, ``inotify_init``/``inotify_init1``, +``pipe``/``pipe2``, ``renameat``/``renameat2`` -- así que aprenda de la +historia del kernel y planee extensiones desde el inicio.) + +Para llamadas al sistema más simples que sólo toman un par de argumentos, +la forma preferida de permitir futuras extensiones es incluir un argumento +flag a la llamada al sistema. Para asegurarse que el userspace pueda usar +de forma segura estos flags entre versiones del kernel, revise si los flags +contienen cualquier flag desconocido, y rechace la llamada al sistema (con +``EINVAL``) si ocurre:: + + if (flags & ~(THING_FLAG1 | THINGFLAG2 | THING_FLAG3)) + return -EINVAL; + +(Si no hay valores de flags usados aún, revise que los argumentos del flag +sean cero.) + +Para llamadas al sistema más sofisticadas que involucran un gran número de +argumentos, es preferible encapsular la mayoría de los argumentos en una +estructura que sea pasada a través de un puntero. Tal estructura puede +hacer frente a futuras extensiones mediante la inclusión de un argumento de +tamaño en la estructura:: + + struct xyzzy_params { + u32 size; /* userspace define p->size = sizeof(struct xyzzy_params) */ + u32 param_1; + u64 param_2; + u64 param_3; + }; + +Siempre que cualquier campo añadido subsecuente, digamos ``param_4``, sea +diseñado de forma tal que un valor cero, devuelva el comportamiento previo, +entonces permite versiones no coincidentes en ambos sentidos: + + - Para hacer frente a programas del userspace más modernos, haciendo + llamadas a un kernel más antiguo, el código del kernel debe revisar que + cualquier memoria más allá del tamaño de la estructura sea cero (revisar + de manera efectiva que ``param_4 == 0``). + - Para hacer frente a programas antiguos del userspace haciendo llamadas a + un kernel más nuevo, el código del kernel puede extender con ceros, una + instancia más pequeña de la estructura (definiendo efectivamente + ``param_4 == 0``). + +Revise :manpage:`perf_event_open(2)` y la función ``perf_copy_attr()`` (en +``kernel/events/code.c``) para un ejemplo de esta aproximación. + + +Diseñando el API: Otras consideraciones +--------------------------------------- + +Si su nueva llamada al sistema permite al userspace hacer referencia a un +objeto del kernel, esta debería usar un descriptor de archivo como el +manipulador de ese objeto -- no invente un nuevo tipo de objeto manipulador +userspace cuando el kernel ya tiene mecanismos y semánticas bien definidas +para usar los descriptores de archivos. + +Si su nueva llamada a sistema :manpage:`xyzzy(2)` retorna un nuevo +descriptor de archivo, entonces el argumento flag debe incluir un valor que +sea equivalente a definir ``O_CLOEXEC`` en el nuevo FD. Esto hace posible +al userspace acortar la brecha de tiempo entre ``xyzzy()`` y la llamada a +``fcntl(fd, F_SETFD, FD_CLOEXEC)``, donde un ``fork()`` inesperado y +``execve()`` en otro hilo podrían filtrar un descriptor al programa +ejecutado. (Sin embargo, resista la tentación de reusar el valor actual de +la constante ``O_CLOEXEC``, ya que es específica de la arquitectura y es +parte de un espacio numerado de flags ``O_*`` que está bastante lleno.) + +Si su llamada de sistema retorna un nuevo descriptor de archivo, debería +considerar también que significa usar la familia de llamadas de sistema +:manpage:`poll(2)` en ese descriptor de archivo. Hacer un descriptor de +archivo listo para leer o escribir es la forma normal para que el kernel +indique al espacio de usuario que un evento ha ocurrido en el +correspondiente objeto del kernel. + +Si su nueva llamada de sistema :manpage:`xyzzy(2)` involucra algún nombre +de archivo como argumento:: + + int sys_xyzzy(const char __user *path, ..., unsigned int flags); + +debería considerar también si una versión :manpage:`xyzzyat(2)` es mas +apropiada:: + + int sys_xyzzyat(int dfd, const char __user *path, ..., unsigned int flags); + +Esto permite más flexibilidad en como el userspace especifica el archivo en +cuestión; en particular esto permite al userspace pedir la funcionalidad a +un descriptor de archivo ya abierto usando el flag ``AT_EMPTY_PATH``, +efectivamente dando una operación :manpage:`fxyzzy(3)` gratis:: + + - xyzzyat(AT_FDCWD, path, ..., 0) es equivalente a xyzzy(path, ...) + - xyzzyat(fd, "", ..., AT_EMPTY_PATH) es equivalente a fxyzzy(fd, ...) + +(Para más detalles sobre la explicación racional de las llamadas \*at(), +revise el man page :manpage:`openat(2)`; para un ejemplo de AT_EMPTY_PATH, +mire el man page :manpage:`fstatat(2)` manpage.) + +Si su nueva llamada de sistema :manpage:`xyzzy(2)` involucra un parámetro +describiendo un describiendo un movimiento dentro de un archivo, ponga de +tipo ``loff_t`` para que movimientos de 64-bit puedan ser soportados +incluso en arquitecturas de 32-bit. + +Si su nueva llamada de sistema :manpage:`xyzzy` involucra una +funcionalidad privilegiada, esta necesita ser gobernada por la capability +bit linux apropiada (revisado con una llamada a ``capable()``), como se +describe en el man page :manpage:`capabilities(7)`. Elija una parte de +capability linux que govierne las funcionalidades relacionadas, pero trate +de evitar combinar muchas funciones sólo relacionadas vagamente bajo la +misma sección, ya que va en contra de los propósitos de las capabilities de +dividir el poder del usuario root. En particular, evite agregar nuevos usos +de la capacidad ya demasiado general de la capabilities ``CAP_SYS_ADMIN``. + +Si su nueva llamada de sistema :manpage:`xyzzy(2)` manipula un proceso que +no es el proceso invocado, este debería ser restringido (usando una llamada +a ``ptrace_may_access()``) de forma que el único proceso con los mismos +permisos del proceso objetivo, o con las capacidades (capabilities) +necesarias, pueda manipulador el proceso objetivo. + +Finalmente, debe ser conciente de que algunas arquitecturas no-x86 tienen +un manejo más sencillo si los parámetros que son explícitamente 64-bit +caigan en argumentos enumerados impares (i.e. parámetros 1,3,5), para +permitir el uso de pares contiguos de registros 32-bits. (Este cuidado no +aplica si el argumento es parte de una estructura que se pasa a través de +un puntero.) + +Proponiendo el API +------------------ + +Para hacer una nueva llamada al sistema fácil de revisar, es mejor dividir +el patchset (conjunto de parches) en trozos separados. Estos deberían +incluir al menos los siguientes items como commits distintos (cada uno de +los cuales se describirá más abajo): + + - La implementación central de la llamada al sistema, junto con + prototipos, numeración genérica, cambios Kconfig e implementaciones de + rutinas de respaldo (fallback stub) + - Conectar la nueva llamada a sistema a una arquitectura particular, + usualmente x86 (incluyendo todas las x86_64, x86_32 y x32). + - Una demostración del use de la nueva llamada a sistema en el userspace + vía un selftest en ``tools/testing/selftest/``. + - Un borrador de man-page para la nueva llamada a sistema, ya sea como + texto plano en la carta de presentación, o como un parche (separado) + para el repositorio man-pages. + +Nuevas propuestas de llamadas de sistema, como cualquier cambio al API del +kernel, debería siempre ser copiado a linux-api@vger.kernel.org. + + +Implementation de Llamada de Sistema Generica +--------------------------------------------- + +La entrada principal a su nueva llamada de sistema :manpage:`xyzzy(2)` será +llamada ``sys_xyzzy()``, pero incluya este punto de entrada con la macro +``SYSCALL_DEFINEn()`` apropiada en vez de explicitamente. El 'n' indica el +numero de argumentos de la llamada de sistema, y la macro toma el nombre de +la llamada de sistema seguida por el par (tipo, nombre) para los parámetros +como argumentos. Usar esta macro permite a la metadata de la nueva llamada +de sistema estar disponible para otras herramientas. + +El nuevo punto de entrada también necesita un prototipo de función +correspondiente en ``include/linux/syscalls.h``, marcado como asmlinkage +para calzar en la manera en que las llamadas de sistema son invocadas:: + + asmlinkage long sys_xyzzy(...); + +Algunas arquitecturas (e.g. x86) tienen sus propias tablas de syscall +específicas para la arquitectura, pero muchas otras arquitecturas comparten +una tabla de syscall genéricas. Agrega su nueva llamada de sistema a la +lista genérica agregando una entrada a la lista en +``include/uapi/asm-generic/unistd.h``:: + + #define __NR_xyzzy 292 + __SYSCALL(__NR_xyzzy, sys_xyzzy ) + +También actualice el conteo de __NR_syscalls para reflejar la llamada de +sistema adicional, y note que si multiples llamadas de sistema nuevas son +añadidas en la misma ventana unida, su nueva llamada de sistema podría +tener que ser ajustada para resolver conflictos. + +El archivo ``kernel/sys_ni.c`` provee una implementación fallback stub +(rutina de respaldo) para cada llamada de sistema, retornando ``-ENOSYS``. +Incluya su nueva llamada a sistema aquí también:: + + COND_SYSCALL(xyzzy); + +Su nueva funcionalidad del kernel, y la llamada de sistema que la controla, +debería normalmente ser opcional, así que incluya una opción ``CONFIG`` +(tipicamente en ``init/Kconfig``) para ella. Como es usual para opciones +``CONFIG`` nuevas: + + - Incluya una descripción para la nueva funcionalidad y llamada al sistema + controlada por la opción. + - Haga la opción dependiendo de EXPERT si esta debe estar escondida de los + usuarios normales. + - Haga que cualquier nuevo archivo fuente que implemente la función + dependa de la opción CONFIG en el Makefile (e.g. + ``obj-$(CONFIG_XYZZY_SYSCALL) += xyzzy.o``). + - Revise dos veces que el kernel se siga compilando con la nueva opción + CONFIG apagada. + +Para resumir, necesita un commit que incluya: + + - una opción ``CONFIG`` para la nueva función, normalmente en ``init/Kconfig`` + - ``SYSCALL_DEFINEn(xyzzy, ...)`` para el punto de entrada + - El correspondiente prototipo en ``include/linux/syscalls.h`` + - Una entrada genérica en ``include/uapi/asm-generic/unistd.h`` + - fallback stub en ``kernel/sys_ni.c`` + + +Implementación de Llamada de Sistema x86 +---------------------------------------- + +Para conectar su nueva llamada de sistema a plataformas x86, necesita +actualizar las tablas maestras syscall. Asumiendo que su nueva llamada de +sistema ni es especial de alguna manera (revise abajo), esto involucra una +entrada "común" (para x86_64 y x86_32) en +arch/x86/entry/syscalls/syscall_64.tbl:: + + 333 common xyzz sys_xyzzy + +y una entrada "i386" en ``arch/x86/entry/syscalls/syscall_32.tbl``:: + + 380 i386 xyzz sys_xyzzy + +De nuevo, estos número son propensos de ser cambiados si hay conflictos en +la ventana de integración relevante. + + +Compatibilidad de Llamadas de Sistema (Genérica) +------------------------------------------------ + +Para la mayoría de llamadas al sistema la misma implementación 64-bit puede +ser invocada incluso cuando el programa de userspace es en si mismo 32-bit; +incluso si los parámetros de la llamada de sistema incluyen un puntero +explícito, esto es manipulado de forma transparente. + +Sin embargo, existe un par de situaciones donde se necesita una capa de +compatibilidad para lidiar con las diferencias de tamaño entre 32-bit y +64-bit. + +La primera es si el kernel 64-bit también soporta programas del userspace +32-bit, y por lo tanto necesita analizar areas de memoria del (``__user``) +que podrían tener valores tanto 32-bit como 64-bit. En particular esto se +necesita siempre que un argumento de la llamada a sistema es: + + - un puntero a un puntero + - un puntero a un struc conteniendo un puntero (por ejemplo + ``struct iovec __user *``) + - un puntero a un type entero de tamaño entero variable (``time_t``, + ``off_t``, ``long``, ...) + - un puntero a un struct conteniendo un type entero de tamaño variable. + +La segunda situación que requiere una capa de compatibilidad es cuando uno +de los argumentos de la llamada a sistema tiene un argumento que es +explícitamente 64-bit incluso sobre arquitectura 32-bit, por ejemplo +``loff_t`` o ``__u64``. En este caso, el valor que llega a un kernel 64-bit +desde una aplicación de 32-bit se separará en dos valores de 32-bit, los +que luego necesitan ser reensamblados en la capa de compatibilidad. + +(Note que un argumento de una llamada a sistema que sea un puntero a un +type explicitamente de 64-bit **no** necesita una capa de compatibilidad; +por ejemplo, los argumentos de :manpage:`splice(2)`) del tipo +``loff_t __user *`` no significan la necesidad de una llamada a sistema +``compat_``.) + +La versión compatible de la llamada de sistema se llama +``compat_sys_xyzzy()``, y se agrega con la macro +``COMPAT_SYSCALL_DEFINEn``, de manera análoga a SYSCALL_DEFINEn. Esta +versión de la implementación se ejecuta como parte de un kernel de 64-bit, +pero espera recibir parametros con valores 32-bit y hace lo que tenga que +hacer para tratar con ellos. (Típicamente, la versión ``compat_sys_`` +convierte los valores a versiones de 64 bits y llama a la versión ``sys_`` +o ambas llaman a una función de implementación interna común.) + +El punto de entrada compat también necesita un prototipo de función +correspondiente, en ``include/linux/compat.h``, marcado como asmlinkage +para igualar la forma en que las llamadas al sistema son invocadas:: + + asmlinkage long compat_sys_xyzzy(...); + +Si la nueva llamada al sistema involucra una estructura que que se dispone +de forma distinta en sistema de 32-bit y 64-bit, digamos +``struct xyzzy_args``, entonces el archivo de cabecera +include/linux/compat.h también debería incluir una versión compatible de la +estructura (``struct compat_xyzzy_args``) donde cada campo de tamaño +variable tiene el tipo ``compat_`` apropiado que corresponde al tipo en +``struct xyzzy_args``. La rutina ``compat_sys_xyzzy()`` puede entonces usar +esta estructura ``compat_`` para analizar los argumentos de una invocación +de 32-bit. + +Por ejemplo, si hay campos:: + + struct xyzzy_args { + const char __user *ptr; + __kernel_long_t varying_val; + u64 fixed_val; + /* ... */ + }; + +en struct xyzzy_args, entonces struct compat_xyzzy_args debe tener:: + + struct compat_xyzzy_args { + compat_uptr_t ptr; + compat_long_t varying_val; + u64 fixed_val; + /* ... */ + }; + +la lista genérica de llamadas al sistema también necesita ajustes para +permitir la versión compat; la entrada en +``include/uapi/asm-generic/unistd.h`` debería usar ``__SC_COMP`` en vez de +``__SYSCALL``:: + + #define __NR_xyzzy 292 + __SC_COMP(__NR_xyzzy, sys_xyzzy, compat_sys_xyzzy) + +Para resumir, necesita: + + - una ``COMPAT_SYSCALL_DEFINEn(xyzzy, ...)`` para el punto de entrada de compat. + - el prototipo correspondiente en ``include/linux/compat.h`` + - (en caso de ser necesario) un struct de mapeo de 32-bit en ``include/linux/compat.h`` + - una instancia de ``__SC_COMP`` no ``__SYSCALL`` en ``include/uapi/asm-generic/unistd.h`` + +Compatibilidad de Llamadas de Sistema (x86) +------------------------------------------- + +Para conectar la arquitectura x86 de una llamada al sistema con una versión +de compatibilidad, las entradas en las tablas de syscall deben ser +ajustadas. + +Primero, la entrada en ``arch/x86/entry/syscalls/syscall_32.tbl`` recibe +una columna extra para indicar que un programa del userspace de 32-bit +corriendo en un kernel de 64-bit debe llegar al punto de entrada compat:: + + 380 i386 xyzzy sys_xyzzy __ia32_compat_sys_xyzzy + +Segundo, tienes que averiguar qué debería pasar para la versión x32 ABI de +la nueva llamada al sistema. Aquí hay una elección: el diseño de los +argumentos debería coincidir con la versión de 64-bit o la versión de +32-bit. + +Si hay involucrado un puntero-a-puntero, la decisión es fácil: x32 es +ILP32, por lo que el diseño debe coincidir con la versión 32-bit, y la +entrada en ``arch/x86/entry/syscalls/syscall_64.tbl`` se divide para que +progamas 32-bit lleguen al envoltorio de compatibilidad:: + + 333 64 xyzzy sys_xyzzy + ... + 555 x32 xyzzy __x32_compat_sys_xyzzy + +Si no hay punteros involucrados, entonces es preferible reutilizar el system +call 64-bit para el x32 ABI (y consecuentemente la entrada en +arch/x86/entry/syscalls/syscall_64.tbl no se cambia). + +En cualquier caso, debes revisar que lo tipos involucrados en su diseño de +argumentos de hecho asigne exactamente de x32 (-mx32) a 32-bit(-m32) o +equivalentes 64-bit (-m64). + + +Llamadas de Sistema Retornando a Otros Lugares +---------------------------------------------- + +Para la mayoría de las llamadas al sistema, una vez que se la llamada al +sistema se ha completado el programa de usuario continúa exactamente donde +quedó -- en la siguiente instrucción, con el stack igual y la mayoría de +los registros igual que antes de la llamada al sistema, y con el mismo +espacio en la memoria virtual. + +Sin embargo, unas pocas llamadas al sistema hacen las cosas diferente. +Estas podrían retornar a una ubicación distinta (``rt_sigreturn``) o +cambiar el espacio de memoria (``fork``/``vfork``/``clone``) o incluso de +arquitectura (``execve``/``execveat``) del programa. + +Para permitir esto, la implementación del kernel de la llamada al sistema +podría necesitar guardar y restaurar registros adicionales al stak del +kernel, brindandole control completo de donde y cómo la ejecución continúa +después de la llamada a sistema. + +Esto es arch-specific, pero típicamente involucra definir puntos de entrada +assembly que guardan/restauran registros adicionales e invocan el punto de +entrada real de la llamada a sistema. + +Para x86_64, esto es implementado como un punto de entrada ``stub_xyzzy`` +en ``arch/x86/entry/entry_64.S``, y la entrada en la tabla syscall +(``arch/x86/entry/syscalls/syscall_32.tbl``) es ajustada para calzar:: + + 333 common xyzzy stub_xyzzy + +El equivalente para programas 32-bit corriendo en un kernel 64-bit es +normalmente llamado ``stub32_xyzzy`` e implementado en +``arch/x86/entry/entry_64_compat.S``, con el correspondiente ajuste en la +tabla syscall en ``arch/x86/syscalls/syscall_32.tbl``:: + + 380 i386 xyzzy sys_xyzzy stub32_xyzzy + +Si la llamada a sistema necesita una capa de compatibilidad (como en la +sección anterior) entonces la versión ``stub32_`` necesita llamar a la +versión ``compat_sys_`` de la llamada a sistema, en vez de la versión +nativa de 64-bit. También, si la implementación de la versión x32 ABI no es +comun con la versión x86_64, entonces su tabla syscall también necesitará +invocar un stub que llame a la versión ``compat_sys_`` + +Para completar, también es agradable configurar un mapeo de modo que el +user-mode linux todavía funcione -- su tabla syscall referenciará +stub_xyzzy, pero el UML construido no incluye una implementación +``arch/x86/entry/entry_64.S``. Arreglar esto es tan simple como agregar un +#define a ``arch/x86/um/sys_call_table_64.c``:: + + #define stub_xyzzy sys_xyzzy + + +Otros detalles +-------------- + +La mayoría del kernel trata las llamadas a sistema de manera genérica, pero +está la excepción ocasional que pueda requerir actualización para su +llamada a sistema particular. + +El subsistema de auditoría es un caso especial; este incluye funciones +(arch-specific) que clasifican algunos tipos especiales de llamadas al +sistema -- específicamente file open (``open``/``openat``), program +execution (``execve`` /``execveat``) o operaciones multiplexores de socket +(``socketcall``). Si su nueva llamada de sistema es análoga a alguna de +estas, entonces el sistema auditor debe ser actualizado. + +Más generalmente, si existe una llamada al sistema que sea análoga a su +nueva llamada al sistema, entonces vale la pena hacer un grep a todo el +kernel de la llamada a sistema existente, para revisar que no exista otro +caso especial. + + +Testing +------- + +Una nueva llamada al sistema debe obviamente ser probada; también es útil +proveer a los revisores con una demostración de cómo los programas del +userspace usarán la llamada al sistema. Una buena forma de combinar estos +objetivos es incluir un simple programa self-test en un nuevo directorio +bajo ``tools/testing/selftests/``. + +Para una nueva llamada al sistema, obviamente no habrá una función +envoltorio libc por lo que el test necesitará ser invocado usando +``syscall()``; también, si la llamada al sistema involucra una nueva +estructura userspace-visible, el encabezado correspondiente necesitará ser +instalado para compilar el test. + +Asegure que selftest corra satisfactoriamente en todas las arquitecturas +soportadas. Por ejemplo, revise si funciona cuando es compilado como un +x86_64 (-m64), x86_32 (-m32) y x32 (-mx32) programa ABI. + +Para pruebas más amplias y exhautivas de la nueva funcionalidad, también +debería considerar agregar tests al Linus Test Project, o al proyecto +xfstests para cambios filesystem-related + + - https://linux-test-project.github.io/ + - git://git.kernel.org/pub/scm/fs/xfs/xfstests-dev.git + + +Man Page +-------- + +Todas las llamada al sistema nueva deben venir con un man page completo, +idealmente usando groff markup, pero texto plano también funciona. Si se +usa groff, es útil incluir una versión ASCII pre-renderizada del man-page +en el cover del email para el patchset, para la conveniencia de los +revisores. + +El man page debe ser cc'do a linux-man@vger.kernel.org +Para más detalles, revise https://www.kernel.org/doc/man-pages/patches.html + + +No invoque las llamadas de sistemas en el kernel +------------------------------------------------ + +Las llamadas al sistema son, cómo se declaró más arriba, puntos de +interacción entre el userspace y el kernel. Por lo tanto, las funciones de +llamada al sistema como ``sys_xyzzy()`` o ``compat_sys_xyzzy()`` deberían +ser llamadas sólo desde el userspace vía la tabla de syscall, pero no de +otro lugar en el kernel. Si la funcionalidad syscall es útil para ser usada +dentro del kernel, necesita ser compartida entre syscalls nuevas o +antiguas, o necesita ser compartida entre una syscall y su variante de +compatibilidad, esta debería ser implementada mediante una función "helper" +(como ``ksys_xyzzy()``). Esta función del kernel puede ahora ser llamada +dentro del syscall stub (``sys_xyzzy()``), la syscall stub de +compatibilidad (``compat_sys_xyzzy()``), y/o otro código del kernel. + +Al menos en 64-bit x86, será un requerimiento duro desde la v4.17 en +adelante no invocar funciones de llamada al sistema (system call) en el +kernel. Este usa una convención de llamada diferente para llamadas al +sistema donde ``struct pt_regs`` es decodificado on-the-fly en un +envoltorio syscall que luego entrega el procesamiento al syscall real. Esto +significa que sólo aquellos parámetros que son realmente necesarios para +una syscall específica son pasados durante la entrada del syscall, en vez +de llenar en seis registros de CPU con contenido random del userspace todo +el tiempo (los cuales podrían causar serios problemas bajando la cadena de +llamadas). + +Más aún, reglas sobre cómo se debería acceder a la data pueden diferir +entre la data del kernel y la data de usuario. Esta es otra razón por la +cual llamar a ``sys_xyzzy()`` es generalmente una mala idea. + +Excepciones a esta regla están permitidas solamente en overrides +específicos de arquitectura, envoltorios de compatibilidad específicos de +arquitectura, u otro código en arch/. + + +Referencias y fuentes +--------------------- + + - Artículo LWN de Michael Kerrisk sobre el uso de argumentos flags en llamadas al + sistema: + https://lwn.net/Articles/585415/ + - Artículo LWN de Michael Kerrisk sobre cómo manejar flags desconocidos en una + llamada al sistema: https://lwn.net/Articles/588444/ + - Artículo LWN de Jake Edge describiendo restricciones en argumentos en + 64-bit system call: https://lwn.net/Articles/311630/ + - Par de artículos LWN de David Drysdale que describen la ruta de implementación + de llamadas al sistema en detalle para v3.14: + + - https://lwn.net/Articles/604287/ + - https://lwn.net/Articles/604515/ + + - Requerimientos arquitectura-específicos para llamadas al sistema son discutidos en el + :manpage:`syscall(2)` man-page: + http://man7.org/linux/man-pages/man2/syscall.2.html#NOTES + - Recopilación de emails de Linus Torvalds discutiendo problemas con ``ioctl()``: + https://yarchive.net/comp/linux/ioctl.html + - "How to not invent kernel interfaces", Arnd Bergmann, + https://www.ukuug.org/events/linux2007/2007/papers/Bergmann.pdf + - Artículo LWN de Michael Kerrisk sobre evitar nuevos usos de CAP_SYS_ADMIN: + https://lwn.net/Articles/486306/ + - Recomendaciones de Andrew Morton que toda la información relacionada a una nueva + llamada al sistema debe venir en el mismo hilo de correos: + https://lore.kernel.org/r/20140724144747.3041b208832bbdf9fbce5d96@linux-foundation.org + - Recomendaciones de Michael Kerrisk que una nueva llamada al sistema debe venir + con un man-page: https://lore.kernel.org/r/CAKgNAkgMA39AfoSoA5Pe1r9N+ZzfYQNvNPvcRN7tOvRb8+v06Q@mail.gmail.com + - Sugerencias de Thomas Gleixner que conexiones x86 deben ir en commits + separados: https://lore.kernel.org/r/alpine.DEB.2.11.1411191249560.3909@nanos + - Sugerencias de Greg Kroah-Hartman que es bueno para las nueva llamadas al sistema + que vengan con man-page y selftest: https://lore.kernel.org/r/20140320025530.GA25469@kroah.com + - Discusión de Michael Kerrisk de nuevas system call vs. extensiones :manpage:`prctl(2)`: + https://lore.kernel.org/r/CAHO5Pa3F2MjfTtfNxa8LbnkeeU8=YJ+9tDqxZpw7Gz59E-4AUg@mail.gmail.com + - Sugerencias de Ingo Molnar que llamadas al sistema que involucran múltiples + argumentos deben encapsular estos argumentos en una estructura, la cual incluye + un campo de tamaño para futura extensibilidad: https://lore.kernel.org/r/20150730083831.GA22182@gmail.com + - Enumerando rarezas por la (re-)utilización de O_* numbering space flags: + + - commit 75069f2b5bfb ("vfs: renumber FMODE_NONOTIFY and add to uniqueness + check") + - commit 12ed2e36c98a ("fanotify: FMODE_NONOTIFY and __O_SYNC in sparc + conflict") + - commit bb458c644a59 ("Safer ABI for O_TMPFILE") + + - Discusión de Matthew Wilcox sobre las restricciones en argumentos 64-bit: + https://lore.kernel.org/r/20081212152929.GM26095@parisc-linux.org + - Recomendaciones de Greg Kroah-Hartman sobre flags desconocidos deben ser + vigilados: https://lore.kernel.org/r/20140717193330.GB4703@kroah.com + - Recomendaciones de Linus Torvalds que las llamadas al sistema x32 deben favorecer + compatibilidad con versiones 64-bit sobre versiones 32-bit: + https://lore.kernel.org/r/CA+55aFxfmwfB7jbbrXxa=K7VBYPfAvmu3XOkGrLbB1UFjX1+Ew@mail.gmail.com diff --git a/Documentation/translations/sp_SP/process/code-of-conduct.rst b/Documentation/translations/sp_SP/process/code-of-conduct.rst new file mode 100644 index 0000000000..adc6c770cc --- /dev/null +++ b/Documentation/translations/sp_SP/process/code-of-conduct.rst @@ -0,0 +1,97 @@ +.. include:: ../disclaimer-sp.rst + +:Original: :ref:`Documentation/process/code-of-conduct.rst <code_of_conduct>` +:Translator: Contributor Covenant and Carlos Bilbao <carlos.bilbao@amd.com> + +.. _sp_code_of_conduct: + +Código de Conducta para Contribuyentes ++++++++++++++++++++++++++++++++++++++++ + +Nuestro Compromiso +================== + +Nosotros, como miembros, contribuyentes y administradores nos comprometemos +a hacer de la participación en nuestra comunidad una experiencia libre de +acoso para todo el mundo, independientemente de la edad, dimensión corporal, +minusvalía visible o invisible, etnicidad, características sexuales, +identidad y expresión de género, nivel de experiencia, educación, nivel +socio-económico, nacionalidad, apariencia personal, raza, religión, o +identidad u orientación sexual. Nos comprometemos a actuar e interactuar de +maneras que contribuyan a una comunidad abierta, acogedora, diversa, +inclusiva y sana. + +Nuestros Estándares +=================== + +Ejemplos de comportamiento que contribuyen a crear un ambiente positivo +para nuestra comunidad: + +* Demostrar empatía y amabilidad ante otras personas +* Respeto a diferentes opiniones, puntos de vista y experiencias +* Dar y aceptar adecuadamente retroalimentación constructiva +* Aceptar la responsabilidad y disculparse ante quienes se vean afectados + por nuestros errores, aprendiendo de la experiencia +* Centrarse en lo que sea mejor no sólo para nosotros como individuos, sino + para la comunidad en general + + +Ejemplos de comportamiento inaceptable: + +* El uso de lenguaje o imágenes sexualizadas, y aproximaciones o + atenciones sexuales de cualquier tipo +* Comentarios despectivos (trolling), insultantes o derogatorios, y ataques + personales o políticos +* El acoso en público o privado +* Publicar información privada de otras personas, tales como direcciones + físicas o de correo + electrónico, sin su permiso explícito +* Otras conductas que puedan ser razonablemente consideradas como + inapropiadas en un entorno profesional + + +Aplicación de las responsabilidades +=================================== + +Los administradores de la comunidad son responsables de aclarar y hacer +cumplir nuestros estándares de comportamiento aceptable y tomarán acciones +apropiadas y correctivas de forma justa en respuesta a cualquier +comportamiento que consideren inapropiado, amenazante, ofensivo o dañino. + +Los administradores de la comunidad tendrán el derecho y la responsabilidad +de eliminar, editar o rechazar comentarios, commits, código, ediciones de +páginas de wiki, issues y otras contribuciones que no se alineen con este +Código de Conducta, y comunicarán las razones para sus decisiones de +moderación cuando sea apropiado. + +Alcance +======= + +Este código de conducta aplica tanto a espacios del proyecto como a +espacios públicos donde un individuo esté en representación del proyecto o +comunidad. Ejemplos de esto incluyen el uso de la cuenta oficial de correo +electrónico, publicaciones a través de las redes sociales oficiales, o +presentaciones con personas designadas en eventos en línea o no. + +Aplicación +========== + +Instancias de comportamiento abusivo, acosador o inaceptable de otro modo +podrán ser reportadas contactando el Code of Conduct Commitee a través de +<conduct@kernel.org>. Todas las quejas serán evaluadas e investigadas de +una manera puntual y justa. El Code of Condut Commitee está obligados a +respetar la privacidad y la seguridad de quienes reporten incidentes. +Detalles de políticas y aplicación en particular, serán incluidos por +separado. + +Atribución +========== + +Este Código de Conducta es una adaptación del Contributor Covenant, versión +1.4, disponible en https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +Interpretación +============== + +Consulte el documento :ref:`code_of_conduct_interpretation` para ver cómo +interpretará la comunidad del kernel Linux este documento. diff --git a/Documentation/translations/sp_SP/process/coding-style.rst b/Documentation/translations/sp_SP/process/coding-style.rst new file mode 100644 index 0000000000..a0261ba5b9 --- /dev/null +++ b/Documentation/translations/sp_SP/process/coding-style.rst @@ -0,0 +1,1315 @@ +.. include:: ../disclaimer-sp.rst + +:Original: :ref:`Documentation/process/coding-style.rst <submittingpatches>` +:Translator: Carlos Bilbao <carlos.bilbao@amd.com> + +.. _sp_codingstyle: + +Estilo en el código del kernel Linux +===================================== + +Este es un breve documento que describe el estilo preferido en el código +del kernel Linux. El estilo de código es muy personal y no **forzaré** mi +puntos de vista sobre nadie, pero esto vale para todo lo que tengo que +mantener, y preferiría que para la mayoría de otras cosas también. Por +favor, por lo menos considere los argumentos expuestos aquí. + +En primer lugar, sugeriría imprimir una copia de los estándares de código +GNU, y NO leerlo. Quémelos, es un gran gesto simbólico. + +De todos modos, aquí va: + + +1) Sangría +----------- + +Las tabulaciones tienen 8 caracteres y, por lo tanto, las sangrías también +tienen 8 caracteres. Hay movimientos heréticos que intentan hacer sangría +de 4 (¡o incluso 2!) caracteres de longitud, y eso es similar a tratar de +definir el valor de PI como 3. + +Justificación: La idea detrás de la sangría es definir claramente dónde +comienza y termina un bloque de control. Especialmente, cuando ha estado +buscando en su pantalla durante 20 horas seguidas, le resultará mucho más +fácil ver cómo funciona la sangría si tiene sangrías grandes. + +Bueno, algunas personas dirán que tener sangrías de 8 caracteres hace que +el código se mueva demasiado a la derecha y dificulta la lectura en una +pantalla de terminal de 80 caracteres. La respuesta a eso es que si +necesita más de 3 niveles de sangría, está en apuros de todos modos y +debería arreglar su programa. + +En resumen, las sangrías de 8 caracteres facilitan la lectura y tienen la +ventaja añadida de advertirle cuando está anidando sus funciones demasiado +profundo. Preste atención a esa advertencia. + +La forma preferida de facilitar múltiples niveles de sangría en una +declaración de switch es para alinear el ``switch`` y sus etiquetas +``case`` subordinadas en la misma columna, en lugar de hacer ``doble +sangría`` (``double-indenting``) en etiquetas ``case``. Por ejemplo: + +.. code-block:: c + + switch (suffix) { + case 'G': + case 'g': + mem <<= 30; + break; + case 'M': + case 'm': + mem <<= 20; + break; + case 'K': + case 'k': + mem <<= 10; + fallthrough; + default: + break; + } + +No ponga varias declaraciones en una sola línea a menos que tenga algo que +ocultar: + +.. code-block:: c + + if (condición) haz_esto; + haz_otra_cosa; + +No use comas para evitar el uso de llaves: + +.. code-block:: c + + if (condición) + haz_esto(), haz_eso(); + +Siempre use llaves para múltiples declaraciones: + +.. code-block:: c + + if (condición) { + haz_esto(); + haz_eso(); + } + +Tampoco ponga varias asignaciones en una sola línea. El estilo de código +del kernel es súper simple. Evite las expresiones engañosas. + + +Aparte de los comentarios, la documentación y excepto en Kconfig, los +espacios nunca se utilizan para la sangría, y el ejemplo anterior se rompe +deliberadamente. + +Consiga un editor decente y no deje espacios en blanco al final de las +líneas. + +2) Rompiendo líneas y strings largos +------------------------------------ + +El estilo de código tiene todo que ver con la legibilidad y la +mantenibilidad usando herramientas disponibles comúnmente. + +El límite preferido en la longitud de una sola línea es de 80 columnas. + +Las declaraciones de más de 80 columnas deben dividirse en partes, a menos +que exceder las 80 columnas aumente significativamente la legibilidad y no +oculte información. + +Los descendientes siempre son sustancialmente más cortos que el padre y +se colocan sustancialmente a la derecha. Un estilo muy usado es alinear +descendientes a un paréntesis de función abierto. + +Estas mismas reglas se aplican a los encabezados de funciones con una larga +lista de argumentos. + +Sin embargo, nunca rompa los strings visibles para el usuario, como los +mensajes printk, porque eso rompe la capacidad de grep a estos. + + +3) Colocación de llaves y espacios +---------------------------------- + +El otro problema que siempre surge en el estilo C es la colocación de +llaves. A diferencia del tamaño de la sangría, existen pocas razones +técnicas para elegir una estrategia de ubicación sobre la otra, pero la +forma preferida, como mostraron los profetas Kernighan y Ritchie, es poner +la llave de apertura en la línea, y colocar la llave de cierre primero, +así: + +.. code-block:: c + + if (x es verdad) { + hacemos y + } + +Esto se aplica a todos los bloques de declaraciones que no son funciones +(if, switch, for, while, do). Por ejemplo: + +.. code-block:: c + + switch (action) { + case KOBJ_ADD: + return "add"; + case KOBJ_REMOVE: + return "remove"; + case KOBJ_CHANGE: + return "change"; + default: + return NULL; + } + +Sin embargo, hay un caso especial, a saber, las funciones: tienen la llave +de apertura al comienzo de la siguiente línea, así: + +.. code-block:: c + + int funcion(int x) + { + cuerpo de la función + } + +Gente hereje de todo el mundo ha afirmado que esta inconsistencia es... +bueno... inconsistente, pero todas las personas sensatas saben que +(a) K&R tienen **razón** y (b) K&R tienen razón. Además, las funciones son +especiales de todos modos (no puede anidarlas en C). + +Tenga en cuenta que la llave de cierre está vacía en su línea propia, +**excepto** en los casos en que es seguida por una continuación de la misma +declaración, es decir, un ``while`` en una sentencia do o un ``else`` en +una sentencia if, como en: + +.. code-block:: c + + do { + cuerpo del bucle do + } while (condition); + +y + +.. code-block:: c + + if (x == y) { + .. + } else if (x > y) { + ... + } else { + .... + } + +Justificación: K&R. + +Además, tenga en cuenta que esta colocación de llaves también minimiza el +número de líneas vacías (o casi vacías), sin pérdida de legibilidad. Así, +como el suministro de nuevas líneas en su pantalla no es un recurso +renovable (piense en pantallas de terminal de 25 líneas), tienes más líneas +vacías para poner comentarios. + +No use llaves innecesariamente donde una sola declaración sea suficiente. + +.. code-block:: c + + if (condition) + accion(); + +y + +.. code-block:: none + + if (condición) + haz_esto(); + else + haz_eso(); + +Esto no aplica si solo una rama de una declaración condicional es una sola +declaración; en este último caso utilice llaves en ambas ramas: + +.. code-block:: c + + if (condición) { + haz_esto(); + haz_eso(); + } else { + en_otro_caso(); + } + +Además, use llaves cuando un bucle contenga más de una declaración simple: + +.. code-block:: c + + while (condición) { + if (test) + haz_eso(); + } + +3.1) Espacios +************* + +El estilo del kernel Linux para el uso de espacios depende (principalmente) +del uso de función versus uso de palabra clave. Utilice un espacio después +de (la mayoría de) las palabras clave. Las excepciones notables son sizeof, +typeof, alignof y __attribute__, que parecen algo así como funciones (y +generalmente se usan con paréntesis en Linux, aunque no son requeridos en +el idioma, como en: ``sizeof info`` después de que ``struct fileinfo info;`` +se declare). + +Así que use un espacio después de estas palabras clave:: + + if, switch, case, for, do, while + +pero no con sizeof, typeof, alignof, o __attribute__. Por ejemplo, + +.. code-block:: c + + + s = sizeof(struct file); + +No agregue espacios alrededor (dentro) de expresiones entre paréntesis. +Este ejemplo es **malo**: + +.. code-block:: c + + + s = sizeof( struct file ); + +Al declarar datos de puntero o una función que devuelve un tipo de puntero, +el uso preferido de ``*`` es adyacente al nombre del dato o nombre de la +función y no junto al nombre del tipo. Ejemplos: + +.. code-block:: c + + + char *linux_banner; + unsigned long long memparse(char *ptr, char **retptr); + char *match_strdup(substring_t *s); + +Use un espacio alrededor (a cada lado de) la mayoría de los operadores +binarios y ternarios, como cualquiera de estos:: + + = + - < > * / % | & ^ <= >= == != ? : + +pero sin espacio después de los operadores unarios:: + + & * + - ~ ! sizeof typeof alignof __attribute__ defined + +sin espacio antes de los operadores unarios de incremento y decremento del +sufijo:: + + ++ -- + +y sin espacio alrededor de los operadores de miembros de estructura ``.`` y +``->``. + +No deje espacios en blanco al final de las líneas. Algunos editores con +``inteligente`` sangría insertarán espacios en blanco al comienzo de las +nuevas líneas como sea apropiado, para que pueda comenzar a escribir la +siguiente línea de código de inmediato. Sin embargo, algunos de estos +editores no eliminan los espacios en blanco si finalmente no termina +poniendo una línea de código allí, como si dejara una línea en blanco. Como +resultado, termina con líneas que contienen espacios en blanco al final. + +Git le advertirá sobre los parches que introducen espacios en blanco al +final y puede, opcionalmente, eliminar los espacios en blanco finales por +usted; sin embargo, si se aplica una serie de parches, esto puede hacer que +los parches posteriores de la serie fallen al cambiar sus líneas de +contexto. + + +4) Nomenclatura +--------------- + +C es un lenguaje espartano, y sus convenciones de nomenclatura deberían +seguir su ejemplo. A diferencia de los programadores de Modula-2 y Pascal, +los programadores de C no usan nombres cuquis como +EstaVariableEsUnContadorTemporal. Un programador de C lo llamaría +variable ``tmp``, que es mucho más fácil de escribir, y no es mas difícil +de comprender. + +SIN EMBARGO, mientras que los nombres de mayúsculas y minúsculas están mal +vistos, los nombres descriptivos para las variables globales son +imprescindibles. Llamar a una función global ``foo`` es un delito. + +Una variable GLOBAL (para usar solo si **realmente** las necesita) necesita +tener un nombre descriptivo, al igual que las funciones globales. Si tiene +una función que cuenta el número de usuarios activos, debe llamar a esta +``contar_usuarios_activos()`` o similar, **no** debe llamarlo ``cntusr()``. + +Codificar el tipo de una función en el nombre (lo llamado notación húngara) +es estúpido: el compilador conoce los tipos de todos modos y puede +verificar estos, y solo confunde al programador. + +Los nombres de las variables LOCALES deben ser breves y directos. Si usted +tiene algún contador aleatorio de tipo entero, probablemente debería +llamarse ``i``. Llamarlo ``loop_counter`` no es productivo, si no hay +posibilidad de ser mal entendido. De manera similar, ``tmp`` puede ser casi +cualquier tipo de variable que se utiliza para contener un valor temporal. + +Si tiene miedo de mezclar los nombres de las variables locales, tiene otro +problema, que se denomina síndrome de +función-crecimiento-desequilibrio-de-hormona. Vea el capítulo 6 (Funciones). + +Para nombres de símbolos y documentación, evite introducir nuevos usos de +'master / slave' (maestro / esclavo) (o 'slave' independientemente de +'master') y 'lista negra / lista blanca' (backlist / whitelist). + +Los reemplazos recomendados para 'maestro / esclavo' son: + '{primary,main} / {secondary,replica,subordinate}' + '{initiator,requester} / {target,responder}' + '{controller,host} / {device,worker,proxy}' + 'leader / follower' + 'director / performer' + +Los reemplazos recomendados para 'backlist / whitelist' son: + 'denylist / allowlist' + 'blocklist / passlist' + +Las excepciones para la introducción de nuevos usos son mantener en espacio +de usuario una ABI/API, o al actualizar la especificación del código de un +hardware o protocolo existente (a partir de 2020) que requiere esos +términos. Para nuevas especificaciones, traduzca el uso de la terminología +de la especificación al estándar de código del kernel donde sea posible. + +5) Typedefs +----------- + +Por favor no use cosas como ``vps_t``. +Es un **error** usar typedef para estructuras y punteros. cuando ve un + +.. code-block:: c + + + vps_t a; + +en el código fuente, ¿qué significa? +En cambio, si dice + +.. code-block:: c + + struct virtual_container *a; + +puede decir qué es ``a`` en realidad. + +Mucha gente piensa que los typedefs ``ayudan a la legibilidad``. No. Son +útiles solamente para: + + (a) objetos totalmente opacos (donde el typedef se usa activamente para + **ocultar** cuál es el objeto). + + Ejemplo: ``pte_t`` etc. objetos opacos a los que solo puede acceder + usando las funciones de acceso adecuadas. + + .. note:: + + La opacidad y las ``funciones de acceso`` no son buenas por sí + mismas. La razón por la que los tenemos para cosas como pte_t, etc. + es que hay real y absolutamente **cero** información accesible de + forma portátil allí. + + (b) Tipos enteros claros, donde la abstracción **ayuda** a evitar + confusiones, ya sea ``int`` o ``long``. + + u8/u16/u32 son definiciones tipográficas perfectamente correctas + aunque encajan en la categoría (d) mejor que aquí. + + .. note:: + + De nuevo - debe haber una **razón** para esto. si algo es + ``unsigned long``, entonces no hay razón para hacerlo + + typedef unsigned long mis_flags_t; + + pero si hay una razón clara de por qué bajo ciertas circunstancias + podría ser un ``unsigned int`` y bajo otras configuraciones podría + ser ``unsigned long``, entonces, sin duda, adelante y use un typedef. + + (c) cuando lo use para crear literalmente un tipo **nuevo** para + comprobación de tipos. + + (d) Nuevos tipos que son idénticos a los tipos estándar C99, en ciertas + circunstancias excepcionales. + + Aunque sólo costaría un corto período de tiempo para los ojos y + cerebro para acostumbrarse a los tipos estándar como ``uint32_t``, + algunas personas se oponen a su uso de todos modos. + + Por lo tanto, los tipos ``u8/u16/u32/u64`` específicos de Linux y sus + equivalentes con signo, que son idénticos a los tipos estándar son + permitidos, aunque no son obligatorios en el nuevo código de su + elección. + + Al editar código existente que ya usa uno u otro conjunto de tipos, + debe ajustarse a las opciones existentes en ese código. + + (e) Tipos seguros para usar en el espacio de usuario. + + En ciertas estructuras que son visibles para el espacio de usuario, no + podemos requerir tipos C99 y o utilizat el ``u32`` anterior. Por lo + tanto, usamos __u32 y tipos similares en todas las estructuras que se + comparten con espacio de usuario. + +Tal vez también haya otros casos, pero la regla básicamente debería ser +NUNCA JAMÁS use un typedef a menos que pueda coincidir claramente con una +de estas reglas. + +En general, un puntero o una estructura que tiene elementos que pueden +ser razonablemente accedidos directamente, **nunca** deben ser un typedef. + +6) Funciones +------------ + +Las funciones deben ser cortas y dulces, y hacer una sola cosa. Deberían +caber en una o dos pantallas de texto (el tamaño de pantalla ISO/ANSI es +80x24, como todos sabemos), y hacer una cosa y hacerla bien. + +La longitud máxima de una función es inversamente proporcional a la +complejidad y el nivel de sangría de esa función. Entonces, si tiene una +función conceptualmente simple que es solo una larga (pero simple) +declaración de case, donde tiene que hacer un montón de pequeñas cosas para +un montón de diferentes casos, está bien tener una función más larga. + +Sin embargo, si tiene una función compleja y sospecha que un estudiante de +primer año de secundaria menos que dotado podría no comprender de qué se +trata la función, debe adherirse a los límites máximos tanto más de +cerca. Use funciones auxiliares con nombres descriptivos (puede pedirle al +compilador que los alinee si cree que es crítico para el rendimiento, y +probablemente lo hará mejor de lo que usted hubiera hecho). + +Otra medida de la función es el número de variables locales. Estas no deben +exceder de 5 a 10, o está haciendo algo mal. Piense de nuevo en la función +y divida en partes más pequeñas. Un cerebro humano puede generalmente +realiza un seguimiento de aproximadamente 7 cosas diferentes, cualquier +elemento más y se confunde. Usted sabe que es brillante, pero tal vez le +gustaría entender lo que hizo dentro de 2 semanas. + +En los archivos fuente, separe las funciones con una línea en blanco. Si la +función es exportada, la macro **EXPORT** debería ponerse inmediatamente +después de la función de cierre de línea de llave. Por ejemplo: + +.. code-block:: c + + int sistema_corriendo(void) + { + return estado_sistema == SISTEMA_CORRIENDO; + } + EXPORT_SYMBOL(sistema_corriendo); + +6.1) Prototipos de funciones +**************************** + +En los prototipos de funciones, incluya nombres de parámetros con sus tipos +de datos. Aunque esto no es requerido por el lenguaje C, se prefiere en +Linux porque es una forma sencilla de añadir información valiosa para el +lector. + +No utilice la palabra clave ``extern`` con declaraciones de función ya que +esto hace las líneas más largas y no es estrictamente necesario. + +Al escribir prototipos de funciones, mantenga el `orden de los elementos regular +<https://lore.kernel.org/mm-commits/CAHk-=wiOCLRny5aifWNhr621kYrJwhfURsa0vFPeUEm8mF0ufg@mail.gmail.com/>`_. +Por ejemplo, usando este ejemplo de declaración de función:: + + __init void * __must_check action(enum magic value, size_t size, u8 count, + char *fmt, ...) __printf(4, 5) __malloc; + +El orden preferido de elementos para un prototipo de función es: + +- clase de almacenamiento (a continuación, ``static __always_inline``, + teniendo en cuenta que ``__always_inline`` es técnicamente un atributo + pero se trata como ``inline``) +- atributos de clase de almacenamiento (aquí, ``__init`` -- es decir, + declaraciones de sección, pero también cosas como ``__cold``) +- tipo de retorno (aquí, ``void *``) +- atributos de tipo de retorno (aquí, ``__must_check``) +- nombre de la función (aquí, ``action``) +- parámetros de la función (aquí, ``(enum magic value, size_t size, u8 count, char *fmt, ...)``, + teniendo en cuenta que los nombres de los parámetros siempre deben + incluirse) +- atributos de parámetros de función (aquí, ``__printf(4, 5)``) +- atributos de comportamiento de la función (aquí, ``__malloc``) + +Tenga en cuenta que para una **definición** de función (es decir, el cuerpo +real de la función), el compilador no permite atributos de parámetros de +función después de parámetros de la función. En estos casos, deberán ir +tras los atributos de clase (por ejemplo, tenga en cuenta el cambio de +posición de ``__printf(4, 5)`` a continuación, en comparación con el +ejemplo de **declaración** anterior):: + + static __always_inline __init __printf(4, 5) void * __must_check action(enum magic value, + size_t size, u8 count, char *fmt, ...) __malloc + { + ... + } + +7) Salida centralizada de funciones +----------------------------------- + +Aunque desaprobado por algunas personas, el equivalente de la instrucción +goto es utilizado con frecuencia por los compiladores, en forma de +instrucción de salto incondicional. + +La declaración goto es útil cuando una función sale desde múltiples +ubicaciones y se deben realizar algunos trabajos comunes, como la limpieza. +Si no se necesita limpieza, entonces simplemente haga return directamente. + +Elija nombres de etiquetas que digan qué hace el goto o por qué existe el +goto. Un ejemplo de un buen nombre podría ser ``out_free_buffer:`` +(``salida_liberar_buffer``) si al irse libera ``buffer``. Evite usar +nombres GW-BASIC como ``err1:`` y ``err2:``, ya que tendría que volver a +numerarlos si alguna vez agrega o elimina rutas de salida, y hacen que sea +difícil de verificar que sean correctos, de todos modos. + +La razón para usar gotos es: + +- Las declaraciones incondicionales son más fáciles de entender y seguir. +- se reduce el anidamiento +- errores al no actualizar los puntos de salida individuales al hacer + modificaciones son evitados +- ahorra el trabajo del compilador de optimizar código redundante ;) + +.. code-block:: c + + int fun(int a) + { + int result = 0; + char *buffer; + + buffer = kmalloc(SIZE, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + if (condition1) { + while (loop1) { + ... + } + result = 1; + goto out_free_buffer; + } + ... + out_free_buffer: + kfree(buffer); + return result; + } + +Un tipo común de error a tener en cuenta es "un error de error" que es algo +así: + +.. code-block:: c + + err: + kfree(foo->bar); + kfree(foo); + return ret; + +El error en este código es que en algunas rutas de salida, ``foo`` es NULL. +Normalmente la solución para esto es dividirlo en dos etiquetas de error +``err_free_bar:`` y ``err_free_foo:``: + +.. code-block:: c + + err_free_bar: + kfree(foo->bar); + err_free_foo: + kfree(foo); + return ret; + +Idealmente, debería simular errores para probar todas las rutas de salida. + + +8) Comentarios +-------------- + +Los comentarios son buenos, pero también existe el peligro de comentar +demasiado. NUNCA trate de explicar CÓMO funciona su código en un +comentario: es mucho mejor escribir el código para que el +**funcionamiento** sea obvio y es una pérdida de tiempo explicar código mal +escrito. + +Generalmente, desea que sus comentarios digan QUÉ hace su código, no CÓMO. +Además, trate de evitar poner comentarios dentro del cuerpo de una función: +si la función es tan compleja que necesita comentar por separado partes de +esta, probablemente debería volver al capítulo 6 una temporada. Puede +hacer pequeños comentarios para notar o advertir sobre algo particularmente +inteligente (o feo), pero trate de evitar el exceso. En su lugar, ponga los +comentarios al principio de la función, diga a la gente lo que hace y +posiblemente POR QUÉ hace esto. + +Al comentar las funciones de la API del kernel, utilice el formato +kernel-doc. Consulte los archivos en :ref:`Documentation/doc-guide/ <doc_guide>` +y ``scripts/kernel-doc`` para más detalles. + +El estilo preferido para comentarios largos (de varias líneas) es: + +.. code-block:: c + + /* + * Este es el estilo preferido para comentarios + * multilínea en el código fuente del kernel Linux. + * Por favor, utilícelo constantemente. + * + * Descripción: Una columna de asteriscos en el lado izquierdo, + * con líneas iniciales y finales casi en blanco. + */ + +Para archivos en net/ y drivers/net/, el estilo preferido para comentarios +largos (multi-linea) es un poco diferente. + +.. code-block:: c + + /* El estilo de comentario preferido para archivos en net/ y drivers/net + * se asemeja a esto. + * + * Es casi lo mismo que el estilo de comentario generalmente preferido, + * pero no hay una línea inicial casi en blanco. + */ + +También es importante comentar los datos, ya sean tipos básicos o +derivados. Para este fin, use solo una declaración de datos por línea (sin +comas para múltiples declaraciones de datos). Esto le deja espacio para un +pequeño comentario sobre cada elemento, explicando su uso. + +9) Has hecho un desastre +--------------------------- + +Está bien, todos lo hacemos. Probablemente un antiguo usuario de Unix le +haya dicho que ``GNU emacs`` formatea automáticamente las fuentes C por +usted, y ha notado que sí, lo hace, pero los por defecto que tiene son +menos que deseables (de hecho, son peores que los aleatorios) escribiendo - +un número infinito de monos escribiendo en GNU emacs nunca harán un buen +programa). + +Por lo tanto, puede deshacerse de GNU emacs o cambiarlo y usar valores más +sanos. Para hacer esto último, puede pegar lo siguiente en su archivo +.emacs: + +.. code-block:: none + + (defun c-lineup-arglist-tabs-only (ignored) + "Line up argument lists by tabs, not spaces" + (let* ((anchor (c-langelem-pos c-syntactic-element)) + (column (c-langelem-2nd-pos c-syntactic-element)) + (offset (- (1+ column) anchor)) + (steps (floor offset c-basic-offset))) + (* (max steps 1) + c-basic-offset))) + + (dir-locals-set-class-variables + 'linux-kernel + '((c-mode . ( + (c-basic-offset . 8) + (c-label-minimum-indentation . 0) + (c-offsets-alist . ( + (arglist-close . c-lineup-arglist-tabs-only) + (arglist-cont-nonempty . + (c-lineup-gcc-asm-reg c-lineup-arglist-tabs-only)) + (arglist-intro . +) + (brace-list-intro . +) + (c . c-lineup-C-comments) + (case-label . 0) + (comment-intro . c-lineup-comment) + (cpp-define-intro . +) + (cpp-macro . -1000) + (cpp-macro-cont . +) + (defun-block-intro . +) + (else-clause . 0) + (func-decl-cont . +) + (inclass . +) + (inher-cont . c-lineup-multi-inher) + (knr-argdecl-intro . 0) + (label . -1000) + (statement . 0) + (statement-block-intro . +) + (statement-case-intro . +) + (statement-cont . +) + (substatement . +) + )) + (indent-tabs-mode . t) + (show-trailing-whitespace . t) + )))) + + (dir-locals-set-directory-class + (expand-file-name "~/src/linux-trees") + 'linux-kernel) + +Esto hará que emacs funcione mejor con el estilo de código del kernel para +C en archivos bajo ``~/src/linux-trees``. + +Pero incluso si no logra que emacs realice un formateo correcto, no todo +está perdido: use ``indent``. + +Ahora bien, de nuevo, la sangría de GNU tiene la misma configuración de +muerte cerebral que GNU emacs tiene, por lo que necesita darle algunas +opciones de línea de comando. Sin embargo, eso no es tan malo, porque +incluso los creadores de GNU indent reconocen la autoridad de K&R (la gente +de GNU no es mala, solo están gravemente equivocados en este asunto), por +lo que simplemente de a la sangría las opciones ``-kr -i8`` (significa +``K&R, guiones de 8 caracteres``), o use ``scripts/Lindent``, que indenta +con ese estilo. + +``indent`` tiene muchas opciones, y especialmente cuando se trata de +comentar reformateos, es posible que desee echar un vistazo a la página del +manual. Pero recuerde: ``indent`` no es la solución para una mala +programación. + +Tenga en cuenta que también puede usar la herramienta ``clang-format`` para +ayudarlo con estas reglas, para volver a formatear rápidamente partes de su +código automáticamente, y revisar archivos completos para detectar errores +de estilo del código, errores tipográficos y posibles mejoras. También es +útil para ordenar ``#includes``, para alinear variables/macros, para +redistribuir texto y otras tareas similares. Vea el archivo +:ref:`Documentation/process/clang-format.rst <clangformat>` para más +detalles. + +10) Archivos de configuración de Kconfig +---------------------------------------- + +Para todos los archivos de configuración de Kconfig* en todo el árbol +fuente, la sangría es algo diferente. Las líneas bajo una definición +``config`` están indentadas con una tabulación, mientras que el texto de +ayuda tiene una sangría adicional de dos espacios. Ejemplo:: + + config AUDIT + bool "Soporte para auditar" + depends on NET + help + Habilita la infraestructura de auditoría que se puede usar con otro + subsistema kernel, como SELinux (que requiere esto para + registro de salida de mensajes avc). No hace auditoría de llamadas al + sistema sin CONFIG_AUDITSYSCALL. + +Características seriamente peligrosas (como soporte de escritura para +ciertos filesystems) deben anunciar esto de forma destacada en su cadena de +solicitud:: + + config ADFS_FS_RW + bool "ADFS write support (DANGEROUS)" + depends on ADFS_FS + ... + +Para obtener la documentación completa sobre los archivos de configuración, +consulte el archivo Documentation/kbuild/kconfig-language.rst. + + +11) Estructuras de datos +------------------------ + +Las estructuras de datos que tienen visibilidad fuera del contexto de un +solo subproceso en el que son creadas y destruidas, siempre debe tener +contadores de referencia. En el kernel, la recolección de basura no existe +(y fuera, la recolección de basura del kernel es lenta e ineficiente), lo +que significa que absolutamente **tiene** para hacer referencia y contar +todos sus usos. + +El conteo de referencias significa que puede evitar el bloqueo y permite +que múltiples usuarios tengan acceso a la estructura de datos en paralelo - +y no tengan que preocuparse de que la estructura, de repente, desaparezca +debajo de su control, solo porque durmieron o hicieron otra cosa por un +tiempo. + +Tenga en cuenta que el bloqueo **no** reemplaza el recuento de referencia. +El bloqueo se utiliza para mantener la coherencia de las estructuras de +datos, mientras que la referencia y contar es una técnica de gestión de +memoria. Por lo general, ambos son necesarios, y no deben confundirse entre +sí. + +De hecho, muchas estructuras de datos pueden tener dos niveles de conteo de +referencias, cuando hay usuarios de diferentes ``clases``. El conteo de +subclases cuenta el número de usuarios de la subclase y disminuye el conteo +global solo una vez, cuando el recuento de subclases llega a cero. + +Se pueden encontrar ejemplos de este tipo de ``recuento de referencias de +niveles múltiples`` en la gestión de memoria (``struct mm_struct``: +mm_users y mm_count), y en código del sistema de archivos +(``struct super_block``: s_count y s_active). + +Recuerde: si otro hilo puede encontrar su estructura de datos y usted no +tiene un recuento de referencias, es casi seguro que tiene un error. + +12) Macros, Enums y RTL +------------------------ + +Los nombres de macros que definen constantes y etiquetas en enumeraciones +(enums) están en mayúsculas. + +.. code-block:: c + + #define CONSTANTE 0x12345 + +Se prefieren los enums cuando se definen varias constantes relacionadas. + +Se aprecian los nombres de macro en MAYÚSCULAS, pero las macros que se +asemejan a funciones puede ser nombradas en minúscula. + +Generalmente, las funciones en línea son preferibles a las macros que se +asemejan a funciones. + +Las macros con varias instrucciones deben contenerse en un bloque do-while: + +.. code-block:: c + + #define macrofun(a, b, c) \ + do { \ + if (a == 5) \ + haz_esto(b, c); \ + } while (0) + +Cosas a evitar al usar macros: + +1) macros que afectan el flujo de control: + +.. code-block:: c + + #define FOO(x) \ + do { \ + if (blah(x) < 0) \ + return -EBUGGERED; \ + } while (0) + +es una **muy** mala idea. Parece una llamada de función pero sale de la +función de ``llamada``; no rompa los analizadores internos de aquellos que +leerán el código. + +2) macros que dependen de tener una variable local con un nombre mágico: + +.. code-block:: c + + #define FOO(val) bar(index, val) + +puede parecer algo bueno, pero es confuso como el infierno cuando uno lee +el código, y es propenso a romperse por cambios aparentemente inocentes. + +3) macros con argumentos que se usan como valores l: FOO(x) = y; le van +a morder si alguien, por ejemplo, convierte FOO en una función en línea. + +4) olvidarse de la precedencia: las macros que definen constantes usando +expresiones deben encerrar la expresión entre paréntesis. Tenga cuidado con +problemas similares con macros usando parámetros. + +.. code-block:: c + + #define CONSTANTE 0x4000 + #define CONSTEXP (CONSTANTE | 3) + +5) colisiones de espacio de nombres ("namespace") al definir variables +locales en macros que se asemejan a funciones: + +.. code-block:: c + + #define FOO(x) \ + ({ \ + typeof(x) ret; \ + ret = calc_ret(x); \ + (ret); \ + }) + +ret es un nombre común para una variable local -es menos probable que +__foo_ret colisione (coincida) con una variable existente. + +El manual de cpp trata las macros de forma exhaustiva. El manual interno de +gcc también cubre RTL, que se usa frecuentemente con lenguaje ensamblador +en el kernel. + +13) Imprimir mensajes del kernel +-------------------------------- + +A los desarrolladores del kernel les gusta ser vistos como alfabetizados. +Cuide la ortografía de los mensajes del kernel para causar una buena +impresión. No utilice contracciones incorrectas como ``dont``; use +``do not`` o ``don't`` en su lugar. Haga sus mensajes concisos, claros e +inequívocos. + +Los mensajes del kernel no tienen que terminar con un punto. + +Imprimir números entre paréntesis (%d) no agrega valor y debe evitarse. + +Hay varias modelos de macros de diagnóstico de driver en <linux/dev_printk.h> +que debe usar para asegurarse de que los mensajes coincidan con el +dispositivo correcto y driver, y están etiquetados con el nivel correcto: +dev_err(), dev_warn(), dev_info(), y así sucesivamente. Para mensajes que +no están asociados con un dispositivo particular, <linux/printk.h> define +pr_notice(), pr_info(), pr_warn(), pr_err(), etc. + +Crear buenos mensajes de depuración puede ser todo un desafío; y una vez +los tiene, pueden ser de gran ayuda para la resolución remota de problemas. +Sin embargo, la impresión de mensajes de depuración se maneja de manera +diferente a la impresión de otros mensajes que no son de depuración. +Mientras que las otras funciones pr_XXX() se imprimen incondicionalmente, +pr_debug() no lo hace; se compila fuera por defecto, a menos que DEBUG sea +definido o se establezca CONFIG_DYNAMIC_DEBUG. Eso es cierto para dev_dbg() +también, y una convención relacionada usa VERBOSE_DEBUG para agregar +mensajes dev_vdbg() a los ya habilitados por DEBUG. + +Muchos subsistemas tienen opciones de depuración de Kconfig para activar +-DDEBUG en el Makefile correspondiente; en otros casos, los archivos +usan #define DEBUG. Y cuando un mensaje de depuración debe imprimirse +incondicionalmente, por ejemplo si es ya dentro de una sección #ifdef +relacionada con la depuración, printk(KERN_DEBUG ...) puede ser usado. + +14) Reservando memoria +---------------------- + +El kernel proporciona los siguientes asignadores de memoria de propósito +general: kmalloc(), kzalloc(), kmalloc_array(), kcalloc(), vmalloc() y +vzalloc(). Consulte la documentación de la API para obtener más información. +a cerca de ellos. :ref:`Documentation/core-api/memory-allocation.rst +<memory_allocation>` + +La forma preferida para pasar el tamaño de una estructura es la siguiente: + +.. code-block:: c + + p = kmalloc(sizeof(*p), ...); + +La forma alternativa donde se deletrea el nombre de la estructura perjudica +la legibilidad, y presenta una oportunidad para un error cuando se cambia +el tipo de variable de puntero, pero el tamaño correspondiente de eso que +se pasa a un asignador de memoria no. + +Convertir el valor devuelto, que es un puntero vacío, es redundante. La +conversión desde el puntero vacío a cualquier otro tipo de puntero está +garantizado por la programación en idioma C. + +La forma preferida para asignar una matriz es la siguiente: + +.. code-block:: c + + p = kmalloc_array(n, sizeof(...), ...); + +La forma preferida para asignar una matriz a cero es la siguiente: + +.. code-block:: c + + p = kcalloc(n, sizeof(...), ...); + +Ambos casos verifican el desbordamiento en el tamaño de asignación n * +sizeof (...), y devuelven NULL si esto ocurrió. + +Todas estas funciones de asignación genéricas emiten un volcado de pila +(" stack dump") en caso de fallo cuando se usan sin __GFP_NOWARN, por lo +que no sirve de nada emitir un mensaje de fallo adicional cuando se +devuelva NULL. + +15) La enfermedad de inline +---------------------------- + +Parece haber una común percepción errónea de que gcc tiene una magica +opción "hazme más rápido" de aceleración, llamada ``inline`` (en línea). +Mientras que el uso de inlines puede ser apropiado (por ejemplo, como un +medio para reemplazar macros, consulte el Capítulo 12), muy a menudo no lo +es. El uso abundante de la palabra clave inline conduce a una mayor kernel, +que a su vez ralentiza el sistema en su conjunto, debido a una mayor huella +de icache para la CPU, y sencillamente porque hay menos memoria disponible +para el pagecache. Solo piense en esto; un fallo en la memoria caché de la +página provoca una búsqueda de disco, que tarda fácilmente 5 milisegundos. +Hay MUCHOS ciclos de CPU que puede entrar en estos 5 milisegundos. + +Una razonable regla general es no poner funciones inline que tengan más de +3 líneas de código en ellas. Una excepción a esta regla son los casos en +que se sabe que un parámetro es una constante en tiempo de compilación, y +como resultado de esto, usted *sabe*, el compilador podrá optimizar la +mayor parte de su función en tiempo de compilación. Para un buen ejemplo de +este último caso, véase la función en línea kmalloc(). + +A menudo, la gente argumenta que agregar funciones en línea que son +estáticas y se usan solo una vez, es siempre una victoria ya que no hay +perdida de espacio. Mientras esto es técnicamente correcto, gcc es capaz de +incorporarlos automáticamente sin ayuda, y esta el problema de +mantenimiento de eliminar el inline, cuando un segundo usuario supera el +valor potencial de la pista que le dice a gcc que haga algo que habría +hecho de todos modos. + +16) Valores devueltos por función y sus nombres +----------------------------------------------- + +Las funciones pueden devolver valores de muchos tipos diferentes, y uno de +lo más común es un valor que indica si la función tuvo éxito o ha fallado. +Dicho valor se puede representar como un número entero de código de error +(-Exxx = falla, 0 = éxito) o un booleano ``con éxito`` (0 = falla, distinto +de cero = éxito). + +La mezcla de estos dos tipos de representaciones es una fuente fértil de +errores difíciles de encontrar. Si el lenguaje C incluyera una fuerte +distinción entre enteros y booleanos, el compilador encontraría estos +errores por nosotros... pero no lo hace. Para ayudar a prevenir tales +errores, siga siempre esta convención:: + + Si el nombre de una función es una acción o un comando imperativo, + la función debe devolver un número entero de código de error. si el nombre + es un predicado, la función debe devolver un valor booleano "exitoso". + +Por ejemplo, ``agregar trabajo`` es un comando, y la función +agregar_trabajo() devuelve 0 en caso de éxito o -EBUSY en caso de fracaso. +De la misma manera, ``dispositivo PCI presente`` es un predicado, y la +función pci_dev_present() devuelve 1 si tiene éxito en encontrar un +dispositivo coincidente o 0 si no es así. + +Todas las funciones EXPORTed (exportadas) deben respetar esta convención, +al igual que todas las funciones publicas. Las funciones privadas +(estáticas) no lo necesitan, pero es recomendado que lo hagan. + +Las funciones cuyo valor devuelto es el resultado real de un cálculo, en +lugar de una indicación de si el cómputo tuvo éxito, no están sujetas a +esta regla. Generalmente indican fallo al devolver valores fuera del rango +de resultados. Los ejemplos típicos serían funciones que devuelven +punteros; estos usan NULL o el mecanismo ERR_PTR para informar de fallos. + +17) Usando bool +---------------- + +El tipo bool del kernel Linux es un alias para el tipo C99 _Bool. Los +valores booleanos pueden solo evaluar a 0 o 1, y la conversión implícita o +explícita a bool convierte automáticamente el valor en verdadero o falso. +Cuando se utilizan tipos booleanos, +!! no se necesita construcción, lo que elimina una clase de errores. + +Cuando se trabaja con valores booleanos, se deben usar las definiciones +verdadera y falsa, en lugar de 1 y 0. + +Los tipos de devolución de función bool y las variables de pila siempre +se pueden usar cuando esto sea adecuado. Se recomienda el uso de bool para +mejorar la legibilidad y, a menudo, es una mejor opción que 'int' para +almacenar valores booleanos. + +No use bool si el diseño de la línea de caché o el tamaño del valor son +importantes, ya que su tamaño y la alineación varía según la arquitectura +compilada. Las estructuras que son optimizadas para la alineación y el +tamaño no debe usar bool. + +Si una estructura tiene muchos valores verdadero/falso, considere +consolidarlos en un bitfield con miembros de 1 bit, o usando un tipo de +ancho fijo apropiado, como u8. + +De manera similar, para los argumentos de función, se pueden consolidar +muchos valores verdaderos/falsos en un solo argumento bit a bit 'flags' y +'flags' a menudo, puede ser una alternativa de argumento más legible si los +sitios de llamada tienen constantes desnudas de tipo verdaderas/falsas. + +De lo contrario, el uso limitado de bool en estructuras y argumentos puede +mejorar la legibilidad. + +18) No reinvente las macros del kernel +--------------------------------------- + +El archivo de cabecera include/linux/kernel.h contiene una serie de macros +que debe usar, en lugar de programar explícitamente alguna variante de +estos por usted mismo. Por ejemplo, si necesita calcular la longitud de una +matriz, aproveche la macro + +.. code-block:: c + + #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +De manera similar, si necesita calcular el tamaño de algún miembro de la +estructura, use + +.. code-block:: c + + #define sizeof_field(t, f) (sizeof(((t*)0)->f)) + +También hay macros min() y max() que realizan una verificación estricta de +tipos si lo necesita. Siéntase libre de leer detenidamente ese archivo de +encabezado para ver qué más ya está definido y que no debe reproducir en su +código. + +19) Editores modeline y otros desastres +--------------------------------------- + +Algunos editores pueden interpretar la información de configuración +incrustada en los archivos fuente, indicado con marcadores especiales. Por +ejemplo, emacs interpreta las líneas marcadas como esto: + +.. code-block:: c + + -*- mode: c -*- + +O así: + +.. code-block:: c + + /* + Local Variables: + compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c" + End: + */ + +Vim interpreta los marcadores que se ven así: + +.. code-block:: c + + /* vim:set sw=8 noet */ + +No incluya ninguno de estos en los archivos fuente. La gente tiene sus +propias configuraciones del editor, y sus archivos de origen no deben +anularlos. Esto incluye marcadores para sangría y configuración de modo. +La gente puede usar su propio modo personalizado, o puede tener algún otro +método mágico para que la sangría funcione correctamente. + + +20) Ensamblador inline +----------------------- + +En el código específico de arquitectura, es posible que deba usar +ensamblador en línea para interactuar con funcionalidades de CPU o +plataforma. No dude en hacerlo cuando sea necesario. Sin embargo, no use +ensamblador en línea de forma gratuita cuando C puede hacer el trabajo. +Puede y debe empujar el hardware desde C cuando sea posible. + +Considere escribir funciones auxiliares simples que envuelvan bits comunes +de ensamblador, en lugar de escribirlos repetidamente con ligeras +variaciones. Recuerde que el ensamblador en línea puede usar parámetros C. + +Las funciones de ensamblador grandes y no triviales deben ir en archivos .S, +con su correspondientes prototipos de C definidos en archivos de encabezado +en C. Los prototipos de C para el ensamblador deben usar ``asmlinkage``. + +Es posible que deba marcar su declaración asm como volátil, para evitar que +GCC la elimine si GCC no nota ningún efecto secundario. No siempre es +necesario hacerlo, sin embargo, y hacerlo innecesariamente puede limitar la +optimización. + +Al escribir una sola declaración de ensamblador en línea que contiene +múltiples instrucciones, ponga cada instrucción en una línea separada en +una string separada, y termine cada string excepto la última con ``\n\t`` +para indentar correctamente la siguiente instrucción en la salida en +ensamblador: + +.. code-block:: c + + asm ("magic %reg1, #42\n\t" + "more_magic %reg2, %reg3" + : /* outputs */ : /* inputs */ : /* clobbers */); + +21) Compilación condicional +--------------------------- + +Siempre que sea posible, no use condicionales de preprocesador (#if, +#ifdef) en archivos .c; de lo contrario, el código es más difícil de leer y +la lógica más difícil de seguir. En cambio, use dichos condicionales en un +archivo de encabezado que defina funciones para usar en esos archivos .c, +proporcionando versiones de código auxiliar sin operación en el caso #else, +y luego llame a estas funciones incondicionalmente desde archivos .c. El +compilador evitará generar cualquier código para las llamadas restantes, +produciendo resultados idénticos, pero la lógica es fácil de seguir. + +Prefiera compilar funciones completas, en lugar de porciones de funciones o +porciones de expresiones. En lugar de poner un ifdef en una expresión, +divida la totalidad de la expresión con una función de ayuda independiente +y aplique el condicional a esa función. + +Si tiene una función o variable que puede potencialmente quedar sin usar en +una configuración en particular, y el compilador advertiría sobre su +definición sin usar, marque la definición como __maybe_unused en lugar de +envolverla en un preprocesador condicional. (Sin embargo, si una función o +variable *siempre* acaba sin ser usada, bórrela.) + +Dentro del código, cuando sea posible, use la macro IS_ENABLED para +convertir un símbolo Kconfig en una expresión booleana de C, y utilícelo en +un condicional de C normal: + +.. code-block:: c + + if (IS_ENABLED(CONFIG_SOMETHING)) { + ... + } + +El compilador "doblará"" constantemente el condicional e incluirá o +excluirá el bloque de código al igual que con un #ifdef, por lo que esto no +agregará ningún tiempo de gastos generales en ejecución. Sin embargo, este +enfoque todavía permite que el compilador de C vea el código dentro del +bloque, y verifique que sea correcto (sintaxis, tipos, símbolo, referencias, +etc.). Por lo tanto, aún debe usar un #ifdef si el código dentro del bloque +hace referencia a símbolos que no existirán si no se cumple la condición. + +Al final de cualquier bloque #if o #ifdef no trivial (más de unas pocas +líneas), incluya un comentario después de #endif en la misma línea, +anotando la expresión condicional utilizada. Por ejemplo: + +.. code-block:: c + + #ifdef CONFIG_SOMETHING + ... + #endif /* CONFIG_SOMETHING */ + +22) No rompa el kernel +----------------------- + +En general, la decisión de romper el kernel pertenece al usuario, más que +al desarrollador del kernel. + +Evite el panic() +**************** + +panic() debe usarse con cuidado y principalmente solo durante el arranque +del sistema. panic() es, por ejemplo, aceptable cuando se queda sin memoria +durante el arranque y no puede continuar. + +Use WARN() en lugar de BUG() +**************************** + +No agregue código nuevo que use cualquiera de las variantes BUG(), como +BUG(), BUG_ON() o VM_BUG_ON(). En su lugar, use una variante WARN*(), +preferiblemente WARN_ON_ONCE(), y posiblemente con código de recuperación. +El código de recuperación no es requerido si no hay una forma razonable de +recuperar, al menos parcialmente. + +"Soy demasiado perezoso para tener en cuenta los errores" no es una excusa +para usar BUG(). Importantes corrupciones internas sin forma de continuar +aún pueden usar BUG(), pero necesitan una buena justificación. + +Use WARN_ON_ONCE() en lugar de WARN() o WARN_ON() +************************************************* + +Generalmente, se prefiere WARN_ON_ONCE() a WARN() o WARN_ON(), porque es +común que una condición de advertencia dada, si ocurre, ocurra varias +veces. Esto puede llenar el registro del kernel, e incluso puede ralentizar +el sistema lo suficiente como para que el registro excesivo se convierta en +su propio, adicional problema. + +No haga WARN a la ligera +************************ + +WARN*() está diseñado para situaciones inesperadas que nunca deberían +suceder. Las macros WARN*() no deben usarse para nada que se espera que +suceda durante un funcionamiento normal. No hay "checkeos" previos o +posteriores a la condición, por ejemplo. De nuevo: WARN*() no debe usarse +para una condición esperada que vaya a activarse fácilmente, por ejemplo, +mediante acciones en el espacio del usuario. pr_warn_once() es una +alternativa posible, si necesita notificar al usuario de un problema. + +No se preocupe sobre panic_on_warn de usuarios +********************************************** + +Algunas palabras más sobre panic_on_warn: Recuerde que ``panic_on_warn`` es +una opción disponible del kernel, y que muchos usuarios configuran esta +opción. Esta es la razón por la que hay un artículo de "No haga WARN a la +ligera", arriba. Sin embargo, la existencia de panic_on_warn de usuarios no +es una razón válida para evitar el uso juicioso de WARN*(). Esto se debe a +que quien habilita panic_on_warn, explícitamente pidió al kernel que +fallara si se dispara un WARN*(), y tales usuarios deben estar preparados +para afrontar las consecuencias de un sistema que es algo más probable que +se rompa. + +Use BUILD_BUG_ON() para aserciones en tiempo de compilación +*********************************************************** + +El uso de BUILD_BUG_ON() es aceptable y recomendado, porque es una aserción +en tiempo de compilación, que no tiene efecto en tiempo de ejecución. + +Apéndice I) Referencias +----------------------- + +The C Programming Language, Segunda edicion +por Brian W. Kernighan and Dennis M. Ritchie. +Prentice Hall, Inc., 1988. +ISBN 0-13-110362-8 (paperback), 0-13-110370-9 (hardback). + +The Practice of Programming +por Brian W. Kernighan and Rob Pike. +Addison-Wesley, Inc., 1999. +ISBN 0-201-61586-X. + +manuales GCC - en cumplimiento con K&R y este texto - para cpp, gcc, +detalles de gcc y sangría, todo disponible en https://www.gnu.org/manual/ + +WG14 es el grupo de trabajo de estandarización internacional de la +programación en lenguaje C, URL: http://www.open-std.org/JTC1/SC22/WG14/ + +:ref:`process/coding-style.rst <codingstyle>` del kernel, por greg@kroah.com at OLS 2002: +http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/ diff --git a/Documentation/translations/sp_SP/process/contribution-maturity-model.rst b/Documentation/translations/sp_SP/process/contribution-maturity-model.rst new file mode 100644 index 0000000000..cc052ae818 --- /dev/null +++ b/Documentation/translations/sp_SP/process/contribution-maturity-model.rst @@ -0,0 +1,120 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. include:: ../disclaimer-sp.rst + +:Original: Documentation/process/contribution-maturity-model.rst +:Translator: Avadhut Naik <avadhut.naik@amd.com> + +==================================================== +Modelo de Madurez de Contribución al Kernel de Linux +==================================================== + + +Los Antecedentes +================ + +Como parte de la cumbre de mantenedores del kernel de Linux 2021, hubo +una `discusión <https://lwn.net/Articles/870581/>`_ sobre los desafíos +en el reclutamiento de mantenedores del kernel, así como la sucesión de +los mantenedores. Algunas de las conclusiones de esa discusión incluyeron +que las empresas que forman parte de la comunidad del kernel de Linux +necesitan permitir que los ingenieros sean mantenedores como parte de su +trabajo, para que puedan convertirse en lideres respetados y finalmente, +en mantenedores del kernel. Para apoyar una fuente solida de talento, se +debe permitir y alentar a los desarrolladores a asumir contribuciones +upstream, como revisar los parches de otras personas, reestructurar la +infraestructura del kernel y escribir documentación. + +Con ese fin, Technical Advisory Board (TAB) de la Fundación Linux propone +este Modelo de Madurez de Contribución al Kernel de Linux. Estas +expectativas comunes para la participación con la comunidad upstream +tienen como objetivo aumentar la influencia de los desarrolladores +individuales, aumentar la colaboración de las organizaciones y mejorar +la salud general del ecosistema del kernel de Linux. + +El TAB insta a las organizaciones a evaluar continuamente su modelo de +madurez de Código Abierto y comprometerse a realizar mejoras para +alinearse con este modelo. Para ser eficaz, esta evaluación debe +incorporar la reacción de toda la organización, incluyendo la gerencia +y los desarrolladores en todos los niveles de antigüedad. En el espíritu +de Código Abierto, alentamos a las organizaciones a publicar sus +evaluaciones y planes para mejorar su participación con la comunidad +upstream. + +Nivel 0 +======= + +* A los ingenieros de software no se les permite contribuir con parches + al kernel de Linux. + +Nivel 1 +======= + +* A los ingenieros de software se les permite contribuir con parches al + kernel de Linux, ya sea como parte de sus responsabilidades de trabajo + o en su propio tiempo. + +Nivel 2 +======= + +* Se espera que los ingenieros de software contribuyan al kernel de Linux + como parte de sus responsabilidades de trabajo. +* Se proporcionará apoyo a los ingenieros de software para asistir a + conferencias relacionadas con Linux como parte de su trabajo. +* Las contribuciones de código upstream de un ingeniero de software se + considerarán en la promoción y las revisiones de rendimiento. + +Nivel 3 +======= + +* Se espera que los ingenieros de software revisen los parches (incluidos + los parches escritos por ingenieros de otras empresas) como parte de + sus responsabilidades de trabajo. +* Contribuir con presentaciones o ponencias a conferencias relacionadas + con Linux o académicas (como las organizadas por la Fundación Linux, + Usenix, ACM, etc.), se consideran parte del trabajo de un ingeniero. +* Las contribuciones a la comunidad de un ingeniero de software se + considerarán en la promoción y las revisiones de rendimiento. +* Las organizaciones informarán regularmente sobre las métricas de sus + contribuciones de código abierto y harán un seguimiento de estas + métricas a lo largo del tiempo. Estas métricas pueden publicarse + solo internamente dentro de la organización, o a discreción de la + organización, algunas o todas pueden publicarse externamente. Las + métricas que se sugieren encarecidamente incluyen: + + * El número de contribuciones al kernel upstream por equipo u + organización (por ejemplo, todas las personas que reportan a un + gerente o director o vicepresidente). + * El porcentaje de desarrolladores del kernel que han realizado + contribuciones upstream relativo al total de desarrolladores + del kernel en la organización. + * El intervalo de tiempo entre los kernels utilizados en los servidores + y/o productos de la organización y la fecha de publicación del kernel + upstream en el que se basa el kernel interno. + * El número de commits fuera del árbol de desarrollo presentes en los + kernels internos. + +Nivel 4 +======= + +* Se anima a los ingenieros de software a pasar una parte de su tiempo de + trabajo centrado en el Trabajo Ascendente, que se define como revisar + parches, servir en los comités de programas, mejorar la infraestructura + del proyecto central como escribir o mantener pruebas, reducir la deuda + de tecnología upstream, escribir documentación, etc. +* Los ingenieros de software son apoyados para ayudar a organizar + conferencias relacionadas con Linux. +* Las organizaciones considerarán los comentarios de los miembros de la + comunidad en las revisiones oficiales de rendimiento. + +Nivel 5 +======= + +* El desarrollo del kernel upstream se considera un puesto de trabajo + formal, con al menos un tercio del tiempo del ingeniero pasado a hacer + el Trabajo Ascendente. +* Las organizaciones buscarán activamente las reacciones de los miembros + de la comunidad como un factor en las revisiones oficiales de + rendimiento. +* Las organizaciones informarán regularmente internamente sobre la ratio + de trabajo upstream a trabajo enfocado en perseguir directamente los + objetivos comerciales. diff --git a/Documentation/translations/sp_SP/process/deprecated.rst b/Documentation/translations/sp_SP/process/deprecated.rst new file mode 100644 index 0000000000..d52120e0d7 --- /dev/null +++ b/Documentation/translations/sp_SP/process/deprecated.rst @@ -0,0 +1,381 @@ +.. include:: ../disclaimer-sp.rst + +:Original: :ref:`Documentation/process/deprecated.rst <deprecated>` +:Translator: Sergio Gonzalez <sergio.collado@gmail.com> + +.. _sp_deprecated: + +============================================================================ +Interfaces obsoletos, Características del lenguaje, Atributos y Convenciones +============================================================================ + +En un mundo perfecto, sería posible convertir todas las instancias de +alguna API obsoleta en una nueva API y quitar la API anterior en un +único ciclo de desarrollo. Desafortunadamente, debido al tamaño del kernel, +la jerarquía de mantenimiento, y el tiempo, no siempre es posible hacer +estos cambios de una única vez. Esto significa que las nuevas instancias +han de ir creándose en el kernel, mientras que las antiguas se quitan, +haciendo que la cantidad de trabajo para limpiar las APIs crezca. Para +informar a los desarrolladores sobre qué ha sido declarado obsoleto y por +qué, ha sido creada esta lista como un lugar donde indicar cuando los usos +obsoletos son propuestos para incluir en el kernel. + +__deprecated +------------ +Mientras que este atributo señala visualmente que un interface ha sido +declarado obsoleto, este `no produce más avisos durante las compilaciones +<https://git.kernel.org/linus/771c035372a036f83353eef46dbb829780330234>`_ +porque uno de los objetivos del kernel es que compile sin avisos, y +nadie ha hecho nada para quitar estos interfaces obsoletos. Mientras +que usar `__deprecated` es sencillo para anotar una API obsoleta en +un archivo de cabecera, no es la solución completa. Dichos interfaces +deben o bien ser quitados por completo, o añadidos a este archivo para +desanimar a otros a usarla en el futuro. + +BUG() y BUG_ON() +---------------- +Use WARN() y WARN_ON() en su lugar, y gestione las condiciones de error +"imposibles" tan elegantemente como se pueda. Mientras que la familia de +funciones BUG() fueron originalmente diseñadas para actuar como una +"situación imposible", confirmar y disponer de un hilo del kernel de forma +"segura", estas funciones han resultado ser demasiado arriesgadas. (e.g. +"¿en qué orden se necesitan liberar los locks? ¿Se han restaurado sus +estados?). La popular función BUG() desestabilizará el sistema o lo romperá +totalmente, lo cual hace imposible depurarlo o incluso generar reportes de +crash. Linus tiene una `opinión muy fuerte +<https://lore.kernel.org/lkml/CA+55aFy6jNLsywVYdGp83AMrXBo_P-pkjkphPGrO=82SPKCpLQ@mail.gmail.com/>`_ +y sentimientos `sobre esto +<https://lore.kernel.org/lkml/CAHk-=whDHsbK3HTOpTF=ue_o04onRwTEaK_ZoJp_fjbqq4+=Jw@mail.gmail.com/>`_. + +Nótese que la familia de funciones WARN() únicamente debería ser usada +en situaciones que se "esperan no sean alcanzables". Si se quiere +avisar sobre situaciones "alcanzables pero no deseadas", úsese la familia +de funciones pr_warn(). Los responsables del sistema pueden haber definido +*panic_on_warn* sysctl para asegurarse que sus sistemas no continúan +ejecutándose en presencia del condiciones "no alcanzables". (Por ejemplo, +véase commits como `este +<https://git.kernel.org/linus/d4689846881d160a4d12a514e991a740bcb5d65a>`_.) + +Operaciones aritméticas en los argumentos de reserva de memoria +--------------------------------------------------------------- +Los cálculos dinámicos de tamaño (especialmente multiplicaciones) no +deberían realizarse en los argumentos de reserva de memoria (o similares) +debido al riesgo de desbordamiento. Esto puede llevar a valores rotando y +que se realicen reservas de memoria menores que las que se esperaban. El +uso de esas reservas puede llevar a desbordamientos en el 'heap' de memoria +y otros funcionamientos incorrectos. (Una excepción a esto son los valores +literales donde el compilador si puede avisar si estos puede desbordarse. +De todos modos, el método recomendado en estos caso es reescribir el código +como se sugiere a continuación para evitar las operaciones aritméticas en +la reserva de memoria.) + +Por ejemplo, no utilice `count * size`` como argumento, como en:: + + foo = kmalloc(count * size, GFP_KERNEL); + +En vez de eso, utilice la reserva con dos argumentos:: + + foo = kmalloc_array(count, size, GFP_KERNEL); + +Específicamente, kmalloc() puede ser sustituido con kmalloc_array(), +kzalloc() puede ser sustituido con kcalloc(). + +Si no existen funciones con dos argumentos, utilice las funciones que se +saturan, en caso de desbordamiento:: + + bar = vmalloc(array_size(count, size)); + +Otro caso común a evitar es calcular el tamaño de una estructura com +la suma de otras estructuras, como en:: + + header = kzalloc(sizeof(*header) + count * sizeof(*header->item), + GFP_KERNEL); + +En vez de eso emplee:: + + header = kzalloc(struct_size(header, item, count), GFP_KERNEL); + +.. note:: Si se usa struct_size() en una estructura que contiene un elemento + de longitud cero o un array de un único elemento como un array miembro, + por favor reescribir ese uso y cambiar a un `miembro array flexible + <#zero-length-and-one-element-arrays>`_ + + +Para otros cálculos, por favor use las funciones de ayuda: size_mul(), +size_add(), and size_sub(). Por ejemplo, en el caso de:: + + foo = krealloc(current_size + chunk_size * (count - 3), GFP_KERNEL); + +Re-escríbase, como:: + + foo = krealloc(size_add(current_size, + size_mul(chunk_size, + size_sub(count, 3))), GFP_KERNEL); + +Para más detalles, mire también array3_size() y flex_array_size(), +como también la familia de funciones relacionadas check_mul_overflow(), +check_add_overflow(), check_sub_overflow(), y check_shl_overflow(). + + +simple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull() +---------------------------------------------------------------------- +Las funciones: simple_strtol(), simple_strtoll(), simple_strtoul(), y +simple_strtoull() explícitamente ignoran los desbordamientos, lo que puede +llevar a resultados inesperados por las funciones que las llaman. Las +funciones respectivas kstrtol(), kstrtoll(), kstrtoul(), y kstrtoull() +tienden a ser reemplazos correctos, aunque nótese que necesitarán que la +cadena de caracteres termine en NUL o en el carácter de línea nueva. + + +strcpy() +-------- +strcpy() no realiza verificaciones de los límites del buffer de destino. +Esto puede resultar en desbordamientos lineals más allá del fin del buffer, +causando todo tipo de errores. Mientras `CONFIG_FORTIFY_SOURCE=y` otras +varias opciones de compilación reducen el riesgo de usar esta función, no +hay ninguna buena razón para añadir nuevos usos de esta. El remplazo seguro +es la función strscpy(), aunque se ha de tener cuidado con cualquier caso +en el el valor retornado por strcpy() sea usado, ya que strscpy() no +devuelve un puntero a el destino, sino el número de caracteres no nulos +compilados (o el valor negativo de errno cuando se trunca la cadena de +caracteres). + +strncpy() en cadenas de caracteres terminadas en NUL +---------------------------------------------------- +El uso de strncpy() no garantiza que el buffer de destino esté terminado en +NUL. Esto puede causar varios errores de desbordamiento en lectura y otros +tipos de funcionamiento erróneo debido a que falta la terminación en NUL. +Esta función también termina la cadena de caracteres en NUL en el buffer de +destino si la cadena de origen es más corta que el buffer de destino, lo +cual puede ser una penalización innecesaria para funciones usen esta +función con cadenas de caracteres que sí están terminadas en NUL. + +Cuando se necesita que la cadena de destino sea terminada en NUL, +el mejor reemplazo es usar la función strscpy(), aunque se ha de tener +cuidado en los casos en los que el valor de strncpy() fuera usado, ya que +strscpy() no devuelve un puntero al destino, sino el número de +caracteres no nulos copiados (o el valor negativo de errno cuando se trunca +la cadena de caracteres). Cualquier caso restante que necesitase todavía +ser terminado en el caracter nulo, debería usar strscpy_pad(). + +Si una función usa cadenas de caracteres que no necesitan terminar en NUL, +debería usarse strtomem(), y el destino debería señalarse con el atributo +`__nonstring +<https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html>`_ +para evitar avisos futuros en el compilador. Para casos que todavía +necesitan cadenas de caracteres que se rellenen al final con el +caracter NUL, usar strtomem_pad(). + +strlcpy() +--------- +strlcpy() primero lee por completo el buffer de origen (ya que el valor +devuelto intenta ser el mismo que el de strlen()). Esta lectura puede +sobrepasar el límite de tamaño del destino. Esto ineficiente y puede causar +desbordamientos de lectura si la cadena de origen no está terminada en el +carácter NUL. El reemplazo seguro de esta función es strscpy(), pero se ha +de tener cuidado que en los casos en lso que se usase el valor devuelto de +strlcpy(), ya que strscpy() devolverá valores negativos de erno cuando se +produzcan truncados. + +Especificación de formato %p +---------------------------- +Tradicionalmente,el uso de "%p" en el formato de cadenas de caracteres +resultaría en exponer esas direcciones en dmesg, proc, sysfs, etc. En vez +de dejar que sean una vulnerabilidad, todos los "%p" que se usan en el +kernel se imprimen como un hash, haciéndolos efectivamente inutilizables +para usarlos como direcciones de memoria. Nuevos usos de "%p" no deberían +ser añadidos al kernel. Para textos de direcciones, usar "%pS" es +mejor, ya que resulta en el nombre del símbolo. Para prácticamente el +resto de casos, mejor no usar "%p" en absoluto. + +Parafraseando las actuales `direcciones de Linus <https://lore.kernel.org/lkml/CA+55aFwQEd_d40g4mUCSsVRZzrFPUJt74vc6PPpb675hYNXcKw@mail.gmail.com/>`_: + +- Si el valor "hasheado" "%p" no tienen ninguna finalidad, preguntarse si el + puntero es realmente importante. ¿Quizás se podría quitar totalmente? +- Si realmente se piensa que el valor del puntero es importante, ¿porqué + algún estado del sistema o nivel de privilegio de usuario es considerado + "especial"? Si piensa que puede justificarse (en comentarios y mensajes + del commit), de forma suficiente como para pasar el escrutinio de Linux, + quizás pueda usar el "%p", a la vez que se asegura que tiene los permisos + correspondientes. + +Si está depurando algo donde el "%p" hasheado está causando problemas, +se puede arrancar temporalmente con la opción de depuración "`no_hash_pointers +<https://git.kernel.org/linus/5ead723a20e0447bc7db33dc3070b420e5f80aa6>`_". + + +Arrays de longitud variable (VLAs) +---------------------------------- +Usando VLA en la pila (stack) produce un código mucho peor que los arrays +de tamaño estático. Mientras que estos errores no triviales de `rendimiento +<https://git.kernel.org/linus/02361bc77888>`_ son razón suficiente +para no usar VLAs, esto además son un riesgo de seguridad. El crecimiento +dinámico del array en la pila, puede exceder la memoria restante en +el segmento de la pila. Esto podría llevara a un fallo, posible sobre-escritura +de contenido al final de la pila (cuando se construye sin +`CONFIG_THREAD_INFO_IN_TASK=y`), o sobre-escritura de la memoria adyacente +a la pila (cuando se construye sin `CONFIG_VMAP_STACK=y`). + + +Switch case fall-through implícito +---------------------------------- +El lenguaje C permite a las sentencias 'switch' saltar de un caso al +siguiente caso cuando la sentencia de ruptura "break" no aparece al final +del caso. Esto, introduce ambigüedad en el código, ya que no siempre está +claro si el 'break' que falta es intencionado o un olvido. Por ejemplo, no +es obvio solamente mirando al código si `STATE_ONE` está escrito para +intencionadamente saltar en `STATE_TWO`:: + + switch (value) { + case STATE_ONE: + do_something(); + case STATE_TWO: + do_other(); + break; + default: + WARN("unknown state"); + } + +Ya que ha habido una larga lista de defectos `debidos a declaraciones de "break" +que faltan <https://cwe.mitre.org/data/definitions/484.html>`_, no se +permiten 'fall-through' implícitos. Para identificar 'fall-through' +intencionados, se ha adoptado la pseudo-palabra-clave macro "falltrhrough", +que expande las extensiones de gcc `__attribute__((__fallthrough__)) +<https://gcc.gnu.org/onlinedocs/gcc/Statement-Attributes.html>`_. +(Cuando la sintaxis de C17/c18 `[[fallthrough]]` sea más comúnmente +soportadas por los compiladores de C, analizadores estáticos, e IDEs, +se puede cambiar a usar esa sintaxis para esa pseudo-palabra-clave. + +Todos los bloques switch/case deben acabar en uno de: + +* break; +* fallthrough; +* continue; +* goto <label>; +* return [expression]; + + +Arrays de longitud cero y un elemento +------------------------------------- +Hay una necesidad habitual en el kernel de proveer una forma para declarar +un grupo de elementos consecutivos de tamaño dinámico en una estructura. +El código del kernel debería usar siempre `"miembros array flexible" <https://en.wikipedia.org/wiki/Flexible_array_member>`_ +en estos casos. El estilo anterior de arrays de un elemento o de longitud +cero, no deben usarse más. + +En el código C más antiguo, los elementos finales de tamaño dinámico se +obtenían especificando un array de un elemento al final de una estructura:: + + struct something { + size_t count; + struct foo items[1]; + }; + +En código C más antiguo, elementos seguidos de tamaño dinámico eran creados +especificando una array de un único elemento al final de una estructura:: + + struct something { + size_t count; + struct foo items[1]; + }; + +Esto llevó a resultados incorrectos en los cálculos de tamaño mediante +sizeof() (el cual hubiera necesitado eliminar el tamaño del último elemento +para tener un tamaño correcto de la "cabecera"). Una `extensión de GNU C +<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_ se empezó a usar +para permitir los arrays de longitud cero, para evitar estos tipos de +problemas de tamaño:: + + struct something { + size_t count; + struct foo items[0]; + }; + +Pero esto llevó a otros problemas, y no solucionó algunos otros problemas +compartidos por ambos estilos, como no ser capaz de detectar cuando ese array +accidentalmente _no_ es usado al final de la estructura (lo que podía pasar +directamente, o cuando dicha estructura era usada en uniones, estructuras +de estructuras, etc). + +C99 introdujo "los arrays miembros flexibles", los cuales carecen de un +tamaño numérico en su declaración del array:: + + struct something { + size_t count; + struct foo items[]; + }; + +Esta es la forma en la que el kernel espera que se declaren los elementos +de tamaño dinámico concatenados. Esto permite al compilador generar +errores, cuando el array flexible no es declarado en el último lugar de la +estructura, lo que ayuda a prevenir errores en él código del tipo +`comportamiento indefinido <https://git.kernel.org/linus/76497732932f15e7323dc805e8ea8dc11bb587cf>`_. +Esto también permite al compilador analizar correctamente los tamaños de +los arrays (via sizeof(), `CONFIG_FORTIFY_SOURCE`, y `CONFIG_UBSAN_BOUNDS`). +Por ejemplo, si no hay un mecanismo que avise que el siguiente uso de +sizeof() en un array de longitud cero, siempre resulta en cero:: + + struct something { + size_t count; + struct foo items[0]; + }; + + struct something *instance; + + instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL); + instance->count = count; + + size = sizeof(instance->items) * instance->count; + memcpy(instance->items, source, size); + +En la última línea del código anterior, ``zero`` vale ``cero``, cuando uno +podría esperar que representa el tamaño total en bytes de la memoria dinámica +reservada para el array consecutivo ``items``. Aquí hay un par de ejemplos +más sobre este tema: `link 1 +<https://git.kernel.org/linus/f2cd32a443da694ac4e28fbf4ac6f9d5cc63a539>`_, +`link 2 +<https://git.kernel.org/linus/ab91c2a89f86be2898cee208d492816ec238b2cf>`_. +Sin embargo, los array de miembros flexibles tienen un type incompleto, y +no se ha de aplicar el operador sizeof()<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_, +así cualquier mal uso de dichos operadores será detectado inmediatamente en +el momento de compilación. + +Con respecto a los arrays de un único elemento, se ha de ser consciente de +que dichos arrays ocupan al menos tanto espacio como un único objeto del +tipo https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_, de ahí que +estos contribuyan al tamaño de la estructura que los contiene. Esto es +proclive a errores cada vez que se quiere calcular el tamaño total de la +memoria dinámica para reservar una estructura que contenga un array de este +tipo como su miembro:: + + struct something { + size_t count; + struct foo items[1]; + }; + + struct something *instance; + + instance = kmalloc(struct_size(instance, items, count - 1), GFP_KERNEL); + instance->count = count; + + size = sizeof(instance->items) * instance->count; + memcpy(instance->items, source, size); + +En el ejemplo anterior, hemos de recordar calcular ``count - 1``, cuando se +usa la función de ayuda struct_size(), de otro modo estaríamos +--desintencionadamente--reservando memoria para un ``items`` de más. La +forma más clara y menos proclive a errores es implementar esto mediante el +uso de `array miembro flexible`, junto con las funciones de ayuda: +struct_size() y flex_array_size():: + + struct something { + size_t count; + struct foo items[]; + }; + + struct something *instance; + + instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL); + instance->count = count; + + memcpy(instance->items, source, flex_array_size(instance, items, instance->count)); diff --git a/Documentation/translations/sp_SP/process/email-clients.rst b/Documentation/translations/sp_SP/process/email-clients.rst new file mode 100644 index 0000000000..fdf1e51b84 --- /dev/null +++ b/Documentation/translations/sp_SP/process/email-clients.rst @@ -0,0 +1,374 @@ +.. include:: ../disclaimer-sp.rst + +:Original: :ref:`Documentation/process/email-clients.rst <email_clients>` +:Translator: Carlos Bilbao <carlos.bilbao@amd.com> + +.. _sp_email_clients: + +Información de clientes de correo electrónico para Linux +======================================================== + +Git +--- + +A día de hoy, la mayoría de los desarrolladores usan ``git send-email`` en +lugar de los clientes de correo electrónico normales. La página de manual +para esto es bastante buena. En la recepción del correo, los maintainers +usan ``git am`` para aplicar los parches. + +Si es usted nuevo en ``git`` entonces envíese su primer parche. Guárdelo +como texto sin formato, incluidos todos los encabezados. Ejecute ``git am raw_email.txt`` +y luego revise el registro de cambios con ``git log``. Cuando eso funcione, +envíe el parche a la(s) lista(s) de correo apropiada(s). + +Preferencias Generales +---------------------- + +Los parches para el kernel de Linux se envían por correo electrónico, +preferiblemente como texto en línea en el cuerpo del correo electrónico. +Algunos maintainers aceptan archivos adjuntos, pero entonces los archivos +adjuntos deben tener tipo de contenido ``text/plain``. Sin embargo, los +archivos adjuntos generalmente están mal vistos porque hacen que citar +partes del parche sea más difícil durante el proceso de revisión del +parche. + +También se recomienda encarecidamente que utilice texto sin formato en el +cuerpo del correo electrónico, para parches y otros correos electrónicos +por igual. https://useplaintext.email puede ser útil para obtener +información sobre cómo configurar su cliente de correo electrónico +preferido, así como una lista de clientes de correo electrónico +recomendados si aún no tiene una preferencia. + +Los clientes de correo electrónico que se utilizan para los parches del +kernel Linux deben enviar el texto del parche intacto. Por ejemplo, no +deben modificar ni eliminar pestañas o espacios, incluso al principio o al +final de las líneas. + +No envíe parches con ``format=flowed``. Esto puede causar saltos de línea +no deseados e inesperados. + +No deje que su cliente de correo electrónico ajuste automáticamente las +palabras por usted. Esto también puede corromper su parche. + +Los clientes de correo electrónico no deben modificar la codificación del +de caracteres del texto. Los parches enviados por correo electrónico deben +estar en codificación ASCII o UTF-8 únicamente. Si configura su cliente de +correo electrónico para enviar correos electrónicos con codificación UTF-8, +evite algunos posibles problemas con los caracteres. + +Los clientes de correo electrónico deben generar y mantener los +encabezados "References:" o "In-Reply-To:" para que el hilo de correo no +se rompa. + +Copiar y pegar (o cortar y pegar) generalmente no funciona para los +parches, porque las tabulaciones se convierten en espacios. Utilizar +xclipboard, xclip y/o xcutsel puede funcionar, pero es mejor probarlo usted +mismo o simplemente evitar copiar y pegar. + +No utilice firmas PGP/GPG en el correo que contiene parches. +Esto rompe muchos scripts que leen y aplican los parches. +(Esto debería ser reparable.) + +Es una buena idea enviarse un parche a sí mismo, guardar el mensaje +recibido, y aplicarlo con éxito con 'patch' antes de enviar el parche a las +listas de correo de Linux. + +Algunas sugerencias para el cliente de correo electrónico (MUA) +--------------------------------------------------------------- + +Aquí hay algunos consejos específicos de configuración de MUA para editar y +enviar parches para el kernel de Linux. Estos no pretenden cubrir todo +detalle de configuración de los paquetes de software. + +Leyenda: + +- TUI = text-based user interface (interfaz de usuario basada en texto) +- GUI = graphical user interface (interfaz de usuario gráfica) + +Alpine (TUI) +************ + +Opciones de configuración: + +En la sección :menuselection:`Sending Preferences`: + +- :menuselection: `Do Not Send Flowed Text` debe estar ``enabled`` +- :menuselection:`Strip Whitespace Before Sending` debe estar ``disabled`` + +Al redactar el mensaje, el cursor debe colocarse donde el parche debería +aparecer, y luego presionando :kbd:`CTRL-R` se le permite especificar e +archivo de parche a insertar en el mensaje. + +Claws Mail (GUI) +**************** + +Funciona. Algunos usan esto con éxito para los parches. + +Para insertar un parche haga :menuselection:`Message-->Insert File` (:kbd:`CTRL-I`) +o use un editor externo. + +Si el parche insertado debe editarse en la ventana de composición de Claws +"Auto wrapping" en +:menuselection:`Configuration-->Preferences-->Compose-->Wrapping` debe +permanecer deshabilitado. + +Evolution (GUI) +*************** + +Algunos usan esto con éxito para sus parches. + +Cuando escriba un correo seleccione: Preformat + desde :menuselection:`Format-->Paragraph Style-->Preformatted` (:kbd:`CTRL-7`) + o en la barra de herramientas + +Luego haga: +:menuselection:`Insert-->Text File...` (:kbd:`ALT-N x`) +para insertar el parche. + +También puede hacer ``diff -Nru old.c new.c | xclip``, seleccione +:menuselection:`Preformat`, luego pege con el boton del medio. + +Kmail (GUI) +*********** + +Algunos usan Kmail con éxito para los parches. + +La configuración predeterminada de no redactar en HTML es adecuada; no haga +cambios en esto. + +Al redactar un correo electrónico, en las opciones, desmarque "word wrap". +La única desventaja es que cualquier texto que escriba en el correo +electrónico no se ajustará a cada palabra, por lo que tendrá que ajustar +manualmente el texto antes del parche. La forma más fácil de evitar esto es +redactar su correo electrónico con Word Wrap habilitado, luego guardar +como borrador. Una vez que lo vuelva a sacar de sus borradores, estará +envuelto por palabras y puede desmarcar "word wrap" sin perder el existente +texto. + +En la parte inferior de su correo electrónico, coloque el delimitador de +parche de uso común antes de insertar su parche: tres guiones (``---``). + +Luego desde la opción de menu :menuselection:`Message` seleccione +:menuselection:`insert file` y busque su parche. +De forma adicional, puede personalizar el menú de la barra de herramientas +de creación de mensajes y poner el icono :menuselection:`insert file`. + +Haga que la ventana del editor sea lo suficientemente ancha para que no se +envuelva ninguna línea. A partir de KMail 1.13.5 (KDE 4.5.4), KMail +aplicará ajuste de texto al enviar el correo electrónico si las líneas se +ajustan en la ventana del redactor. Tener ajuste de palabras deshabilitado +en el menú Opciones no es suficiente. Por lo tanto, si su parche tiene +líneas muy largas, debe hacer que la ventana del redactor sea muy amplia +antes de enviar el correo electrónico. Consulte: https://bugs.kde.org/show_bug.cgi?id=174034 + +You can safely GPG sign attachments, but inlined text is preferred for +patches so do not GPG sign them. Signing patches that have been inserted +as inlined text will make them tricky to extract from their 7-bit encoding. + +Puede firmar archivos adjuntos con GPG de forma segura, pero se prefiere el +texto en línea para parches, así que no los firme con GPG. Firmar parches +que se han insertado como texto en línea hará que sea difícil extraerlos de +su codificación de 7 bits. + +Si es absolutamente necesario enviar parches como archivos adjuntos en +lugar de como texto en línea, haga clic con el botón derecho en el archivo +adjunto y seleccione :menuselection:`properties`, y luego +:menuselection:`Suggest automatic display` para hacer que el archivo +adjunto esté en línea para que sea más visible. + +Al guardar parches que se envían como texto en línea, seleccione el correo +electrónico que contiene el parche del panel de la lista de mensajes, haga +clic con el botón derecho y seleccione :menuselection:`save as`. Puede usar +todo el correo electrónico sin modificar como un parche de estar bien +compuesto. Los correos electrónicos se guardan como lectura y escritura +solo para el usuario, por lo que tendrá que cambiarlos para que sean +legibles en grupo y en todo el mundo si copia estos en otro lugar. + +Notas de Lotus (GUI) +******************** + +Huya de este. + +IBM Verse (Web GUI) +******************* + +Vea notas sobre Lotus. + +Mutt (TUI) +********** + +Muchos desarrolladores de Linux usan ``mutt``, por lo que debe funcionar +bastante bien. + +Mutt no viene con un editor, por lo que cualquier editor que use debe ser +utilizado de forma que no haya saltos de línea automáticos. La mayoría de +los editores tienen una opción :menuselection:`insert file` que inserta el +contenido de un archivo inalterado. + +Para usar ``vim`` con mutt:: + + set editor="vi" + +Si utiliza xclip, escriba el comando:: + + :set paste + +antes del boton del medio o shift-insert o use:: + + :r filename + +si desea incluir el parche en línea. +(a)ttach (adjuntar) funciona bien sin ``set paste``. + +También puedes generar parches con ``git format-patch`` y luego usar Mutt +para enviarlos:: + + $ mutt -H 0001-some-bug-fix.patch + +Opciones de configuración: + +Debería funcionar con la configuración predeterminada. +Sin embargo, es una buena idea establecer ``send_charset`` en: + + set send_charset="us-ascii:utf-8" + +Mutt es altamente personalizable. Aquí tiene una configuración mínima para +empezar a usar Mutt para enviar parches a través de Gmail:: + + # .muttrc + # ================ IMAP ==================== + set imap_user = 'suusuario@gmail.com' + set imap_pass = 'sucontraseña' + set spoolfile = imaps://imap.gmail.com/INBOX + set folder = imaps://imap.gmail.com/ + set record="imaps://imap.gmail.com/[Gmail]/Sent Mail" + set postponed="imaps://imap.gmail.com/[Gmail]/Drafts" + set mbox="imaps://imap.gmail.com/[Gmail]/All Mail" + + # ================ SMTP ==================== + set smtp_url = "smtp://username@smtp.gmail.com:587/" + set smtp_pass = $imap_pass + set ssl_force_tls = yes # Requerir conexión encriptada + + # ================ Composición ==================== + set editor = `echo \$EDITOR` + set edit_headers = yes # Ver los encabezados al editar + set charset = UTF-8 # valor de $LANG; also fallback for send_charset + # El remitente, la dirección de correo electrónico y la línea de firma deben coincidir + unset use_domain # Porque joe@localhost es simplemente vergonzoso + set realname = "SU NOMBRE" + set from = "username@gmail.com" + set use_from = yes + +Los documentos Mutt tienen mucha más información: + + https://gitlab.com/muttmua/mutt/-/wikis/UseCases/Gmail + + http://www.mutt.org/doc/manual/ + +Pine (TUI) +********** + +Pine ha tenido algunos problemas de truncamiento de espacios en blanco en +el pasado, pero estos todo debería estar arreglados ahora. + +Use alpine (sucesor de pino) si puede. + +Opciones de configuración: + +- ``quell-flowed-text`` necesitado para versiones actuales +- la opción ``no-strip-whitespace-before-send`` es necesaria + + +Sylpheed (GUI) +************** + +- Funciona bien para insertar texto (o usar archivos adjuntos). +- Permite el uso de un editor externo. +- Es lento en carpetas grandes. +- No realizará la autenticación TLS SMTP en una conexión que no sea SSL. +- Tiene una útil barra de reglas en la ventana de redacción. +- Agregar direcciones a la libreta de direcciones no las muestra + adecuadamente. + +Thunderbird (GUI) +***************** + +Thunderbird es un clon de Outlook al que le gusta alterar el texto, pero +hay formas para obligarlo a comportarse. + +Después de hacer las modificaciones, que incluye instalar las extensiones, +necesita reiniciar Thunderbird. + +- Permitir el uso de un editor externo: + + Lo más fácil de hacer con Thunderbird y los parches es usar extensiones + que abran su editor externo favorito. + + Aquí hay algunas extensiones de ejemplo que son capaces de hacer esto. + + - "External Editor Revived" + + https://github.com/Frederick888/external-editor-revived + + https://addons.thunderbird.net/en-GB/thunderbird/addon/external-editor-revived/ + + Requiere instalar un "native messaging host". + Por favor, lea la wiki que se puede encontrar aquí: + https://github.com/Frederick888/external-editor-revived/wiki + + - "External Editor" + + https://github.com/exteditor/exteditor + + Para hacer esto, descargue e instale la extensión, luego abra la ventana + :menuselection:`compose`, agregue un botón para ello usando + :menuselection:`View-->Toolbars-->Customize...` + luego simplemente haga clic en el botón nuevo cuando desee usar el editor + externo. + + Tenga en cuenta que "External Editor" requiere que su editor no haga + fork, o en otras palabras, el editor no debe regresar antes de cerrar. + Es posible que deba pasar flags adicionales o cambiar la configuración + de su editor. En particular, si está utilizando gvim, debe pasar la + opción -f a gvim poniendo ``/usr/bin/gvim --nofork"`` (si el binario + está en ``/usr/bin``) al campo del editor de texto en los ajustes + :menuselection:`external editor`. Si está utilizando algún otro editor, + lea su manual para saber cómo hacer esto. + +Para sacarle algo de sentido al editor interno, haga esto: + +- Edite sus ajustes de configuración de Thunderbird para que no utilice ``format=flowed``! + Vaya a su ventana principal y busque el botón de su menú desplegable principal. + :menuselection:`Main Menu-->Preferences-->General-->Config Editor...` + para abrir el editor de registro de Thunderbird. + + - Seleccione ``mailnews.send_plaintext_flowed`` como ``false`` + + - Seleccione ``mailnews.wraplength`` de ``72`` a ``0`` + +- ¡No escriba mensajes HTML! Acuda a la ventana principal + :menuselection:`Main Menu-->Account Settings-->youracc@server.something-->Composition & Addressing`! + Ahí puede deshabilitar la opción "Compose messages in HTML format". + +- ¡Abra mensajes solo como texto sin formato! Acuda a la ventana principal + :menuselection:`Main Menu-->View-->Message Body As-->Plain Text`! + +TkRat (GUI) +*********** + +Funciona. Utilice "Insert file..." o un editor externo. + +Gmail (Web GUI) +*************** + +No funciona para enviar parches. + +El cliente web de Gmail convierte las tabulaciones en espacios automáticamente. + +Al mismo tiempo, envuelve líneas cada 78 caracteres con saltos de línea de +estilo CRLF aunque el problema de tab2space se puede resolver con un editor +externo. + +Otro problema es que Gmail codificará en base64 cualquier mensaje que tenga +un carácter no ASCII. Eso incluye cosas como nombres europeos. diff --git a/Documentation/translations/sp_SP/process/index.rst b/Documentation/translations/sp_SP/process/index.rst new file mode 100644 index 0000000000..09bfece0f5 --- /dev/null +++ b/Documentation/translations/sp_SP/process/index.rst @@ -0,0 +1,24 @@ +.. raw:: latex + + \renewcommand\thesection* + \renewcommand\thesubsection* + +.. include:: ../disclaimer-sp.rst + +.. _sp_process_index: + +.. toctree:: + :maxdepth: 1 + + submitting-patches + kernel-docs + coding-style + code-of-conduct + kernel-enforcement-statement + email-clients + magic-number + programming-language + deprecated + adding-syscalls + researcher-guidelines + contribution-maturity-model diff --git a/Documentation/translations/sp_SP/process/kernel-docs.rst b/Documentation/translations/sp_SP/process/kernel-docs.rst new file mode 100644 index 0000000000..2f9b3df8f8 --- /dev/null +++ b/Documentation/translations/sp_SP/process/kernel-docs.rst @@ -0,0 +1,187 @@ +.. include:: ../disclaimer-sp.rst + +:Original: :ref:`Documentation/process/kernel-docs.rst <kernel_docs>` +:Translator: Carlos Bilbao <carlos.bilbao@amd.com> + +.. _sp_kernel_docs: + +Índice de documentación adicional del kernel +============================================ + +La necesidad de un documento como este se hizo evidente en la lista de +correo de linux-kernel cuando las mismas preguntas, solicitando sugerencias +e información, aparecieron una y otra vez. + +Afortunadamente, a medida que más y más gente accede a GNU/Linux, más +desarrolladores se interesan por el kernel. Sin embargo, leer las fuentes +no siempre es suficiente. Es fácil entender el código, pero se pierden los +conceptos, la filosofía y decisiones de diseño detrás de dicho código. + +Desafortunadamente, no existen muchos documentos disponibles para que los +principiantes comiencen. Y, aunque existieran, no habría ningún lugar +"conocido" que les pudiera seguir la pista. Estas líneas tratan de cubrir +esta carencia. + +POR FAVOR, si conoce algún documento que no figura aquí, o si escribe un +nuevo documento, incluya una referencia aquí, siguiendo el proceso de envío +de parches del kernel. Cualquier corrección, idea o comentario también es +bienvenida. + +Todos los documentos se catalogan con los siguientes campos: el "Título", +el "Autor"/es, la "URL" donde se encuentran, algunas "Palabras clave" +útiles para buscar temas específicos, y una breve "Descripción" del +documento en cuestión. + +.. note:: + + Los documentos de cada sección en este documento están ordenados por su + fecha de publicación, del más reciente al más antiguo. Los maintainers + deben ir retirando recursos obsoletos o anticuados. + +Documentos en el árbol del kernel Linux +----------------------------------------- + +Los libros de Sphinx deben compilarse con ``make {htmldocs | pdfdocs | epubdocs}``. + + * Título: **linux/Documentation** + + :Autor: Many. + :Ubicación: Documentation/ + :Palabras Clave: archivos de texto, Sphinx. + :Descripción: Documentación que viene con las fuentes del kernel, + dentro del directorio Documentation. Algunas páginas de este documento + (incluido este documento en sí) se han trasladado allí, y podrían + estar más actualizadas que la versión web. + +Documentos en línea +------------------- + + * Título: **Linux Kernel Mailing List Glossary** + + :Autor: various + :URL: https://kernelnewbies.org/KernelGlossary + :Fecha: rolling version + :Palabras Clave: glosario terminos, linux-kernel. + :Descripción: De la Introducción: "This glossary is intended as + a brief description of some of the acronyms and terms you may hear + during discussion of the Linux kernel". + + * Título: **The Linux Kernel Module Programming Guide** + + :Autor: Peter Jay Salzman, Michael Burian, Ori Pomerantz, Bob Mottram, + Jim Huang. + :URL: https://sysprog21.github.io/lkmpg/ + :Fecha: 2021 + :Palabras Clave: modules, GPL book, /proc, ioctls, system calls, + interrupt handlers, llamadas al sistema, interrupciones. + :Descripción: Un muy buen libro GPL sobre el tema de la programación + de módulos. Muchos ejemplos. Actualmente la nueva versión está + siendo mantenida activamente ent https://github.com/sysprog21/lkmpg. + +Libros publicados +----------------- + + * Título: **Linux Kernel Programming: A Comprehensive Guide to Kernel Internals, Writing Kernel Modules, and Kernel Synchronization** + + :Autor: Kaiwan N. Billimoria + :Publica: Packt Publishing Ltd + :Fecha: 2021 + :Paginas: 754 + :ISBN: 978-1789953435 + + * Título: **Linux Kernel Development, 3rd Edition** + + :Autor: Robert Love + :Publica: Addison-Wesley + :Fecha: July, 2010 + :Paginas: 440 + :ISBN: 978-0672329463 + :Notas: Libro fundacional + +.. _sp_ldd3_published: + + * Título: **Linux Device Drivers, 3rd Edition** + + :Authors: Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman + :Publica: O'Reilly & Associates + :Fecha: 2005 + :Paginas: 636 + :ISBN: 0-596-00590-3 + :Notas: Libro fundacional. Más información en + http://www.oreilly.com/catalog/linuxdrive3/ + formato PDF, URL: https://lwn.net/Kernel/LDD3/ + + * Título: **The Design of the UNIX Operating System** + + :Autor: Maurice J. Bach + :Publica: Prentice Hall + :Fecha: 1986 + :Paginas: 471 + :ISBN: 0-13-201757-1 + :Notas: Libro fundacional + +Recursos varios +--------------- + + * Título: **Cross-Referencing Linux** + + :URL: https://elixir.bootlin.com/ + :Palabras Clave: Browsing source code. + :Descripción: Otro navegador de código fuente del kernel Linux que se + encuentra en la web. Muchas referencias cruzadas a variables y + funciones. Puedes ver dónde se definen y dónde se utilizan. + + * Título: **Linux Weekly News** + + :URL: https://lwn.net + :Palabras Clave: latest kernel news, noticias del kernel Linux. + :Descripción: El título lo dice todo (Noticias Semanales de Linux). + Hay una sección fija sobre el kernel, resumiendo el trabajo de sus + desarrolladores, correcciones de errores, nuevas funciones y + versiones, producido durante la semana. + + * Título: **The home page of Linux-MM** + + :Autor: The Linux-MM team. + :URL: https://linux-mm.org/ + :Palabras Clave: memory management, Linux-MM, mm patches, TODO, docs, + mailing list, administración de memoria, Linux-MM, parches mm, listas + de correo. + :Descripción: Sitio dedicado al desarrollo de la gestión de memoria + de Linux. Parches relacionados con la memoria, HOWTOs, enlaces, + desarrolladores de mm... ¡Si está interesado en el desarrollo de la + gestión de memoria no te lo pierdas! + + * Título: **Kernel Newbies IRC Channel and Website** + + :URL: https://www.kernelnewbies.org + :Palabras Clave: IRC, newbies, channel, asking doubts, canal, dudas, + novatos, preguntar. + :Descripción: #kernelnewbies en irc.oftc.net. + #kernelnewbies es una red de IRC dedicada al hacker del kernel + 'novato'. La audiencia se compone principalmente de personas que + quieren aprender sobre el kernel, trabajar en proyectos del kernel + o hackers profesionales del kernel que quieren ayudar a la gente + menos experimentada. + #kernelnewbies es parte de la red OFTC IRC. + Pruebe con irc.oftc.net como su servidor y luego haga /join + #kernelnewbies. + El sitio web kernelnewbies también alberga artículos, documentos, FAQs... + + * Título: **linux-kernel mailing list archives and search engines** + + :URL: http://vger.kernel.org/vger-lists.html + :URL: http://www.uwsg.indiana.edu/hypermail/linux/kernel/index.html + :URL: http://groups.google.com/group/mlist.linux.kernel + :Palabras Clave: linux-kernel, archives, buscar, search, archivos. + :Descripción: Algunos de los archivadores de listas de correo del + kernel de Linux. Si usted tiene uno mejor/otro, por favor hágamelo + saber. + +------- + +Este documento se basaba originalmente en: + + https://www.dit.upm.es/~jmseyas/linux/kernel/hackers-docs.html + +escrito por Juan-Mariano de Goyenche diff --git a/Documentation/translations/sp_SP/process/kernel-enforcement-statement.rst b/Documentation/translations/sp_SP/process/kernel-enforcement-statement.rst new file mode 100644 index 0000000000..d669026940 --- /dev/null +++ b/Documentation/translations/sp_SP/process/kernel-enforcement-statement.rst @@ -0,0 +1,174 @@ +.. include:: ../disclaimer-sp.rst + +:Original: :ref:`Documentation/process/kernel-enforcement-statement.rst <process_statement_kernel>` +:Translator: Carlos Bilbao <carlos.bilbao@amd.com> + +.. _sp_process_statement_kernel: + +Aplicación de la licencia en el kernel Linux +============================================ + +Como desarrolladores del kernel Linux, tenemos un gran interés en cómo se +se utiliza nuestro software y cómo se aplica la licencia de nuestro software. +El cumplimiento de las obligaciones de intercambio recíproco de GPL-2.0 son +fundamentales en el largo plazo para la sostenibilidad de nuestro software +y comunidad. + +Aunque existe el derecho de hacer valer un copyright distinto en las +contribuciones hechas a nuestra comunidad, compartimos el interés de +asegurar que las acciones individuales para proteger estos se lleven a cabo +de una manera que beneficia a nuestra comunidad y no tenga un indeseado +impacto negativo en la salud y crecimiento de nuestro ecosistema de software. +Con el fin de disuadir la aplicación inútil de acciones, estamos de acuerdo +en que es en el mejor interés de nuestro desarrollo como comunidad asumir +el siguiente compromiso con los usuarios del kernel Linux, en nombre +nuestro y de cualquier sucesor de nuestros derechos de autor (copyright): + + Sin perjuicio de las disposiciones de terminación de GPL-2.0, aceptamos + que es en el mejor interés de nuestra comunidad de desarrollo adoptar + las siguientes disposiciones de GPL-3.0 como permisos adicionales bajo + nuestra licencia, con respecto a cualquier interposición de alegación + de infringimiento (en inglés, "non-defensive assertion") de los + derechos bajo la licencia. + + Sin embargo, si deja de violar esta Licencia, entonces su licencia + de copyright como particular se restablece (a) provisionalmente, + a menos que y hasta que el titular de los derechos de autor explícita + y finalmente rescinda su licencia, y (b) de forma permanente, si el + titular de los derechos de autor no le notifica la violación por algún + medio razonable antes de 60 días después del cese. + + Además, su licencia de un titular de derechos de autor en particular es + restablecida permanentemente si el titular de los derechos de autor le + notifica de la violación por algún medio razonable, esta es la primera + vez que ha recibido notificación de violación de esta Licencia (para + cualquier trabajo) de ese titular de los derechos de autor, y subsana + la infracción antes de los 30 días posteriores de recibir el aviso. + +Nuestra intención al proporcionar estas garantías es fomentar un mayor uso +del software. Queremos que empresas y particulares utilicen, modifiquen y +distribuyan este software. Queremos trabajar con los usuarios de forma +abierta y transparente para eliminar cualquier incertidumbre sobre nuestras +expectativas con respecto al cumplimiento que podría limitar la adopción de +nuestro software. Entendemos la acción legal como último recurso, que se +iniciará solo cuando otros esfuerzos de la comunidad no hayan podido +resolver el problema. + +Finalmente, una vez que se resuelva un problema de incumplimiento, +esperamos que el usuario se sienta bienvenido a unirse a nosotros en +nuestros esfuerzos con este proyecto. Trabajando juntos, somos más fuertes. + +Excepto donde se indica a continuación, hablamos solo por nosotros mismos y +no por ninguna compañía donde puede que trabajemos hoy, o hayamos trabajado +en el pasado, o trabajaremos en el futuro. + +- Laura Abbott +- Bjorn Andersson (Linaro) +- Andrea Arcangeli +- Neil Armstrong +- Jens Axboe +- Pablo Neira Ayuso +- Khalid Aziz +- Ralf Baechle +- Felipe Balbi +- Arnd Bergmann +- Ard Biesheuvel +- Tim Bird +- Paolo Bonzini +- Christian Borntraeger +- Mark Brown (Linaro) +- Paul Burton +- Javier Martinez Canillas +- Rob Clark +- Kees Cook (Google) +- Jonathan Corbet +- Dennis Dalessandro +- Vivien Didelot (Savoir-faire Linux) +- Hans de Goede +- Mel Gorman (SUSE) +- Sven Eckelmann +- Alex Elder (Linaro) +- Fabio Estevam +- Larry Finger +- Bhumika Goyal +- Andy Gross +- Juergen Gross +- Shawn Guo +- Ulf Hansson +- Stephen Hemminger (Microsoft) +- Tejun Heo +- Rob Herring +- Masami Hiramatsu +- Michal Hocko +- Simon Horman +- Johan Hovold (Hovold Consulting AB) +- Christophe JAILLET +- Olof Johansson +- Lee Jones (Linaro) +- Heiner Kallweit +- Srinivas Kandagatla +- Jan Kara +- Shuah Khan (Samsung) +- David Kershner +- Jaegeuk Kim +- Namhyung Kim +- Colin Ian King +- Jeff Kirsher +- Greg Kroah-Hartman (Linux Foundation) +- Christian König +- Vinod Koul +- Krzysztof Kozlowski +- Viresh Kumar +- Aneesh Kumar K.V +- Julia Lawall +- Doug Ledford +- Chuck Lever (Oracle) +- Daniel Lezcano +- Shaohua Li +- Xin Long +- Tony Luck +- Catalin Marinas (Arm Ltd) +- Mike Marshall +- Chris Mason +- Paul E. McKenney +- Arnaldo Carvalho de Melo +- David S. Miller +- Ingo Molnar +- Kuninori Morimoto +- Trond Myklebust +- Martin K. Petersen (Oracle) +- Borislav Petkov +- Jiri Pirko +- Josh Poimboeuf +- Sebastian Reichel (Collabora) +- Guenter Roeck +- Joerg Roedel +- Leon Romanovsky +- Steven Rostedt (VMware) +- Frank Rowand +- Ivan Safonov +- Anna Schumaker +- Jes Sorensen +- K.Y. Srinivasan +- David Sterba (SUSE) +- Heiko Stuebner +- Jiri Kosina (SUSE) +- Willy Tarreau +- Dmitry Torokhov +- Linus Torvalds +- Thierry Reding +- Rik van Riel +- Luis R. Rodriguez +- Geert Uytterhoeven (Glider bvba) +- Eduardo Valentin (Amazon.com) +- Daniel Vetter +- Linus Walleij +- Richard Weinberger +- Dan Williams +- Rafael J. Wysocki +- Arvind Yadav +- Masahiro Yamada +- Wei Yongjun +- Lv Zheng +- Marc Zyngier (Arm Ltd) + diff --git a/Documentation/translations/sp_SP/process/magic-number.rst b/Documentation/translations/sp_SP/process/magic-number.rst new file mode 100644 index 0000000000..7c7dfb4ba8 --- /dev/null +++ b/Documentation/translations/sp_SP/process/magic-number.rst @@ -0,0 +1,89 @@ +.. include:: ../disclaimer-sp.rst + +:Original: :ref:`Documentation/process/magic-number.rst <magicnumbers>` +:Translator: Carlos Bilbao <carlos.bilbao@amd.com> + +.. _sp_magicnumbers: + +Números mágicos de Linux +======================== + +Este archivo es un registro de los números mágicos que están en uso. Cuando +usted incluya un número mágico a una estructura, también debe agregarlo a +este documento, ya que es mejor si los números mágicos utilizados por +varias estructuras son únicos. + +Es una muy buena idea proteger las estructuras de datos del kernel con +números mágicos. Esto le permite verificar en tiempo de ejecución si (a) +una estructura ha sido manipulada, o (b) ha pasado la estructura incorrecta +a una rutina. Esto último es especialmente útil --- particularmente cuando +pasa punteros a estructuras a través de un puntero void \*. El código tty, +por ejemplo, hace esto con frecuencia para pasar información específica del +driver y líneas de estructuras específicas de protocolo de un lado al +otro. + +La forma de usar números mágicos es declararlos al principio de la +estructura, así:: + + struct tty_ldisc { + int magic; + ... + }; + +Por favor, siga este método cuando agregue futuras mejoras al kernel! Me ha +ahorrado innumerables horas de depuración, especialmente en los casos +complicados donde una matriz ha sido invadida y las estructuras que siguen +a la matriz se han sobrescrito. Usando este método, estos casos se detectan +de forma rápida y segura. + +Changelog:: + + Theodore Ts'o + 31 Mar 94 + + La tabla mágica ha sido actualizada para Linux 2.1.55. + + Michael Chastain + <mailto:mec@shout.net> + 22 Sep 1997 + + Ahora debería estar actualizada con Linux 2.1.112. Porque + estamos en fase de "feature freeze", es muy poco probable que + algo cambiará antes de 2.2.x. Las entradas son + ordenados por campo numérico. + + Krzysztof G. Baranowski + <mailto: kgb@knm.org.pl> + 29 Jul 1998 + + Se actualizó la tabla mágica a Linux 2.5.45. Justo sobre el feature + freeze, pero es posible que algunos nuevos números mágicos se cuelen en + el kernel antes de 2.6.x todavía. + + Petr Baudis + <pasky@ucw.cz> + 03 Nov 2002 + + La tabla mágica ha sido actualizada para Linux 2.5.74. + + Fabian Frederick + <ffrederick@users.sourceforge.net> + 09 Jul 2003 + +===================== ================ ======================== ========================================== +Magic Name Number Structure File +===================== ================ ======================== ========================================== +PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/pg.h`` +APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` +FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` +SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h`` +BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c`` +HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h`` +KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h`` +CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h`` +YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c`` +CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c`` +QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c`` +QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c`` +NMI_MAGIC 0x48414d4d455201 nmi_s ``arch/mips/include/asm/sn/nmi.h`` +===================== ================ ======================== ========================================== diff --git a/Documentation/translations/sp_SP/process/programming-language.rst b/Documentation/translations/sp_SP/process/programming-language.rst new file mode 100644 index 0000000000..301f525372 --- /dev/null +++ b/Documentation/translations/sp_SP/process/programming-language.rst @@ -0,0 +1,53 @@ +.. include:: ../disclaimer-sp.rst + +:Original: :ref:`Documentation/process/programming-language.rst <programming_language>` +:Translator: Carlos Bilbao <carlos.bilbao@amd.com> + +.. _sp_programming_language: + +Lenguaje de programación +======================== + +El kernel está escrito en el lenguaje de programación C [sp-c-language]_. +Más concretamente, el kernel normalmente se compila con ``gcc`` [sp-gcc]_ +bajo ``-std=gnu11`` [sp-gcc-c-dialect-options]_: el dialecto GNU de ISO C11. +``clang`` [sp-clang]_ también es compatible, consulte los documentos en +:ref:`Building Linux with Clang/LLVM <kbuild_llvm>`. + +Este dialecto contiene muchas extensiones del lenguaje [sp-gnu-extensions]_, +y muchos de ellos se usan dentro del kernel de forma habitual. + +Hay algo de soporte para compilar el núcleo con ``icc`` [sp-icc]_ para varias +de las arquitecturas, aunque en el momento de escribir este texto, eso no +está terminado y requiere parches de terceros. + +Atributos +--------- + +Una de las comunes extensiones utilizadas en todo el kernel son los atributos +[sp-gcc-attribute-syntax]_. Los atributos permiten introducir semántica +definida por la implementación a las entidades del lenguaje (como variables, +funciones o tipos) sin tener que hacer cambios sintácticos significativos +al idioma (por ejemplo, agregar una nueva palabra clave) [sp-n2049]_. + +En algunos casos, los atributos son opcionales (es decir, hay compiladores +que no los admiten pero de todos modos deben producir el código adecuado, +incluso si es más lento o no realiza tantas comprobaciones/diagnósticos en +tiempo de compilación). + +El kernel define pseudo-palabras clave (por ejemplo, ``__pure``) en lugar +de usar directamente la sintaxis del atributo GNU (por ejemplo, +``__attribute__((__pure__))``) con el fin de detectar cuáles se pueden +utilizar y/o acortar el código. + +Por favor consulte ``include/linux/compiler_attributes.h`` para obtener +más información. + +.. [sp-c-language] http://www.open-std.org/jtc1/sc22/wg14/www/standards +.. [sp-gcc] https://gcc.gnu.org +.. [sp-clang] https://clang.llvm.org +.. [sp-icc] https://software.intel.com/en-us/c-compilers +.. [sp-gcc-c-dialect-options] https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html +.. [sp-gnu-extensions] https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html +.. [sp-gcc-attribute-syntax] https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html +.. [sp-n2049] http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2049.pdf diff --git a/Documentation/translations/sp_SP/process/researcher-guidelines.rst b/Documentation/translations/sp_SP/process/researcher-guidelines.rst new file mode 100644 index 0000000000..462b3290b7 --- /dev/null +++ b/Documentation/translations/sp_SP/process/researcher-guidelines.rst @@ -0,0 +1,150 @@ +.. SPDX-License-Identifier: GPL-2.0 + +:Original: :ref:`Documentation/process/researcher-guidelines.rst` +:Translator: Avadhut Naik <avadhut.naik@amd.com> + +Directrices para Investigadores +++++++++++++++++++++++++++++++++ + +La comunidad del kernel de Linux da la bienvenida a la investigación +transparente sobre el kernel de Linux, las actividades involucradas +en su producción, otros subproductos de su desarrollo. Linux se +beneficia mucho de este tipo de investigación, y la mayoría de los +aspectos de Linux son impulsados por investigación en una forma u otra. + +La comunidad agradece mucho si los investigadores pueden compartir +los hallazgos preliminares antes de hacer públicos sus resultados, +especialmente si tal investigación involucra seguridad. Involucrarse +temprano ayuda a mejorar la calidad de investigación y la capacidad +de Linux para mejorar a partir de ella. En cualquier caso, se recomienda +compartir copias de acceso abierto de la investigación publicada con +la comunidad. + +Este documento busca clarificar lo que la comunidad del kernel de Linux +considera practicas aceptables y no aceptables al llevar a cabo +investigación de este tipo. Por lo menos, dicha investigación y +actividades afines deben seguir las reglas estándar de ética de la +investigación. Para más información sobre la ética de la investigación +en general, ética en la tecnología y la investigación de las comunidades +de desarrolladores en particular, ver: + + +* `Historia de la Ética en la Investigación <https://www.unlv.edu/research/ORI-HSR/history-ethics>`_ +* `Ética de la IEEE <https://www.ieee.org/about/ethics/index.html>`_ +* `Perspectivas de Desarrolladores e Investigadores sobre la Ética de los Experimentos en Proyectos de Código Abierto <https://arxiv.org/pdf/2112.13217.pdf>`_ + +La comunidad del kernel de Linux espera que todos los que interactúan con +el proyecto están participando en buena fe para mejorar Linux. La +investigación sobre cualquier artefacto disponible públicamente (incluido, +pero no limitado a código fuente) producido por la comunidad del kernel +de Linux es bienvenida, aunque la investigación sobre los desarrolladores +debe ser claramente opcional. + +La investigación pasiva que se basa completamente en fuentes disponibles +públicamente, incluidas las publicaciones en listas de correo públicas y +las contribuciones a los repositorios públicos, es claramente permitida. +Aunque, como con cualquier investigación, todavía se debe seguir la ética +estándar. + +La investigación activa sobre el comportamiento de los desarrolladores, +sin embargo, debe hacerse con el acuerdo explícito y la divulgación +completa a los desarrolladores individuales involucrados. No se puede +interactuar / experimentar con los desarrolladores sin consentimiento; +esto también es ética de investigación estándar. + +Para ayudar a aclarar: enviar parches a los desarrolladores es interactuar +con ellos, pero ya han dado su consentimiento para recibir contribuciones +en buena fe. No se ha dado consentimiento para enviar parches intencionalmente +defectuosos / vulnerables o contribuir con la información engañosa a las +discusiones. Dicha comunicación puede ser perjudicial al desarrollador (por +ejemplo, agotar el tiempo, el esfuerzo, y la moral) y perjudicial para el +proyecto al erosionar la confianza de toda la comunidad de desarrolladores en +el colaborador (y la organización del colaborador en conjunto), socavando +los esfuerzos para proporcionar reacciones constructivas a los colaboradores +y poniendo a los usuarios finales en riesgo de fallas de software. + +La participación en el desarrollo de Linux en sí mismo por parte de +investigadores, como con cualquiera, es bienvenida y alentada. La +investigación del código de Linux es una práctica común, especialmente +cuando se trata de desarrollar o ejecutar herramientas de análisis que +producen resultados procesables. + +Cuando se interactúa con la comunidad de desarrolladores, enviar un +parche ha sido tradicionalmente la mejor manera para hacer un impacto. +Linux ya tiene muchos errores conocidos – lo que es mucho más útil es +tener soluciones verificadas. Antes de contribuir, lea cuidadosamente +la documentación adecuada. + +* Documentation/process/development-process.rst +* Documentation/process/submitting-patches.rst +* Documentation/admin-guide/reporting-issues.rst +* Documentation/process/security-bugs.rst + +Entonces envíe un parche (incluyendo un registro de confirmación con +todos los detalles enumerados abajo) y haga un seguimiento de cualquier +comentario de otros desarrolladores. + +* ¿Cuál es el problema específico que se ha encontrado? +* ¿Como podría llegar al problema en un sistema en ejecución? +* ¿Qué efecto tendría encontrar el problema en el sistema? +* ¿Como se encontró el problema? Incluya específicamente detalles sobre + cualquier prueba, programas de análisis estáticos o dinámicos, y cualquier + otra herramienta o método utilizado para realizar el trabajo. +* ¿En qué versión de Linux se encontró el problema? Se prefiere usar la + versión más reciente o una rama reciente de linux-next (ver + Documentation/process/howto.rst). +* ¿Que se cambió para solucionar el problema y por qué se cree es correcto? +* ¿Como se probó el cambio para la complicación y el tiempo de ejecución? +* ¿Qué confirmación previa corrige este cambio? Esto debería ir en un “Fixes:” + etiqueta como se describe en la documentación. +* ¿Quién más ha revisado este parche? Esto debería ir con la adecuada “Reviewed-by” + etiqueta; Vea abajo. + +Por ejemplo (en inglés, pues es en las listas):: + + From: Author <author@email> + Subject: [PATCH] drivers/foo_bar: Add missing kfree() + + The error path in foo_bar driver does not correctly free the allocated + struct foo_bar_info. This can happen if the attached foo_bar device + rejects the initialization packets sent during foo_bar_probe(). This + would result in a 64 byte slab memory leak once per device attach, + wasting memory resources over time. + + This flaw was found using an experimental static analysis tool we are + developing, LeakMagic[1], which reported the following warning when + analyzing the v5.15 kernel release: + + path/to/foo_bar.c:187: missing kfree() call? + + Add the missing kfree() to the error path. No other references to + this memory exist outside the probe function, so this is the only + place it can be freed. + + x86_64 and arm64 defconfig builds with CONFIG_FOO_BAR=y using GCC + 11.2 show no new warnings, and LeakMagic no longer warns about this + code path. As we don't have a FooBar device to test with, no runtime + testing was able to be performed. + + [1] https://url/to/leakmagic/details + + Reported-by: Researcher <researcher@email> + Fixes: aaaabbbbccccdddd ("Introduce support for FooBar") + Signed-off-by: Author <author@email> + Reviewed-by: Reviewer <reviewer@email> + +Si usted es un colaborador por primera vez, se recomienda que el parche en +si sea examinado por otros en privado antes de ser publicado en listas +públicas. (Esto es necesario si se le ha dicho explícitamente que sus parches +necesitan una revisión interna más cuidadosa.) Se espera que estas personas +tengan su etiqueta “Reviewed-by” incluida en el parche resultante. Encontrar +otro desarrollador con conocimiento de las contribuciones a Linux, especialmente +dentro de su propia organización, y tener su ayuda con las revisiones antes de +enviarlas a las listas de correo publico tiende a mejorar significativamente la +calidad de los parches resultantes, y reduce así la carga de otros desarrolladores. + +Si no se puede encontrar a nadie para revisar internamente los parches y necesita +ayuda para encontrar a esa persona, o si tiene alguna otra pregunta relacionada +con este documento y las expectativas de la comunidad de desarrolladores, por +favor contacte con la lista de correo privada Technical Advisory Board: +<tech-board@lists.linux-foundation.org>. diff --git a/Documentation/translations/sp_SP/process/submitting-patches.rst b/Documentation/translations/sp_SP/process/submitting-patches.rst new file mode 100644 index 0000000000..c2757d9ab2 --- /dev/null +++ b/Documentation/translations/sp_SP/process/submitting-patches.rst @@ -0,0 +1,894 @@ +.. include:: ../disclaimer-sp.rst + +:Original: :ref:`Documentation/process/submitting-patches.rst <submittingpatches>` +:Translator: Carlos Bilbao <carlos.bilbao@amd.com> + +.. _sp_submittingpatches: + +Envío de parches: la guía esencial para incluir su código en el kernel +======================================================================= + +Para una persona o empresa que desee enviar un cambio al kernel Linux, +el proceso puede en ocasiones resultar desalentador si no se está +familiarizado con "el sistema". Este texto es una colección de sugerencias +que pueden aumentar considerablemente las posibilidades de que se acepte su +cambio. + +Este documento contiene una gran cantidad de sugerencias en un formato +relativamente conciso. Para obtener información detallada sobre cómo +funciona el proceso de desarrollo del kernel, consulte +Documentation/process/development-process.rst. Además, lea +Documentation/process/submit-checklist.rst para obtener una lista de +elementos a verificar antes de enviar código. Para los parches de +"binding" del árbol de dispositivos, lea +Documentation/devicetree/bindings/submitting-patches.rst. + +Esta documentación asume que está usando ``git`` para preparar sus parches. +Si no está familiarizado con ``git``, le recomendamos que aprenda a +usarlo, le hará la vida como desarrollador del kernel y en general mucho +más sencilla. + +Algunos subsistemas y árboles de mantenimiento cuentan con información +adicional sobre su flujo de trabajo y expectativas, consulte +:ref:`Documentation/process/maintainer-handbooks.rst <maintainer_handbooks_main>`. + +Obtenga el código fuente actual +-------------------------------- + +Si no tiene a mano un repositorio con el código fuente actual del kernel, +use ``git`` para obtener uno. Querrá comenzar con el repositorio principal, +que se puede descargar con:: + + git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git + +Tenga en cuenta, sin embargo, que es posible que no desee desarrollar con +el árbol principal directamente. La mayoría de los maintainers de +subsistemas usan sus propios árboles de código fuente y quieren ver parches +preparados para esos árboles. Revise el campo **T:** para el subsistema +en el archivo MAINTAINERS para encontrar dicho árbol, o simplemente +pregunte al maintainer si el árbol no está listado allí. + +.. _sp_describe_changes: + +Describa sus cambios +--------------------- + +Describa su problema. Sea su parche una corrección de un error de una +línea o 5000 líneas para una nuevo "feature", debe haber un problema +subyacente que le motivó a hacer ese trabajo. Convenza al revisor de que +hay un problema que merece la pena solucionar y de que tiene sentido que +lea más allá del primer párrafo. + +Describa el impacto relativo al usuario. Cosas que estropeen el kernel y +los bloqueos son bastante convincentes, pero no todos los errores son tan +evidentes. Incluso si se detectó un problema durante la revisión del +código, describa el impacto que cree pueda tener en los usuarios. Tenga en +cuenta que la mayoría de instalaciones de Linux ejecutan kernels desde +árboles estables secundarios o árboles específicos de proveedor/producto +que seleccionan ("cherry-pick") solo parches específicos de upstream, así +que incluya cualquier cosa que pueda ayudar a dirigir su cambio +aguas abajo: circunstancias que producen cierta situación, extractos de +dmesg, descripciones del error fatal, regresiones de rendimiento, picos de +latencia, bloqueos, etc. + +Cuantifique optimizaciones y beneficios/perdidas. Si asegura mejoras en +rendimiento, consumo de memoria, huella del stack o tamaño de binario, +incluya números que lo respalden. Pero también describa costes no obvios. +Las optimizaciones generalmente no son gratuitas, sino un equilibrio entre +CPU, memoria y legibilidad; o, cuando se trata de heurísticas, entre +diferentes cargas de trabajo. Describa las desventajas esperadas de su +optimización para que el revisor pueda comparar las perdidas con los +beneficios. + +Una vez establecido el problema, describa lo que realmente está haciendo +al respecto en detalles técnicos. Es importante describir el cambio en +lenguaje sencillo para que el revisor verifique que el código se está +comportando como se pretende. + +El maintainer le agradecerá que escriba la descripción de su parche en un +formato que se pueda incorporar fácilmente en la gestión del código fuente +del sistema, ``git``, como un "commit log" (registros de los commits). +Consulte :ref:`sp_the_canonical_patch_format`. + +Resuelva solo un problema por parche. Si su descripción comienza a ser muy +larga, eso es una señal de que probablemente necesite dividir su parche. +Lea :ref:`split_changes`. + +Cuando envíe o vuelva a enviar un parche o una serie de parches, incluya la +descripción completa del parche y justificación del mismo. No se limite a +decir que esa es la versión N del parche (serie). No espere que el +maintainer del subsistema referencie versiones de parches anteriores o use +referencias URL para encontrar la descripción del parche y colocarla en el +parche. Es decir, el parche (serie) y su descripción deben ser +independientes. Esto beneficia tanto a los maintainers como a los +revisores. Algunos revisores probablemente ni siquiera recibieran versiones +anteriores del parche. + +Describa sus cambios en la forma imperativa, por ejemplo, "hacer que xyzzy +haga frotz" en lugar de "[Este parche] hace que xyzzy haga frotz" o "[Yo] +Cambié xyzzy para que haga frotz", como si estuviera dando órdenes al +código fuente para cambiar su comportamiento. + +Si desea hacer referencia a un commit específico, no se limite a hacer +referencia al ID SHA-1 del commit. Incluya también el resumen de una línea +del commit, para que sea más fácil para los revisores saber de qué se +trata. +Ejemplo:: + + Commit e21d2170f36602ae2708 ("video: quitar platform_set_drvdata() + innecesario") eliminó innecesario platform_set_drvdata(), pero dejó la + variable "dev" sin usar, bórrese. + +También debe asegurarse de utilizar al menos los primeros doce caracteres +del identificador SHA-1. El repositorio del kernel contiene muchos *muchos* +objetos, por lo que las colisiones con identificaciones más cortas son una +posibilidad real. Tenga en cuenta que, aunque no hay colisión con su +identificación de seis caracteres ahora, esa condición puede cambiar dentro +de cinco años. + +Si las discusiones relacionadas o cualquier otra información relativa al +cambio se pueden encontrar en la web, agregue las etiquetas 'Link:' que +apunten a estos. En caso de que su parche corrija un error, por poner un +ejemplo, agregue una etiqueta con una URL que haga referencia al informe en +los archivos de las listas de correo o un rastreador de errores; si el +parche es el resultado de alguna discusión anterior de la lista de correo o +algo documentado en la web, referencie esto. + +Cuando se vincule a archivos de listas de correo, preferiblemente use el +servicio de archivador de mensajes lore.kernel.org. Para crear la URL del +enlace, utilice el contenido del encabezado ("header") ``Message-Id`` del +mensaje sin los corchetes angulares que lo rodean. +Por ejemplo:: + + Link: https://lore.kernel.org/r/30th.anniversary.repost@klaava.Helsinki.FI/ + +Verifique el enlace para asegurarse de que realmente funciona y apunta al +mensaje correspondiente. + +Sin embargo, intente que su explicación sea comprensible sin recursos +externos. Además de dar una URL a un archivo o error de la lista de correo, +resuma los puntos relevantes de la discusión que condujeron al parche tal y +como se envió. + +Si su parche corrige un error en un commit específico, por ejemplo +encontró un problema usando ``git bisect``, utilice la etiqueta 'Fixes:' +con los primeros 12 caracteres del ID SHA-1 y el resumen de una línea. No +divida la etiqueta en varias líneas, las etiquetas están exentas de la +regla "ajustar a 75 columnas" para simplificar análisis de scripts. Por +ejemplo:: + + Fixes: 54a4f0239f2e ("KVM: MMU: hacer que kvm_mmu_zap_page() + devuelva la cantidad de páginas que realmente liberó") + +Las siguientes configuraciones de ``git config`` se pueden usar para +agregar un bonito formato y generar este estilo con los comandos +``git log`` o ``git show``:: + + [core] + abbrev = 12 + [pretty] + fixes = Fixes: %h (\"%s\") + +Un ejemplo de uso:: + + $ git log -1 --pretty=fixes 54a4f0239f2e + Fixes: 54a4f0239f2e ("KVM: MMU: hacer que kvm_mmu_zap_page() devuelva la cantidad de páginas que realmente liberó") + +.. _sp_split_changes: + +Separe sus cambios +------------------- + +Separe cada **cambio lógico** en un parche separado. + +Por ejemplo, si sus cambios incluyen correcciones de errores y mejoras en +el rendimiento de un controlador, separe esos cambios en dos o más parches. +Si sus cambios incluyen una actualización de la API y una nueva controlador +que usa esta nueva API, sepárelos en dos parches. + +Por otro lado, si realiza un solo cambio en numerosos archivos, agrupe esos +cambios en un solo parche. Por lo tanto, un solo cambio lógico estará +contenido en un solo parche. + +El punto a recordar es que cada parche debe realizar un cambio que puede +ser verificado por los revisores fácilmente. Cada parche debe ser +justificable por sus propios méritos. + +Si un parche depende de otro parche para que un cambio sea completo, eso +está bien. Simplemente incluya que **"este parche depende del parche X"** +en la descripción de su parche. + +Cuando divida su cambio en una serie de parches, tenga especial cuidado en +asegurarse de que el kernel se compila y ejecuta correctamente después de +cada parche en la serie. Los desarrolladores que usan ``git bisect`` +para rastrear un problema pueden terminar dividiendo su serie de parches en +cualquier punto; no le agradecerán si introdujo errores a la mitad. + +Si no puede condensar su conjunto de parches en un conjunto más pequeño de +parches, solo publique, más o menos 15 a la vez, y espere la revisión e +integración. + + +Revise el estilo en sus cambios +-------------------------------- + +Revise su parche para ver si hay violaciones de estilo básico, cuyos +detalles pueden ser encontrados en Documentation/process/coding-style.rst. +No hacerlo simplemente desperdicia el tiempo de los revisores y su parche +será rechazado, probablemente sin siquiera ser leído. + +Una excepción importante es cuando se mueve código de un archivo a otro. +En tal caso, en absoluto debe modificar el código movido en el mismo parche +en que lo mueve. Esto divide claramente el acto de mover el código y sus +cambios. Esto ayuda mucho a la revisión de la diferencias reales y permite +que las herramientas rastreen mejor el historial del código en sí. + +Verifique sus parches con el verificador de estilo de parches antes de +enviarlos (scripts/checkpatch.pl). Tenga en cuenta, sin embargo, que el +verificador de estilo debe ser visto como una guía, no como un reemplazo +del juicio humano. Si su código es mejor con una violación entonces +probablemente sea mejor dejarlo estar. + +El verificador informa a tres niveles: + - ERROR: cosas que es muy probable que estén mal + - WARNING: Advertencia. Cosas que requieren una revisión cuidadosa + - CHECK: Revisar. Cosas que requieren pensarlo + +Debe poder justificar todas las violaciones que permanezcan en su parche. + + +Seleccione los destinatarios de su parche +------------------------------------------ + +Siempre debe incluir en copia a los apropiados maintainers del subsistema +en cualquier parche con código que mantengan; revise a través del archivo +MAINTAINERS y el historial de revisión del código fuente para ver quiénes +son esos maintainers. El script scripts/get_maintainer.pl puede ser muy +útil en este paso (pase rutas a sus parches como argumentos para +scripts/get_maintainer.pl). Si no puede encontrar un maintainer del +subsistema en el que está trabajando, Andrew Morton +(akpm@linux-foundation.org) sirve como maintainer de último recurso. + +Normalmente, también debe elegir al menos una lista de correo para recibir +una copia de su conjunto de parches. linux-kernel@vger.kernel.org debe +usarse de forma predeterminada para todos los parches, pero el volumen en +esta lista ha hecho que muchos desarrolladores se desconecten. Busque en el +archivo MAINTAINERS una lista específica de los subsistemas; su parche +probablemente recibirá más atención allí. Sin embargo, no envíe spam a +listas no relacionadas. + +Muchas listas relacionadas con el kernel están alojadas en vger.kernel.org; +puedes encontrar un listado de estas en +http://vger.kernel.org/vger-lists.html. Existen listas relacionadas con el +kernel alojadas en otros lugares, no obstante. + +¡No envíe más de 15 parches a la vez a las listas de correo de vger! + +Linus Torvalds es el árbitro final de todos los cambios aceptados en el +kernel de Linux. Su dirección de correo electrónico es +<torvalds@linux-foundation.org>. Recibe muchos correos electrónicos y, en +este momento, muy pocos parches pasan por Linus directamente, por lo que +normalmente debe hacer todo lo posible para -evitar- enviarle un correo +electrónico. + +Si tiene un parche que corrige un error de seguridad explotable, envíe ese +parche a security@kernel.org. Para errores graves, se debe mantener un +poco de discreción y permitir que los distribuidores entreguen el parche a +los usuarios; en esos casos, obviamente, el parche no debe enviarse a +ninguna lista pública. Revise también +Documentation/process/security-bugs.rst. + +Los parches que corrigen un error grave en un kernel en uso deben dirigirse +hacia los maintainers estables poniendo una línea como esta:: + + CC: stable@vger.kernel.org + +en el área de sign-off de su parche (es decir, NO un destinatario de correo +electrónico). También debe leer +Documentation/process/stable-kernel-rules.rst además de este documento. + +Si los cambios afectan las interfaces del kernel para el usuario, envíe al +maintainer de las MAN-PAGES (como se indica en el archivo MAINTAINERS) un +parche de páginas de manual, o al menos una notificación del cambio, para +que alguna información se abra paso en las páginas del manual. Los cambios +de la API del espacio de usuario también deben copiarse en +linux-api@vger.kernel.org. + + +Sin MIME, enlaces, compresión o archivos adjuntos. Solo texto plano +-------------------------------------------------------------------- + +Linus y otros desarrolladores del kernel deben poder leer y comentar sobre +los cambios que está enviando. Es importante para un desarrollador kernel +poder "citar" sus cambios, utilizando herramientas estándar de correo +electrónico, de modo que puedan comentar sobre partes específicas de su +código. + +Por este motivo, todos los parches deben enviarse por correo electrónico +"inline". La forma más sencilla de hacerlo es con ``git send-email``, que +es muy recomendable. Un tutorial interactivo para ``git send-email`` está +disponible en https://git-send-email.io. + +Si elige no usar ``git send-email``: + +.. warning:: + + Tenga cuidado con el ajuste de palabras de su editor que corrompe su + parche, si elige cortar y pegar su parche. + +No adjunte el parche como un archivo adjunto MIME, comprimido o no. Muchas +populares aplicaciones de correo electrónico no siempre transmiten un MIME +archivo adjunto como texto sin formato, por lo que es imposible comentar +en su código. Linus también necesita un poco más de tiempo para procesar un +archivo adjunto MIME, disminuyendo la probabilidad de que se acepte su +cambio adjunto en MIME. + +Excepción: si su proveedor de correo está destrozando parches, entonces +alguien puede pedir que los vuelva a enviar usando MIME. + +Consulte Documentation/process/email-clients.rst para obtener sugerencias +sobre cómo configurar su cliente de correo electrónico para que envíe sus +parches intactos. + +Responda a los comentarios de revisión +--------------------------------------- + +Es casi seguro que su parche recibirá comentarios de los revisores sobre +maneras en que se pueda mejorar el parche, en forma de respuesta a su +correo electrónico. Debe responder a esos comentarios; ignorar a los +revisores es una buena manera de ser ignorado de vuelta. Simplemente puede +responder a sus correos electrónicos para contestar a sus comentarios. +Revisiones a los comentarios o preguntas que no conduzcan a un cambio de +código deben casi con certeza generar un comentario o una entrada en el +"changelog" para que el próximo revisor entienda lo que está pasando. + +Asegúrese de decirles a los revisores qué cambios está haciendo y de +agradecerles que dediquen su tiempo. La revisión del código es un proceso +agotador y lento, y los revisores a veces se ponen de mal humor. Sin +embargo, incluso en ese caso, responda cortésmente y aborde los problemas +que hayan señalado. Al enviar un siguiente versión, agregue un +``patch changelog`` (registro de cambios en los parches) a la carta de +presentación ("cover letter") o a parches individuales explicando la +diferencia con la presentación anterior (ver +:ref:`sp_the_canonical_patch_format`). + +Consulte Documentation/process/email-clients.rst para obtener +recomendaciones sobre clientes de correo electrónico y normas de etiqueta +en la lista de correo. + +.. _sp_resend_reminders: + +No se desanime o impaciente +--------------------------- + +Después de haber entregado su cambio, sea paciente y espere. Los revisores +son personas ocupadas y es posible que no lleguen a su parche de inmediato. + +Érase una vez, los parches solían desaparecer en el vacío sin comentarios, +pero el proceso de desarrollo funciona mejor que eso ahora. Debería +recibir comentarios dentro de una semana más o menos; si eso no sucede, +asegúrese de que ha enviado sus parches al lugar correcto. Espere un mínimo +de una semana antes de volver a enviar o hacer ping a los revisores, +posiblemente más durante periodos de mucho trabajo ocupados como "merge +windows". + +También está bien volver a enviar el parche o la serie de parches después +de un par de semanas con la palabra "RESEND" (reenviar) añadida a la línea +de asunto:: + + [PATCH Vx RESEND] sub/sys: Resumen condensado de parche + +No incluya "RESEND" cuando envíe una versión modificada de su parche o +serie de parches: "RESEND" solo se aplica al reenvío de un parche o serie +de parches que no hayan sido modificados de ninguna manera con respecto a +la presentación anterior. + + +Incluya PATCH en el asunto +-------------------------- + +Debido al alto tráfico de correo electrónico a Linus y al kernel de Linux, +es común prefijar su línea de asunto con [PATCH]. Esto le permite a Linus +y otros desarrolladores del kernel distinguir más fácilmente los parches de +otras discusiones por correo electrónico. + +``git send-email`` lo hará automáticamente. + + +Firme su trabajo: el Certificado de Origen del Desarrollador +------------------------------------------------------------ + +Para mejorar el seguimiento de quién hizo qué, especialmente con parches +que pueden filtrarse hasta su destino final a través de varias capas de +maintainers, hemos introducido un procedimiento de "sign-off" (aprobación) +en parches que se envían por correo electrónico. + +La aprobación es una simple línea al final de la explicación del parche, +que certifica que usted lo escribió o que tiene derecho a enviarlo como un +parche de código abierto. Las reglas son bastante simples: si usted puede +certificar lo siguiente: + +Certificado de Origen del Desarrollador 1.1 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Al hacer una contribución a este proyecto, certifico que: + + (a) La contribución fue creada en su totalidad o en parte por mí y + tengo derecho a enviarlo bajo la licencia de código abierto + indicada en el documento; o + + (b) La contribución se basa en trabajo previo que, hasta donde yo + soy consciente, está cubierto por una licencia de código + abierto apropiada y tengo el derecho bajo esa licencia de + presentar tal trabajo con modificaciones, ya sean creadas en su + totalidad o en parte por mí, bajo la misma licencia de código + (salvo que sea permitido presentar bajo una licencia diferente), + tal y como se indica en el documento; o + + (c) La contribución me fue proporcionada directamente por alguna + otra persona que certificó (a), (b) o (c) y no he modificado + esto. + + (d) Entiendo y acepto que este proyecto y la contribución + son públicos y que un registro de la contribución (incluyendo + toda la información personal que envío con él, incluida mi + firma) es mantenida indefinidamente y puede ser redistribuida + de manera consistente con este proyecto o la(s) licencia(s) de + código abierto involucradas. + +entonces simplemente incluya una línea que rece:: + + Signed-off-by: Random J Developer <random@developer.example.org> + +usando su nombre real (lamentablemente, no pseudónimos ni contribuciones +anónimas). Esto se hará por usted automáticamente si usa ``git commit -s``. +Las reversiones de código también deben incluir "Signed-off-by". +``git revert -s`` hace eso por usted. + +Algunas personas también ponen etiquetas adicionales al final. Simplemente +serán ignoradas por ahora, pero puede hacer esto para marcar procedimientos +internos de su empresa o simplemente señalar algún detalle especial sobre +la firma. + +Cualquier otro SoB (Signed-off-by:) después del SoB del autor es de +personas que manipulen y transporten el parche, pero no participaron en su +desarrollo. Las cadenas de SoB deben reflejar la ruta **real** del parche +de cómo se propagó a los maintainers y, en última instancia, a Linus, con +la primera entrada de SoB que señala la autoría principal de un solo autor. + + +Cuándo usar Acked-by:, Cc: y Co-developed-by por: +------------------------------------------------- + +La etiqueta Signed-off-by: indica que el firmante estuvo involucrado en el +desarrollo del parche, o que él/ella se encontraba en el camino de entrega +del parche. + +Si una persona no estuvo directamente involucrada en la preparación o +administración de un parche pero desea expresar y registrar su aprobación, +entonces puede pedir que se agregue una línea Acked-by: al registro de +cambios del parche. + +Acked-by: a menudo lo usa el maintainer del código afectado cuando ese +maintainer no contribuyó ni envió el parche. + +Acked-by: no es tan formal como Signed-off-by:. Es una manera de marcar que +el "acker" ha revisado al menos ese parche y ha indicado su aceptación. Por +los merge de parches a veces convertirán manualmente el "sí, me parece bien" +de un acker en un Acked-by: (pero tenga en cuenta que por lo general es +mejor pedir un acuse de recibo explícito). + +Acked-by: no necesariamente indica el reconocimiento de todo el parche. +Por ejemplo, si un parche afecta a varios subsistemas y tiene un +Acked-by: de un maintainer del subsistema, entonces esto generalmente +indica el reconocimiento de solo la parte que afecta el código de ese +maintainer. Buen juicio debe ejercitarse aquí. En caso de duda, la gente +debe consultar la discusión original en los archivos de la lista de correo. + +Si una persona ha tenido la oportunidad de comentar un parche, pero no lo +ha hecho, puede incluir opcionalmente una etiqueta ``Cc:`` al parche. +Esta es la única etiqueta que se puede agregar sin una acción explícita por +parte de la persona a la que se nombre - pero debe indicar que esta persona +fue copiada en el parche. Esta etiqueta documenta que las partes +potencialmente interesadas han sido incluidas en la discusión. + +Co-developed-by: establece que el parche fue co-creado por múltiples +desarrolladores; se utiliza para dar atribución a los coautores (además del +autor atribuido por la etiqueta From:) cuando varias personas trabajan en +un solo parche. Ya que Co-developed-by: denota autoría, cada +Co-developed-by: debe ser inmediatamente seguido de Signed-off-by: del +coautor asociado. Se mantiene el procedimiento estándar, es decir, el orden +de las etiquetas Signed-off-by: debe reflejar el historial cronológico del +parche en la medida de lo posible, independientemente de si el autor se +atribuye a través de From: o Co-developed-by:. Cabe destacar que el último +Signed-off-by: siempre debe ser del desarrollador que envía el parche. + +Tenga en cuenta que la etiqueta From: es opcional cuando el autor From: es +también la persona (y correo electrónico) enumerados en la línea From: del +encabezado del correo electrónico. + +Ejemplo de un parche enviado por el From: autor:: + + <changelog> + + Co-developed-by: Primer coautor <primer@coauthor.example.org> + Signed-off-by: Primer coautor <primer@coauthor.example.org> + Co-developed-by: Segundo coautor <segundo@coautor.ejemplo.org> + Signed-off-by: Segundo coautor <segundo@coautor.ejemplo.org> + Signed-off-by: Autor del From <from@author.example.org> + +Ejemplo de un parche enviado por un Co-developed-by: autor:: + + From: Autor del From <from@author.example.org> + + <changelog> + + Co-developed-by: Co-Autor aleatorio <aleatorio@coauthor.example.org> + Signed-off-by: Coautor aleatorio <aleatorio@coauthor.example.org> + Signed-off-by: Autor del From <from@author.example.org> + Co-developed-by: Coautor que envió <sub@coauthor.example.org> + Signed-off-by: Coautor que envía <sub@coauthor.example.org> + +Uso de Reported-by:, Tested-by:, Reviewed-by:, Suggested-by: y Fixes: +---------------------------------------------------------------------- + +La etiqueta Reported-by (Reportado-por) otorga crédito a las personas que +encuentran errores y los reportan. Por favor, tenga en cuenta que si se +informó de un error en privado, debe pedir primero permiso antes de usar la +etiqueta Reported-by. La etiqueta está destinada a errores; por favor no la +use para acreditar peticiones de características. + +Una etiqueta Tested-by: indica que el parche se probó con éxito (en algún +entorno) por la persona nombrada. Esta etiqueta informa a los maintainers +de que se han realizado algunas pruebas, proporciona un medio para ubicar +"testers" (gente que pruebe) otros parches futuros y asegura el crédito +para los testers. + +Reviewed-by: en cambio, indica que el parche ha sido revisado y encontrado +aceptable de acuerdo con la Declaración del Revisor: + +Declaración de Supervisión del Revisor +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Al ofrecer mi etiqueta Reviewed-by:, afirmo que: + +(a) He llevado a cabo una revisión técnica de este parche para +evaluar su idoneidad y preparación para su inclusión en +el kernel principal. + +(b) Cualquier problema, inquietud o pregunta relacionada con el parche +han sido comunicados al remitente. Estoy satisfecho +con la respuesta del remitente a mis comentarios. + +(c) Si bien puede haber cosas que podrían mejorarse con esta +entrega, creo que es, en este momento, (1) una +modificación valiosa al kernel, y (2) libre de conocidas +cuestiones que argumentarían en contra de su inclusión. + +(d) Si bien he revisado el parche y creo que es correcto, +no hago (a menos que se indique explícitamente en otro lugar) ninguna +garantía o avales de que logrará su definido +propósito o función en cualquier situación dada. + +Una etiqueta Reviewed-by es una declaración de opinión de que el parche es +una modificación apropiada al kernel sin que haya ningún problema grave +a nivel técnico. Cualquier revisor interesado (que haya hecho el trabajo) +puede ofrecer una etiqueta Reviewed-by para un parche. Esta etiqueta sirve +para dar crédito a revisores e informar a los maintainers del grado de +revisión que se ha hecho en el parche. Las etiquetas Reviewed-by, cuando +las otorgan revisores conocidos por entender del tema y realizar +revisiones exhaustivas, normalmente aumentan la probabilidad de que su +parche entre en el kernel. + +Las etiquetas Tested-by y Reviewed-by, una vez recibidas en la lista de +correo por el tester o revisor, deben ser incluidas por el autor de los +parches pertinentes al enviar próximas versiones. Sin embargo, si el parche +ha cambiado sustancialmente en la siguiente versión, es posible que estas +etiquetas ya no sean aplicables y, por lo tanto, deben eliminarse. Por lo +general, se debe mencionar la eliminación de las etiquetas Tested-by o +Reviewed-by de alguien en el registro de cambios del parche (después del +separador '---'). + +Una etiqueta Suggested-by: indica que la idea del parche es sugerida por la +persona nombrada y asegura el crédito a la persona por la idea. Tenga en +cuenta que esto no debe agregarse sin el permiso del "reporter", +especialmente si la idea no fue publicada en un foro público. Dicho esto, +si diligentemente acreditamos a los reporters de ideas, con suerte, se +sentirán inspirados para ayudarnos nuevamente en el futuro. + +Una etiqueta Fixes: indica que el parche corrige un problema en un commit +anterior. Esto se utiliza para facilitar descubrir dónde se originó un +error, lo que puede ayudar a revisar una corrección de errores. Esta +etiqueta también ayuda al equipo del kernel estable a determinar qué +versiones estables del kernel deberían recibir su corrección. Este es el +método preferido para indicar un error corregido por el parche. Revise +:ref:`describe_changes` para más detalles. + +Nota: Adjuntar una etiqueta Fixes: no subvierte las reglas estables del +proceso del kernel ni el requisito de CC: stable@vger.kernel.org en todos +los parches candidatos de ramas estables. Para obtener más información, lea +Documentation/process/stable-kernel-rules.rst. + +.. _sp_the_canonical_patch_format: + +Formato de parche canónico +--------------------------- + +Esta sección describe cómo debe darse formato al propio parche. Tenga en +cuenta que, si tiene sus parches almacenados en un repositorio ``git``, el +parche con formato adecuado se puede obtener con ``git format-patch``. Las +herramientas no pueden crear el texto necesario, sin embargo, así que lea +las instrucciones a continuación de todos modos. + +La línea de asunto del parche canónico es:: + + Asunto: [PATCH 001/123] subsistema: frase de resumen + +El cuerpo del mensaje del parche canónico contiene lo siguiente: + + - Una línea ``from`` que especifica el autor del parche, seguida de una + línea vacía (solo es necesario si la persona que envía el parche no es + el autor). + + - El cuerpo de la explicación, línea envuelta en 75 columnas, que se + copiara en el registro de cambios permanente para describir este parche. + + - Una línea vacía. + + - Las líneas ``Signed-off-by:``, descritas anteriormente, que + también vaya en el registro de cambios. + + - Una línea de marcador que contiene simplemente ``---``. + + - Cualquier comentario adicional que no sea adecuado para el registro de + cambios. + + - El parche real (output de ``diff``). + +El formato de la línea de asunto hace que sea muy fácil ordenar los correos +electrónicos alfabéticamente por línea de asunto - prácticamente cualquier +lector de correo electrónico permite esto, ya que debido a que el número de +secuencia se rellena con ceros, el orden numérico y alfabético es el mismo. + +El ``subsistema`` en el asunto del correo electrónico debe identificar qué +área o subsistema del kernel está siendo parcheado. + +La ``frase de resumen`` en el Asunto del correo electrónico debe describir +de forma concisa el parche que contiene ese correo electrónico. La +``frase resumen`` no debe ser un nombre de archivo. No use la mismo ``frase +resumen`` para cada parche en una serie completa de parches (donde una +`` serie de parches`` (patch series) es una secuencia ordenada de múltiples +parches relacionados). + +Tenga en cuenta que la ``frase de resumen`` de su correo electrónico se +convierte en un identificador global único para ese parche. Se propaga por +hasta el registro de cambios de ``git``. La ``frase resumida`` se puede +usar más adelante en discusiones de desarrolladores que se refieran al +parche. La gente querrá buscar en Google la ``frase de resumen`` para leer +la discusión al respecto del parche. También será lo único que la gente +podrá ver rápidamente cuando, dos o tres meses después, estén pasando por +quizás miles de parches usando herramientas como ``gitk`` o ``git log +--oneline``. + +Por estas razones, el ``resumen`` no debe tener más de 70-75 caracteres, y +debe describir tanto lo que cambia el parche como por qué el parche podría +ser necesario. Es un reto ser tanto sucinto como descriptivo, pero eso es +lo que un resumen bien escrito debería hacer. + +La ``frase de resumen`` puede estar precedida por etiquetas encerradas en +corchetes: "Asunto: [PATCH <etiqueta>...] <frase de resumen>". Las +etiquetas no se consideran parte de la frase de resumen, pero describen +cómo debería ser tratado el parche. Las etiquetas comunes pueden incluir un +descriptor de versión si las múltiples versiones del parche se han enviado +en respuesta a comentarios (es decir, "v1, v2, v3") o "RFC" para indicar +una solicitud de comentarios. + +Si hay cuatro parches en una serie de parches, los parches individuales +pueden enumerarse así: 1/4, 2/4, 3/4, 4/4. Esto asegura que los +desarrolladores entiendan el orden en que se deben aplicar los parches y +que han revisado o aplicado todos los parches de la serie de parches. + +Aquí hay algunos buenos ejemplos de Asuntos:: + + Asunto: [PATCH 2/5] ext2: mejorar la escalabilidad de la búsqueda de mapas de bits + Asunto: [PATCH v2 27/01] x86: corregir el seguimiento de eflags + Asunto: [PATCH v2] sub/sys: resumen conciso del parche + Asunto: [PATCH v2 M/N] sub/sys: resumen conciso del parche + +La línea ``from`` debe ser la primera línea en el cuerpo del mensaje, +y tiene la forma:: + + From: Autor del parche <autor@ejemplo.com> + +La línea ``From`` especifica quién será acreditado como el autor del parche +en el registro de cambios permanente. Si falta la línea ``from``, entonces +la línea ``From:`` del encabezado del correo electrónico se usará para +determinar el autor del parche en el registro de cambios. + +La explicación estará incluida en el commit del changelog permanente, por +lo que debería tener sentido para un lector competente que hace mucho tiempo +ha olvidado los detalles de la discusión que podrían haber llevado a +este parche. Incluidos los síntomas del fallo que el parche trate +(mensajes de registro del kernel, mensajes de oops, etc.) son especialmente +útiles para personas que podrían estar buscando en los registros de +commits en busca de la aplicación del parche. El texto debe estar escrito +con tal detalle que cuando se lea semanas, meses o incluso años después, +pueda dar al lector la información necesaria y detalles para comprender el +razonamiento de **por qué** se creó el parche. + +Si un parche corrige una falla de compilación, puede que no sea necesario +incluir _todos_ los errores de compilación; pero lo suficiente como para +que sea probable que alguien que busque el parche puede encontrarlo. Como +en la ``frase de resumen``, es importante ser tanto sucinto como +descriptivo. + +La línea marcadora ``---`` cumple el propósito esencial de marcar para +herramientas de manejo de parches donde termina el mensaje de registro de +cambios. + +Un buen uso de los comentarios adicionales después del marcador ``---`` es +para ``diffstat``, para mostrar qué archivos han cambiado, y el número de +líneas insertadas y eliminadas por archivo. Un ``diffstat`` es +especialmente útil en parches más grandes. Si va a incluir un ``diffstat`` +después del marcador ``---``, utilice las opciones ``diffstat`` +``-p 1 -w 70`` para que los nombres de archivo se enumeran desde la parte +superior del árbol de fuentes del kernel y no use demasiado espacio +horizontal (que encaje fácilmente en 80 columnas, tal vez con alguna +indentación). (``git`` genera diffstats apropiados por defecto). + +Otros comentarios relevantes solo en el momento o para el maintainer, pero +no adecuados para el registro de cambios permanente, también debe ir aquí. +Un buen ejemplo de tales comentarios podría ser ``registros de cambios de +parches`` que describen qué ha cambiado entre la versión v1 y v2 del +parche. + +Por favor, ponga esta información **después** de la línea ``---`` que +separa el registro de cambios del resto del parche. La información de la +versión no forma parte del registro de cambios que se incluye con el árbol +git. Es información adicional para los revisores. Si se coloca encima de la +etiquetas de commit, necesita interacción manual para eliminarlo. Si esta +debajo de la línea de separación, se quita automáticamente al aplicar el +parche:: + + <mensaje de commit> + ... + Signed-off-by: Autor <autor@correo> + --- + V2 -> V3: función auxiliar redundante eliminada + V1 -> V2: estilo de código limpio y comentarios de revisión abordados + + ruta/al/archivo | 5+++-- + ... + +Revise más detalles sobre el formato de parche adecuado en las siguientes +referencias + +.. _sp_backtraces: + +Retrocesos en mensajes de confirmación +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Los "backtraces" (deshacer el camino) ayuda a documentar la cadena de +llamadas que conducen a un problema. Sin embargo, no todos los rastreos son +útiles. Por ejemplo, las tempranas cadenas de llamadas de inicio son únicas +y obvias. Sin embargo, al copiar la salida completa de dmesg textualmente, +incluye información que distrae, como marcas de tiempo, listas de módulos, +registro y volcados de pila. + +Por lo tanto, los backtraces más útiles deben contener los datos +relevantes de la información vertida, lo que hace que sea más fácil +centrarse en el verdadero tema. Este es un ejemplo de un backtrace bien +recortado:: + + error de acceso de MSR no verificado: WRMSR a 0xd51 (intentó escribir 0x0000000000000064) + en rIP: 0xffffffffae059994 (native_write_msr+0x4/0x20) + Rastreo de llamadas: + mba_wrmsr + update_domains + rdtgroup_mkdir + +.. _sp_explicit_in_reply_to: + +In-Reply-To explicitos en las cabeceras +--------------------------------------- + +Puede ser útil agregar manualmente encabezados In-Reply-To: a un parche +(por ejemplo, al usar ``git send-email``) para asociar el parche con una +discusión anterior relevante, por ejemplo para vincular una corrección de +errores al correo electrónico con el informe de errores. Sin embargo, para +una serie de parches múltiples, generalmente es mejor evitar usar +In-Reply-To: para vincular a versiones anteriores de la serie. De esta +forma, varias versiones del parche no se convierten en un inmanejable +bosque de referencias en clientes de correo electrónico. Si un enlace es +útil, puede usar el redirector https://lore.kernel.org/ (por ejemplo, en +el texto de la carta de introducción del correo electrónico) para vincular +a una versión anterior de la serie de parches. + + +Proporcionar información de árbol base +-------------------------------------- + +Cuando otros desarrolladores reciben sus parches y comienzan el proceso de +revisión, a menudo es útil para ellos saber en qué parte del historial del +árbol deben colocar su trabajo. Esto es particularmente útil para CI +automatizado de procesos que intentan ejecutar una serie de pruebas para +establecer la calidad de su envío antes de que el maintainer comience la +revisión. + +Si está utilizando ``git format-patch`` para generar sus parches, puede +incluir automáticamente la información del árbol base en su envío usando el +parámetro ``--base``. La forma más fácil y conveniente de usar esta opción +es con "topical branches" (ramas de temas):: + + $ git checkout -t -b my-topical-branch master + Branch 'my-topical-branch' set up to track local branch 'master'. + Switched to a new branch 'my-topical-branch' + + [realice sus cambios y ediciones] + + $ git format-patch --base=auto --cover-letter -o outgoing/ master + outgoing/0000-cover-letter.patch + outgoing/0001-First-Commit.patch + outgoing/... + +Cuando abra ``outgoing/0000-cover-letter.patch`` para editar, tenga en +cuenta que tendrá el tráiler ``base-commit:`` al final, que proporciona al +revisor y a las herramientas de CI suficiente información para realizar +correctamente ``git am`` sin preocuparse por los conflictos:: + + $ git checkout -b patch-review [base-commit-id] + Switched to a new branch 'patch-review' + $ git am patches.mbox + Applying: First Commit + Applying: ... + +Consulte ``man git-format-patch`` para obtener más información al respecto +de esta opción. + +.. Note:: + + La función ``--base`` se introdujo en la versión 2.9.0 de git. + +Si no está utilizando git para dar forma a sus parches, aún puede incluir +el mismo tráiler ``base-commit`` para indicar el hash de confirmación del +árbol en que se basa su trabajo. Debe agregarlo en la carta de presentación +o en el primer parche de la serie y debe colocarse ya sea bajo la línea +``---`` o en la parte inferior de todos los demás contenido, justo antes de +su firma del correo electrónico. + + +Referencias +----------- + +"The perfect patch" (tpp) por Andrew Morton. + <https://www.ozlabs.org/~akpm/stuff/tpp.txt> + +"Linux kernel patch submission format" por Jeff Garzik. + <https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html> + +"How to piss off a kernel subsystem maintainer" por Greg Kroah-Hartman. + <http://www.kroah.com/log/linux/maintainer.html> + + <http://www.kroah.com/log/linux/maintainer-02.html> + + <http://www.kroah.com/log/linux/maintainer-03.html> + + <http://www.kroah.com/log/linux/maintainer-04.html> + + <http://www.kroah.com/log/linux/maintainer-05.html> + + <http://www.kroah.com/log/linux/maintainer-06.html> + +NO!!!! Gente, no mas bombas enormes de parches a linux-kernel@vger.kernel.org! + <https://lore.kernel.org/r/20050711.125305.08322243.davem@davemloft.net> + +Kernel Documentation/process/coding-style.rst + +Email de Linus Torvalds sobre la forma canónica de los parches: + <https://lore.kernel.org/r/Pine.LNX.4.58.0504071023190.28951@ppc970.osdl.org> + +"On submitting kernel patches" por Andi Kleen + Algunas estrategias para conseguir incluir cambios complicados o + controvertidos. + + http://halobates.de/on-submitting-patches.pdf diff --git a/Documentation/translations/sp_SP/wrappers/memory-barriers.rst b/Documentation/translations/sp_SP/wrappers/memory-barriers.rst new file mode 100644 index 0000000000..50715b7d51 --- /dev/null +++ b/Documentation/translations/sp_SP/wrappers/memory-barriers.rst @@ -0,0 +1,19 @@ +.. SPDX-License-Identifier: GPL-2.0 + This is a simple wrapper to bring memory-barriers.txt (Spanish + translation) into the RST world until such a time as that file can be + converted directly. + +==================================== +Barreras de Memoria del kernel Linux +==================================== + +.. raw:: latex + + \footnotesize + +.. include:: ../memory-barriers.txt + :literal: + +.. raw:: latex + + \normalsize |