精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Linux內核中信號相關的系統調用

jf_0tjVfeJz ? 來源:嵌入式ARM和Linux ? 2024-01-20 09:34 ? 次閱讀

正如我們所知,運行在用戶態下的程序可以發送和接收信號。這意味著必須定義一組系統調用來允許這類操作。不幸的是,由于歷史原因,有些系統調用可能功能相同。 因此,其中一些系統調用永遠不會被調用。例如,sys_sigaction()和sys_rt_sigaction()幾乎相同,因此C庫中包含的sigaction()包裝函數最終會調用sys_rt_sigaction()而不是sys_sigaction()。

1 kill()

kill(pid,sig)系統調用用來給常規進程或多線程應用程序發送信號,相應的服務例程是sys_kill()。pid根據值的不同具有不同意義:

pid > 0:sig信號被發送給pid指定進程所屬的線程組。

pid = 0:sig信號被發送給與調用進程同一進程組內所有進程的線程組。

pid = –1:sig信號被發送給所有進程,除了swapper(PID 0)、init(PID 1和current進程。

pid < –1:信號被發送給-pid進程組中所有進程的所屬線程組。

sys_kill()為信號建立一個最小siginfo_t表,然后調用kill_something_info():

info.si_signo=sig;
info.si_errno=0;
info.si_code=SI_USER;
info._sifields._kill._pid=current->tgid;
info._sifields._kill._uid=current->uid;
returnkill_something_info(sig,&info,pid);

繼而,kill_something_info()既可以調用kill_proc_info()(通過group_send_sig_info()發送信號給單個線程組),也可以調用kill_pg_info()(掃描目標進程組所有進程并為每個進程調用send_sig_info()),還可以為系統中的每個進程重復調用group_send_sig_info()(pid=-1)。

kill()能夠發送任何信號,包括所謂的實時信號(32~64)。但是,正如我們在信號的產生過程一節中看到的,kill()系統調用不能確保將信號添加到目標進程的掛起信號隊列中,因此可能會丟失多個掛起信號。實時信號應該通過諸如rt_sigqueueinfo()之類的系統調用來發送。

System V和BSD Unix變體也有一個killpg()系統調用,它能夠顯式地向一組進程發送信號。在Linux中,該函數是作為使用kill()系統調用的庫函數實現的。另一種變體是raise(),它向當前進程(即執行函數的進程)發送信號。在Linux中,raise()是作為庫函數實現的。

2 tkill()/tgkill()

tkill()和tgkill()向線程組中的特定進程發送信號。每個兼容POSIX的pthread庫的pthread_kill()函數調用其中的一個來向特定的輕量級進程發送信號。

tkill()需要2個參數:pid,目標進程的PID;sig,信號編碼。內核中的sys_tkill()服務例程填充siginfo表,獲取進程描述符地址,進行一些權限檢查,并調用specific_send_sig_info()發送信號。

tgkill()不同于tkill(),它需要第3個參數:tgid,線程組ID,該線程組包含信號的目標進程。sys_tgkill()服務例程執行與sys_tkill()完全相同的操作,但也檢查信號的目標進程是否屬于線程組tgid。這個額外的檢查解決了當信號被發送到一個正在被終止的進程時發生的競爭條件:如果另一個多線程應用程序創建輕量級進程的速度足夠快,那么信號可能會被傳遞給錯誤的進程。tgkill()解決了這個問題,因為線程組ID在多線程應用程序的生命周期內永遠不會更改。

3 更改信號行為

sigaction(sig,act,oact)系統調用允許用戶為信號指定動作;當然,如果沒有定義信號動作,內核將執行信號相關聯的默認動作。

相應的sys_sigaction()服務例程作用于2個參數:sig,信號值;act,類型為old_sigaction的表,用以指定新行為;oact,可選輸出參數,用以獲取信號之前的行為動作。(old_sigaction和sigaction具有相同的數據結構,但是成員順序不一致)

該函數首先檢查act地址是否有效。然后用*act的字段填充k_sigaction類型的new_ka局部變量的sa_handler、sa_flags和sa_mask字段:

__get_user(new_ka.sa.sa_handler,&act->sa_handler);
__get_user(new_ka.sa.sa_flags,&act->sa_flags);
__get_user(mask,&act->sa_mask);
siginitset(&new_ka.sa.sa_mask,mask);

函數調用do_sigaction()將新的new_ka表復制到current->sig->action表的第sig-1項中:

k=¤t->sig->action[sig-1];
if(act){
*k=*act;
sigdelsetmask(&k->sa.sa_mask,sigmask(SIGKILL)|sigmask(SIGSTOP));
if(k->sa.sa_handler==SIG_IGN||(k->sa.sa_handler==SIG_DFL&&
(sig==SIGCONT||sig==SIGCHLD||sig==SIGWINCH||sig==SIGURG))){
rm_from_queue(sigmask(sig),¤t->signal->shared_pending);
t=current;
do{
rm_from_queue(sigmask(sig),¤t->pending);
recalc_sigpending_tsk(t);
t=next_thread(t);
}while(t!=current);
}
}

POSIX標準要求,當默認動作為ignore時,將信號動作設置為SIG_IGN或SIG_DFL會導致所有相同類型的掛起信號被丟棄。此外,請注意,無論信號處理程序請求的屏蔽信號是什么,SIGKILL和SIGSTOP都不會被屏蔽。

sigaction()系統調用還允許用戶初始化sigaction表中的sa_flags字段。我們在前面曾經列出了該字段允許的值和相關含義。

舊的System V Unix變體提供了signal()系統調用,它仍然被程序員廣泛使用。最近的C庫通過rt_sigaction()實現了signal()。然而,Linux仍然支持舊的C庫,并提供sys_signal()服務例程:

new_sa.sa.sa_handler=handler;
new_sa.sa.sa_flags=SA_ONESHOT|SA_NOMASK;
ret=do_sigaction(sig,&new_sa,&old_sa);
returnret?ret:(unsignedlong)old_sa.sa.sa_handler;

4 檢查掛起的阻塞信號

sigpending()系統調用允許進程檢查掛起的阻塞信號集,例如那些在阻塞時產生的信號。對應的sys_sigpending()服務例程作用于單個參數set,用戶變量的地址,在其中,位數組需要被拷貝:

sigorsets(&pending,¤t->pending.signal,
¤t->signal->shared_pending.signal);
sigandsets(&pending,¤t->blocked,&pending);
copy_to_user(set,&pending,4);

5 修改阻塞信號集

sigprocmask()系統調用允許進程修改阻塞信號集; 它僅適用于常規(非實時)信號。 相應的sys_sigprocmask()服務例程作用于3個參數:

oset: 進程地址空間中,指向存儲先前位掩碼的位數組的指針。

set: 進程地址空間中,指向存儲新位掩碼的位數組的指針。

how:標志,可取的值如下所示:

SIG_BLOCK:set指向的位掩碼數組必須被添加阻塞信號的位掩碼數組中。

SIG_UNBLOCK:set指向的位掩碼數組必須從阻塞信號的位掩碼數組中移除。

SIG_SETMASK:set指向的位掩碼數組設定為新的阻塞信號的位掩碼數組。

該函數調用copy_from_user()將set指向的值拷貝到new_set這個局部變量中,并將current進程的阻塞的標準信號的位掩碼數組拷貝到old_set這個局部變量中。然后根據how標志設置這兩個變量:

if(copy_from_user(&new_set,set,sizeof(*set)))
return-EFAULT;
new_set&=~(sigmask(SIGKILL)|sigmask(SIGSTOP));
old_set=current->blocked.sig[0];
if(how==SIG_BLOCK)
sigaddsetmask(¤t->blocked,new_set);
elseif(how==SIG_UNBLOCK)
sigdelsetmask(¤t->blocked,new_set);
elseif(how==SIG_SETMASK)
current->blocked.sig[0]=new_set;
else
return-EINVAL;
recalc_sigpending(current);
if(oset&©_to_user(oset,&old_set,sizeof(*oset)))
return-EFAULT;
return0;

6 掛起進程

在阻塞了由mask參數對應的標準信號之后,sigsuspend()系統調用將進程置于TASK_INTERRUPTIBLE狀態。只有當一個非忽略、非阻塞的信號被發送給進程時,進程才會被喚醒。

相應的sys_sigsuspend()服務例程執行以下內容:

mask&=~(sigmask(SIGKILL)|sigmask(SIGSTOP));
saveset=current->blocked;
siginitset(¤t->blocked,mask);
recalc_sigpending(current);
regs->eax=-EINTR;
while(1){
current->state=TASK_INTERRUPTIBLE;
schedule();
if(do_signal(regs,&saveset))
return-EINTR;
}

將進程設置為可中斷的掛起狀態后,調用schedule()函數選擇其它進程來運行。 當發出sigsuspend()系統調用的進程再次執行時,sys_sigsuspend()調用do_signal()函數來傳遞喚醒進程的信號。 如果該函數返回值1,則不會忽略該信號。因此,系統調用通過返回錯誤代碼-EINTR來終止。

其實,這個功能完全可以通過組合sigprocmask()和sleep()來實現。但是,sigsuspend()解決了一個競態問題:因為進程隨時會交叉執行,先通過系統調用執行A動作,然后通過系統調用執行B動作,并不等價于通過單個系統調用直接執行A和B兩個動作。

這種情況下,sigprocmask()可能會在調用sleep()之前對信號解除阻塞。如果這個發生,因為喚醒信號已經傳遞過,從而進程得不到喚醒而永遠留在TASK_INTERRUPTIBLE狀態。相反,sigsuspend()不允許在解除阻塞之后和schedule()調用之前發送信號,因為其它進程在這個時間段不可能搶占CPU時間。

7 實時信號的系統調用

前面介紹的系統調用都是針對標準信號的,對于實時信號有專門的的系統調用。

實時信號的系統調用,如rt_sigaction()、rt_sigpending()、rt_sigprocmask()、rt_sigsuspend()與前面的標準信號對應的系統調用類似,不再贅述。簡單介紹一下實時信號隊列相關的兩個系統調用:

rt_sigqueueinfo()

發送實時信號,以便將其添加目標進程的共享掛起信號隊列中。通常通過標準庫函數中的sigqueue()實現。

rt_sigtimedwait()

將阻塞的掛起信號從隊列中取出而不發送它,并將信號值返回給調用者;如果沒有阻塞信號掛起,則將當前進程掛起一段固定的時間。通常通過標準庫函數sigwaitinfo()和sigtimedwait()調用。

審核編輯:湯梓紅

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 內核
    +關注

    關注

    3

    文章

    1363

    瀏覽量

    40228
  • Linux
    +關注

    關注

    87

    文章

    11227

    瀏覽量

    208925
  • 線程
    +關注

    關注

    0

    文章

    504

    瀏覽量

    19651
  • 系統調用
    +關注

    關注

    0

    文章

    28

    瀏覽量

    8320

原文標題:Linux內核-信號相關的系統調用

文章出處:【微信號:嵌入式ARM和Linux,微信公眾號:嵌入式ARM和Linux】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Linux內核系統調用詳解

    Linux內核中設置了一組用于實現各種系統功能的子程序,稱為系統調用。用戶可以通過系統
    發表于 08-23 10:37 ?763次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內核</b>中<b class='flag-5'>系統</b><b class='flag-5'>調用</b>詳解

    linux內核系統調用之參數傳遞

    與普通函數一樣,系統調用通常需要一些輸入/輸出參數,這些參數可能包括實際值(即數字)、用戶模式進程地址空間中的變量地址,甚至包括指向用戶模式函數指針的數據結構的地址(參見第11章“信號相關
    的頭像 發表于 12-20 09:32 ?1443次閱讀

    Linux內核中信號詳解

    ? 1 信號的角色 1.1 x86/64架構信號定義 1.2 ARM架構信號定義 1.3 RISC-V架構信號定義 1.4 信號
    的頭像 發表于 01-13 09:40 ?1331次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內核</b><b class='flag-5'>中信號</b>詳解

    Linux內核中信號的傳遞過程

    前面我們已經介紹了內核注意到信號的到來,調用相關函數更新進程描述符以便進程接收處理信號。但是,如果目標進程此時沒有運行,
    的頭像 發表于 01-17 09:51 ?1063次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內核</b><b class='flag-5'>中信號</b>的傳遞過程

    Linux內核系統調用

    Linux內核系統調用1. 應用程序通過API而不是直接調用系統
    發表于 02-21 10:49

    ARM linux系統調用的實現原理

    大家都知道linux的應用程序要想訪問內核必須使用系統調用從而實現從usr模式轉到svc模式。下面咱們看看它的實現過程。
    發表于 05-30 11:24 ?2232次閱讀

    Linux內核系統調用擴展研究

    系統凋用是操作系統內核提供給用戶使用內核服務的接口。LinuX操作系統由于其自由開放性,用戶可在
    發表于 07-25 16:09 ?40次下載
    <b class='flag-5'>Linux</b><b class='flag-5'>內核</b><b class='flag-5'>系統</b><b class='flag-5'>調用</b>擴展研究

    編譯Linux2.6內核并添加一個系統調用

    本文以實例來詳細描述了從準備一直到使用新內核Linux2.6 內核編譯過程,然后介紹了添加系統調用的實現步驟,最后給實驗結果。
    發表于 12-01 15:54 ?46次下載

    透了解系統調用助你成為Linux下編程高手

    Linux內核中設置了一組用于實現各種系統功能的子程序,稱為系統調用。用戶可以通過系統
    的頭像 發表于 05-11 11:27 ?3414次閱讀
    透了解<b class='flag-5'>系統</b><b class='flag-5'>調用</b>助你成為<b class='flag-5'>Linux</b>下編程高手

    你知道Linux系統調用的原理

    系統調用是應用程序與操作系統內核之間的接口,它決定了程序如何與內核打交道的。無論程序是直接進行系統
    發表于 05-16 16:21 ?1484次閱讀
    你知道<b class='flag-5'>Linux</b><b class='flag-5'>系統</b><b class='flag-5'>調用</b>的原理

    Linux系統調用的技巧

    前以及大部分中斷服務返回前,都會跳轉至此處入口地址。 該段程序不僅僅為系統調用服務,它還處理中斷嵌套、CPU調度、信號等事務。  2.通過修改內核源代碼添加
    發表于 04-02 14:36 ?383次閱讀

    Linux系統調用是什么

    所謂系統調用是指操作系統提供給用戶程序調用的一組“特殊”接口,用戶程序可以通過這組“特殊”接口獲得操作系統
    發表于 06-11 09:33 ?2340次閱讀

    如何區分xenomai、linux系統調用/服務

    對于同一個POSIX接口應用程序,可能既需要xenomai內核提供服務(xenomai 系統調用),又需要調用linux
    的頭像 發表于 05-10 10:28 ?2009次閱讀

    Linux內核系統調用概述及實現原理

    本文介紹了系統調用的一些實現細節。首先分析了系統調用的意義,它們與庫函數和應用程序接口(API)有怎樣的關系。然后,我們考察了Linux
    的頭像 發表于 05-14 14:11 ?2182次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內核</b><b class='flag-5'>系統</b><b class='flag-5'>調用</b>概述及實現原理

    Linux系統調用的具體實現原理

    文我將基于 ARM 體系結構角度,從 Linux 應用層例子到內核系統調用函數的整個過程來梳理一遍,講清楚linux
    的頭像 發表于 09-05 17:16 ?1064次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>系統</b><b class='flag-5'>調用</b>的具體實現原理