451 lines · plain
1.. include:: ../disclaimer-ita.rst2 3:Original: :ref:`Documentation/process/4.Coding.rst <development_coding>`4:Translator: Alessia Mantegazza <amantegazza@vaga.pv.it>5 6.. _it_development_coding:7 8Scrivere codice corretto9========================10 11Nonostante ci sia molto da dire sul processo di creazione, sulla sua solidità12e sul suo orientamento alla comunità, la prova di ogni progetto di sviluppo13del kernel si trova nel codice stesso. È il codice che sarà esaminato dagli14altri sviluppatori ed inserito (o no) nel ramo principale. Quindi è la15qualità di questo codice che determinerà il successo finale del progetto.16 17Questa sezione esaminerà il processo di codifica. Inizieremo con uno sguardo18sulle diverse casistiche nelle quali gli sviluppatori kernel possono19sbagliare. Poi, l'attenzione si sposterà verso "il fare le cose20correttamente" e sugli strumenti che possono essere utili in questa missione.21 22Trappole23--------24 25Lo stile del codice26*******************27 28Il kernel ha da tempo delle norme sullo stile di codifica che sono descritte in29:ref:`Documentation/translations/it_IT/process/coding-style.rst <codingstyle>`.30Per la maggior parte del tempo, la politica descritta in quel file è stata31praticamente informativa. Ne risulta che ci sia una quantità sostanziale di32codice nel kernel che non rispetta le linee guida relative allo stile.33La presenza di quel codice conduce a due distinti pericoli per gli34sviluppatori kernel.35 36Il primo di questi è credere che gli standard di codifica del kernel37non sono importanti e possono non essere applicati. La verità è che38aggiungere nuovo codice al kernel è davvero difficile se questo non39rispetta le norme; molti sviluppatori richiederanno che il codice sia40riformulato prima che anche solo lo revisionino. Una base di codice larga41quanto il kernel richiede una certa uniformità, in modo da rendere possibile42per gli sviluppatori una comprensione veloce di ogni sua parte. Non ci sono,43quindi, più spazi per un codice formattato alla carlona.44 45Occasionalmente, lo stile di codifica del kernel andrà in conflitto con lo46stile richiesto da un datore di lavoro. In alcuni casi, lo stile del kernel47dovrà prevalere prima che il codice venga inserito. Mettere il codice48all'interno del kernel significa rinunciare a un certo grado di controllo49in differenti modi - incluso il controllo sul come formattare il codice.50 51L’altra trappola è quella di pensare che il codice già presente nel kernel52abbia urgentemente bisogno di essere sistemato. Gli sviluppatori potrebbero53iniziare a generare patch che correggono lo stile come modo per prendere54famigliarità con il processo, o come modo per inserire i propri nomi nei55changelog del kernel – o entrambe. La comunità di sviluppo vede un attività56di codifica puramente correttiva come "rumore"; queste attività riceveranno57una fredda accoglienza. Di conseguenza è meglio evitare questo tipo di patch.58Mentre si lavora su un pezzo di codice è normale correggerne anche lo stile,59ma le modifiche di stile non dovrebbero essere fatte fini a se stesse.60 61Il documento sullo stile del codice non dovrebbe essere letto come una legge62assoluta che non può mai essere trasgredita. Se c’è un a buona ragione63(per esempio, una linea che diviene poco leggibile se divisa per rientrare64nel limite di 80 colonne), fatelo e basta.65 66Notate che potete utilizzare lo strumento “clang-format” per aiutarvi con67le regole, per una riformattazione automatica e veloce del vostro codice68e per revisionare interi file per individuare errori nello stile di codifica,69refusi e possibili miglioramenti. Inoltre è utile anche per classificare gli70``#includes``, per allineare variabili/macro, per testi derivati ed altri71compiti del genere. Consultate il file72:ref:`Documentation/translations/it_IT/process/clang-format.rst <clangformat>`73per maggiori dettagli74 75Se utilizzate un programma compatibile con EditorConfig, allora alcune76configurazioni basilari come l'indentazione e la fine delle righe verranno77applicate automaticamente. Per maggiori informazioni consultate la pagina:78https://editorconfig.org/79 80Livelli di astrazione81*********************82 83 84I professori di Informatica insegnano ai propri studenti a fare ampio uso dei85livelli di astrazione nel nome della flessibilità e del nascondere informazioni.86Certo il kernel fa un grande uso dell'astrazione; nessun progetto con milioni87di righe di codice potrebbe fare altrimenti e sopravvivere. Ma l'esperienza88ha dimostrato che un'eccessiva o prematura astrazione può rivelarsi dannosa89al pari di una prematura ottimizzazione. L'astrazione dovrebbe essere usata90fino al livello necessario e non oltre.91 92Ad un livello base, considerate una funzione che ha un argomento che viene93sempre impostato a zero da tutti i chiamanti. Uno potrebbe mantenere94quell'argomento nell'eventualità qualcuno volesse sfruttare la flessibilità95offerta. In ogni caso, tuttavia, ci sono buone possibilità che il codice96che va ad implementare questo argomento aggiuntivo, sia stato rotto in maniera97sottile, in un modo che non è mai stato notato - perché non è mai stato usato.98Oppure, quando sorge la necessità di avere più flessibilità, questo argomento99non la fornisce in maniera soddisfacente. Gli sviluppatori di Kernel,100sottopongono costantemente patch che vanno a rimuovere gli argomenti101inutilizzate; anche se, in generale, non avrebbero dovuto essere aggiunti.102 103I livelli di astrazione che nascondono l'accesso all'hardware -104spesso per poter usare dei driver su diversi sistemi operativi - vengono105particolarmente disapprovati. Tali livelli oscurano il codice e possono106peggiorare le prestazioni; essi non appartengono al kernel Linux.107 108D'altro canto, se vi ritrovate a dover copiare una quantità significativa di109codice proveniente da un altro sottosistema del kernel, è tempo di chiedersi110se, in effetti, non avrebbe più senso togliere parte di quel codice e metterlo111in una libreria separata o di implementare quella funzionalità ad un livello112più elevato. Non c'è utilità nel replicare lo stesso codice per tutto113il kernel.114 115 116#ifdef e l'uso del preprocessore in generale117********************************************118 119Il preprocessore C sembra essere una fonte di attrazione per qualche120programmatore C, che ci vede una via per ottenere una grande flessibilità121all'interno di un file sorgente. Ma il preprocessore non è scritto in C,122e un suo massiccio impiego conduce a un codice che è molto più difficile123da leggere per gli altri e che rende più difficile il lavoro di verifica del124compilatore. L'uso eccessivo del preprocessore è praticamente sempre il segno125di un codice che necessita di un certo lavoro di pulizia.126 127La compilazione condizionata con #ifdef è, in effetti, un potente strumento,128ed esso viene usato all'interno del kernel. Ma esiste un piccolo desiderio:129quello di vedere il codice coperto solo da una leggera spolverata di130blocchi #ifdef. Come regola generale, quando possibile, l'uso di #ifdef131dovrebbe essere confinato nei file d'intestazione. Il codice compilato132condizionatamente può essere confinato a funzioni tali che, nel caso in cui133il codice non deve essere presente, diventano vuote. Il compilatore poi134ottimizzerà la chiamata alla funzione vuota rimuovendola. Il risultato è135un codice molto più pulito, più facile da seguire.136 137Le macro del preprocessore C presentano una serie di pericoli, inclusi138valutazioni multiple di espressioni che hanno effetti collaterali e non139garantiscono una sicurezza rispetto ai tipi. Se siete tentati dal definire140una macro, considerate l'idea di creare invece una funzione inline. Il codice141che ne risulterà sarà lo stesso, ma le funzioni inline sono più leggibili,142non considerano i propri argomenti più volte, e permettono al compilatore di143effettuare controlli sul tipo degli argomenti e del valore di ritorno.144 145 146Funzioni inline147***************148 149Comunque, anche le funzioni inline hanno i loro pericoli. I programmatori150potrebbero innamorarsi dell'efficienza percepita derivata dalla rimozione151di una chiamata a funzione. Queste funzioni, tuttavia, possono ridurre le152prestazioni. Dato che il loro codice viene replicato ovunque vi sia una153chiamata ad esse, si finisce per gonfiare le dimensioni del kernel compilato.154Questi, a turno, creano pressione sulla memoria cache del processore, e questo155può causare rallentamenti importanti. Le funzioni inline, di norma, dovrebbero156essere piccole e usate raramente. Il costo di una chiamata a funzione, dopo157tutto, non è così alto; la creazione di molte funzioni inline è il classico158esempio di un'ottimizzazione prematura.159 160In generale, i programmatori del kernel ignorano gli effetti della cache a161loro rischio e pericolo. Il classico compromesso tempo/spazio teorizzato162all'inizio delle lezioni sulle strutture dati spesso non si applica163all'hardware moderno. Lo spazio *è* tempo, in questo senso un programma164più grande sarà più lento rispetto ad uno più compatto.165 166I compilatori più recenti hanno preso un ruolo attivo nel decidere se167una data funzione deve essere resa inline oppure no. Quindi l'uso168indiscriminato della parola chiave "inline" potrebbe non essere non solo169eccessivo, ma anche irrilevante.170 171Sincronizzazione172****************173 174Nel maggio 2006, il sistema di rete "Devicescape" fu rilasciato in pompa magna175sotto la licenza GPL e reso disponibile per la sua inclusione nella ramo176principale del kernel. Questa donazione fu una notizia bene accolta;177il supporto per le reti senza fili era considerata, nel migliore dei casi,178al di sotto degli standard; il sistema Deviscape offrì la promessa di una179risoluzione a tale situazione. Tuttavia, questo codice non fu inserito nel180ramo principale fino al giugno del 2007 (2.6.22). Cosa accadde?181 182Quel codice mostrava numerosi segnali di uno sviluppo in azienda avvenuto183a porte chiuse. Ma in particolare, un grosso problema fu che non fu184progettato per girare in un sistema multiprocessore. Prima che questo185sistema di rete (ora chiamato mac80211) potesse essere inserito, fu necessario186un lavoro sugli schemi di sincronizzazione.187 188Una volta, il codice del kernel Linux poteva essere sviluppato senza pensare189ai problemi di concorrenza presenti nei sistemi multiprocessore. Ora,190comunque, questo documento è stato scritto su di un portatile dual-core.191Persino su sistemi a singolo processore, il lavoro svolto per incrementare192la capacità di risposta aumenterà il livello di concorrenza interno al kernel.193I giorni nei quali il codice poteva essere scritto senza pensare alla194sincronizzazione sono da passati tempo.195 196Ogni risorsa (strutture dati, registri hardware, etc.) ai quali si potrebbe197avere accesso simultaneo da più di un thread deve essere sincronizzato. Il198nuovo codice dovrebbe essere scritto avendo tale accortezza in testa;199riadattare la sincronizzazione a posteriori è un compito molto più difficile.200Gli sviluppatori del kernel dovrebbero prendersi il tempo di comprendere bene201le primitive di sincronizzazione, in modo da sceglier lo strumento corretto202per eseguire un compito. Il codice che presenta una mancanza di attenzione203alla concorrenza avrà un percorso difficile all'interno del ramo principale.204 205Regressioni206***********207 208Vale la pena menzionare un ultimo pericolo: potrebbe rivelarsi accattivante209l'idea di eseguire un cambiamento (che potrebbe portare a grandi210miglioramenti) che porterà ad alcune rotture per gli utenti esistenti.211Questa tipologia di cambiamento è chiamata "regressione", e le regressioni son212diventate mal viste nel ramo principale del kernel. Con alcune eccezioni,213i cambiamenti che causano regressioni saranno fermati se quest'ultime non214potranno essere corrette in tempo utile. È molto meglio quindi evitare215la regressione fin dall'inizio.216 217Spesso si è argomentato che una regressione può essere giustificata se essa218porta risolve più problemi di quanti non ne crei. Perché, dunque, non fare219un cambiamento se questo porta a nuove funzionalità a dieci sistemi per220ognuno dei quali esso determina una rottura? La migliore risposta a questa221domanda ci è stata fornita da Linus nel luglio 2007:222 223::224 Dunque, noi non sistemiamo bachi introducendo nuovi problemi. Quella225 via nasconde insidie, e nessuno può sapere del tutto se state facendo226 dei progressi reali. Sono due passi avanti e uno indietro, oppure227 un passo avanti e due indietro?228 229(http://lwn.net/Articles/243460/).230 231Una particolare tipologia di regressione mal vista consiste in una qualsiasi232sorta di modifica all'ABI dello spazio utente. Una volta che un'interfaccia233viene esportata verso lo spazio utente, dev'essere supportata all'infinito.234Questo fatto rende la creazione di interfacce per lo spazio utente235particolarmente complicato: dato che non possono venir cambiate introducendo236incompatibilità, esse devono essere fatte bene al primo colpo. Per questa237ragione sono sempre richieste: ampie riflessioni, documentazione chiara e238ampie revisioni dell'interfaccia verso lo spazio utente.239 240 241Strumenti di verifica del codice242--------------------------------243Almeno per ora la scrittura di codice priva di errori resta un ideale244irraggiungibile ai più. Quello che speriamo di poter fare, tuttavia, è245trovare e correggere molti di questi errori prima che il codice entri nel246ramo principale del kernel. A tal scopo gli sviluppatori del kernel devono247mettere insieme una schiera impressionante di strumenti che possano248localizzare automaticamente un'ampia varietà di problemi. Qualsiasi problema249trovato dal computer è un problema che non affliggerà l'utente in seguito,250ne consegue che gli strumenti automatici dovrebbero essere impiegati ovunque251possibile.252 253Il primo passo consiste semplicemente nel fare attenzione agli avvertimenti254proveniente dal compilatore. Versioni moderne di gcc possono individuare255(e segnalare) un gran numero di potenziali errori. Molto spesso, questi256avvertimenti indicano problemi reali. Di regola, il codice inviato per la257revisione non dovrebbe produrre nessun avvertimento da parte del compilatore.258Per mettere a tacere gli avvertimenti, cercate di comprenderne le cause reali259e cercate di evitare le "riparazioni" che fan sparire l'avvertimento senza260però averne trovato la causa.261 262Tenete a mente che non tutti gli avvertimenti sono disabilitati di default.263Costruite il kernel con "make KCFLAGS=-W" per ottenerli tutti.264 265Il kernel fornisce differenti opzioni che abilitano funzionalità di debugging;266molti di queste sono trovano all'interno del sotto menu "kernel hacking".267La maggior parte di queste opzioni possono essere attivate per qualsiasi268kernel utilizzato per lo sviluppo o a scopo di test. In particolare dovreste269attivare:270 271 - FRAME_WARN per ottenere degli avvertimenti su stack frame più272 grandi di un dato valore. Il risultato generato da questi273 avvertimenti può risultare verboso, ma non bisogna preoccuparsi per274 gli avvertimenti provenienti da altre parti del kernel.275 276 - DEBUG_OBJECTS aggiungerà un codice per tracciare il ciclo di vita di277 diversi oggetti creati dal kernel e avvisa quando qualcosa viene eseguito278 fuori controllo. Se state aggiungendo un sottosistema che crea (ed279 esporta) oggetti complessi propri, considerate l'aggiunta di un supporto280 al debugging dell'oggetto.281 282 - DEBUG_SLAB può trovare svariati errori di uso e di allocazione di memoria;283 esso dovrebbe esser usato dalla maggior parte dei kernel di sviluppo.284 285 - DEBUG_SPINLOCK, DEBUG_ATOMIC_SLEEP, e DEBUG_MUTEXES troveranno un certo286 numero di errori comuni di sincronizzazione.287 288Esistono ancora delle altre opzioni di debugging, di alcune di esse289discuteremo qui sotto. Alcune di esse hanno un forte impatto e non dovrebbero290essere usate tutte le volte. Ma qualche volta il tempo speso nell'capire291le opzioni disponibili porterà ad un risparmio di tempo nel breve termine.292 293Uno degli strumenti di debugging più tosti è il *locking checker*, o294"lockdep". Questo strumento traccerà qualsiasi acquisizione e rilascio di295ogni *lock* (spinlock o mutex) nel sistema, l'ordine con il quale i *lock*296sono acquisiti in relazione l'uno con l'altro, l'ambiente corrente di297interruzione, eccetera. Inoltre esso può assicurare che i *lock* vengano298acquisiti sempre nello stesso ordine, che le stesse assunzioni sulle299interruzioni si applichino in tutte le occasioni, e così via. In altre parole,300lockdep può scovare diversi scenari nei quali il sistema potrebbe, in rari301casi, trovarsi in stallo. Questa tipologia di problema può essere grave302(sia per gli sviluppatori che per gli utenti) in un sistema in uso; lockdep303permette di trovare tali problemi automaticamente e in anticipo.304 305In qualità di programmatore kernel diligente, senza dubbio, dovrete controllare306il valore di ritorno di ogni operazione (come l'allocazione della memoria)307poiché esso potrebbe fallire. Il nocciolo della questione è che i percorsi308di gestione degli errori, con grande probabilità, non sono mai stati309collaudati del tutto. Il codice collaudato tende ad essere codice bacato;310potrete quindi essere più a vostro agio con il vostro codice se tutti questi311percorsi fossero stati verificati un po' di volte.312 313Il kernel fornisce un framework per l'inserimento di fallimenti che fa314esattamente al caso, specialmente dove sono coinvolte allocazioni di memoria.315Con l'opzione per l'inserimento dei fallimenti abilitata, una certa percentuale316di allocazione di memoria sarà destinata al fallimento; questi fallimenti317possono essere ridotti ad uno specifico pezzo di codice. Procedere con318l'inserimento dei fallimenti attivo permette al programmatore di verificare319come il codice risponde quando le cose vanno male. Consultate:320Documentation/fault-injection/fault-injection.rst per avere maggiori321informazioni su come utilizzare questo strumento.322 323Altre tipologie di errori possono essere riscontrati con lo strumento di324analisi statica "sparse". Con Sparse, il programmatore può essere avvisato325circa la confusione tra gli indirizzi dello spazio utente e dello spazio326kernel, un miscuglio fra quantità big-endian e little-endian, il passaggio327di un valore intero dove ci sia aspetta un gruppo di flag, e così via.328Sparse deve essere installato separatamente (se il vostra distribuzione non329lo prevede, potete trovarlo su https://sparse.wiki.kernel.org/index.php/Main_Page);330può essere attivato sul codice aggiungendo "C=1" al comando make.331 332Lo strumento "Coccinelle" (http://coccinelle.lip6.fr/) è in grado di trovare333una vasta varietà di potenziali problemi di codifica; e può inoltre proporre334soluzioni per risolverli. Un buon numero di "patch semantiche" per il kernel335sono state preparate nella cartella scripts/coccinelle; utilizzando336"make coccicheck" esso percorrerà tali patch semantiche e farà rapporto su337qualsiasi problema trovato. Per maggiori informazioni, consultate338:ref:`Documentation/dev-tools/coccinelle.rst <devtools_coccinelle>`.339 340Altri errori di portabilità sono meglio scovati compilando il vostro codice341per altre architetture. Se non vi accade di avere un sistema S/390 o una342scheda di sviluppo Blackfin sotto mano, potete comunque continuare la fase343di compilazione. Un vasto numero di cross-compilatori per x86 possono344essere trovati al sito:345 346 http://www.kernel.org/pub/tools/crosstool/347 348Il tempo impiegato nell'installare e usare questi compilatori sarà d'aiuto349nell'evitare situazioni imbarazzanti nel futuro.350 351 352Documentazione353--------------354 355La documentazione è spesso stata più un'eccezione che una regola nello356sviluppo del kernel. Nonostante questo, un'adeguata documentazione aiuterà357a facilitare l'inserimento di nuovo codice nel kernel, rende la vita più358facile per gli altri sviluppatori e sarà utile per i vostri utenti. In molti359casi, la documentazione è divenuta sostanzialmente obbligatoria.360 361La prima parte di documentazione per qualsiasi patch è il suo changelog.362Questi dovrebbero descrivere le problematiche risolte, la tipologia di363soluzione, le persone che lavorano alla patch, ogni effetto rilevante364sulle prestazioni e tutto ciò che può servire per la comprensione della365patch. Assicuratevi che il changelog dica *perché*, vale la pena aggiungere366la patch; un numero sorprendente di sviluppatori sbaglia nel fornire tale367informazione.368 369Qualsiasi codice che aggiunge una nuova interfaccia in spazio utente - inclusi370nuovi file in sysfs o /proc - dovrebbe includere la documentazione di tale371interfaccia così da permette agli sviluppatori dello spazio utente di sapere372con cosa stanno lavorando. Consultate: Documentation/ABI/README per avere una373descrizione di come questi documenti devono essere impostati e quali374informazioni devono essere fornite.375 376Il file :ref:`Documentation/translations/it_IT/admin-guide/kernel-parameters.rst <kernelparameters>`377descrive tutti i parametri di avvio del kernel. Ogni patch che aggiunga378nuovi parametri dovrebbe aggiungere nuove voci a questo file.379 380Ogni nuova configurazione deve essere accompagnata da un testo di supporto381che spieghi chiaramente le opzioni e spieghi quando l'utente potrebbe volerle382selezionare.383 384Per molti sottosistemi le informazioni sull'API interna sono documentate sotto385forma di commenti formattati in maniera particolare; questi commenti possono386essere estratti e formattati in differenti modi attraverso lo script387"kernel-doc". Se state lavorando all'interno di un sottosistema che ha388commenti kerneldoc dovreste mantenerli e aggiungerli, in maniera appropriata,389per le funzioni disponibili esternamente. Anche in aree che non sono molto390documentate, non c'è motivo per non aggiungere commenti kerneldoc per il391futuro; infatti, questa può essere un'attività utile per sviluppatori novizi392del kernel. Il formato di questi commenti, assieme alle informazione su come393creare modelli per kerneldoc, possono essere trovati in394:ref:`Documentation/translations/it_IT/doc-guide/ <doc_guide>`.395 396Chiunque legga un ammontare significativo di codice kernel noterà che, spesso,397i commenti si fanno maggiormente notare per la loro assenza. Ancora una volta,398le aspettative verso il nuovo codice sono più alte rispetto al passato;399inserire codice privo di commenti sarà più difficile. Detto ciò, va aggiunto400che non si desiderano commenti prolissi per il codice. Il codice dovrebbe401essere, di per sé, leggibile, con dei commenti che spieghino gli aspetti più402sottili.403 404Determinate cose dovrebbero essere sempre commentate. L'uso di barriere405di memoria dovrebbero essere accompagnate da una riga che spieghi perché sia406necessaria. Le regole di sincronizzazione per le strutture dati, generalmente,407necessitano di una spiegazioni da qualche parte. Le strutture dati più408importanti, in generale, hanno bisogno di una documentazione onnicomprensiva.409Le dipendenze che non sono ovvie tra bit separati di codice dovrebbero essere410indicate. Tutto ciò che potrebbe indurre un inserviente del codice a fare411una "pulizia" incorretta, ha bisogno di un commento che dica perché è stato412fatto in quel modo. E così via.413 414Cambiamenti interni dell'API415----------------------------416 417L'interfaccia binaria fornita dal kernel allo spazio utente non può essere418rotta tranne che in circostanze eccezionali. L'interfaccia di programmazione419interna al kernel, invece, è estremamente fluida e può essere modificata al420bisogno. Se vi trovate a dover lavorare attorno ad un'API del kernel o421semplicemente non state utilizzando una funzionalità offerta perché questa422non rispecchia i vostri bisogni, allora questo potrebbe essere un segno che423l'API ha bisogno di essere cambiata. In qualità di sviluppatore del kernel,424hai il potere di fare questo tipo di modifica.425 426Ci sono ovviamente alcuni punti da cogliere. I cambiamenti API possono essere427fatti, ma devono essere giustificati. Quindi ogni patch che porta ad una428modifica dell'API interna dovrebbe essere accompagnata da una descrizione429della modifica in sé e del perché essa è necessaria. Questo tipo di430cambiamenti dovrebbero, inoltre, essere fatti in una patch separata, invece di431essere sepolti all'interno di una patch più grande.432 433L'altro punto da cogliere consiste nel fatto che uno sviluppatore che434modifica l'API deve, in generale, essere responsabile della correzione435di tutto il codice del kernel che viene rotto per via della sua modifica.436Per una funzione ampiamente usata, questo compito può condurre letteralmente437a centinaia o migliaia di modifiche, molte delle quali sono in conflitto con438il lavoro svolto da altri sviluppatori. Non c'è bisogno di dire che questo439può essere un lavoro molto grosso, quindi è meglio essere sicuri che la440motivazione sia ben solida. Notate che lo strumento Coccinelle può fornire441un aiuto con modifiche estese dell'API.442 443Quando viene fatta una modifica API incompatibile, una persona dovrebbe,444quando possibile, assicurarsi che quel codice non aggiornato sia trovato445dal compilatore. Questo vi aiuterà ad essere sicuri d'avere trovato,446tutti gli usi di quell'interfaccia. Inoltre questo avviserà gli sviluppatori447di codice fuori dal kernel che c'è un cambiamento per il quale è necessario del448lavoro. Il supporto al codice fuori dal kernel non è qualcosa di cui gli449sviluppatori del kernel devono preoccuparsi, ma non dobbiamo nemmeno rendere450più difficile del necessario la vita agli sviluppatori di questo codice.451