关于软中断和系统调用的一点分析

感觉之前对于软中断一直有一些误解。

 

软中断的定义:

软中断是利用硬件中断的概念,用软件方式进行模拟,实现宏观上的异步执行效果。很多情况下,软中断和“信号”类似。同时,软中断又是和硬中断相对应的,“硬中断是外部设备对CPU的中断”,“软中断通常是硬件中断服务程序对内核的中断”

 

作为系统调用而言,对于i386则是通过软中断int80实现

对于其它的软中断,则是在硬件中断之后触发的软中断。

 

系统调用在Linux2.6中的实现

 

 

set_system_trap_gate(SYSCALL_VECTOR, &system_call);

# define SYSCALL_VECTOR			0x80

ENTRY(system_call)
	RING0_INT_FRAME			# can't unwind into user space anyway
	pushl_cfi %eax			# save orig_eax
	SAVE_ALL
	GET_THREAD_INFO(%ebp)
					# system call tracing in operation / emulation
	testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
	jnz syscall_trace_entry
	cmpl $(nr_syscalls), %eax
	jae syscall_badsys
syscall_call:
	call *sys_call_table(,%eax,4)
	movl %eax,PT_EAX(%esp)		# store the return value
 

 ENTRY(sys_call_table)
	.long sys_restart_syscall	/* 0 - old "setup()" system call, used for restarting */
	.long sys_exit
	.long ptregs_fork
	.long sys_read
	.long sys_write
	.long sys_open		/* 5 */
	.long sys_close
	.long sys_waitpid
	.long sys_creat
	.long sys_link
	.long sys_unlink	/* 10 */
	.long ptregs_execve
	.long sys_chdir
	.long sys_time
	.long sys_mknod
	.long sys_chmod		/* 15 */
	.long sys_lchown16
	.long sys_ni_syscall	/* old break syscall holder */
	.long sys_stat
	.long sys_lseek
	.long sys_getpid	/* 20 */
	.long sys_mount
	.long sys_oldumount
...

 

 

 

 

 

对于软中断而言,则稍微复杂些

1.注册软中断当然是通过open_softirq

例子如下:

[cpp] 

view plain

copy

  1. void __init init_timers(void)  
  1. {  
  2.     int err = timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE,  
  3.                 (void *)(long)smp_processor_id());  
  4.   
  5.     init_timer_stats();  
  6.   
  7.     BUG_ON(err == NOTIFY_BAD);  
  8.     register_cpu_notifier(&timers_nb);  
  9.     open_softirq(TIMER_SOFTIRQ, run_timer_softirq);  
  10. }  
  11.   
  1. void open_softirq(int nr, void (*action)(struct softirq_action *))  
  1. {  
  2.     softirq_vec[nr].action = action;  
  3. }  

软中断TIMER_SOFTIRQ的中断处理函数为:run_timer_softirq

之所以成为softirq,是因为这些中断是由硬件中断来间接触发的,如何间接触发的呢:

硬件中断处理函数-->对软中断的相应位置位-->唤醒ksoftirqd线程-->执行软中断的中断处理函数

 

2.硬件中断如何通过置位唤醒ksoftirqd线程

timer interrupthandler->

timer_tick->

update_process_times->

run_local_timers->

hrtimer_run_queues()raise_softirq(TIMER_SOFTIRQ)->

raise_softirq_irqoff->

__raise_softirq_irqoff{ or_softirq_pending(1UL << (nr)); }

(local_softirq_pending() |= (x))

 

3.如何执行软中断的action<中断处理函数>

对于TIMER_SOFTIRQ来说,每次system clock产生中断时,即一个tick到来时,在system clock的中断处理函数中会调用run_local_timers来设置TIMER_SOFTIRQ触发条件;也就是当前CPU对应的irq_cpustat_t结构体中的__softirq_pending成员的第TIMER_SOFTIRQBIT被置为1而当这个条件满足时,ksoftirqd线程(入口函数run_ksoftirqd,cpu_callback:kthread_create(run_ksoftirqd,hcpu, "ksoftirqd/%d", hotcpu);)会被唤醒,然后按照下面的流程调用TIMER_SOFTIRQ在数组softirq_vec中注册的action,即run_timer_softirq

run_ksoftirqd--->do_softirq--->__do_softirq--->softirq_vec[TIMER_SOFTIRQ].action

 

 

[cpp] 

view plain

copy

  1. static int run_ksoftirqd(void * __bind_cpu)  
  1. {  
  2.     set_current_state(TASK_INTERRUPTIBLE);  
  3.   
  4.     while (!kthread_should_stop()) {  
  5.         preempt_disable();  
  6.         if (!local_softirq_pending()) {  
  7.             preempt_enable_no_resched();  
  8.             schedule();  
  9.             preempt_disable();  
  10.         }  
  11.   
  12.         __set_current_state(TASK_RUNNING);  
  13.   
  14.         while (local_softirq_pending()) {  
  15.             /* Preempt disable stops cpu going offline. 
  1.                If already offline, we'll be on wrong CPU: 
  2.                don't process */  
  1.             if (cpu_is_offline((long)__bind_cpu))  
  2.                 goto wait_to_die;  
  3.             do_softirq();  
  4.             preempt_enable_no_resched();  
  5.             cond_resched();  
  6.             preempt_disable();  
  7.             rcu_sched_qs((long)__bind_cpu);  
  8.         }  
  9.         preempt_enable();  
  10.         set_current_state(TASK_INTERRUPTIBLE);  
  11.     }  
  12.     __set_current_state(TASK_RUNNING);  
  13.     return 0;  
  14.   
  15. wait_to_die:  
  16.     preempt_enable();  
  17.     /* Wait for kthread_stop */  
  18.     set_current_state(TASK_INTERRUPTIBLE);  
  19.     while (!kthread_should_stop()) {  
  20.         schedule();  
  21.         set_current_state(TASK_INTERRUPTIBLE);  
  22.     }  
  23.     __set_current_state(TASK_RUNNING);  
  24.     return 0;  
  25. }  

 

From <http://blog.csdn.net/myarrow/article/details/7064060>

 

 

从上面两种情况的对比可以看出,系统调用的中断由于是软件触发的中断,所以称为软中断,而对于后者的软中断,虽然也是软件触发,但是并不经过中断向量表。

 

posted @ 2013-09-15 19:35  pangbangb  阅读(2014)  评论(0编辑  收藏  举报