cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

volatile-considered-harmful.rst (6722B)


      1.. include:: ../disclaimer-ita.rst
      2
      3:Original: :ref:`Documentation/process/volatile-considered-harmful.rst <volatile_considered_harmful>`
      4:Translator: Federico Vaga <federico.vaga@vaga.pv.it>
      5
      6.. _it_volatile_considered_harmful:
      7
      8Perché la parola chiave "volatile" non dovrebbe essere usata
      9------------------------------------------------------------
     10
     11Spesso i programmatori C considerano volatili quelle variabili che potrebbero
     12essere cambiate al di fuori dal thread di esecuzione corrente; come risultato,
     13a volte saranno tentati dall'utilizzare *volatile* nel kernel per le
     14strutture dati condivise.  In altre parole, gli è stato insegnato ad usare
     15*volatile* come una variabile atomica di facile utilizzo, ma non è così.
     16L'uso di *volatile* nel kernel non è quasi mai corretto; questo documento ne
     17descrive le ragioni.
     18
     19Il punto chiave da capire su *volatile* è che il suo scopo è quello di
     20sopprimere le ottimizzazioni, che non è quasi mai quello che si vuole.
     21Nel kernel si devono proteggere le strutture dati condivise contro accessi
     22concorrenti e indesiderati: questa è un'attività completamente diversa.
     23Il processo di protezione contro gli accessi concorrenti indesiderati eviterà
     24anche la maggior parte dei problemi relativi all'ottimizzazione in modo più
     25efficiente.
     26
     27Come *volatile*, le primitive del kernel che rendono sicuro l'accesso ai dati
     28(spinlock, mutex, barriere di sincronizzazione, ecc) sono progettate per
     29prevenire le ottimizzazioni indesiderate.  Se vengono usate opportunamente,
     30non ci sarà bisogno di utilizzare *volatile*.  Se vi sembra che *volatile* sia
     31comunque necessario, ci dev'essere quasi sicuramente un baco da qualche parte.
     32In un pezzo di codice kernel scritto a dovere, *volatile* può solo servire a
     33rallentare le cose.
     34
     35Considerate questo tipico blocco di codice kernel::
     36
     37    spin_lock(&the_lock);
     38    do_something_on(&shared_data);
     39    do_something_else_with(&shared_data);
     40    spin_unlock(&the_lock);
     41
     42Se tutto il codice seguisse le regole di sincronizzazione, il valore di un
     43dato condiviso non potrebbe cambiare inaspettatamente mentre si trattiene un
     44lock.  Un qualsiasi altro blocco di codice che vorrà usare quel dato rimarrà
     45in attesa del lock.  Gli spinlock agiscono come barriere di sincronizzazione
     46- sono stati esplicitamente scritti per agire così - il che significa che gli
     47accessi al dato condiviso non saranno ottimizzati.  Quindi il compilatore
     48potrebbe pensare di sapere cosa ci sarà nel dato condiviso ma la chiamata
     49spin_lock(), che agisce come una barriera di sincronizzazione, gli imporrà di
     50dimenticarsi tutto ciò che sapeva su di esso.
     51
     52Se il dato condiviso fosse stato dichiarato come *volatile*, la
     53sincronizzazione rimarrebbe comunque necessaria.  Ma verrà impedito al
     54compilatore di ottimizzare gli accessi al dato anche _dentro_ alla sezione
     55critica, dove sappiamo che in realtà nessun altro può accedervi.  Mentre si
     56trattiene un lock, il dato condiviso non è *volatile*.  Quando si ha a che
     57fare con dei dati condivisi, un'opportuna sincronizzazione rende inutile
     58l'uso di *volatile* - anzi potenzialmente dannoso.
     59
     60L'uso di *volatile* fu originalmente pensato per l'accesso ai registri di I/O
     61mappati in memoria.  All'interno del kernel, l'accesso ai registri, dovrebbe
     62essere protetto dai lock, ma si potrebbe anche desiderare che il compilatore
     63non "ottimizzi" l'accesso ai registri all'interno di una sezione critica.
     64Ma, all'interno del kernel, l'accesso alla memoria di I/O viene sempre fatto
     65attraverso funzioni d'accesso; accedere alla memoria di I/O direttamente
     66con i puntatori è sconsigliato e non funziona su tutte le architetture.
     67Queste funzioni d'accesso sono scritte per evitare ottimizzazioni indesiderate,
     68quindi, di nuovo, *volatile* è inutile.
     69
     70Un'altra situazione dove qualcuno potrebbe essere tentato dall'uso di
     71*volatile*, è nel caso in cui il processore è in un'attesa attiva sul valore
     72di una variabile.  Il modo giusto di fare questo tipo di attesa è il seguente::
     73
     74    while (my_variable != what_i_want)
     75        cpu_relax();
     76
     77La chiamata cpu_relax() può ridurre il consumo di energia del processore
     78o cedere il passo ad un processore hyperthreaded gemello; funziona anche come
     79una barriera per il compilatore, quindi, ancora una volta, *volatile* non è
     80necessario.  Ovviamente, tanto per puntualizzare, le attese attive sono
     81generalmente un atto antisociale.
     82
     83Ci sono comunque alcune rare situazioni dove l'uso di *volatile* nel kernel
     84ha senso:
     85
     86  - Le funzioni d'accesso sopracitate potrebbero usare *volatile* su quelle
     87    architetture che supportano l'accesso diretto alla memoria di I/O.
     88    In pratica, ogni chiamata ad una funzione d'accesso diventa una piccola
     89    sezione critica a se stante, e garantisce che l'accesso avvenga secondo
     90    le aspettative del programmatore.
     91
     92  - I codice *inline assembly* che fa cambiamenti nella memoria, ma che non
     93    ha altri effetti espliciti, rischia di essere rimosso da GCC.  Aggiungere
     94    la parola chiave *volatile* a questo codice ne previene la rimozione.
     95
     96  - La variabile jiffies è speciale in quanto assume un valore diverso ogni
     97    volta che viene letta ma può essere lette senza alcuna sincronizzazione.
     98    Quindi jiffies può essere *volatile*, ma l'aggiunta ad altre variabili di
     99    questo è sconsigliata.  Jiffies è considerata uno "stupido retaggio"
    100    (parole di Linus) in questo contesto; correggerla non ne varrebbe la pena e
    101    causerebbe più problemi.
    102
    103  - I puntatori a delle strutture dati in una memoria coerente che potrebbe
    104    essere modificata da dispositivi di I/O può, a volte, essere legittimamente
    105    *volatile*.  Un esempio pratico può essere quello di un adattatore di rete
    106    che utilizza un puntatore ad un buffer circolare, questo viene cambiato
    107    dall'adattatore per indicare quali descrittori sono stati processati.
    108
    109Per la maggior parte del codice, nessuna delle giustificazioni sopracitate può
    110essere considerata.  Di conseguenza, l'uso di *volatile* è probabile che venga
    111visto come un baco e porterà a verifiche aggiuntive.  Gli sviluppatori tentati
    112dall'uso di *volatile* dovrebbero fermarsi e pensare a cosa vogliono davvero
    113ottenere.
    114
    115Le modifiche che rimuovono variabili *volatile* sono generalmente ben accette
    116- purché accompagnate da una giustificazione che dimostri che i problemi di
    117concorrenza siano stati opportunamente considerati.
    118
    119Riferimenti
    120===========
    121
    122[1] http://lwn.net/Articles/233481/
    123
    124[2] http://lwn.net/Articles/233482/
    125
    126Crediti
    127=======
    128
    129Impulso e ricerca originale di Randy Dunlap
    130
    131Scritto da Jonathan Corbet
    132
    133Migliorato dai commenti di Satyam Sharma, Johannes Stezenbach, Jesper
    134Juhl, Heikki Orsila, H. Peter Anvin, Philipp Hahn, e Stefan Richter.