进程调度:
Linux里的进程管理调度,如何调度使用不同的进程占用不同的时间片段,主要在核心函数 scheduler_tick (kernel/sched.c)
硬中断触发:
对操作系统来说,中断是一种电信号,由硬件设备产生,并直接送入中断控制器(如8259A)的输入引脚上,然后再由中断控制器向处理器发送相应的信号。处理器一经检测到
该信号,便中断自己当前正在处理的工作,转而去处理中断。此后,处理器会通知 OS 已经产生中断。这样,OS 就可以对这个中断进行适当的处理了。不同的设备对应的中断不同,而每个中断都通过一个唯一的数字标识。这些中断值通常被称为中断请求线,这里所说的中断就是硬中断,也是我们常说的中断的上半部分。
硬中断的执行:
不同的架构在linux上是不同的执行,在x86架构中,源码程序在/arch/x86_64/kernel/irq.c
- asmlinkage unsigned int do_IRQ(struct pt_regs *regs)
- {
- /* high bit used in ret_from_ code */
- unsigned irq = ~regs->orig_rax;
- if (unlikely(irq >= NR_IRQS)) {
- printk(KERN_EMERG “%s: cannot handle IRQ %d\n”,
- __FUNCTION__, irq);
- BUG();
- }
- exit_idle();
- irq_enter();
- #ifdef CONFIG_DEBUG_STACKOVERFLOW
- stack_overflow_check(regs);
- #endif
- __do_IRQ(irq, regs);
- irq_exit();
- return 1;
- }
在__do_IRQ()的处理函数中,handle_IRQ_event (irq/handle.c)主要负责调用不同的中断信号所注册的函数。
- /**
- * handle_IRQ_event – irq action chain handler
- * @irq: the interrupt number
- * @regs: pointer to a register structure
- * @action: the interrupt action chain for this irq
- *
- * Handles the action chain of an irq event
- */
- irqreturn_t handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
- struct irqaction *action)
- {
- irqreturn_t ret, retval = IRQ_NONE;
- unsigned int status = 0;
- handle_dynamic_tick(action);
- if (!(action->flags & IRQF_DISABLED))
- local_irq_enable_in_hardirq();
- do {
- ret = action->handler(irq, action->dev_id, regs);
- if (ret == IRQ_HANDLED)
- status |= action->flags;
- retval |= ret;
- action = action->next;
- } while (action);
- if (status & IRQF_SAMPLE_RANDOM)
- add_interrupt_randomness(irq);
- local_irq_disable();
- return retval;
- }
我们在来看看时间中断里所注册的处理函数,x86_64/kernel/time.c
- static struct irqaction irq0 = {
- timer_interrupt, IRQF_DISABLED, CPU_MASK_NONE, “timer”, NULL, NULL
- };
timer_interrupt 函数
- static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
- {
- if (apic_runs_main_timer > 1)
- return IRQ_HANDLED;
- main_timer_handler(regs);
- #ifdef CONFIG_X86_LOCAL_APIC
- if (using_apic_timer)
- smp_send_timer_broadcast_ipi();
- #endif
- return IRQ_HANDLED;
- }
- #ifndef CONFIG_SMP
- update_process_times(user_mode(regs));
- #endif
- /*
- * Called from the timer interrupt handler to charge one tick to the current
- * process. user_tick is 1 if the tick is user time, 0 for system.
- */
- void update_process_times(int user_tick)
- {
- struct task_struct *p = current;
- int cpu = smp_processor_id();
- /* Note: this timer irq context must be accounted for as well. */
- if (user_tick)
- account_user_time(p, jiffies_to_cputime(1));
- else
- account_system_time(p, HARDIRQ_OFFSET, jiffies_to_cputime(1));
- run_local_timers();
- if (rcu_pending(cpu))
- rcu_check_callbacks(cpu, user_tick);
- scheduler_tick();
- run_posix_cpu_timers(p);
- }