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.