Como o kernel do Linux descobre qual processo acordar durante o tratamento de interrupção?

5

Eu estava lendo o livro Linux Kernel Development no Capítulo Programação de Processos . Na página 61, seção Waking Up , o primeiro parágrafo diz:

Waking is handled via wake_up(), which wakes up all the tasks waiting on the given wait queue. It (Q1:what does this it refer to?) calls try_to_wake_up(), which sets the task’s(Q2:which task? all awoken tasks?) state to TASK_RUNNING, calls enqueue_task() to add the task to the red-black tree, and sets need_resched if the awakened task’s priority is higher than the priority of the current task.The code that causes the event to occur typically calls wake_up() itself. For example, when data arrives from the hard disk, the VFS calls wake_up() on the wait queue that holds the processes waiting for the data.

Estou bastante confuso sobre o que foi dito acima. Deixe-me usar o exemplo no parágrafo acima, ou seja, o disco foi interrompido após a leitura dos dados, mas com uma imagem mais completa. Por favor, corrija-me se alguma das seguintes situações estiver errada ou incompleta:

  1. Algum processo do usuário emitiu uma operação de leitura de bloqueio, acionando uma chamada sys e o processo está no reino do kernel.

  2. O Kernel configura o controlador de disco solicitando os dados necessários e coloca esse processo em suspensão (esse processo é colocado em uma fila de espera). O Kernel agenda outro processo para ser executado.

  3. Ocorre uma interrupção no disco. A CPU suspende o processo de execução atual e pula para o tratamento de interrupção do disco.

  4. O controlador de disco inicializará durante o manuseio da interrupção para transferir os dados lidos do disco para a memória principal (sob a direção da CPU ou por DMA)

  5. (Não tenho certeza, por favor corrija) Como diz o parágrafo, o VFS chama wake_up () na fila de espera que mantém os processos aguardando pelos dados.

Minhas perguntas específicas são as seguintes:

Q1 (consulte o parágrafo citado): Assumo que o It na segunda frase se refere à função wake_up() . Por que a função wake_up acorda all tarefas em vez de apenas esperar por esses dados de disco?

Q2 (consulte o parágrafo citado): try_to_wake_up() de alguma forma conhece a tarefa específica cujo estado precisa ser definido como TASK_RUNNING? Ou try_to_wake_up() define o estado de todas as tarefas acordadas como TASK_RUNNING?

Q3 : Quantas filas de espera existem para o kernel gerenciar? Se houver mais de duas filas de espera, como o kernel saberá qual fila selecionar, de modo que o processo que aguarda os dados do disco esteja na fila de espera?

Q4 : Agora digamos que sabemos a fila onde o processo de espera está. Como o kernel sabe qual processo está aguardando os dados do disco? Eu só posso imaginar que alguma informação específica para o processo solicitando os dados do disco é passada para o controlador de disco, como PID do processo, endereço de memória ou algo assim. Em seguida, ao concluir o tratamento de interrupção, o controlador de disco (ou kernel?) Usa essa informação para identificar o processo na fila de espera.

Por favor me ajude a completar esta foto do processo wake_up! Obrigado!

    
por Rich 06.03.2016 / 20:03

3 respostas

7

Q1: "É" wake_up . Ele acorda todas as tarefas que estão esperando pelos dados do disco . Se eles não estivessem esperando por esses dados, eles não estariam esperando naquela fila.

Q2: Não tenho certeza se entendi a pergunta. Cada entrada da fila de despertar contém um ponteiro para a tarefa. try_to_wake_up recebe um ponteiro para a tarefa que deve acordar. É chamado uma vez por função.

Q3: existem muitas filas de espera. Há um para cada evento que pode acontecer. O driver de disco configura uma fila de espera para cada solicitação para o disco. Por exemplo, quando o driver do sistema de arquivos quer o conteúdo de um determinado bloco de disco, ele pergunta ao driver do disco por esse bloco e, em seguida, a solicitação começa com a tarefa que fez a solicitação do sistema de arquivos. Outras entradas podem ser adicionadas à fila de espera se outra solicitação para o mesmo bloco chegar enquanto esta ainda estiver pendente.

Quando ocorre uma interrupção, o driver de disco determina qual disco possui dados disponíveis a partir das informações transmitidas pelo hardware e procura a estrutura de dados que contém os dados do kernel para esse disco para localizar qual solicitação deve ser preenchida. Nessa estrutura de dados, entre outras, estão a localização onde os dados devem ser gravados e a fila de ativação correspondente indicando o que fazer a seguir.

Q4: O processo faz uma chamada de sistema, digamos, para ler um arquivo. Isso aciona algum código no driver do sistema de arquivos que determina que os dados precisam ser carregados do disco. Esse código faz uma solicitação ao driver de disco e adiciona o processo de chamada à fila de espera da solicitação. (Na verdade, existem mais camadas do que isso, mas você entende.) Quando a leitura do disco é concluída, o evento da fila de espera é acionado e o processo é removido da fila de espera do disco. O código acionado pelo evento da fila de espera é uma função fornecida pelo driver do sistema de arquivos, que copia os dados para a memória do processo e faz com que a chamada do sistema read retorne.

    
por 06.03.2016 / 21:26
3

Para aproveitar a resposta de Gilles,

Q2 : não tenho certeza, mas eu interpretaria a passagem do livro significa que o manipulador de interrupção chama wake_up() uma vez (passando o identificador de fila como argumento) e wake_up() chama try_to_wake_up() para cada processo que está nessa fila. (Isso reitera a resposta de Gilles a Q1 : não acorda todas as tarefas, apenas as que estão na fila de espera associado ao evento que chamou wake_up() .)

Q3 : cada fila de espera é "de propriedade" de algum código do kernel - principalmente drivers de dispositivos, alguns outros. A rotina que possui uma fila atribui a ela um identificador exclusivo, com base em alguma característica exclusiva do evento para o qual a fila é destinada. Quando ele (o driver / outro módulo) coloca um processo para dormir, especifica (por ID) em qual fila colocá-lo. A rotina que chama wake_up() (normalmente um manipulador de interrupção) deve fazer parte do mesmo módulo que coloca o processo para dormir, por isso sabe o identificador para a fila que corresponde ao evento que aconteceu.

A última vez que eu olhei o código-fonte do kernel Unix (que foi há muitos anos atrás), os drivers de disco tinham um ID de evento diferente para cada solicitação de E / S. Como diz Gilles, vários processos podem estar esperando pelo mesmo evento se eles estão lendo o mesmo arquivo ao mesmo tempo. (Isso, claro, também está relacionado a Q1 .)

Q4 : Quando ouço a frase “controlador de disco”, penso em hardware. Mas, além disso, você está certo; o disco driver (um módulo de software no kernel) tem (pelo menos potencialmente) acesso a todas informações sobre qualquer processo que o invoque (isto é, fazendo disco I / O). Então, quando o driver de disco coloca um processo para dormir porque iniciou uma E / S física que leva tempo para ser concluída, ele (o motorista) coloca “o PID do processo, endereço de memória ou algo assim” na fila de espera. Seja o que for, basta que try_to_wake_up() acorde o processo.

A última frase da passagem que você citou diz: “… O VFS chama wake_up () na fila de espera…”. Eu questiono se isso é literalmente correto. O código do sistema de arquivos é uma camada acima do driver de disco. Eu esperaria a interrupção (um sinal do hardware de disco para a CPU) a ser tratado pelo manipulador de interrupção de disco (parte do driver de disco) que acordaria o (s) processo (s) que estão esperando (chamando wake_up() ). O driver, em seguida, acordaria o código do sistema de arquivos. (Essa terminologia pode ser imprecisa também. Pode ser melhor dizer que o motorista faz alguma coisa para permitir que o código do sistema de arquivos continue o processamento.) O código do sistema de arquivos pode retornar ao processo do usuário, ou pode invocar o driver de disco novamente, resultando na suspensão do processo novamente.

Eu brinco com o seu passo # 4. Se um dispositivo estiver usando o DMA, não irá interromper até que a transferência de dados seja concluída.

    
por 07.03.2016 / 00:52
2

O problema que você cita, acordar todos os processos em espera é o que é chamado de "rebanho trovejante" (muitos processos são despertados quando um recurso se torna disponível, eles lutam sobre qual deles obtém acesso exclusivo para o recurso, os outros voltam a dormir). Isso se torna um problema quando há muitos processadores e, portanto, há muitos processadores lutando aqui. Versões mais recentes do Linux resolvem isso simplesmente despertando um dos processos em espera.

Na maioria das vezes, haverá um (ou apenas alguns) processos aguardando um evento específico (não há um número fixo, muito menos pequeno, de eventos nos quais um processo pode estar aguardando).

A resposta de Gilles passa pelos seus pontos um por um, não há muito a acrescentar a isso aqui.

    
por 07.03.2016 / 00:57