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