久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

linux內(nèi)核中的信號機(jī)制

 lchjczw 2013-04-14

linux內(nèi)核中的信號機(jī)制--信號發(fā)送

Kernel version:2.6.14

CPU architecture:ARM920T

Author:ce123(http://blog.csdn.net/ce123)


應(yīng)用程序發(fā)送信號時,,主要通過kill進(jìn)行,。注意:不要被“kill”迷惑,,它并不是發(fā)送SIGKILL信號專用函數(shù),。這個函數(shù)主要通過系統(tǒng)調(diào)用sys_kill()進(jìn)入內(nèi)核,,它接收兩個參數(shù):

第一個參數(shù)為目標(biāo)進(jìn)程id,,kill()可以向進(jìn)程(或進(jìn)程組),線程(輕權(quán)線程)發(fā)送信號,,因此pid有以下幾種情況:

  • pid>0:目標(biāo)進(jìn)程(可能是輕權(quán)進(jìn)程)由pid指定,。
  • pid=0:信號被發(fā)送到當(dāng)前進(jìn)程組中的每一個進(jìn)程。
  • pid=-1:信號被發(fā)送到任何一個進(jìn)程,,init進(jìn)程(PID=1)和以及當(dāng)前進(jìn)程無法發(fā)送信號的進(jìn)程除外,。
  • pid<-1:信號被發(fā)送到目標(biāo)進(jìn)程組,其id由參數(shù)中的pid的絕對值指定,。
第二個參數(shù)為需要發(fā)送的信號,。

由于sys_kill處理的情況比較多,分析起來比較復(fù)雜,,我們從tkill()函數(shù)入手,,這個函數(shù)把信號發(fā)送到由參數(shù)指定pid指定的線程(輕權(quán)進(jìn)程)中。tkill的內(nèi)核入口是sys_tkill(kernel/signal.c),,其定義如下:

  1. /*  
  2.  *  Send a signal to only one task, even if it's a CLONE_THREAD task.  
  3.  */  
  4. asmlinkage long  
  5. sys_tkill(int pid, int sig)  
  6. {  
  7.     struct siginfo info;  
  8.     int error;  
  9.     struct task_struct *p;  
  10.   
  11.     /* This is only valid for single tasks */  
  12.     if (pid <= 0)//對參數(shù)pid進(jìn)行檢查  
  13.         return -EINVAL;  
  14.   
  15.     info.si_signo = sig; //根據(jù)參數(shù)初始化一個siginfo結(jié)構(gòu)  
  16.     info.si_errno = 0;  
  17.     info.si_code = SI_TKILL;  
  18.     info.si_pid = current->tgid;  
  19.     info.si_uid = current->uid;  
  20.   
  21.     read_lock(&tasklist_lock);  
  22.     p = find_task_by_pid(pid);//獲取由pid指定的線程的task_struct結(jié)構(gòu)  
  23.     error = -ESRCH;  
  24.     if (p) {  
  25.         error = check_kill_permission(sig, &info, p);//權(quán)限檢查  
  26.         /*  
  27.          * The null signal is a permissions and process existence  
  28.          * probe.  No signal is actually delivered.  
  29.          */  
  30.         if (!error && sig && p->sighand) {  
  31.             spin_lock_irq(&p->sighand->siglock);  
  32.             handle_stop_signal(sig, p);  
  33.             //對某些特殊信號進(jìn)程處理,,例如當(dāng)收到SIGSTOP時,需要把信號隊(duì)列中的SIGCONT全部刪除  
  34.             error = specific_send_sig_info(sig, &info, p);//把信號加入到信號隊(duì)列  
  35.             spin_unlock_irq(&p->sighand->siglock);  
  36.         }  
  37.     }  
  38.     read_unlock(&tasklist_lock);  
  39.     return error;  
  40. }  

sys_tkill函數(shù)主要是通過pecific_send_sig_info()函數(shù)實(shí)現(xiàn)的,下面我們看一下pecific_send_sig_info()(kernel/signal.c)的定義:

  1. static int  
  2. specific_send_sig_info(int sig, struct siginfo *info, struct task_struct *t)  
  3. {  
  4.     int ret = 0;  
  5.   
  6.     if (!irqs_disabled())  
  7.         BUG();  
  8.     assert_spin_locked(&t->sighand->siglock);  
  9.   
  10.     if (((unsigned long)info > 2) && (info->si_code == SI_TIMER))  
  11.         /*  
  12.          * Set up a return to indicate that we dropped the signal.  
  13.          */  
  14.         ret = info->si_sys_private;  
  15.     /*信號被忽略*/  
  16.     /* Short-circuit ignored signals.  */  
  17.     if (sig_ignored(t, sig))  
  18.         goto out;  
  19.   
  20.     /* Support queueing exactly one non-rt signal, so that we  
  21.        can get more detailed information about the cause of  
  22.        the signal. */  
  23.     if (LEGACY_QUEUE(&t->pending, sig))  
  24.         goto out;  
  25.   
  26.     ret = send_signal(sig, info, t, &t->pending);//實(shí)際的發(fā)送工作  
  27.     if (!ret && !sigismember(&t->blocked, sig))  
  28.         signal_wake_up(t, sig == SIGKILL);  
  29. out:  
  30.     return ret;  
  31. }  
首先調(diào)用sig_ignored檢查信號是否被忽略,,然后檢查發(fā)送的信號是不是普通信號,,如果是普通信號,就需要根據(jù)信號位圖來檢查當(dāng)前信號隊(duì)列中是否已經(jīng)存在該信號,,如果已經(jīng)存在,,對于普通信號不需要做任何處理。然后調(diào)用send_signal來完成實(shí)際的發(fā)送工作,,send_signal()是信號發(fā)送的重點(diǎn),,除sys_tkill之外的函數(shù),最終都是通過send_signal()來完成信號的發(fā)送工作的,。

這里注意到想send_signal()傳遞的參數(shù)時t->pending,,也就是連接Private Signal Queue的那條鏈。最后,,如果發(fā)送成功就調(diào)用signal_wake_up()來喚醒目標(biāo)進(jìn)程,,這樣可以保證該進(jìn)程進(jìn)入就緒狀態(tài),從而有機(jī)會被調(diào)度執(zhí)行信號處理函數(shù),。

現(xiàn)在我們來看看send_signal()(kernel/signal.c)函數(shù),,這個函數(shù)的主要工作就是分配并初始化一個sigqueue結(jié)構(gòu),然后把它添加到信號隊(duì)列中,。

  1. static int send_signal(int sig, struct siginfo *info, struct task_struct *t,  
  2.             struct sigpending *signals)  
  3. {  
  4.     struct sigqueue * q = NULL;  
  5.     int ret = 0;  
  6.   
  7.     /*  
  8.      * fast-pathed signals for kernel-internal things like SIGSTOP  
  9.      * or SIGKILL.  
  10.      */  
  11.     if ((unsigned long)info == 2)  
  12.         goto out_set;  
  13.   
  14.     /* Real-time signals must be queued if sent by sigqueue, or  
  15.        some other real-time mechanism.  It is implementation  
  16.        defined whether kill() does so.  We attempt to do so, on  
  17.        the principle of least surprise, but since kill is not  
  18.        allowed to fail with EAGAIN when low on memory we just  
  19.        make sure at least one signal gets delivered and don't  
  20.        pass on the info struct.  */  
  21.   
  22.     q = __sigqueue_alloc(t, GFP_ATOMIC, (sig < SIGRTMIN &&  
  23.                          ((unsigned long) info < 2 ||  
  24.                           info->si_code >= 0)));//分配sigqueue結(jié)構(gòu)  
  25.     if (q) {//如果成功分配到sigqueue結(jié)構(gòu),,就把它添加到隊(duì)列中,并對其初始化  
  26.         list_add_tail(&q->list, &signals->list);  
  27.         switch ((unsigned long) info) {  
  28.         case 0:  
  29.             q->info.si_signo = sig;  
  30.             q->info.si_errno = 0;  
  31.             q->info.si_code = SI_USER;  
  32.             q->info.si_pid = current->pid;  
  33.             q->info.si_uid = current->uid;  
  34.             break;  
  35.         case 1:  
  36.             q->info.si_signo = sig;  
  37.             q->info.si_errno = 0;  
  38.             q->info.si_code = SI_KERNEL;  
  39.             q->info.si_pid = 0;  
  40.             q->info.si_uid = 0;  
  41.             break;  
  42.         default:  
  43.             copy_siginfo(&q->info, info);//拷貝sigqueue結(jié)構(gòu)  
  44.             break;  
  45.         }  
  46.     } else {  
  47.         if (sig >= SIGRTMIN && info && (unsigned long)info != 1  
  48.            && info->si_code != SI_USER)  
  49.         /*  
  50.          * Queue overflow, abort.  We may abort if the signal was rt  
  51.          * and sent by user using something other than kill().  
  52.          */  
  53.             return -EAGAIN;  
  54.         if (((unsigned long)info > 1) && (info->si_code == SI_TIMER))  
  55.             /*  
  56.              * Set up a return to indicate that we dropped   
  57.              * the signal.  
  58.              */  
  59.             ret = info->si_sys_private;  
  60.     }  
  61.   
  62. out_set:  
  63.     sigaddset(&signals->signal, sig);//設(shè)置信號位圖  
  64.     return ret;  
  65. }  
從上面的分析可以看出,,我們看到信號被添加到信號隊(duì)列之后,,會調(diào)用signal_wake_up()喚醒這個進(jìn)程,signal_wake_up()(kernel/signal.c)的定義如下:

  1. /*  
  2.  * Tell a process that it has a new active signal..  
  3.  *  
  4.  * NOTE! we rely on the previous spin_lock to  
  5.  * lock interrupts for us! We can only be called with  
  6.  * "siglock" held, and the local interrupt must  
  7.  * have been disabled when that got acquired!  
  8.  *  
  9.  * No need to set need_resched since signal event passing  
  10.  * goes through ->blocked  
  11.  */  
  12. void signal_wake_up(struct task_struct *t, int resume)  
  13. {  
  14.     unsigned int mask;  
  15.   
  16.     set_tsk_thread_flag(t, TIF_SIGPENDING);//為進(jìn)程設(shè)置TIF_SIGPENDING標(biāo)志  
  17.   
  18.     /*  
  19.      * For SIGKILL, we want to wake it up in the stopped/traced case.  
  20.      * We don't check t->state here because there is a race with it  
  21.      * executing another processor and just now entering stopped state.  
  22.      * By using wake_up_state, we ensure the process will wake up and  
  23.      * handle its death signal.  
  24.      */  
  25.     mask = TASK_INTERRUPTIBLE;  
  26.     if (resume)  
  27.         mask |= TASK_STOPPED | TASK_TRACED;  
  28.     if (!wake_up_state(t, mask))  
  29.         kick_process(t);  
  30. }  
signal_wake_up()首先為進(jìn)程設(shè)置TIF_SIGPENDING標(biāo)志,,說明該進(jìn)程有延遲的信號要等待處理,。然后再調(diào)用wake_up_state()喚醒目標(biāo)進(jìn)程,如果目標(biāo)進(jìn)程在其他的CPU上運(yùn)行,,wake_up_state()將返回0,,此時調(diào)用kick_process()向該CPU發(fā)送一個處理器間中斷。當(dāng)中斷返回前戲,,會為當(dāng)前進(jìn)程處理延遲的信號,。

此后當(dāng)該進(jìn)程被調(diào)度時,在進(jìn)程返回用戶空間前,,會調(diào)用do_notify_resume()處理該進(jìn)程的信號,。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多