1. 程式人生 > >關於軟中斷和系統呼叫的一點分析

關於軟中斷和系統呼叫的一點分析

感覺之前對於軟中斷一直有一些誤解。

軟中斷的定義:

軟中斷是利用硬體中斷的概念,用軟體方式進行模擬,實現巨集觀上的非同步執行效果。很多情況下,軟中斷和“訊號”類似。同時,軟中斷又是和硬中斷相對應的,“硬中斷是外部裝置對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] 

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.     init_timer_stats();  
  5.     BUG_ON(err == NOTIFY_BAD);  
  6.     register_cpu_notifier(&timers_nb);  
  7.     open_softirq(TIMER_SOFTIRQ, run_timer_softirq);  
  8. }
  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] 

copy

  1. staticint run_ksoftirqd(void * __bind_cpu)  
  1. {
  2.     set_current_state(TASK_INTERRUPTIBLE);  
  3. while (!kthread_should_stop()) {  
  4.         preempt_disable();  
  5. if (!local_softirq_pending()) {  
  6.             preempt_enable_no_resched();  
  7.             schedule();  
  8.             preempt_disable();  
  9.         }  
  10.         __set_current_state(TASK_RUNNING);  
  11. while (local_softirq_pending()) {  
  12. /* 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. wait_to_die:
  15.     preempt_enable();  
  16. /* Wait for kthread_stop */
  17.     set_current_state(TASK_INTERRUPTIBLE);  
  18. while (!kthread_should_stop()) {  
  19.         schedule();  
  20.         set_current_state(TASK_INTERRUPTIBLE);  
  21.     }  
  22.     __set_current_state(TASK_RUNNING);  
  23. return 0;  
  24. }

從上面兩種情況的對比可以看出,系統呼叫的中斷由於是軟體觸發的中斷,所以稱為軟中斷,而對於後者的軟中斷,雖然也是軟體觸發,但是並不經過中斷向量表。