Re-entrancy è / diventa un grosso problema quanto più i tuoi ISR sono complessi. La voce di wikipedia ha una descrizione piuttosto succinta di un ISR rientrante:
Un gestore di interrupt rientrante è un gestore di interrupt che riattiva gli interrupt all'inizio del gestore di interrupt. Ciò potrebbe ridurre la latenza degli interrupt. [6] In generale, durante la programmazione delle routine del servizio di interrupt, si consiglia di riattivare gli interrupt il prima possibile nel gestore degli interrupt. Questa pratica aiuta a evitare di perdere interruzioni. [7]
Supponendo che tu non stia scrivendo un sistema operativo generico in cui il rientro potrebbe essere inevitabile, devi tenere presente che l'ulteriore complessità di rientrare nel codice del controller personalizzato potrebbe non valere la pena percepita facilità di scrittura di ISR pigri e di lunga durata.
Ecco un esempio:
- ISR di lunga durata e priorità bassa inizia a fare qualcosa, chiama una versione di
malloc
che hai implementato.
- Chiamata
malloc
media, vieni interrotto da un thread con priorità più alta: chiama anche malloc
- scenario a: l'ISR ad alta priorità esce da malloc prima della priorità bassa
- scenario b: l'ISR ad alta priorità esce da malloc dopo una priorità bassa *
Ok, dirai, metterò un blocco di rotazione su malloc, quindi tutto ciò che devi fare è ripetere la condizione precedente alla primitiva spinlock_aquire
che hai creato: è it rientrante?
Dovrei sottolineare qui che semplicemente schiaffeggiare le cose e chiamarlo un giorno è una ricetta per i deadlock basati sull'inversione di priorità. Non è così semplice.
La soluzione del povero uomo a tutti questi problemi è mantenere brevi i tuoi ISR. Ad esempio, nel kernel NT, molto tempo fa (non si è tenuto aggiornato), a qualsiasi IRQL sopra gli ultimi due non era nemmeno permesso guardare la memoria di paging. Questo perché il paging era gestito da un interrupt ...
Quindi la scelta diventa: implementare un meccanismo di accodamento di base e fare in modo che i propri ISR inviano unità di lavoro, oppure fare in modo che i propri ISR si comportino liberamente ma assicurarsi di avere un ambiente estremamente robusto che non soffocerà su questioni strane (ad es. inversione di priorità).
Se il tuo compito è semplicissimo, come accendere una luce nel tuo drone controllato da arduino, allora vai avanti con tutti i mezzi. Ma se vuoi evitare grattacapi ingegneristici in seguito man mano che il tuo codice diventa più complesso, dovresti davvero evitare il beneficio percepito di non darti alcun vincolo con un ISR.
* chiarimento: lo scenario b non può verificarsi al valore nominale poiché l'ISR con priorità più alta verrà sempre eseguito e completato prima di quello con priorità più bassa. Tuttavia, il percorso del codice preso da uno dei due può essere scambiato. Quindi nella stessa routine malloc
, se c'è un accesso a una struttura dati globale, quel codice può essere interrotto in ogni possibile combinazione di modi.
Oltre a questo punto, si dovrebbe affermare che il requisito di rientranza per qualsiasi funzione riguarda l'intero albero delle chiamate. Questo diventa molto difficile da garantire se si finisce per utilizzare librerie di terze parti.
Nota anche: per indirizzare un commento da @ user253751, il re-entrancy non viene risolto semplicemente avvolgendo le cose in un lucchetto. Piuttosto, re-entrancy ha una serie di requisiti che sono ben compresi. Ecco alcuni esempi di codice banali che illustrano la questione.
Si può vedere, osservando questo aspetto, che la scrittura di una funzione di acquisizione di risorse o malloc rientranti diventa molto difficile.