1.. SPDX-License-Identifier: GPL-2.0 2 3Por que a classe de tipo "volatile" não deve ser usada 4-------------------------------------------------------- 5 6Programadores C frequentemente interpretam volatile como uma indicação de 7que uma variável pode ser alterada fora da thread de execução atual; como 8resultado, às vezes são tentados a usá-la no código do kernel quando 9estruturas de dados compartilhadas estão sendo utilizadas. Em outras 10palavras, há quem trate tipos volatile como uma espécie de variável 11atômica simplificada, mas não são. O uso de volatile no código do 12kernel quase nunca é correto; este documento explica o porquê. 13 14O ponto-chave a entender sobre volatile é que seu propósito é suprimir 15otimizações, o que quase nunca é o que realmente se deseja fazer. No kernel, 16é necessário proteger estruturas de dados compartilhadas contra acessos 17concorrentes indesejados, o que é uma tarefa bastante diferente. O processo 18de proteção contra concorrência indesejada também evita, de forma mais 19eficiente, quase todos os problemas relacionados a otimizações. 20 21Assim como volatile, as primitivas do kernel que tornam seguro o acesso 22concorrente a dados (spinlocks, mutexes, barreiras de memória etc.) são 23projetadas para evitar otimizações indesejadas. Se forem usadas 24corretamente, também não haverá necessidade de usar volatile. Se 25volatile ainda for necessário, quase certamente há algum bug no código. 26Em código de kernel corretamente escrito, volatile só serve para deixar 27as coisas mais lentas. 28 29Considere um bloco típico de código do kernel:: 30 31 spin_lock(&the_lock); 32 do_something_on(&shared_data); 33 do_something_else_with(&shared_data); 34 spin_unlock(&the_lock); 35 36Se todo o código seguir as regras de bloqueio, o valor de shared_data não 37poderá mudar inesperadamente enquanto the_lock estiver mantido. Qualquer 38outro código que queira manipular esses dados estará aguardando o bloqueio. 39As primitivas de spinlock atuam como barreiras de memória (são escritas 40explicitamente para isso), o que significa que os acessos aos dados não 41serão otimizados de forma a atravessar essas barreiras. Assim, o compilador 42até pode achar que sabe qual será o valor de shared_data, mas a chamada a 43spin_lock(), por atuar como barreira de memória, o forçará a esquecer tudo 44o que sabia. Não haverá problemas de otimização nos acessos a esses dados. 45 46Se shared_data fosse declarada volatile, o bloqueio ainda seria 47necessário. No entanto, o compilador também seria impedido de otimizar o 48acesso a shared_data _dentro_ da seção crítica, justamente quando sabemos 49que ninguém mais pode estar manipulando esses dados. Enquanto o bloqueio 50estiver mantido, shared_data não é volatile. Ao lidar com dados 51compartilhados, um bloqueio adequado torna volatile desnecessário e 52potencialmente prejudicial. 53 54A classe de armazenamento volatile foi originalmente concebida para 55registradores de E/S mapeados em memória. No kernel, os acessos a esses 56registradores também devem ser protegidos por bloqueios, mas também não se 57deseja que o compilador "otimize" esses acessos dentro de uma seção crítica. 58Contudo, no kernel, os acessos à memória de E/S são sempre feitos por meio de 59funções de acesso; acessar diretamente a memória de E/S via ponteiros é 60desencorajado e não funciona em todas as arquiteturas. Essas funções de 61acesso são implementadas de modo a impedir otimizações indesejadas e, 62portanto, mais uma vez, volatile é desnecessário. 63 64Outra situação em que se pode ser tentado a usar volatile é quando o 65processador fica em espera ocupada pelo valor de uma variável. A forma 66correta de realizar essa espera ocupada é:: 67 68 while (my_variable != what_i_want) 69 cpu_relax(); 70 71A chamada a cpu_relax() pode reduzir o consumo de energia da CPU ou ceder 72recursos a um processador lógico gêmeo hyperthreaded; ela também atua 73como barreira para o compilador e, portanto, mais uma vez, volatile é 74desnecessário. Naturalmente, a espera ocupada já é, por si só, uma prática 75geralmente antissocial. 76 77Ainda existem algumas situações raras em que volatile faz sentido no 78kernel: 79 80 - As funções de acesso mencionadas acima podem usar volatile em 81 arquiteturas nas quais o acesso direto à memória de E/S funciona. 82 Essencialmente, cada chamada a uma função de acesso torna-se uma 83 pequena seção crítica por si só e garante que o acesso ocorra conforme 84 esperado pelo programador. 85 - Código assembly inline que modifica memória, mas não tem outros 86 efeitos colaterais visíveis, corre o risco de ser removido pelo GCC. 87 Adicionar a palavra-chave volatile às instruções asm impede essa 88 remoção. 89 - A variável jiffies é especial, pois pode ter um valor diferente a cada 90 vez que é referenciada, mas pode ser lida sem qualquer bloqueio 91 especial. Portanto, jiffies pode ser volatile, mas a adição de 92 outras variáveis desse tipo é fortemente desencorajada. Nesse 93 sentido, jiffies é considerada um problema de "legado idiota" (nas 94 palavras de Linus); corrigi-la daria mais trabalho do que valeria a 95 pena. 96 - Ponteiros para estruturas de dados em memória coerente que possam ser 97 modificadas por dispositivos de E/S podem, às vezes, ser 98 legitimamente volatile. Um buffer circular usado por um adaptador 99 de rede, no qual esse adaptador altera ponteiros para indicar quais 100 descritores já foram processados, é um exemplo desse tipo de 101 situação. 102 103Na maior parte do código, nenhuma das justificativas acima para o uso de 104volatile se aplica. Como resultado, o uso de volatile provavelmente 105será considerado um bug e fará com que o código seja submetido a uma análise 106mais rigorosa. Desenvolvedores que se sintam tentados a usar volatile devem 107dar um passo atrás e pensar no que realmente estão tentando alcançar. 108 109Patches para remover variáveis volatile são, em geral, bem-vindos, desde 110que venham acompanhados de uma justificativa que demonstre que as questões 111de concorrência foram devidamente analisadas. 112 113 114Referências 115=========== 116 117[1] https://lwn.net/Articles/233481/ 118 119[2] https://lwn.net/Articles/233482/ 120 121Créditos 122======== 123 124Motivação original e pesquisa por Randy Dunlap 125 126Escrito por Jonathan Corbet 127 128Melhorias a partir de comentários de Satyam Sharma, Johannes Stezenbach, 129Jesper Juhl, Heikki Orsila, H. Peter Anvin, Philipp Hahn e Stefan 130Richter. 131