關於軟中斷和系統呼叫的一點分析
感覺之前對於軟中斷一直有一些誤解。
軟中斷的定義:
軟中斷是利用硬體中斷的概念,用軟體方式進行模擬,實現巨集觀上的非同步執行效果。很多情況下,軟中斷和“訊號”類似。同時,軟中斷又是和硬中斷相對應的,“硬中斷是外部裝置對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]
- void __init init_timers(void)
- {
- int err = timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE,
- (void *)(long)smp_processor_id());
- init_timer_stats();
- BUG_ON(err == NOTIFY_BAD);
-
register_cpu_notifier(&timers_nb);
- open_softirq(TIMER_SOFTIRQ, run_timer_softirq);
- }
- void open_softirq(int nr, void (*action)(struct softirq_action *))
- {
- softirq_vec[nr].action = action;
- }
軟中斷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_SOFTIRQ個BIT被置為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]
- staticint run_ksoftirqd(void * __bind_cpu)
- {
- set_current_state(TASK_INTERRUPTIBLE);
- while (!kthread_should_stop()) {
- preempt_disable();
- if (!local_softirq_pending()) {
- preempt_enable_no_resched();
- schedule();
- preempt_disable();
- }
- __set_current_state(TASK_RUNNING);
- while (local_softirq_pending()) {
- /* Preempt disable stops cpu going offline.
- If already offline, we'll be on wrong CPU:
- don't process */
- if (cpu_is_offline((long)__bind_cpu))
- goto wait_to_die;
- do_softirq();
- preempt_enable_no_resched();
- cond_resched();
- preempt_disable();
- rcu_sched_qs((long)__bind_cpu);
- }
- preempt_enable();
- set_current_state(TASK_INTERRUPTIBLE);
- }
- __set_current_state(TASK_RUNNING);
- return 0;
- wait_to_die:
- preempt_enable();
- /* Wait for kthread_stop */
- set_current_state(TASK_INTERRUPTIBLE);
- while (!kthread_should_stop()) {
- schedule();
- set_current_state(TASK_INTERRUPTIBLE);
- }
- __set_current_state(TASK_RUNNING);
- return 0;
- }
從上面兩種情況的對比可以看出,系統呼叫的中斷由於是軟體觸發的中斷,所以稱為軟中斷,而對於後者的軟中斷,雖然也是軟體觸發,但是並不經過中斷向量表。