Por código do kernel / thread em execução no contexto de interrupção não consegue dormir?

StackOverflow https://stackoverflow.com/questions/1053572

  •  20-08-2019
  •  | 
  •  

Pergunta

Estou lendo seguinte artigo por Robert Love

http://www.linuxjournal.com/article/6916

que diz

" ... Vamos discutir o fato de que as filas de trabalho executado no contexto de processo. Isso está em contraste com os outros mecanismos bottom-meia, que todos os executados no contexto de interrupção. Código em execução no contexto de interrupção é incapaz de dormir, ou bloco , porque contexto de interrupção não tem um processo de apoio com o qual para reagendar. Portanto, como manipuladores de interrupção não estão associadas a um processo, não há nada para o programador para colocar para dormir e, mais importante, nada para o programador para acordar. .. "

Eu não entendo. AFAIK, scheduler no kernel é O (1), que é implementado através do bitmap. Então, o que pára o scehduler de colocar contexto de interrupção de sono e tomando próximo processo escalonável e passando o controle?

Foi útil?

Solução

Eu acho que é uma idéia do projeto.

Claro, você pode projetar um sistema que você pode dormir em interrupção, mas exceto para fazer para o sistema difícil de compreender e complicado (muitos muitos situação que você tem que levar em conta), que de não ajuda nada. Assim, a partir de uma exibição de design, declare manipulador de interrupção de sono não pode é muito clara e fácil de implementar.


De Robert Love (um hacker kernel): http://permalink.gmane.org/gmane.linux.kernel.kernelnewbies/1791

Você não pode dormir em um manipulador de interrupção porque interrupções não têm contexto de um processo de suporte, e, assim, não há nada para trás reprogramar para dentro. Em outras palavras, manipuladores de interrupção não estão associados a uma tarefa, então não há nada de "colocar para dormir" e (mais importante) "nada a acordar". Eles devem executar atomicamente.

Isto não é diferente de outros sistemas operacionais. Na maioria dos sistemas operacionais, as interrupções não são roscados. metades inferiores muitas vezes são, no entanto.

A razão da falha de página manipulador pode dormir é que ele só é invocado pelo código que está em execução no contexto de processo. Como o kernel é própria memória não é pagable, apenas acessos à memória do espaço do usuário pode resultar em uma falha de página. Assim, apenas alguns determinados lugares (tais como chamadas para copy_ {para, a partir} _USER ()) pode causar uma falha de página dentro do kernel. Essa lugares devem ser feitos pelo código que pode dormir (ou seja, o contexto do processo, sem bloqueios, et cetera).

Outras dicas

Então, o que pára o scehduler de colocar contexto de interrupção de sono e tomando próximo processo escalonável e passando o controle?

O problema é que o contexto de interrupção não é um processo e, portanto, não pode ser posto para dormir.

Quando uma interrupção ocorre, o processador salva os registradores na pilha e pula para o início da rotina de serviço de interrupção. Isto significa que, quando o processador de interrupção é executado, ele está em execução no contexto do processo que foi executada quando ocorreu a interrupção. A interrupção está executando na pilha desse processo, e quando da conclusão do manipulador de interrupção, esse processo será retomado a execução.

Se você tentou dormir ou bloco dentro de um manipulador de interrupção, você acabaria não só parar o manipulador de interrupção, mas também o processo que interrompeu. Isso pode ser perigoso, como o manipulador de interrupção não tem como saber o que o processo interrompido estava fazendo, ou mesmo se ele é seguro para que o processo deve ser suspenso.

Um cenário simples, onde as coisas poderiam dar errado seria um impasse entre o manipulador de interrupção eo processo que interrupções.

  1. Process1 entra em modo kernel.
  2. Process1 adquire Locka .
  3. ocorre interrupção.
  4. começa ISR execução usando Process1 's pilha.
  5. tentativas ISR para adquirir Locka .
  6. chamadas ISR dormir para esperar Locka para ser liberado.

Neste ponto, você tem um impasse. Process1 não pode continuar a execução até que o ISR é feito com a sua stack. Mas o ISR está bloqueado à espera de Process1 para liberar Locka .

Como a infra-estrutura de comutação de linha é inutilizável naquele ponto. Ao fazer a manutenção de uma interrupção, único material de maior prioridade pode executar - Veja o Intel Software Developer manual de interrupção, a tarefa ea prioridade processador . Se você não permitir outro segmento para executar (que implica na sua pergunta que seria fácil de fazer), você não seria capaz de deixá-lo fazer qualquer coisa - se ele causou uma falha de página, você teria que usar serviços no kernel que não são utilizáveis ??enquanto a interrupção está sendo atendido (veja abaixo o porquê).

Normalmente, o seu único objetivo em uma rotina de interrupção é fazer com que o dispositivo para parar de interromper e fila de algo em um nível de interrupção inferior (em unix este é tipicamente um nível não-interrupção, mas para Windows, expedição, apc-lo de ou passiva nível) para fazer o trabalho pesado, onde você tem acesso a mais recursos do kernel / oS. Veja -. implementando um manipulador

É uma propriedade de como o O / S tem que trabalhar, não é algo inerente Linux. Uma rotina de interrupção pode executar em qualquer ponto para o estado do que você interrompeu é inconsistente. Se você interrompeu o código de programação fio, seu estado é inconsistente para que você não pode ter certeza que você pode "dormir" e comutação tópicos. Mesmo se você proteger o código de troca de thread de ser interrompido, troca de thread é um recurso muito alto nível do O / S e se você protegido tudo o que depende, uma interrupção torna-se mais de uma sugestão do que o imperativo implícito pelo seu nome.

Então, o que pára o scehduler de colocar contexto de interrupção de sono e tomando próximo processo escalonável e passando o controle?

Agendamento acontece em interrupções do timer. A regra básica é que apenas uma interrupção pode ser aberto ao mesmo tempo, então se você ir dormir na interrupção "de dados tenho de dispositivo X", a interrupção do timer não pode correr para programá-lo para fora.

Interrupções também acontecem muitas vezes e se sobrepõem. Se você colocar os "dados tem" interromper a dormir, e em seguida, obter mais dados, o que acontece? É confuso (e frágil) o suficiente para que o catch-all regra é: não dormir em interrupções. Você vai fazê-lo errado.

Mesmo que você poderia colocar um ISR para dormir, você não gostaria de fazê-lo. Você quer que seus ISRs ser tão rápido quanto possível para reduzir o risco de perder as interrupções subseqüentes.

Não permitir um manipulador de interrupção para o bloco é uma escolha design. Quando alguns dados está no dispositivo, as interceptações manipulador de interrupção do processo atual, prepara a transferência dos dados e permite a interrupção; antes do manipulador permite a interrupção de corrente, o dispositivo tem para pendurar. Queremos manter o nosso I / O ocupado e nosso sistema ágil, então é melhor não bloquear o manipulador de interrupção.

Eu não acho que os "estados instáveis" são uma razão essencial. Processos, não importa o que eles estão em user-mode ou modo kernel, deve estar ciente de que pode ser interrompida por interrupções. Se alguma estrutura de dados de modo kernel será acessado por ambos manipulador de interrupção eo processo atual e condição de corrida existe, então o processo atual deve desativar interrupções locais e, além disso para arquiteturas multi-processador, spinlocks deve ser usado para durante as seções críticas .

Eu também não acho que se o manipulador de interrupção foram bloqueadas, não podem ser despertar. Quando dizemos "block", basicamente isso significa que o processo bloqueado está esperando por algum evento / recurso, por isso liga-se em alguns espera-fila para esse evento / recurso. Sempre que o recurso é liberado, o processo de liberação é responsável por acordar o processo de espera (ES).

No entanto, a coisa realmente irritante é que o processo bloqueado não pode fazer nada durante o tempo de bloqueio; ele fez de errado nada para esta punição, o que é injusto. E ninguém poderia certamente prever o tempo de bloqueio, de modo que o processo de inocente tem que esperar por uma razão clara e por tempo ilimitado.

Por natureza, a questão é se no manipulador de interrupção você pode obter um válido "atual" (endereço ao task_structure processo atual), se sim, é possível modificar o conteúdo lá acordo para fazê-lo em estado de "sono", que pode estar de volta ao programador mais tarde, se o estado ter mudado de alguma forma. A resposta pode ser dependente de hardware.

Mas em ARM, é impossível, já que 'atual' é irrelevante para processo em modo de interrupção. Veja o código abaixo:

#linux/arch/arm/include/asm/thread_info.h 
94 static inline struct thread_info *current_thread_info(void)
95 {
96  register unsigned long sp asm ("sp");
97  return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));
98 }

sp no modo de usuário e modo de SVC são o "mesmo" ( "mesmo" aqui não significa que eles são iguais, em vez disso, ponto sp do modo de usuário para pilha de espaço do usuário, enquanto o ponto sp r13_svc de modo svc à pilha de kernel, onde task_structure do processo de usuário foi atualizado no interruptor de tarefa anterior, quando uma chamada de sistema ocorre, o processo de entrar no espaço do kernel novamente, quando o sp (sp_svc) ainda não é alterado, estes 2 sp estão associados uns com os outros, neste sentido, eles' re 'mesmo'), So no modo SVC, o código do kernel pode obter o válida 'atual'. Mas sob outros modos privilegiados, dizer o modo de interrupção, sp é 'diferente', aponte para endereço dedicado definido no cpu_init (). O 'atual' calculado de acordo com estes modo será irrelevante para o processo interrompido, acessá-lo irá resultar em comportamentos inesperados. É por isso que é sempre disse que chamada de sistema pode dormir, mas manipulador de interrupção não pode, obras de chamadas de sistema no contexto do processo, mas não interrompê-lo.

manipuladores de interrupção

Alto Nível mascarar as operações de todas as interrupções de menor prioridade, incluindo os da interrupção do timer do sistema. Consequentemente, o manipulador de interrupção deve evitar se envolver em uma atividade que pode causar-lhe a dormir. Se o manipulador dorme, então o sistema pode travar porque o temporizador é mascarado e incapaz de programar o fio dormir. Isso faz sentido?

Se um alto nível rotina de interrupção chega ao ponto onde a próxima coisa que deve fazer tem que acontecer depois de um período de tempo, então ele precisa para colocar um pedido na fila de timer, pedindo que uma outra rotina de interrupção ser executado ( no nível de prioridade inferior) algum tempo depois.

Ao que interrompem corridas de rotina, seria então o nível de volta prioridade aumento ao nível da rotina de interrupção original, e continuar a execução. Isto tem o mesmo efeito que um sono.

O kernel do Linux tem duas maneiras de alocar pilha de interrupção. Um está na pilha do kernel do processo interrompido, o outro é uma pilha de interrupção dedicado por CPU. Se o contexto de interrupção é salvo na pilha de interrupção dedicado por CPU, então de fato o contexto de interrupção é completamente não associado a qualquer processo. A macro "atual" irá produzir um ponteiro inválido para o processo de execução atual, uma vez que a macro "atual" com alguma arquitetura são computadas com o ponteiro de pilha. O ponteiro de pilha no contexto de interrupção pode apontar para a pilha de interrupção dedicada, não a pilha do kernel de algum processo.

É apenas a escolhas de design / implementação em Linux OS. A vantagem deste projeto é simples, mas pode não ser bom para Requisitos mínimos tempo real.

Outros sistemas operacionais têm outros projetos / implementações.

Por exemplo, no Solaris, as interrupções podem ter diferentes prioridades, que a maioria dos dispositivos interrupções são invocadas em fios de interrupção permite. Os fios de interrupção permite sono, porque cada um dos fios de interrupção tem pilha separada no contexto da discussão. O design tópicos interrupção é bom para tópicos em tempo real que devem ter prioridades mais altas do que as interrupções.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top