进程调度:
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() 是处理不同的中断信号的函数, 而在irq_exit()里所处理的是中断的下半部分,也就是我们常说的软中断。
在__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; 
	}
	
	其中struct irqaction 是就是每个不同的硬件中断所注册的处理函数
我们在来看看时间中断里所注册的处理函数,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; 
	}
	
	在 main_timer_handler 函数里,我们可以清楚的看到
	#ifndef CONFIG_SMP  
	update_process_times(user_mode(regs)); 
	#endif
	
	函数update_process_times 里显示的调用了 scheduler_tick
	/*
	* 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); 
	}
	
	我们可以看到在时间中断里会调用进程调度,并且在中断的上半部分,也就是不可被打断。

