O temporizador ISR não chama schedule()
diretamente. Ele acaba chamando update_process_times()
para que as informações contábeis do processo do planejador estejam atualizadas.
O agendador é eventualmente chamado ao retornar ao userspace. Se o kernel é preemptivo, ele também é chamado ao retornar da interrupção do cronômetro para o kernelspace.
Como exemplo, imagine um processo A que emite um syscall que é interrompido por uma interrupção gerada pelo dispositivo, que é então interrompida por uma interrupção do temporizador:
process A userspace → process A kernelspace → device ISR → timer ISR syscall device IRQ timer IRQ
Quando o ISR do timer termina, ele retorna para outro ISR, que retorna ao kernelspace, que retorna ao userspace. Um kernel preventivo verifica se precisa reprogramar processos a cada retorno. Um kernel não preemptivo só faz essa verificação ao retornar ao espaço do usuário.
Em terra ARM, o caminho de código é amplamente semelhante a:
- Um IRQ recebido no espaço do usuário acaba chamando
__irq_usr
, enquanto um IRQ recebido no modo SVC acaba chamando__irq_svc
. IRQs não devem ser recebidos enquanto estiverem em outros modos de processador. - Em
__irq_svc
, depois de manipular o IRQ, se o kernel é preemptivo , a preempção não está desabilitada, e um reagendamento é necessário, o kernel salta parasvc_preempt
, que chamapreempt_schedule_irq
, que chamaschedule
. Caso contrário, nenhum reagendamento é feito. - Por fim, a CPU retornará ao userspace, seja de um manipulador de IRQ (
__irq_usr
→ret_to_user_from_irq
) ou de um syscall (vector_swi
→ret_fast_syscall
). Lá, o kernel verifica se há trabalho a ser feito e, se for necessário reagendar,schedule
é chamado.