mirror of https://gitee.com/openkylin/linux.git
doc:it_IT: align Italian translation
Translation for the following patches: commitc4f4af4094
("docs: Add documentation for Symbol Namespaces") commit36bc683dde
("kernel-doc: rename the kernel-doc directive 'functions' to 'identifiers'") commita035d552a9
("Makefile: Globally enable fall-through warning") commitb9918bdcac
("Documentation/process: Add fallthrough pseudo-keyword") commit58ad30cf91
("docs: fix reference to core-api/namespaces.rst") commitfb0e0ffe7f
("Documentation: bring process docs up to date") commit7af51678b6
("docs: deprecated.rst: Add BUG()-family") commit7929b9836e
("docs: Remove :c:func: from process/deprecated.rst") commit76136e028d
("docs: deprecated.rst: Clean up fall-through details") commitd8401f504b
("docs: deprecated.rst: Add %p to the list") commitb1735296ce
("docs: locking: Drop :c:func: throughout") commit6adb775599
("docs: locking: Add 'need' to hardirq section") Signed-off-by: Federico Vaga <federico.vaga@vaga.pv.it> Link: https://lore.kernel.org/r/20200430222037.4480-1-federico.vaga@vaga.pv.it Signed-off-by: Jonathan Corbet <corbet@lwn.net>
This commit is contained in:
parent
16a398d176
commit
b67aa4ef68
|
@ -515,6 +515,22 @@ internal: *[source-pattern ...]*
|
||||||
.. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c
|
.. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c
|
||||||
:internal:
|
:internal:
|
||||||
|
|
||||||
|
identifiers: *[ function/type ...]*
|
||||||
|
Include la documentazione per ogni *function* e *type* in *source*.
|
||||||
|
Se non vengono esplicitamente specificate le funzioni da includere, allora
|
||||||
|
verranno incluse tutte quelle disponibili in *source*.
|
||||||
|
|
||||||
|
Esempi::
|
||||||
|
|
||||||
|
.. kernel-doc:: lib/bitmap.c
|
||||||
|
:identifiers: bitmap_parselist bitmap_parselist_user
|
||||||
|
|
||||||
|
.. kernel-doc:: lib/idr.c
|
||||||
|
:identifiers:
|
||||||
|
|
||||||
|
functions: *[ function ...]*
|
||||||
|
Questo è uno pseudonimo, deprecato, per la direttiva 'identifiers'.
|
||||||
|
|
||||||
doc: *title*
|
doc: *title*
|
||||||
Include la documentazione del paragrafo ``DOC:`` identificato dal titolo
|
Include la documentazione del paragrafo ``DOC:`` identificato dal titolo
|
||||||
(*title*) all'interno del file sorgente (*source*). Gli spazi in *title* sono
|
(*title*) all'interno del file sorgente (*source*). Gli spazi in *title* sono
|
||||||
|
@ -528,15 +544,6 @@ doc: *title*
|
||||||
.. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c
|
.. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c
|
||||||
:doc: High Definition Audio over HDMI and Display Port
|
:doc: High Definition Audio over HDMI and Display Port
|
||||||
|
|
||||||
functions: *function* *[...]*
|
|
||||||
Dal file sorgente (*source*) include la documentazione per le funzioni
|
|
||||||
elencate (*function*).
|
|
||||||
|
|
||||||
Esempio::
|
|
||||||
|
|
||||||
.. kernel-doc:: lib/bitmap.c
|
|
||||||
:functions: bitmap_parselist bitmap_parselist_user
|
|
||||||
|
|
||||||
Senza alcuna opzione, la direttiva kernel-doc include tutti i commenti di
|
Senza alcuna opzione, la direttiva kernel-doc include tutti i commenti di
|
||||||
documentazione presenti nel file sorgente (*source*).
|
documentazione presenti nel file sorgente (*source*).
|
||||||
|
|
||||||
|
|
|
@ -627,6 +627,24 @@ Alcuni manutentori e sviluppatori potrebbero comunque richiedere
|
||||||
:c:func:`EXPORT_SYMBOL_GPL()` quando si aggiungono nuove funzionalità o
|
:c:func:`EXPORT_SYMBOL_GPL()` quando si aggiungono nuove funzionalità o
|
||||||
interfacce.
|
interfacce.
|
||||||
|
|
||||||
|
:c:func:`EXPORT_SYMBOL_NS()`
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Definita in ``include/linux/export.h``
|
||||||
|
|
||||||
|
Questa è una variate di `EXPORT_SYMBOL()` che permette di specificare uno
|
||||||
|
spazio dei nomi. Lo spazio dei nomi è documentato in
|
||||||
|
:doc:`../core-api/symbol-namespaces`
|
||||||
|
|
||||||
|
:c:func:`EXPORT_SYMBOL_NS_GPL()`
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
Definita in ``include/linux/export.h``
|
||||||
|
|
||||||
|
Questa è una variate di `EXPORT_SYMBOL_GPL()` che permette di specificare uno
|
||||||
|
spazio dei nomi. Lo spazio dei nomi è documentato in
|
||||||
|
:doc:`../core-api/symbol-namespaces`
|
||||||
|
|
||||||
Procedure e convenzioni
|
Procedure e convenzioni
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
|
|
|
@ -159,17 +159,17 @@ Sincronizzazione in contesto utente
|
||||||
Se avete una struttura dati che verrà utilizzata solo dal contesto utente,
|
Se avete una struttura dati che verrà utilizzata solo dal contesto utente,
|
||||||
allora, per proteggerla, potete utilizzare un semplice mutex
|
allora, per proteggerla, potete utilizzare un semplice mutex
|
||||||
(``include/linux/mutex.h``). Questo è il caso più semplice: inizializzate il
|
(``include/linux/mutex.h``). Questo è il caso più semplice: inizializzate il
|
||||||
mutex; invocate :c:func:`mutex_lock_interruptible()` per trattenerlo e
|
mutex; invocate mutex_lock_interruptible() per trattenerlo e
|
||||||
:c:func:`mutex_unlock()` per rilasciarlo. C'è anche :c:func:`mutex_lock()`
|
mutex_unlock() per rilasciarlo. C'è anche mutex_lock()
|
||||||
ma questa dovrebbe essere evitata perché non ritorna in caso di segnali.
|
ma questa dovrebbe essere evitata perché non ritorna in caso di segnali.
|
||||||
|
|
||||||
Per esempio: ``net/netfilter/nf_sockopt.c`` permette la registrazione
|
Per esempio: ``net/netfilter/nf_sockopt.c`` permette la registrazione
|
||||||
di nuove chiamate per :c:func:`setsockopt()` e :c:func:`getsockopt()`
|
di nuove chiamate per setsockopt() e getsockopt()
|
||||||
usando la funzione :c:func:`nf_register_sockopt()`. La registrazione e
|
usando la funzione nf_register_sockopt(). La registrazione e
|
||||||
la rimozione vengono eseguite solamente quando il modulo viene caricato
|
la rimozione vengono eseguite solamente quando il modulo viene caricato
|
||||||
o scaricato (e durante l'avvio del sistema, qui non abbiamo concorrenza),
|
o scaricato (e durante l'avvio del sistema, qui non abbiamo concorrenza),
|
||||||
e la lista delle funzioni registrate viene consultata solamente quando
|
e la lista delle funzioni registrate viene consultata solamente quando
|
||||||
:c:func:`setsockopt()` o :c:func:`getsockopt()` sono sconosciute al sistema.
|
setsockopt() o getsockopt() sono sconosciute al sistema.
|
||||||
In questo caso ``nf_sockopt_mutex`` è perfetto allo scopo, in particolar modo
|
In questo caso ``nf_sockopt_mutex`` è perfetto allo scopo, in particolar modo
|
||||||
visto che setsockopt e getsockopt potrebbero dormire.
|
visto che setsockopt e getsockopt potrebbero dormire.
|
||||||
|
|
||||||
|
@ -179,19 +179,19 @@ Sincronizzazione fra il contesto utente e i softirq
|
||||||
Se un softirq condivide dati col contesto utente, avete due problemi.
|
Se un softirq condivide dati col contesto utente, avete due problemi.
|
||||||
Primo, il contesto utente corrente potrebbe essere interroto da un softirq,
|
Primo, il contesto utente corrente potrebbe essere interroto da un softirq,
|
||||||
e secondo, la sezione critica potrebbe essere eseguita da un altro
|
e secondo, la sezione critica potrebbe essere eseguita da un altro
|
||||||
processore. Questo è quando :c:func:`spin_lock_bh()`
|
processore. Questo è quando spin_lock_bh()
|
||||||
(``include/linux/spinlock.h``) viene utilizzato. Questo disabilita i softirq
|
(``include/linux/spinlock.h``) viene utilizzato. Questo disabilita i softirq
|
||||||
sul processore e trattiene il *lock*. Invece, :c:func:`spin_unlock_bh()` fa
|
sul processore e trattiene il *lock*. Invece, spin_unlock_bh() fa
|
||||||
l'opposto. (Il suffisso '_bh' è un residuo storico che fa riferimento al
|
l'opposto. (Il suffisso '_bh' è un residuo storico che fa riferimento al
|
||||||
"Bottom Halves", il vecchio nome delle interruzioni software. In un mondo
|
"Bottom Halves", il vecchio nome delle interruzioni software. In un mondo
|
||||||
perfetto questa funzione si chiamerebbe 'spin_lock_softirq()').
|
perfetto questa funzione si chiamerebbe 'spin_lock_softirq()').
|
||||||
|
|
||||||
Da notare che in questo caso potete utilizzare anche :c:func:`spin_lock_irq()`
|
Da notare che in questo caso potete utilizzare anche spin_lock_irq()
|
||||||
o :c:func:`spin_lock_irqsave()`, queste fermano anche le interruzioni hardware:
|
o spin_lock_irqsave(), queste fermano anche le interruzioni hardware:
|
||||||
vedere :ref:`Contesto di interruzione hardware <it_hardirq-context>`.
|
vedere :ref:`Contesto di interruzione hardware <it_hardirq-context>`.
|
||||||
|
|
||||||
Questo funziona alla perfezione anche sui sistemi monoprocessore: gli spinlock
|
Questo funziona alla perfezione anche sui sistemi monoprocessore: gli spinlock
|
||||||
svaniscono e questa macro diventa semplicemente :c:func:`local_bh_disable()`
|
svaniscono e questa macro diventa semplicemente local_bh_disable()
|
||||||
(``include/linux/interrupt.h``), la quale impedisce ai softirq d'essere
|
(``include/linux/interrupt.h``), la quale impedisce ai softirq d'essere
|
||||||
eseguiti.
|
eseguiti.
|
||||||
|
|
||||||
|
@ -224,8 +224,8 @@ Differenti tasklet/timer
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Se un altro tasklet/timer vuole condividere dati col vostro tasklet o timer,
|
Se un altro tasklet/timer vuole condividere dati col vostro tasklet o timer,
|
||||||
allora avrete bisogno entrambe di :c:func:`spin_lock()` e
|
allora avrete bisogno entrambe di spin_lock() e
|
||||||
:c:func:`spin_unlock()`. Qui :c:func:`spin_lock_bh()` è inutile, siete già
|
spin_unlock(). Qui spin_lock_bh() è inutile, siete già
|
||||||
in un tasklet ed avete la garanzia che nessun altro verrà eseguito sullo
|
in un tasklet ed avete la garanzia che nessun altro verrà eseguito sullo
|
||||||
stesso processore.
|
stesso processore.
|
||||||
|
|
||||||
|
@ -243,13 +243,13 @@ processore (vedere :ref:`Dati per processore <it_per-cpu>`). Se siete arrivati
|
||||||
fino a questo punto nell'uso dei softirq, probabilmente tenete alla scalabilità
|
fino a questo punto nell'uso dei softirq, probabilmente tenete alla scalabilità
|
||||||
delle prestazioni abbastanza da giustificarne la complessità aggiuntiva.
|
delle prestazioni abbastanza da giustificarne la complessità aggiuntiva.
|
||||||
|
|
||||||
Dovete utilizzare :c:func:`spin_lock()` e :c:func:`spin_unlock()` per
|
Dovete utilizzare spin_lock() e spin_unlock() per
|
||||||
proteggere i dati condivisi.
|
proteggere i dati condivisi.
|
||||||
|
|
||||||
Diversi Softirqs
|
Diversi Softirqs
|
||||||
~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Dovete utilizzare :c:func:`spin_lock()` e :c:func:`spin_unlock()` per
|
Dovete utilizzare spin_lock() e spin_unlock() per
|
||||||
proteggere i dati condivisi, che siano timer, tasklet, diversi softirq o
|
proteggere i dati condivisi, che siano timer, tasklet, diversi softirq o
|
||||||
lo stesso o altri softirq: uno qualsiasi di essi potrebbe essere in esecuzione
|
lo stesso o altri softirq: uno qualsiasi di essi potrebbe essere in esecuzione
|
||||||
su un diverso processore.
|
su un diverso processore.
|
||||||
|
@ -270,40 +270,40 @@ Se un gestore di interruzioni hardware condivide dati con un softirq, allora
|
||||||
avrete due preoccupazioni. Primo, il softirq può essere interrotto da
|
avrete due preoccupazioni. Primo, il softirq può essere interrotto da
|
||||||
un'interruzione hardware, e secondo, la sezione critica potrebbe essere
|
un'interruzione hardware, e secondo, la sezione critica potrebbe essere
|
||||||
eseguita da un'interruzione hardware su un processore diverso. Questo è il caso
|
eseguita da un'interruzione hardware su un processore diverso. Questo è il caso
|
||||||
dove :c:func:`spin_lock_irq()` viene utilizzato. Disabilita le interruzioni
|
dove spin_lock_irq() viene utilizzato. Disabilita le interruzioni
|
||||||
sul processore che l'esegue, poi trattiene il lock. :c:func:`spin_unlock_irq()`
|
sul processore che l'esegue, poi trattiene il lock. spin_unlock_irq()
|
||||||
fa l'opposto.
|
fa l'opposto.
|
||||||
|
|
||||||
Il gestore d'interruzione hardware non usa :c:func:`spin_lock_irq()` perché
|
Il gestore d'interruzione hardware non ha bisogno di usare spin_lock_irq()
|
||||||
i softirq non possono essere eseguiti quando il gestore d'interruzione hardware
|
perché i softirq non possono essere eseguiti quando il gestore d'interruzione
|
||||||
è in esecuzione: per questo si può usare :c:func:`spin_lock()`, che è un po'
|
hardware è in esecuzione: per questo si può usare spin_lock(), che è un po'
|
||||||
più veloce. L'unica eccezione è quando un altro gestore d'interruzioni
|
più veloce. L'unica eccezione è quando un altro gestore d'interruzioni
|
||||||
hardware utilizza lo stesso *lock*: :c:func:`spin_lock_irq()` impedirà a questo
|
hardware utilizza lo stesso *lock*: spin_lock_irq() impedirà a questo
|
||||||
secondo gestore di interrompere quello in esecuzione.
|
secondo gestore di interrompere quello in esecuzione.
|
||||||
|
|
||||||
Questo funziona alla perfezione anche sui sistemi monoprocessore: gli spinlock
|
Questo funziona alla perfezione anche sui sistemi monoprocessore: gli spinlock
|
||||||
svaniscono e questa macro diventa semplicemente :c:func:`local_irq_disable()`
|
svaniscono e questa macro diventa semplicemente local_irq_disable()
|
||||||
(``include/asm/smp.h``), la quale impedisce a softirq/tasklet/BH d'essere
|
(``include/asm/smp.h``), la quale impedisce a softirq/tasklet/BH d'essere
|
||||||
eseguiti.
|
eseguiti.
|
||||||
|
|
||||||
:c:func:`spin_lock_irqsave()` (``include/linux/spinlock.h``) è una variante che
|
spin_lock_irqsave() (``include/linux/spinlock.h``) è una variante che
|
||||||
salva lo stato delle interruzioni in una variabile, questa verrà poi passata
|
salva lo stato delle interruzioni in una variabile, questa verrà poi passata
|
||||||
a :c:func:`spin_unlock_irqrestore()`. Questo significa che lo stesso codice
|
a spin_unlock_irqrestore(). Questo significa che lo stesso codice
|
||||||
potrà essere utilizzato in un'interruzione hardware (dove le interruzioni sono
|
potrà essere utilizzato in un'interruzione hardware (dove le interruzioni sono
|
||||||
già disabilitate) e in un softirq (dove la disabilitazione delle interruzioni
|
già disabilitate) e in un softirq (dove la disabilitazione delle interruzioni
|
||||||
è richiesta).
|
è richiesta).
|
||||||
|
|
||||||
Da notare che i softirq (e quindi tasklet e timer) sono eseguiti al ritorno
|
Da notare che i softirq (e quindi tasklet e timer) sono eseguiti al ritorno
|
||||||
da un'interruzione hardware, quindi :c:func:`spin_lock_irq()` interrompe
|
da un'interruzione hardware, quindi spin_lock_irq() interrompe
|
||||||
anche questi. Tenuto conto di questo si può dire che
|
anche questi. Tenuto conto di questo si può dire che
|
||||||
:c:func:`spin_lock_irqsave()` è la funzione di sincronizzazione più generica
|
spin_lock_irqsave() è la funzione di sincronizzazione più generica
|
||||||
e potente.
|
e potente.
|
||||||
|
|
||||||
Sincronizzazione fra due gestori d'interruzioni hardware
|
Sincronizzazione fra due gestori d'interruzioni hardware
|
||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
|
|
||||||
Condividere dati fra due gestori di interruzione hardware è molto raro, ma se
|
Condividere dati fra due gestori di interruzione hardware è molto raro, ma se
|
||||||
succede, dovreste usare :c:func:`spin_lock_irqsave()`: è una specificità
|
succede, dovreste usare spin_lock_irqsave(): è una specificità
|
||||||
dell'architettura il fatto che tutte le interruzioni vengano interrotte
|
dell'architettura il fatto che tutte le interruzioni vengano interrotte
|
||||||
quando si eseguono di gestori di interruzioni.
|
quando si eseguono di gestori di interruzioni.
|
||||||
|
|
||||||
|
@ -317,11 +317,11 @@ Pete Zaitcev ci offre il seguente riassunto:
|
||||||
il mutex e dormire (``copy_from_user*(`` o ``kmalloc(x,GFP_KERNEL)``).
|
il mutex e dormire (``copy_from_user*(`` o ``kmalloc(x,GFP_KERNEL)``).
|
||||||
|
|
||||||
- Altrimenti (== i dati possono essere manipolati da un'interruzione) usate
|
- Altrimenti (== i dati possono essere manipolati da un'interruzione) usate
|
||||||
:c:func:`spin_lock_irqsave()` e :c:func:`spin_unlock_irqrestore()`.
|
spin_lock_irqsave() e spin_unlock_irqrestore().
|
||||||
|
|
||||||
- Evitate di trattenere uno spinlock per più di 5 righe di codice incluse
|
- Evitate di trattenere uno spinlock per più di 5 righe di codice incluse
|
||||||
le chiamate a funzione (ad eccezione di quell per l'accesso come
|
le chiamate a funzione (ad eccezione di quell per l'accesso come
|
||||||
:c:func:`readb()`).
|
readb()).
|
||||||
|
|
||||||
Tabella dei requisiti minimi
|
Tabella dei requisiti minimi
|
||||||
----------------------------
|
----------------------------
|
||||||
|
@ -334,7 +334,7 @@ processore alla volta, ma se deve condividere dati con un altro thread, allora
|
||||||
la sincronizzazione è necessaria).
|
la sincronizzazione è necessaria).
|
||||||
|
|
||||||
Ricordatevi il suggerimento qui sopra: potete sempre usare
|
Ricordatevi il suggerimento qui sopra: potete sempre usare
|
||||||
:c:func:`spin_lock_irqsave()`, che è un sovrainsieme di tutte le altre funzioni
|
spin_lock_irqsave(), che è un sovrainsieme di tutte le altre funzioni
|
||||||
per spinlock.
|
per spinlock.
|
||||||
|
|
||||||
============== ============= ============= ========= ========= ========= ========= ======= ======= ============== ==============
|
============== ============= ============= ========= ========= ========= ========= ======= ======= ============== ==============
|
||||||
|
@ -378,13 +378,13 @@ protetti dal *lock* quando qualche altro thread lo sta già facendo
|
||||||
trattenendo il *lock*. Potrete acquisire il *lock* più tardi se vi
|
trattenendo il *lock*. Potrete acquisire il *lock* più tardi se vi
|
||||||
serve accedere ai dati protetti da questo *lock*.
|
serve accedere ai dati protetti da questo *lock*.
|
||||||
|
|
||||||
La funzione :c:func:`spin_trylock()` non ritenta di acquisire il *lock*,
|
La funzione spin_trylock() non ritenta di acquisire il *lock*,
|
||||||
se ci riesce al primo colpo ritorna un valore diverso da zero, altrimenti
|
se ci riesce al primo colpo ritorna un valore diverso da zero, altrimenti
|
||||||
se fallisce ritorna 0. Questa funzione può essere utilizzata in un qualunque
|
se fallisce ritorna 0. Questa funzione può essere utilizzata in un qualunque
|
||||||
contesto, ma come :c:func:`spin_lock()`: dovete disabilitare i contesti che
|
contesto, ma come spin_lock(): dovete disabilitare i contesti che
|
||||||
potrebbero interrompervi e quindi trattenere lo spinlock.
|
potrebbero interrompervi e quindi trattenere lo spinlock.
|
||||||
|
|
||||||
La funzione :c:func:`mutex_trylock()` invece di sospendere il vostro processo
|
La funzione mutex_trylock() invece di sospendere il vostro processo
|
||||||
ritorna un valore diverso da zero se è possibile trattenere il lock al primo
|
ritorna un valore diverso da zero se è possibile trattenere il lock al primo
|
||||||
colpo, altrimenti se fallisce ritorna 0. Nonostante non dorma, questa funzione
|
colpo, altrimenti se fallisce ritorna 0. Nonostante non dorma, questa funzione
|
||||||
non può essere usata in modo sicuro in contesti di interruzione hardware o
|
non può essere usata in modo sicuro in contesti di interruzione hardware o
|
||||||
|
@ -506,7 +506,7 @@ della memoria che il suo contenuto sono protetti dal *lock*. Questo
|
||||||
caso è semplice dato che copiamo i dati dall'utente e non permettiamo
|
caso è semplice dato che copiamo i dati dall'utente e non permettiamo
|
||||||
mai loro di accedere direttamente agli oggetti.
|
mai loro di accedere direttamente agli oggetti.
|
||||||
|
|
||||||
C'è una piccola ottimizzazione qui: nella funzione :c:func:`cache_add()`
|
C'è una piccola ottimizzazione qui: nella funzione cache_add()
|
||||||
impostiamo i campi dell'oggetto prima di acquisire il *lock*. Questo è
|
impostiamo i campi dell'oggetto prima di acquisire il *lock*. Questo è
|
||||||
sicuro perché nessun altro potrà accedervi finché non lo inseriremo
|
sicuro perché nessun altro potrà accedervi finché non lo inseriremo
|
||||||
nella memoria.
|
nella memoria.
|
||||||
|
@ -514,7 +514,7 @@ nella memoria.
|
||||||
Accesso dal contesto utente
|
Accesso dal contesto utente
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
Ora consideriamo il caso in cui :c:func:`cache_find()` può essere invocata
|
Ora consideriamo il caso in cui cache_find() può essere invocata
|
||||||
dal contesto d'interruzione: sia hardware che software. Un esempio potrebbe
|
dal contesto d'interruzione: sia hardware che software. Un esempio potrebbe
|
||||||
essere un timer che elimina oggetti dalla memoria.
|
essere un timer che elimina oggetti dalla memoria.
|
||||||
|
|
||||||
|
@ -583,15 +583,15 @@ sono quelle rimosse, mentre quelle ``+`` sono quelle aggiunte.
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Da notare che :c:func:`spin_lock_irqsave()` disabiliterà le interruzioni
|
Da notare che spin_lock_irqsave() disabiliterà le interruzioni
|
||||||
se erano attive, altrimenti non farà niente (quando siamo già in un contesto
|
se erano attive, altrimenti non farà niente (quando siamo già in un contesto
|
||||||
d'interruzione); dunque queste funzioni possono essere chiamante in
|
d'interruzione); dunque queste funzioni possono essere chiamante in
|
||||||
sicurezza da qualsiasi contesto.
|
sicurezza da qualsiasi contesto.
|
||||||
|
|
||||||
Sfortunatamente, :c:func:`cache_add()` invoca :c:func:`kmalloc()` con
|
Sfortunatamente, cache_add() invoca kmalloc() con
|
||||||
l'opzione ``GFP_KERNEL`` che è permessa solo in contesto utente. Ho supposto
|
l'opzione ``GFP_KERNEL`` che è permessa solo in contesto utente. Ho supposto
|
||||||
che :c:func:`cache_add()` venga chiamata dal contesto utente, altrimenti
|
che cache_add() venga chiamata dal contesto utente, altrimenti
|
||||||
questa opzione deve diventare un parametro di :c:func:`cache_add()`.
|
questa opzione deve diventare un parametro di cache_add().
|
||||||
|
|
||||||
Esporre gli oggetti al di fuori del file
|
Esporre gli oggetti al di fuori del file
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
@ -610,7 +610,7 @@ Il secondo problema è il problema del ciclo di vita: se un'altra struttura
|
||||||
mantiene un puntatore ad un oggetto, presumibilmente si aspetta che questo
|
mantiene un puntatore ad un oggetto, presumibilmente si aspetta che questo
|
||||||
puntatore rimanga valido. Sfortunatamente, questo è garantito solo mentre
|
puntatore rimanga valido. Sfortunatamente, questo è garantito solo mentre
|
||||||
si trattiene il *lock*, altrimenti qualcuno potrebbe chiamare
|
si trattiene il *lock*, altrimenti qualcuno potrebbe chiamare
|
||||||
:c:func:`cache_delete()` o peggio, aggiungere un oggetto che riutilizza lo
|
cache_delete() o peggio, aggiungere un oggetto che riutilizza lo
|
||||||
stesso indirizzo.
|
stesso indirizzo.
|
||||||
|
|
||||||
Dato che c'è un solo *lock*, non potete trattenerlo a vita: altrimenti
|
Dato che c'è un solo *lock*, non potete trattenerlo a vita: altrimenti
|
||||||
|
@ -710,9 +710,9 @@ Ecco il codice::
|
||||||
}
|
}
|
||||||
|
|
||||||
Abbiamo incapsulato il contatore di riferimenti nelle tipiche funzioni
|
Abbiamo incapsulato il contatore di riferimenti nelle tipiche funzioni
|
||||||
di 'get' e 'put'. Ora possiamo ritornare l'oggetto da :c:func:`cache_find()`
|
di 'get' e 'put'. Ora possiamo ritornare l'oggetto da cache_find()
|
||||||
col vantaggio che l'utente può dormire trattenendo l'oggetto (per esempio,
|
col vantaggio che l'utente può dormire trattenendo l'oggetto (per esempio,
|
||||||
:c:func:`copy_to_user()` per copiare il nome verso lo spazio utente).
|
copy_to_user() per copiare il nome verso lo spazio utente).
|
||||||
|
|
||||||
Un altro punto da notare è che ho detto che il contatore dovrebbe incrementarsi
|
Un altro punto da notare è che ho detto che il contatore dovrebbe incrementarsi
|
||||||
per ogni puntatore ad un oggetto: quindi il contatore di riferimenti è 1
|
per ogni puntatore ad un oggetto: quindi il contatore di riferimenti è 1
|
||||||
|
@ -727,8 +727,8 @@ Ci sono un certo numbero di operazioni atomiche definite
|
||||||
in ``include/asm/atomic.h``: queste sono garantite come atomiche su qualsiasi
|
in ``include/asm/atomic.h``: queste sono garantite come atomiche su qualsiasi
|
||||||
processore del sistema, quindi non sono necessari i *lock*. In questo caso è
|
processore del sistema, quindi non sono necessari i *lock*. In questo caso è
|
||||||
più semplice rispetto all'uso degli spinlock, benché l'uso degli spinlock
|
più semplice rispetto all'uso degli spinlock, benché l'uso degli spinlock
|
||||||
sia più elegante per casi non banali. Le funzioni :c:func:`atomic_inc()` e
|
sia più elegante per casi non banali. Le funzioni atomic_inc() e
|
||||||
:c:func:`atomic_dec_and_test()` vengono usate al posto dei tipici operatori di
|
atomic_dec_and_test() vengono usate al posto dei tipici operatori di
|
||||||
incremento e decremento, e i *lock* non sono più necessari per proteggere il
|
incremento e decremento, e i *lock* non sono più necessari per proteggere il
|
||||||
contatore stesso.
|
contatore stesso.
|
||||||
|
|
||||||
|
@ -820,7 +820,7 @@ al nome di cambiare abbiamo tre possibilità:
|
||||||
- Si può togliere static da ``cache_lock`` e dire agli utenti che devono
|
- Si può togliere static da ``cache_lock`` e dire agli utenti che devono
|
||||||
trattenere il *lock* prima di modificare il nome di un oggetto.
|
trattenere il *lock* prima di modificare il nome di un oggetto.
|
||||||
|
|
||||||
- Si può fornire una funzione :c:func:`cache_obj_rename()` che prende il
|
- Si può fornire una funzione cache_obj_rename() che prende il
|
||||||
*lock* e cambia il nome per conto del chiamante; si dirà poi agli utenti
|
*lock* e cambia il nome per conto del chiamante; si dirà poi agli utenti
|
||||||
di usare questa funzione.
|
di usare questa funzione.
|
||||||
|
|
||||||
|
@ -878,11 +878,11 @@ Da notare che ho deciso che il contatore di popolarità dovesse essere
|
||||||
protetto da ``cache_lock`` piuttosto che dal *lock* dell'oggetto; questo
|
protetto da ``cache_lock`` piuttosto che dal *lock* dell'oggetto; questo
|
||||||
perché è logicamente parte dell'infrastruttura (come
|
perché è logicamente parte dell'infrastruttura (come
|
||||||
:c:type:`struct list_head <list_head>` nell'oggetto). In questo modo,
|
:c:type:`struct list_head <list_head>` nell'oggetto). In questo modo,
|
||||||
in :c:func:`__cache_add()`, non ho bisogno di trattenere il *lock* di ogni
|
in __cache_add(), non ho bisogno di trattenere il *lock* di ogni
|
||||||
oggetto mentre si cerca il meno popolare.
|
oggetto mentre si cerca il meno popolare.
|
||||||
|
|
||||||
Ho anche deciso che il campo id è immutabile, quindi non ho bisogno di
|
Ho anche deciso che il campo id è immutabile, quindi non ho bisogno di
|
||||||
trattenere il lock dell'oggetto quando si usa :c:func:`__cache_find()`
|
trattenere il lock dell'oggetto quando si usa __cache_find()
|
||||||
per leggere questo campo; il *lock* dell'oggetto è usato solo dal chiamante
|
per leggere questo campo; il *lock* dell'oggetto è usato solo dal chiamante
|
||||||
che vuole leggere o scrivere il campo name.
|
che vuole leggere o scrivere il campo name.
|
||||||
|
|
||||||
|
@ -907,7 +907,7 @@ Questo è facile da diagnosticare: non è uno di quei problemi che ti tengono
|
||||||
sveglio 5 notti a parlare da solo.
|
sveglio 5 notti a parlare da solo.
|
||||||
|
|
||||||
Un caso un pochino più complesso; immaginate d'avere una spazio condiviso
|
Un caso un pochino più complesso; immaginate d'avere una spazio condiviso
|
||||||
fra un softirq ed il contesto utente. Se usate :c:func:`spin_lock()` per
|
fra un softirq ed il contesto utente. Se usate spin_lock() per
|
||||||
proteggerlo, il contesto utente potrebbe essere interrotto da un softirq
|
proteggerlo, il contesto utente potrebbe essere interrotto da un softirq
|
||||||
mentre trattiene il lock, da qui il softirq rimarrà in attesa attiva provando
|
mentre trattiene il lock, da qui il softirq rimarrà in attesa attiva provando
|
||||||
ad acquisire il *lock* già trattenuto nel contesto utente.
|
ad acquisire il *lock* già trattenuto nel contesto utente.
|
||||||
|
@ -1006,12 +1006,12 @@ potreste fare come segue::
|
||||||
spin_unlock_bh(&list_lock);
|
spin_unlock_bh(&list_lock);
|
||||||
|
|
||||||
Primo o poi, questo esploderà su un sistema multiprocessore perché un
|
Primo o poi, questo esploderà su un sistema multiprocessore perché un
|
||||||
temporizzatore potrebbe essere già partiro prima di :c:func:`spin_lock_bh()`,
|
temporizzatore potrebbe essere già partiro prima di spin_lock_bh(),
|
||||||
e prenderà il *lock* solo dopo :c:func:`spin_unlock_bh()`, e cercherà
|
e prenderà il *lock* solo dopo spin_unlock_bh(), e cercherà
|
||||||
di eliminare il suo oggetto (che però è già stato eliminato).
|
di eliminare il suo oggetto (che però è già stato eliminato).
|
||||||
|
|
||||||
Questo può essere evitato controllando il valore di ritorno di
|
Questo può essere evitato controllando il valore di ritorno di
|
||||||
:c:func:`del_timer()`: se ritorna 1, il temporizzatore è stato già
|
del_timer(): se ritorna 1, il temporizzatore è stato già
|
||||||
rimosso. Se 0, significa (in questo caso) che il temporizzatore è in
|
rimosso. Se 0, significa (in questo caso) che il temporizzatore è in
|
||||||
esecuzione, quindi possiamo fare come segue::
|
esecuzione, quindi possiamo fare come segue::
|
||||||
|
|
||||||
|
@ -1032,9 +1032,9 @@ esecuzione, quindi possiamo fare come segue::
|
||||||
spin_unlock_bh(&list_lock);
|
spin_unlock_bh(&list_lock);
|
||||||
|
|
||||||
Un altro problema è l'eliminazione dei temporizzatori che si riavviano
|
Un altro problema è l'eliminazione dei temporizzatori che si riavviano
|
||||||
da soli (chiamando :c:func:`add_timer()` alla fine della loro esecuzione).
|
da soli (chiamando add_timer() alla fine della loro esecuzione).
|
||||||
Dato che questo è un problema abbastanza comune con una propensione
|
Dato che questo è un problema abbastanza comune con una propensione
|
||||||
alle corse critiche, dovreste usare :c:func:`del_timer_sync()`
|
alle corse critiche, dovreste usare del_timer_sync()
|
||||||
(``include/linux/timer.h``) per gestire questo caso. Questa ritorna il
|
(``include/linux/timer.h``) per gestire questo caso. Questa ritorna il
|
||||||
numero di volte che il temporizzatore è stato interrotto prima che
|
numero di volte che il temporizzatore è stato interrotto prima che
|
||||||
fosse in grado di fermarlo senza che si riavviasse.
|
fosse in grado di fermarlo senza che si riavviasse.
|
||||||
|
@ -1116,7 +1116,7 @@ chiamata ``list``::
|
||||||
wmb();
|
wmb();
|
||||||
list->next = new;
|
list->next = new;
|
||||||
|
|
||||||
La funzione :c:func:`wmb()` è una barriera di sincronizzazione delle
|
La funzione wmb() è una barriera di sincronizzazione delle
|
||||||
scritture. Questa garantisce che la prima operazione (impostare l'elemento
|
scritture. Questa garantisce che la prima operazione (impostare l'elemento
|
||||||
``next`` del nuovo elemento) venga completata e vista da tutti i processori
|
``next`` del nuovo elemento) venga completata e vista da tutti i processori
|
||||||
prima che venga eseguita la seconda operazione (che sarebbe quella di mettere
|
prima che venga eseguita la seconda operazione (che sarebbe quella di mettere
|
||||||
|
@ -1127,7 +1127,7 @@ completamente il nuovo elemento; oppure che lo vedano correttamente e quindi
|
||||||
il puntatore ``next`` deve puntare al resto della lista.
|
il puntatore ``next`` deve puntare al resto della lista.
|
||||||
|
|
||||||
Fortunatamente, c'è una funzione che fa questa operazione sulle liste
|
Fortunatamente, c'è una funzione che fa questa operazione sulle liste
|
||||||
:c:type:`struct list_head <list_head>`: :c:func:`list_add_rcu()`
|
:c:type:`struct list_head <list_head>`: list_add_rcu()
|
||||||
(``include/linux/list.h``).
|
(``include/linux/list.h``).
|
||||||
|
|
||||||
Rimuovere un elemento dalla lista è anche più facile: sostituiamo il puntatore
|
Rimuovere un elemento dalla lista è anche più facile: sostituiamo il puntatore
|
||||||
|
@ -1138,7 +1138,7 @@ l'elemento o lo salteranno.
|
||||||
|
|
||||||
list->next = old->next;
|
list->next = old->next;
|
||||||
|
|
||||||
La funzione :c:func:`list_del_rcu()` (``include/linux/list.h``) fa esattamente
|
La funzione list_del_rcu() (``include/linux/list.h``) fa esattamente
|
||||||
questo (la versione normale corrompe il vecchio oggetto, e non vogliamo che
|
questo (la versione normale corrompe il vecchio oggetto, e non vogliamo che
|
||||||
accada).
|
accada).
|
||||||
|
|
||||||
|
@ -1146,9 +1146,9 @@ Anche i lettori devono stare attenti: alcuni processori potrebbero leggere
|
||||||
attraverso il puntatore ``next`` il contenuto dell'elemento successivo
|
attraverso il puntatore ``next`` il contenuto dell'elemento successivo
|
||||||
troppo presto, ma non accorgersi che il contenuto caricato è sbagliato quando
|
troppo presto, ma non accorgersi che il contenuto caricato è sbagliato quando
|
||||||
il puntatore ``next`` viene modificato alla loro spalle. Ancora una volta
|
il puntatore ``next`` viene modificato alla loro spalle. Ancora una volta
|
||||||
c'è una funzione che viene in vostro aiuto :c:func:`list_for_each_entry_rcu()`
|
c'è una funzione che viene in vostro aiuto list_for_each_entry_rcu()
|
||||||
(``include/linux/list.h``). Ovviamente, gli scrittori possono usare
|
(``include/linux/list.h``). Ovviamente, gli scrittori possono usare
|
||||||
:c:func:`list_for_each_entry()` dato che non ci possono essere due scrittori
|
list_for_each_entry() dato che non ci possono essere due scrittori
|
||||||
in contemporanea.
|
in contemporanea.
|
||||||
|
|
||||||
Il nostro ultimo dilemma è il seguente: quando possiamo realmente distruggere
|
Il nostro ultimo dilemma è il seguente: quando possiamo realmente distruggere
|
||||||
|
@ -1156,15 +1156,15 @@ l'elemento rimosso? Ricordate, un lettore potrebbe aver avuto accesso a questo
|
||||||
elemento proprio ora: se eliminiamo questo elemento ed il puntatore ``next``
|
elemento proprio ora: se eliminiamo questo elemento ed il puntatore ``next``
|
||||||
cambia, il lettore salterà direttamente nella spazzatura e scoppierà. Dobbiamo
|
cambia, il lettore salterà direttamente nella spazzatura e scoppierà. Dobbiamo
|
||||||
aspettare finché tutti i lettori che stanno attraversando la lista abbiano
|
aspettare finché tutti i lettori che stanno attraversando la lista abbiano
|
||||||
finito. Utilizziamo :c:func:`call_rcu()` per registrare una funzione di
|
finito. Utilizziamo call_rcu() per registrare una funzione di
|
||||||
richiamo che distrugga l'oggetto quando tutti i lettori correnti hanno
|
richiamo che distrugga l'oggetto quando tutti i lettori correnti hanno
|
||||||
terminato. In alternative, potrebbe essere usata la funzione
|
terminato. In alternative, potrebbe essere usata la funzione
|
||||||
:c:func:`synchronize_rcu()` che blocca l'esecuzione finché tutti i lettori
|
synchronize_rcu() che blocca l'esecuzione finché tutti i lettori
|
||||||
non terminano di ispezionare la lista.
|
non terminano di ispezionare la lista.
|
||||||
|
|
||||||
Ma come fa l'RCU a sapere quando i lettori sono finiti? Il meccanismo è
|
Ma come fa l'RCU a sapere quando i lettori sono finiti? Il meccanismo è
|
||||||
il seguente: innanzi tutto i lettori accedono alla lista solo fra la coppia
|
il seguente: innanzi tutto i lettori accedono alla lista solo fra la coppia
|
||||||
:c:func:`rcu_read_lock()`/:c:func:`rcu_read_unlock()` che disabilita la
|
rcu_read_lock()/rcu_read_unlock() che disabilita la
|
||||||
prelazione così che i lettori non vengano sospesi mentre stanno leggendo
|
prelazione così che i lettori non vengano sospesi mentre stanno leggendo
|
||||||
la lista.
|
la lista.
|
||||||
|
|
||||||
|
@ -1253,12 +1253,12 @@ codice RCU è un po' più ottimizzato di così, ma questa è l'idea di fondo.
|
||||||
}
|
}
|
||||||
|
|
||||||
Da notare che i lettori modificano il campo popularity nella funzione
|
Da notare che i lettori modificano il campo popularity nella funzione
|
||||||
:c:func:`__cache_find()`, e ora non trattiene alcun *lock*. Una soluzione
|
__cache_find(), e ora non trattiene alcun *lock*. Una soluzione
|
||||||
potrebbe essere quella di rendere la variabile ``atomic_t``, ma per l'uso
|
potrebbe essere quella di rendere la variabile ``atomic_t``, ma per l'uso
|
||||||
che ne abbiamo fatto qui, non ci interessano queste corse critiche perché un
|
che ne abbiamo fatto qui, non ci interessano queste corse critiche perché un
|
||||||
risultato approssimativo è comunque accettabile, quindi non l'ho cambiato.
|
risultato approssimativo è comunque accettabile, quindi non l'ho cambiato.
|
||||||
|
|
||||||
Il risultato è che la funzione :c:func:`cache_find()` non ha bisogno di alcuna
|
Il risultato è che la funzione cache_find() non ha bisogno di alcuna
|
||||||
sincronizzazione con le altre funzioni, quindi è veloce su un sistema
|
sincronizzazione con le altre funzioni, quindi è veloce su un sistema
|
||||||
multi-processore tanto quanto lo sarebbe su un sistema mono-processore.
|
multi-processore tanto quanto lo sarebbe su un sistema mono-processore.
|
||||||
|
|
||||||
|
@ -1271,9 +1271,9 @@ riferimenti.
|
||||||
|
|
||||||
Ora, dato che il '*lock* di lettura' di un RCU non fa altro che disabilitare
|
Ora, dato che il '*lock* di lettura' di un RCU non fa altro che disabilitare
|
||||||
la prelazione, un chiamante che ha sempre la prelazione disabilitata fra le
|
la prelazione, un chiamante che ha sempre la prelazione disabilitata fra le
|
||||||
chiamate :c:func:`cache_find()` e :c:func:`object_put()` non necessita
|
chiamate cache_find() e object_put() non necessita
|
||||||
di incrementare e decrementare il contatore di riferimenti. Potremmo
|
di incrementare e decrementare il contatore di riferimenti. Potremmo
|
||||||
esporre la funzione :c:func:`__cache_find()` dichiarandola non-static,
|
esporre la funzione __cache_find() dichiarandola non-static,
|
||||||
e quel chiamante potrebbe usare direttamente questa funzione.
|
e quel chiamante potrebbe usare direttamente questa funzione.
|
||||||
|
|
||||||
Il beneficio qui sta nel fatto che il contatore di riferimenti no
|
Il beneficio qui sta nel fatto che il contatore di riferimenti no
|
||||||
|
@ -1293,10 +1293,10 @@ singolo contatore. Facile e pulito.
|
||||||
Se questo dovesse essere troppo lento (solitamente non lo è, ma se avete
|
Se questo dovesse essere troppo lento (solitamente non lo è, ma se avete
|
||||||
dimostrato che lo è devvero), potreste usare un contatore per ogni processore
|
dimostrato che lo è devvero), potreste usare un contatore per ogni processore
|
||||||
e quindi non sarebbe più necessaria la mutua esclusione. Vedere
|
e quindi non sarebbe più necessaria la mutua esclusione. Vedere
|
||||||
:c:func:`DEFINE_PER_CPU()`, :c:func:`get_cpu_var()` e :c:func:`put_cpu_var()`
|
DEFINE_PER_CPU(), get_cpu_var() e put_cpu_var()
|
||||||
(``include/linux/percpu.h``).
|
(``include/linux/percpu.h``).
|
||||||
|
|
||||||
Il tipo di dato ``local_t``, la funzione :c:func:`cpu_local_inc()` e tutte
|
Il tipo di dato ``local_t``, la funzione cpu_local_inc() e tutte
|
||||||
le altre funzioni associate, sono di particolare utilità per semplici contatori
|
le altre funzioni associate, sono di particolare utilità per semplici contatori
|
||||||
per-processore; su alcune architetture sono anche più efficienti
|
per-processore; su alcune architetture sono anche più efficienti
|
||||||
(``include/asm/local.h``).
|
(``include/asm/local.h``).
|
||||||
|
@ -1324,11 +1324,11 @@ da un'interruzione software. Il gestore d'interruzione non utilizza alcun
|
||||||
enable_irq(irq);
|
enable_irq(irq);
|
||||||
spin_unlock(&lock);
|
spin_unlock(&lock);
|
||||||
|
|
||||||
La funzione :c:func:`disable_irq()` impedisce al gestore d'interruzioni
|
La funzione disable_irq() impedisce al gestore d'interruzioni
|
||||||
d'essere eseguito (e aspetta che finisca nel caso fosse in esecuzione su
|
d'essere eseguito (e aspetta che finisca nel caso fosse in esecuzione su
|
||||||
un altro processore). Lo spinlock, invece, previene accessi simultanei.
|
un altro processore). Lo spinlock, invece, previene accessi simultanei.
|
||||||
Naturalmente, questo è più lento della semplice chiamata
|
Naturalmente, questo è più lento della semplice chiamata
|
||||||
:c:func:`spin_lock_irq()`, quindi ha senso solo se questo genere di accesso
|
spin_lock_irq(), quindi ha senso solo se questo genere di accesso
|
||||||
è estremamente raro.
|
è estremamente raro.
|
||||||
|
|
||||||
.. _`it_sleeping-things`:
|
.. _`it_sleeping-things`:
|
||||||
|
@ -1336,7 +1336,7 @@ Naturalmente, questo è più lento della semplice chiamata
|
||||||
Quali funzioni possono essere chiamate in modo sicuro dalle interruzioni?
|
Quali funzioni possono essere chiamate in modo sicuro dalle interruzioni?
|
||||||
=========================================================================
|
=========================================================================
|
||||||
|
|
||||||
Molte funzioni del kernel dormono (in sostanza, chiamano ``schedule()``)
|
Molte funzioni del kernel dormono (in sostanza, chiamano schedule())
|
||||||
direttamente od indirettamente: non potete chiamarle se trattenere uno
|
direttamente od indirettamente: non potete chiamarle se trattenere uno
|
||||||
spinlock o avete la prelazione disabilitata, mai. Questo significa che
|
spinlock o avete la prelazione disabilitata, mai. Questo significa che
|
||||||
dovete necessariamente essere nel contesto utente: chiamarle da un
|
dovete necessariamente essere nel contesto utente: chiamarle da un
|
||||||
|
@ -1354,23 +1354,23 @@ dormire.
|
||||||
|
|
||||||
- Accessi allo spazio utente:
|
- Accessi allo spazio utente:
|
||||||
|
|
||||||
- :c:func:`copy_from_user()`
|
- copy_from_user()
|
||||||
|
|
||||||
- :c:func:`copy_to_user()`
|
- copy_to_user()
|
||||||
|
|
||||||
- :c:func:`get_user()`
|
- get_user()
|
||||||
|
|
||||||
- :c:func:`put_user()`
|
- put_user()
|
||||||
|
|
||||||
- :c:func:`kmalloc(GFP_KERNEL) <kmalloc>`
|
- kmalloc(GFP_KERNEL) <kmalloc>`
|
||||||
|
|
||||||
- :c:func:`mutex_lock_interruptible()` and
|
- mutex_lock_interruptible() and
|
||||||
:c:func:`mutex_lock()`
|
mutex_lock()
|
||||||
|
|
||||||
C'è anche :c:func:`mutex_trylock()` che però non dorme.
|
C'è anche mutex_trylock() che però non dorme.
|
||||||
Comunque, non deve essere usata in un contesto d'interruzione dato
|
Comunque, non deve essere usata in un contesto d'interruzione dato
|
||||||
che la sua implementazione non è sicura in quel contesto.
|
che la sua implementazione non è sicura in quel contesto.
|
||||||
Anche :c:func:`mutex_unlock()` non dorme mai. Non può comunque essere
|
Anche mutex_unlock() non dorme mai. Non può comunque essere
|
||||||
usata in un contesto d'interruzione perché un mutex deve essere rilasciato
|
usata in un contesto d'interruzione perché un mutex deve essere rilasciato
|
||||||
dallo stesso processo che l'ha acquisito.
|
dallo stesso processo che l'ha acquisito.
|
||||||
|
|
||||||
|
@ -1380,11 +1380,11 @@ Alcune funzioni che non dormono
|
||||||
Alcune funzioni possono essere chiamate tranquillamente da qualsiasi
|
Alcune funzioni possono essere chiamate tranquillamente da qualsiasi
|
||||||
contesto, o trattenendo un qualsiasi *lock*.
|
contesto, o trattenendo un qualsiasi *lock*.
|
||||||
|
|
||||||
- :c:func:`printk()`
|
- printk()
|
||||||
|
|
||||||
- :c:func:`kfree()`
|
- kfree()
|
||||||
|
|
||||||
- :c:func:`add_timer()` e :c:func:`del_timer()`
|
- add_timer() e del_timer()
|
||||||
|
|
||||||
Riferimento per l'API dei Mutex
|
Riferimento per l'API dei Mutex
|
||||||
===============================
|
===============================
|
||||||
|
@ -1444,14 +1444,14 @@ prelazione
|
||||||
bh
|
bh
|
||||||
Bottom Half: per ragioni storiche, le funzioni che contengono '_bh' nel
|
Bottom Half: per ragioni storiche, le funzioni che contengono '_bh' nel
|
||||||
loro nome ora si riferiscono a qualsiasi interruzione software; per esempio,
|
loro nome ora si riferiscono a qualsiasi interruzione software; per esempio,
|
||||||
:c:func:`spin_lock_bh()` blocca qualsiasi interuzione software sul processore
|
spin_lock_bh() blocca qualsiasi interuzione software sul processore
|
||||||
corrente. I *Bottom Halves* sono deprecati, e probabilmente verranno
|
corrente. I *Bottom Halves* sono deprecati, e probabilmente verranno
|
||||||
sostituiti dai tasklet. In un dato momento potrà esserci solo un
|
sostituiti dai tasklet. In un dato momento potrà esserci solo un
|
||||||
*bottom half* in esecuzione.
|
*bottom half* in esecuzione.
|
||||||
|
|
||||||
contesto d'interruzione
|
contesto d'interruzione
|
||||||
Non è il contesto utente: qui si processano le interruzioni hardware e
|
Non è il contesto utente: qui si processano le interruzioni hardware e
|
||||||
software. La macro :c:func:`in_interrupt()` ritorna vero.
|
software. La macro in_interrupt() ritorna vero.
|
||||||
|
|
||||||
contesto utente
|
contesto utente
|
||||||
Il kernel che esegue qualcosa per conto di un particolare processo (per
|
Il kernel che esegue qualcosa per conto di un particolare processo (per
|
||||||
|
@ -1461,12 +1461,12 @@ contesto utente
|
||||||
che hardware.
|
che hardware.
|
||||||
|
|
||||||
interruzione hardware
|
interruzione hardware
|
||||||
Richiesta di interruzione hardware. :c:func:`in_irq()` ritorna vero in un
|
Richiesta di interruzione hardware. in_irq() ritorna vero in un
|
||||||
gestore d'interruzioni hardware.
|
gestore d'interruzioni hardware.
|
||||||
|
|
||||||
interruzione software / softirq
|
interruzione software / softirq
|
||||||
Gestore di interruzioni software: :c:func:`in_irq()` ritorna falso;
|
Gestore di interruzioni software: in_irq() ritorna falso;
|
||||||
:c:func:`in_softirq()` ritorna vero. I tasklet e le softirq sono entrambi
|
in_softirq() ritorna vero. I tasklet e le softirq sono entrambi
|
||||||
considerati 'interruzioni software'.
|
considerati 'interruzioni software'.
|
||||||
|
|
||||||
In soldoni, un softirq è uno delle 32 interruzioni software che possono
|
In soldoni, un softirq è uno delle 32 interruzioni software che possono
|
||||||
|
|
|
@ -23,18 +23,18 @@ ogni due o tre mesi viene effettuata un rilascio importante del kernel.
|
||||||
I rilasci più recenti sono stati:
|
I rilasci più recenti sono stati:
|
||||||
|
|
||||||
====== =================
|
====== =================
|
||||||
4.11 Aprile 30, 2017
|
5.0 3 marzo, 2019
|
||||||
4.12 Luglio 2, 2017
|
5.1 5 maggio, 2019
|
||||||
4.13 Settembre 3, 2017
|
5.2 7 luglio, 2019
|
||||||
4.14 Novembre 12, 2017
|
5.3 15 settembre, 2019
|
||||||
4.15 Gennaio 28, 2018
|
5.4 24 novembre, 2019
|
||||||
4.16 Aprile 1, 2018
|
5.5 6 gennaio, 2020
|
||||||
====== =================
|
====== =================
|
||||||
|
|
||||||
Ciascun rilascio 4.x è un importante rilascio del kernel con nuove
|
Ciascun rilascio 5.x è un importante rilascio del kernel con nuove
|
||||||
funzionalità, modifiche interne dell'API, e molto altro. Un tipico
|
funzionalità, modifiche interne dell'API, e molto altro. Un tipico
|
||||||
rilascio 4.x contiene quasi 13,000 gruppi di modifiche con ulteriori
|
rilascio contiene quasi 13,000 gruppi di modifiche con ulteriori
|
||||||
modifiche a parecchie migliaia di linee di codice. La 4.x. è pertanto la
|
modifiche a parecchie migliaia di linee di codice. La 5.x. è pertanto la
|
||||||
linea di confine nello sviluppo del kernel Linux; il kernel utilizza un sistema
|
linea di confine nello sviluppo del kernel Linux; il kernel utilizza un sistema
|
||||||
di sviluppo continuo che integra costantemente nuove importanti modifiche.
|
di sviluppo continuo che integra costantemente nuove importanti modifiche.
|
||||||
|
|
||||||
|
@ -55,8 +55,8 @@ verrà descritto dettagliatamente più avanti).
|
||||||
La finestra di inclusione resta attiva approssimativamente per due settimane.
|
La finestra di inclusione resta attiva approssimativamente per due settimane.
|
||||||
Al termine di questo periodo, Linus Torvald dichiarerà che la finestra è
|
Al termine di questo periodo, Linus Torvald dichiarerà che la finestra è
|
||||||
chiusa e rilascerà il primo degli "rc" del kernel.
|
chiusa e rilascerà il primo degli "rc" del kernel.
|
||||||
Per il kernel che è destinato ad essere 2.6.40, per esempio, il rilascio
|
Per il kernel che è destinato ad essere 5.6, per esempio, il rilascio
|
||||||
che emerge al termine della finestra d'inclusione si chiamerà 2.6.40-rc1.
|
che emerge al termine della finestra d'inclusione si chiamerà 5.6-rc1.
|
||||||
Questo rilascio indica che il momento di aggiungere nuovi componenti è
|
Questo rilascio indica che il momento di aggiungere nuovi componenti è
|
||||||
passato, e che è iniziato il periodo di stabilizzazione del prossimo kernel.
|
passato, e che è iniziato il periodo di stabilizzazione del prossimo kernel.
|
||||||
|
|
||||||
|
@ -76,22 +76,23 @@ Mentre le correzioni si aprono la loro strada all'interno del ramo principale,
|
||||||
il ritmo delle modifiche rallenta col tempo. Linus rilascia un nuovo
|
il ritmo delle modifiche rallenta col tempo. Linus rilascia un nuovo
|
||||||
kernel -rc circa una volta alla settimana; e ne usciranno circa 6 o 9 prima
|
kernel -rc circa una volta alla settimana; e ne usciranno circa 6 o 9 prima
|
||||||
che il kernel venga considerato sufficientemente stabile e che il rilascio
|
che il kernel venga considerato sufficientemente stabile e che il rilascio
|
||||||
finale 2.6.x venga fatto. A quel punto tutto il processo ricomincerà.
|
finale venga fatto. A quel punto tutto il processo ricomincerà.
|
||||||
|
|
||||||
Esempio: ecco com'è andato il ciclo di sviluppo della versione 4.16
|
Esempio: ecco com'è andato il ciclo di sviluppo della versione 5.4
|
||||||
(tutte le date si collocano nel 2018)
|
(tutte le date si collocano nel 2018)
|
||||||
|
|
||||||
|
|
||||||
============== =======================================
|
============== =======================================
|
||||||
Gennaio 28 4.15 rilascio stabile
|
15 settembre 5.3 rilascio stabile
|
||||||
Febbraio 11 4.16-rc1, finestra di inclusione chiusa
|
30 settembre 5.4-rc1, finestra di inclusione chiusa
|
||||||
Febbraio 18 4.16-rc2
|
6 ottobre 5.4-rc2
|
||||||
Febbraio 25 4.16-rc3
|
13 ottobre 5.4-rc3
|
||||||
Marzo 4 4.16-rc4
|
20 ottobre 5.4-rc4
|
||||||
Marzo 11 4.16-rc5
|
27 ottobre 5.4-rc5
|
||||||
Marzo 18 4.16-rc6
|
3 novembre 5.4-rc6
|
||||||
Marzo 25 4.16-rc7
|
10 novembre 5.4-rc7
|
||||||
Aprile 1 4.17 rilascio stabile
|
17 novembre 5.4-rc8
|
||||||
|
24 novembre 5.4 rilascio stabile
|
||||||
============== =======================================
|
============== =======================================
|
||||||
|
|
||||||
In che modo gli sviluppatori decidono quando chiudere il ciclo di sviluppo e
|
In che modo gli sviluppatori decidono quando chiudere il ciclo di sviluppo e
|
||||||
|
@ -108,43 +109,44 @@ tipo di perfezione difficilmente viene raggiunta; esistono troppe variabili
|
||||||
in un progetto di questa portata. Arriva un punto dove ritardare il rilascio
|
in un progetto di questa portata. Arriva un punto dove ritardare il rilascio
|
||||||
finale peggiora la situazione; la quantità di modifiche in attesa della
|
finale peggiora la situazione; la quantità di modifiche in attesa della
|
||||||
prossima finestra di inclusione crescerà enormemente, creando ancor più
|
prossima finestra di inclusione crescerà enormemente, creando ancor più
|
||||||
regressioni al giro successivo. Quindi molti kernel 4.x escono con una
|
regressioni al giro successivo. Quindi molti kernel 5.x escono con una
|
||||||
manciata di regressioni delle quali, si spera, nessuna è grave.
|
manciata di regressioni delle quali, si spera, nessuna è grave.
|
||||||
|
|
||||||
Una volta che un rilascio stabile è fatto, il suo costante mantenimento è
|
Una volta che un rilascio stabile è fatto, il suo costante mantenimento è
|
||||||
affidato al "squadra stabilità", attualmente composta da Greg Kroah-Hartman.
|
affidato al "squadra stabilità", attualmente composta da Greg Kroah-Hartman.
|
||||||
Questa squadra rilascia occasionalmente degli aggiornamenti relativi al
|
Questa squadra rilascia occasionalmente degli aggiornamenti relativi al
|
||||||
rilascio stabile usando la numerazione 4.x.y. Per essere presa in
|
rilascio stabile usando la numerazione 5.x.y. Per essere presa in
|
||||||
considerazione per un rilascio d'aggiornamento, una modifica deve:
|
considerazione per un rilascio d'aggiornamento, una modifica deve:
|
||||||
(1) correggere un baco importante (2) essere già inserita nel ramo principale
|
(1) correggere un baco importante (2) essere già inserita nel ramo principale
|
||||||
per il prossimo sviluppo del kernel. Solitamente, passato il loro rilascio
|
per il prossimo sviluppo del kernel. Solitamente, passato il loro rilascio
|
||||||
iniziale, i kernel ricevono aggiornamenti per più di un ciclo di sviluppo.
|
iniziale, i kernel ricevono aggiornamenti per più di un ciclo di sviluppo.
|
||||||
Quindi, per esempio, la storia del kernel 4.13 appare così:
|
Quindi, per esempio, la storia del kernel 5.2 appare così (anno 2019):
|
||||||
|
|
||||||
============== ===============================
|
============== ===============================
|
||||||
Settembre 3 4.13 rilascio stabile
|
15 settembre 5.2 rilascio stabile FIXME settembre è sbagliato
|
||||||
Settembre 13 4.13.1
|
14 luglio 5.2.1
|
||||||
Settembre 20 4.13.2
|
21 luglio 5.2.2
|
||||||
Settembre 27 4.13.3
|
26 luglio 5.2.3
|
||||||
Ottobre 5 4.13.4
|
28 luglio 5.2.4
|
||||||
Ottobre 12 4.13.5
|
31 luglio 5.2.5
|
||||||
... ...
|
... ...
|
||||||
Novembre 24 4.13.16
|
11 ottobre 5.2.21
|
||||||
============== ===============================
|
============== ===============================
|
||||||
|
|
||||||
La 4.13.16 fu l'aggiornamento finale per la versione 4.13.
|
La 5.2.21 fu l'aggiornamento finale per la versione 5.2.
|
||||||
|
|
||||||
Alcuni kernel sono destinati ad essere kernel a "lungo termine"; questi
|
Alcuni kernel sono destinati ad essere kernel a "lungo termine"; questi
|
||||||
riceveranno assistenza per un lungo periodo di tempo. Al momento in cui
|
riceveranno assistenza per un lungo periodo di tempo. Al momento in cui
|
||||||
scriviamo, i manutentori dei kernel stabili a lungo termine sono:
|
scriviamo, i manutentori dei kernel stabili a lungo termine sono:
|
||||||
|
|
||||||
====== ====================== ==========================================
|
====== ================================ ==========================================
|
||||||
3.16 Ben Hutchings (kernel stabile molto più a lungo termine)
|
3.16 Ben Hutchings (kernel stabile molto più a lungo termine)
|
||||||
4.1 Sasha Levin
|
4.4 Greg Kroah-Hartman e Sasha Levin (kernel stabile molto più a lungo termine)
|
||||||
4.4 Greg Kroah-Hartman (kernel stabile molto più a lungo termine)
|
4.9 Greg Kroah-Hartman e Sasha Levin
|
||||||
4.9 Greg Kroah-Hartman
|
4.14 Greg Kroah-Hartman e Sasha Levin
|
||||||
4.14 Greg Kroah-Hartman
|
4.19 Greg Kroah-Hartman e Sasha Levin
|
||||||
====== ====================== ==========================================
|
5.4i Greg Kroah-Hartman e Sasha Levin
|
||||||
|
====== ================================ ==========================================
|
||||||
|
|
||||||
|
|
||||||
Questa selezione di kernel di lungo periodo sono puramente dovuti ai loro
|
Questa selezione di kernel di lungo periodo sono puramente dovuti ai loro
|
||||||
|
@ -229,12 +231,13 @@ Come le modifiche finiscono nel Kernel
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
|
|
||||||
Esiste una sola persona che può inserire le patch nel repositorio principale
|
Esiste una sola persona che può inserire le patch nel repositorio principale
|
||||||
del kernel: Linus Torvalds. Ma, di tutte le 9500 patch che entrarono nella
|
del kernel: Linus Torvalds. Ma, per esempio, di tutte le 9500 patch
|
||||||
versione 2.6.38 del kernel, solo 112 (circa l'1,3%) furono scelte direttamente
|
che entrarono nella versione 2.6.38 del kernel, solo 112 (circa
|
||||||
da Linus in persona. Il progetto del kernel è cresciuto fino a raggiungere
|
l'1,3%) furono scelte direttamente da Linus in persona. Il progetto
|
||||||
una dimensione tale per cui un singolo sviluppatore non può controllare e
|
del kernel è cresciuto fino a raggiungere una dimensione tale per cui
|
||||||
selezionare indipendentemente ogni modifica senza essere supportato.
|
un singolo sviluppatore non può controllare e selezionare
|
||||||
La via scelta dagli sviluppatori per indirizzare tale crescita è stata quella
|
indipendentemente ogni modifica senza essere supportato. La via
|
||||||
|
scelta dagli sviluppatori per indirizzare tale crescita è stata quella
|
||||||
di utilizzare un sistema di "sottotenenti" basato sulla fiducia.
|
di utilizzare un sistema di "sottotenenti" basato sulla fiducia.
|
||||||
|
|
||||||
Il codice base del kernel è spezzato in una serie si sottosistemi: rete,
|
Il codice base del kernel è spezzato in una serie si sottosistemi: rete,
|
||||||
|
|
|
@ -313,7 +313,7 @@ che conta gli utenti attivi, dovreste chiamarla ``count_active_users()`` o
|
||||||
qualcosa di simile, **non** dovreste chiamarla ``cntusr()``.
|
qualcosa di simile, **non** dovreste chiamarla ``cntusr()``.
|
||||||
|
|
||||||
Codificare il tipo di funzione nel suo nome (quella cosa chiamata notazione
|
Codificare il tipo di funzione nel suo nome (quella cosa chiamata notazione
|
||||||
ungherese) fa male al cervello - il compilatore conosce comunque il tipo e
|
ungherese) è stupido - il compilatore conosce comunque il tipo e
|
||||||
può verificarli, e inoltre confonde i programmatori. Non c'è da
|
può verificarli, e inoltre confonde i programmatori. Non c'è da
|
||||||
sorprendersi che MicroSoft faccia programmi bacati.
|
sorprendersi che MicroSoft faccia programmi bacati.
|
||||||
|
|
||||||
|
@ -825,8 +825,8 @@ linguaggio assembler.
|
||||||
|
|
||||||
Agli sviluppatori del kernel piace essere visti come dotti. Tenete un occhio
|
Agli sviluppatori del kernel piace essere visti come dotti. Tenete un occhio
|
||||||
di riguardo per l'ortografia e farete una belle figura. In inglese, evitate
|
di riguardo per l'ortografia e farete una belle figura. In inglese, evitate
|
||||||
l'uso di parole mozzate come ``dont``: usate ``do not`` oppure ``don't``.
|
l'uso incorretto di abbreviazioni come ``dont``: usate ``do not`` oppure
|
||||||
Scrivete messaggi concisi, chiari, e inequivocabili.
|
``don't``. Scrivete messaggi concisi, chiari, e inequivocabili.
|
||||||
|
|
||||||
I messaggi del kernel non devono terminare con un punto fermo.
|
I messaggi del kernel non devono terminare con un punto fermo.
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,33 @@ interfaccia come 'vecchia', questa non è una soluzione completa. L'interfaccia
|
||||||
deve essere rimossa dal kernel, o aggiunta a questo documento per scoraggiarne
|
deve essere rimossa dal kernel, o aggiunta a questo documento per scoraggiarne
|
||||||
l'uso.
|
l'uso.
|
||||||
|
|
||||||
|
BUG() e BUG_ON()
|
||||||
|
----------------
|
||||||
|
Al loro posto usate WARN() e WARN_ON() per gestire le
|
||||||
|
condizioni "impossibili" e gestitele come se fosse possibile farlo.
|
||||||
|
Nonostante le funzioni della famiglia BUG() siano state progettate
|
||||||
|
per asserire "situazioni impossibili" e interrompere in sicurezza un
|
||||||
|
thread del kernel, queste si sono rivelate essere troppo rischiose
|
||||||
|
(per esempio, in quale ordine rilasciare i *lock*? Ci sono stati che
|
||||||
|
sono stati ripristinati?). Molto spesso l'uso di BUG()
|
||||||
|
destabilizza il sistema o lo corrompe del tutto, il che rende
|
||||||
|
impossibile un'attività di debug o anche solo leggere un rapporto
|
||||||
|
circa l'errore. Linus ha un'opinione molto critica al riguardo:
|
||||||
|
`email 1
|
||||||
|
<https://lore.kernel.org/lkml/CA+55aFy6jNLsywVYdGp83AMrXBo_P-pkjkphPGrO=82SPKCpLQ@mail.gmail.com/>`_,
|
||||||
|
`email 2
|
||||||
|
<https://lore.kernel.org/lkml/CAHk-=whDHsbK3HTOpTF=ue_o04onRwTEaK_ZoJp_fjbqq4+=Jw@mail.gmail.com/>`_
|
||||||
|
|
||||||
|
Tenete presente che la famiglia di funzioni WARN() dovrebbe essere
|
||||||
|
usato solo per situazioni che si suppone siano "impossibili". Se
|
||||||
|
volete avvisare gli utenti riguardo a qualcosa di possibile anche se
|
||||||
|
indesiderato, usare le funzioni della famiglia pr_warn(). Chi
|
||||||
|
amministra il sistema potrebbe aver attivato l'opzione sysctl
|
||||||
|
*panic_on_warn* per essere sicuri che il sistema smetta di funzionare
|
||||||
|
in caso si verifichino delle condizioni "inaspettate". (per esempio,
|
||||||
|
date un'occhiata al questo `commit
|
||||||
|
<https://git.kernel.org/linus/d4689846881d160a4d12a514e991a740bcb5d65a>`_)
|
||||||
|
|
||||||
Calcoli codificati negli argomenti di un allocatore
|
Calcoli codificati negli argomenti di un allocatore
|
||||||
----------------------------------------------------
|
----------------------------------------------------
|
||||||
Il calcolo dinamico delle dimensioni (specialmente le moltiplicazioni) non
|
Il calcolo dinamico delle dimensioni (specialmente le moltiplicazioni) non
|
||||||
|
@ -68,52 +95,81 @@ Invece, usate la seguente funzione::
|
||||||
|
|
||||||
header = kzalloc(struct_size(header, item, count), GFP_KERNEL);
|
header = kzalloc(struct_size(header, item, count), GFP_KERNEL);
|
||||||
|
|
||||||
Per maggiori dettagli fate riferimento a :c:func:`array_size`,
|
Per maggiori dettagli fate riferimento a array_size(),
|
||||||
:c:func:`array3_size`, e :c:func:`struct_size`, così come la famiglia di
|
array3_size(), e struct_size(), così come la famiglia di
|
||||||
funzioni :c:func:`check_add_overflow` e :c:func:`check_mul_overflow`.
|
funzioni check_add_overflow() e check_mul_overflow().
|
||||||
|
|
||||||
simple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull()
|
simple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull()
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
Le funzioni :c:func:`simple_strtol`, :c:func:`simple_strtoll`,
|
Le funzioni simple_strtol(), simple_strtoll(),
|
||||||
:c:func:`simple_strtoul`, e :c:func:`simple_strtoull` ignorano volutamente
|
simple_strtoul(), e simple_strtoull() ignorano volutamente
|
||||||
i possibili overflow, e questo può portare il chiamante a generare risultati
|
i possibili overflow, e questo può portare il chiamante a generare risultati
|
||||||
inaspettati. Le rispettive funzioni :c:func:`kstrtol`, :c:func:`kstrtoll`,
|
inaspettati. Le rispettive funzioni kstrtol(), kstrtoll(),
|
||||||
:c:func:`kstrtoul`, e :c:func:`kstrtoull` sono da considerarsi le corrette
|
kstrtoul(), e kstrtoull() sono da considerarsi le corrette
|
||||||
sostitute; tuttavia va notato che queste richiedono che la stringa sia
|
sostitute; tuttavia va notato che queste richiedono che la stringa sia
|
||||||
terminata con il carattere NUL o quello di nuova riga.
|
terminata con il carattere NUL o quello di nuova riga.
|
||||||
|
|
||||||
strcpy()
|
strcpy()
|
||||||
--------
|
--------
|
||||||
La funzione :c:func:`strcpy` non fa controlli agli estremi del buffer
|
La funzione strcpy() non fa controlli agli estremi del buffer
|
||||||
di destinazione. Questo può portare ad un overflow oltre i limiti del
|
di destinazione. Questo può portare ad un overflow oltre i limiti del
|
||||||
buffer e generare svariati tipi di malfunzionamenti. Nonostante l'opzione
|
buffer e generare svariati tipi di malfunzionamenti. Nonostante l'opzione
|
||||||
`CONFIG_FORTIFY_SOURCE=y` e svariate opzioni del compilatore aiutano
|
`CONFIG_FORTIFY_SOURCE=y` e svariate opzioni del compilatore aiutano
|
||||||
a ridurne il rischio, non c'è alcuna buona ragione per continuare ad usare
|
a ridurne il rischio, non c'è alcuna buona ragione per continuare ad usare
|
||||||
questa funzione. La versione sicura da usare è :c:func:`strscpy`.
|
questa funzione. La versione sicura da usare è strscpy().
|
||||||
|
|
||||||
strncpy() su stringe terminate con NUL
|
strncpy() su stringe terminate con NUL
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
L'utilizzo di :c:func:`strncpy` non fornisce alcuna garanzia sul fatto che
|
L'utilizzo di strncpy() non fornisce alcuna garanzia sul fatto che
|
||||||
il buffer di destinazione verrà terminato con il carattere NUL. Questo
|
il buffer di destinazione verrà terminato con il carattere NUL. Questo
|
||||||
potrebbe portare a diversi overflow di lettura o altri malfunzionamenti
|
potrebbe portare a diversi overflow di lettura o altri malfunzionamenti
|
||||||
causati, appunto, dalla mancanza del terminatore. Questa estende la
|
causati, appunto, dalla mancanza del terminatore. Questa estende la
|
||||||
terminazione nel buffer di destinazione quando la stringa d'origine è più
|
terminazione nel buffer di destinazione quando la stringa d'origine è più
|
||||||
corta; questo potrebbe portare ad una penalizzazione delle prestazioni per
|
corta; questo potrebbe portare ad una penalizzazione delle prestazioni per
|
||||||
chi usa solo stringe terminate. La versione sicura da usare è
|
chi usa solo stringe terminate. La versione sicura da usare è
|
||||||
:c:func:`strscpy`. (chi usa :c:func:`strscpy` e necessita di estendere la
|
strscpy(). (chi usa strscpy() e necessita di estendere la
|
||||||
terminazione con NUL deve aggiungere una chiamata a :c:func:`memset`)
|
terminazione con NUL deve aggiungere una chiamata a memset())
|
||||||
|
|
||||||
Se il chiamate no usa stringhe terminate con NUL, allore :c:func:`strncpy()`
|
Se il chiamate no usa stringhe terminate con NUL, allore strncpy()()
|
||||||
può continuare ad essere usata, ma i buffer di destinazione devono essere
|
può continuare ad essere usata, ma i buffer di destinazione devono essere
|
||||||
marchiati con l'attributo `__nonstring <https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html>`_
|
marchiati con l'attributo `__nonstring <https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html>`_
|
||||||
per evitare avvisi durante la compilazione.
|
per evitare avvisi durante la compilazione.
|
||||||
|
|
||||||
strlcpy()
|
strlcpy()
|
||||||
---------
|
---------
|
||||||
La funzione :c:func:`strlcpy`, per prima cosa, legge interamente il buffer di
|
La funzione strlcpy(), per prima cosa, legge interamente il buffer di
|
||||||
origine, magari leggendo più di quanto verrà effettivamente copiato. Questo
|
origine, magari leggendo più di quanto verrà effettivamente copiato. Questo
|
||||||
è inefficiente e può portare a overflow di lettura quando la stringa non è
|
è inefficiente e può portare a overflow di lettura quando la stringa non è
|
||||||
terminata con NUL. La versione sicura da usare è :c:func:`strscpy`.
|
terminata con NUL. La versione sicura da usare è strscpy().
|
||||||
|
|
||||||
|
Segnaposto %p nella stringa di formato
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
Tradizionalmente, l'uso del segnaposto "%p" nella stringa di formato
|
||||||
|
esponne un indirizzo di memoria in dmesg, proc, sysfs, eccetera. Per
|
||||||
|
evitare che questi indirizzi vengano sfruttati da malintenzionati,
|
||||||
|
tutto gli usi di "%p" nel kernel rappresentano l'hash dell'indirizzo,
|
||||||
|
rendendolo di fatto inutilizzabile. Nuovi usi di "%p" non dovrebbero
|
||||||
|
essere aggiunti al kernel. Per una rappresentazione testuale di un
|
||||||
|
indirizzo usate "%pS", l'output è migliore perché mostrerà il nome del
|
||||||
|
simbolo. Per tutto il resto, semplicemente non usate "%p".
|
||||||
|
|
||||||
|
Parafrasando la `guida
|
||||||
|
<https://lore.kernel.org/lkml/CA+55aFwQEd_d40g4mUCSsVRZzrFPUJt74vc6PPpb675hYNXcKw@mail.gmail.com/>`_
|
||||||
|
di Linus:
|
||||||
|
|
||||||
|
- Se il valore hash di "%p" è inutile, chiediti se il puntatore stesso
|
||||||
|
è importante. Forse dovrebbe essere rimosso del tutto?
|
||||||
|
- Se credi davvero che il vero valore del puntatore sia importante,
|
||||||
|
perché alcuni stati del sistema o i livelli di privilegi di un
|
||||||
|
utente sono considerati "special"? Se pensi di poterlo giustificare
|
||||||
|
(in un commento e nel messaggio del commit) abbastanza bene da
|
||||||
|
affrontare il giudizio di Linus, allora forse potrai usare "%px",
|
||||||
|
assicurandosi anche di averne il permesso.
|
||||||
|
|
||||||
|
Infine, sappi che un cambio in favore di "%p" con hash `non verrà
|
||||||
|
accettato
|
||||||
|
<https://lore.kernel.org/lkml/CA+55aFwieC1-nAs+NFq9RTwaR8ef9hWa4MjNBWL41F-8wM49eA@mail.gmail.com/>`_.
|
||||||
|
|
||||||
Vettori a dimensione variabile (VLA)
|
Vettori a dimensione variabile (VLA)
|
||||||
------------------------------------
|
------------------------------------
|
||||||
|
@ -127,3 +183,47 @@ Questo può portare a dei malfunzionamenti, potrebbe sovrascrivere
|
||||||
dati importanti alla fine dello stack (quando il kernel è compilato senza
|
dati importanti alla fine dello stack (quando il kernel è compilato senza
|
||||||
`CONFIG_THREAD_INFO_IN_TASK=y`), o sovrascrivere un pezzo di memoria adiacente
|
`CONFIG_THREAD_INFO_IN_TASK=y`), o sovrascrivere un pezzo di memoria adiacente
|
||||||
allo stack (quando il kernel è compilato senza `CONFIG_VMAP_STACK=y`).
|
allo stack (quando il kernel è compilato senza `CONFIG_VMAP_STACK=y`).
|
||||||
|
|
||||||
|
Salto implicito nell'istruzione switch-case
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
Il linguaggio C permette ai casi di un'istruzione `switch` di saltare al
|
||||||
|
prossimo caso quando l'istruzione "break" viene omessa alla fine del caso
|
||||||
|
corrente. Tuttavia questo rende il codice ambiguo perché non è sempre ovvio se
|
||||||
|
l'istruzione "break" viene omessa intenzionalmente o è un baco. Per esempio,
|
||||||
|
osservando il seguente pezzo di codice non è chiaro se lo stato
|
||||||
|
`STATE_ONE` è stato progettato apposta per eseguire anche `STATE_TWO`::
|
||||||
|
|
||||||
|
switch (value) {
|
||||||
|
case STATE_ONE:
|
||||||
|
do_something();
|
||||||
|
case STATE_TWO:
|
||||||
|
do_other();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
WARN("unknown state");
|
||||||
|
}
|
||||||
|
|
||||||
|
Dato che c'è stata una lunga lista di problemi `dovuti alla mancanza dell'istruzione
|
||||||
|
"break" <https://cwe.mitre.org/data/definitions/484.html>`_, oggigiorno non
|
||||||
|
permettiamo più che vi sia un "salto implicito" (*fall-through*). Per
|
||||||
|
identificare un salto implicito intenzionale abbiamo adottato la pseudo
|
||||||
|
parola chiave 'fallthrough' che viene espansa nell'estensione di gcc
|
||||||
|
`__attribute__((fallthrough))` `Statement Attributes
|
||||||
|
<https://gcc.gnu.org/onlinedocs/gcc/Statement-Attributes.html>`_.
|
||||||
|
(Quando la sintassi C17/C18 `[[fallthrough]]` sarà più comunemente
|
||||||
|
supportata dai compilatori C, analizzatori statici, e dagli IDE,
|
||||||
|
allora potremo usare quella sintassi per la pseudo parola chiave)
|
||||||
|
|
||||||
|
Quando la sintassi [[fallthrough]] sarà più comunemente supportata dai
|
||||||
|
compilatori, analizzatori statici, e ambienti di sviluppo IDE,
|
||||||
|
allora potremo usarla anche noi.
|
||||||
|
|
||||||
|
Ne consegue che tutti i blocchi switch/case devono finire in uno dei seguenti
|
||||||
|
modi:
|
||||||
|
|
||||||
|
* ``break;``
|
||||||
|
* `fallthrough;``
|
||||||
|
* ``continue;``
|
||||||
|
* ``goto <label>;``
|
||||||
|
* ``return [expression];``
|
||||||
|
|
Loading…
Reference in New Issue