Quando un processo è in modalità utente, può essere interrotto in qualsiasi momento (passando alla modalità kernel). Quando il kernel torna in modalità utente, controlla se ci sono segnali in sospeso (compresi quelli che vengono usati per terminare il processo, come SIGTERM
e SIGKILL
). Ciò significa che un processo può essere interrotto solo al ritorno in modalità utente.
Il motivo per cui un processo non può essere interrotto in modalità kernel è che potrebbe potenzialmente danneggiare le strutture del kernel utilizzate da tutti gli altri processi nella stessa macchina (allo stesso modo l'uccisione di un thread può potenzialmente danneggiare le strutture dati utilizzate da altri thread nello stesso processo) .
Quando il kernel ha bisogno di fare qualcosa che potrebbe richiedere molto tempo (aspettando su una pipe scritta da un altro processo o aspettando che l'hardware faccia qualcosa, per esempio), dorme contrassegnandosi come sleep e chiamando lo scheduler per passare a un altro processo (se non esiste un processo non inattivo, passa a un processo "fittizio" che dice alla CPU di rallentare un po 'e si trova in un ciclo - il ciclo inattivo).
Se un segnale viene inviato a un processo di sospensione, deve essere svegliato prima che ritorni nello spazio utente e quindi elabori il segnale in sospeso. Qui abbiamo la differenza tra i due principali tipi di sonno:
TASK_INTERRUPTIBLE
, il sonno interrompibile. Se un'attività è contrassegnata con questa bandiera, sta dormendo, ma può essere svegliata dai segnali. Ciò significa che il codice che ha contrassegnato l'attività come inattiva si aspetta un segnale possibile e dopo che si è svegliato lo controlla e torna dalla chiamata di sistema. Dopo che il segnale è stato gestito, la chiamata di sistema può essere potenzialmente riavviata automaticamente (e non entrerò nei dettagli su come funziona).
TASK_UNINTERRUPTIBLE
, il sonno ininterrotto. Se un'attività è contrassegnata con questo flag, non si aspetta che venga svegliata da qualcosa di diverso da quello che sta aspettando, sia perché non può essere riavviata facilmente, sia perché i programmi si aspettano che la chiamata di sistema sia atomica. Questo può essere usato anche per dormire noti per essere molto brevi.
TASK_KILLABLE
(menzionato nell'articolo LWN collegato alla risposta di ddaa) è una nuova variante.
Questo risponde alla tua prima domanda. Per quanto riguarda la tua seconda domanda: non puoi evitare di dormire ininterrottamente, sono una cosa normale (succede, ad esempio, ogni volta che un processo legge / scrive da / sul disco); tuttavia, dovrebbero durare solo una frazione di secondo. Se durano molto più a lungo, di solito significa un problema hardware (o un problema del driver del dispositivo, che sembra lo stesso al kernel), in cui il driver del dispositivo è in attesa che l'hardware faccia qualcosa che non accadrà mai. Può anche significare che stai usando NFS e il server NFS è inattivo (è in attesa che il server si ripristini; puoi anche usare l'opzione "intr" per evitare il problema).
Infine, il motivo per cui non è possibile ripristinare è lo stesso motivo che il kernel attende fino al ritorno in modalità utente per inviare un segnale o interrompere il processo: potrebbe corrompere potenzialmente le strutture di dati del kernel (il codice in attesa di un sonno interrompibile potrebbe ricevere un errore che lo dice per tornare allo spazio utente, dove il processo può essere interrotto; il codice in attesa di un sonno ininterrotto non prevede alcun errore).
TASK_UNINTERUPTIBLE
stato ogni volta che il sistema non è in uno stato inattivo, in tal modo raccogliendo forzatamente i dati, in attesa di trasmettere una volta uscito il superutente? Questa sarebbe una miniera d'oro per gli hacker per recuperare informazioni, tornare allo stato di zombi e trasmettere informazioni attraverso la rete in idle. Alcuni possono sostenere che questo è un modo per creare unBlackdoor
per i poteri che sono, per entrare e uscire da qualsiasi sistema come desiderato. Credo fermamente che questa scappatoia possa essere sigillata per sempre, eliminando il `TASK_UNINTERUPTIB