導航:首頁 > 操作系統 > linux用戶態鎖

linux用戶態鎖

發布時間:2022-06-28 09:10:40

1. linux 用戶進程 可以搶占內核進程嗎

1.2.1 調度過程中關閉內核搶占
我們在上一篇linux內核主調度器schele(文章鏈接, CSDN, Github)中在分析主調度器的時候, 我們會發現內核在進行調度之前都會通過preempt_disable關閉內核搶占, 而在完成調度工作後, 又會重新開啟內核搶占
參見主調度器函數schele
do {
preempt_disable(); /* 關閉內核搶占 */
__schele(false); /* 完成調度 */
sched_preempt_enable_no_resched(); /* 開啟內核搶占 */

} while (need_resched()); /* 如果該進程被其他進程設置了TIF_NEED_RESCHED標志,則函數重新執行進行調度 */123456123456

這個很容易理解, 我們在內核完成調度器過程中, 這時候如果發生了內核搶占, 我們的調度會被中斷, 而調度卻還沒有完成, 這樣會丟失我們調度的信息.
1.2.2 調度完成檢查need_resched看是否需要重新調度
而同樣我們可以看到, 在調度完成後, 內核會去判斷need_resched條件, 如果這個時候為真, 內核會重新進程一次調度.
這個的原因, 我們在前一篇博客中, 也已經說的很明白了,
內核在thread_info的flag中設置了一個標識來標志進程是否需要重新調度, 即重新調度need_resched標識TIF_NEED_RESCHED, 內核在即將返回用戶空間時會檢查標識TIF_NEED_RESCHED標志進程是否需要重新調度,如果設置了,就會發生調度, 這被稱為用戶搶占
2 非搶占式和可搶占式內核
為了簡化問題,我使用嵌入式實時系統uC/OS作為例子
首先要指出的是,uC/OS只有內核態,沒有用戶態,這和Linux不一樣
多任務系統中, 內核負責管理各個任務, 或者說為每個任務分配CPU時間, 並且負責任務之間的通訊.
內核提供的基本服務是任務切換. 調度(Scheler),英文還有一詞叫dispatcher, 也是調度的意思.
這是內核的主要職責之一, 就是要決定該輪到哪個任務運行了. 多數實時內核是基於優先順序調度法的, 每個任務根據其重要程度的不同被賦予一定的優先順序. 基於優先順序的調度法指,CPU總是讓處在就緒態的優先順序最高的任務先運行. 然而, 究竟何時讓高優先順序任務掌握CPU的使用權, 有兩種不同的情況, 這要看用的是什麼類型的內核, 是不可剝奪型的還是可剝奪型內核
2.1 非搶占式內核
非搶占式內核是由任務主動放棄CPU的使用權
非搶占式調度法也稱作合作型多任務, 各個任務彼此合作共享一個CPU. 非同步事件還是由中斷服務來處理. 中斷服務可以使一個高優先順序的任務由掛起狀態變為就緒狀態.
但中斷服務以後控制權還是回到原來被中斷了的那個任務, 直到該任務主動放棄CPU的使用權時,那個高優先順序的任務才能獲得CPU的使用權。非搶占式內核如下圖所示.

非搶占式內核的優點有
中斷響應快(與搶占式內核比較);
允許使用不可重入函數;
幾乎不需要使用信號量保護共享數據, 運行的任務佔有CPU,不必擔心被別的任務搶占。這不是絕對的,在列印機的使用上,仍需要滿足互斥條件。
非搶占式內核的缺點有
任務響應時間慢。高優先順序的任務已經進入就緒態,但還不能運行,要等到當前運行著的任務釋放CPU
非搶占式內核的任務級響應時間是不確定的,不知道什麼時候最高優先順序的任務才能拿到CPU的控制權,完全取決於應用程序什麼時候釋放CPU
2.2 搶占式內核
使用搶占式內核可以保證系統響應時間. 最高優先順序的任務一旦就緒, 總能得到CPU的使用權。當一個運行著的任務使一個比它優先順序高的任務進入了就緒態, 當前任務的CPU使用權就會被剝奪,或者說被掛起了,那個高優先順序的任務立刻得到了CPU的控制權。如果是中斷服務子程序使一個高優先順序的任務進入就緒態,中斷完成時,中斷了的任務被掛起,優先順序高的那個任務開始運行。
搶占式內核如下圖所示

搶占式內核的優點有
使用搶占式內核,最高優先順序的任務什麼時候可以執行,可以得到CPU的使用權是可知的。使用搶占式內核使得任務級響應時間得以最優化。
搶占式內核的缺點有:
不能直接使用不可重入型函數。調用不可重入函數時,要滿足互斥條件,這點可以使用互斥型信號量來實現。如果調用不可重入型函數時,低優先順序的任務CPU的使用權被高優先順序任務剝奪,不可重入型函數中的數據有可能被破壞。
3 linux用戶搶占
3.1 linux用戶搶占
當內核即將返回用戶空間時, 內核會檢查need_resched是否設置, 如果設置, 則調用schele(),此時,發生用戶搶占.
3.2 need_resched標識
內核如何檢查一個進程是否需要被調度呢?
內核在即將返回用戶空間時檢查進程是否需要重新調度,如果設置了,就會發生調度, 這被稱為用戶搶占, 因此內核在thread_info的flag中設置了一個標識來標志進程是否需要重新調度, 即重新調度need_resched標識TIF_NEED_RESCHED
並提供了一些設置可檢測的函數

函數
描述
定義

set_tsk_need_resched 設置指定進程中的need_resched標志 include/linux/sched.h, L2920
clear_tsk_need_resched 清除指定進程中的need_resched標志 include/linux/sched.h, L2926
test_tsk_need_resched 檢查指定進程need_resched標志 include/linux/sched.h, L2931
而我們內核中調度時常用的need_resched()函數檢查進程是否需要被重新調度其實就是通過test_tsk_need_resched實現的, 其定義如下所示
// http://lxr.free-electrons.com/source/include/linux/sched.h?v=4.6#L3093
static __always_inline bool need_resched(void)
{
return unlikely(tif_need_resched());
}

// http://lxr.free-electrons.com/source/include/linux/thread_info.h?v=4.6#L106
#define tif_need_resched() test_thread_flag(TIF_NEED_RESCHED)1234567812345678

3.3 用戶搶占的發生時機(什麼時候需要重新調度need_resched)
一般來說,用戶搶占發生幾下情況:
從系統調用返回用戶空間;
從中斷(異常)處理程序返回用戶空間
從這里我們可以看到, 用戶搶占是發生在用戶空間的搶占現象.
更詳細的觸發條件如下所示, 其實不外乎就是前面所說的兩種情況: 從系統調用或者中斷返回用戶空間
時鍾中斷處理常式檢查當前任務的時間片,當任務的時間片消耗完時,scheler_tick()函數就會設置need_resched標志;
信號量、等到隊列、completion等機制喚醒時都是基於waitqueue的,而waitqueue的喚醒函數為default_wake_function,其調用try_to_wake_up將被喚醒的任務更改為就緒狀態並設置need_resched標志。
設置用戶進程的nice值時,可能會使高優先順序的任務進入就緒狀態;
改變任務的優先順序時,可能會使高優先順序的任務進入就緒狀態;
新建一個任務時,可能會使高優先順序的任務進入就緒狀態;
對CPU(SMP)進行負載均衡時,當前任務可能需要放到另外一個CPU上運行
4 linux內核搶占
4.1 內核搶占的概念
對比用戶搶占, 顧名思義, 內核搶占就是指一個在內核態運行的進程, 可能在執行內核函數期間被另一個進程取代.
4.2 為什麼linux需要內核搶占
linux系統中, 進程在系統調用後返回用戶態之前, 或者是內核中某些特定的點上, 都會調用調度器. 這確保除了一些明確指定的情況之外, 內核是無法中斷的, 這不同於用戶進程.
如果內核處於相對耗時的操作中, 比如文件系統或者內存管理相關的任務, 這種行為可能會帶來問題. 這種情況下, 內核代替特定的進程執行相當長的時間, 而其他進程無法執行, 無法調度, 這就造成了系統的延遲增加, 用戶體驗到」緩慢」的響應. 比如如果多媒體應用長時間無法得到CPU, 則可能發生視頻和音頻漏失現象.
編譯內核時如果啟用了對內核搶占的支持, 則可以解決這些問題. 如果高優先順序進程有事情需要完成, 那麼在啟用了內核搶占的情況下, 不僅用戶空間應用程序可以被中斷, 內核也可以被中斷,
linux內核搶占是在Linux2.5.4版本發布時加入的, 盡管使內核可搶占需要的改動特別少, 但是該機制不像搶佔用戶空間進程那樣容易實現. 如果內核無法一次性完成某些操作(例如, 對數據結構的操作), 那麼可能出現靜態條件而使得系統不一致.
內核搶占和用戶層進程被其他進程搶占是兩個不同的概念, 內核搶佔主要是從實時系統中引入的, 在非實時系統中的確也能提高系統的響應速度, 但也不是在所有情況下都是最優的,因為搶占也需要調度和同步開銷,在某些情況下甚至要關閉內核搶占, 比如前面我們將主調度器的時候, linux內核在完成調度的過程中是關閉了內核搶占的.
內核不能再任意點被中斷, 幸運的是, 大多數不能中斷的點已經被SMP實現標識出來了. 並且在實現內核搶占時可以重用這些信息. 如果內核可以被搶占, 那麼單處理器系統也會像是一個SMP系統
4.3 內核搶占的發生時機
要滿足什麼條件,kernel才可以搶佔一個任務的內核態呢?
沒持有鎖。鎖是用於保護臨界區的,不能被搶占。
Kernel code可重入(reentrant)。因為kernel是SMP-safe的,所以滿足可重入性。
內核搶占發生的時機,一般發生在:
當從中斷處理程序正在執行,且返回內核空間之前。當一個中斷處理常式退出,在返回到內核態時(kernel-space)。這是隱式的調用schele()函數,當前任務沒有主動放棄CPU使用權,而是被剝奪了CPU使用權。
當內核代碼再一次具有可搶占性的時候,如解鎖(spin_unlock_bh)及使能軟中斷(local_bh_enable)等, 此時當kernel code從不可搶占狀態變為可搶占狀態時(preemptible again)。也就是preempt_count從正整數變為0時。這也是隱式的調用schele()函數
如果內核中的任務顯式的調用schele(), 任務主動放棄CPU使用權
如果內核中的任務阻塞(這同樣也會導致調用schele()), 導致需要調用schele()函數。任務主動放棄CPU使用權
內核搶占,並不是在任何一個地方都可以發生,以下情況不能發生
內核正進行中斷處理。在Linux內核中進程不能搶佔中斷(中斷只能被其他中斷中止、搶占,進程不能中止、搶佔中斷),在中斷常式中不允許進行進程調度。進程調度函數schele()會對此作出判斷,如果是在中斷中調用,會列印出錯信息。
內核正在進行中斷上下文的Bottom Half(中斷下半部,即軟中斷)處理。硬體中斷返回前會執行軟中斷,此時仍然處於中斷上下文中。如果此時正在執行其它軟中斷,則不再執行該軟中斷。
內核的代碼段正持有spinlock自旋鎖、writelock/readlock讀寫鎖等鎖,處干這些鎖的保護狀態中。內核中的這些鎖是為了在SMP系統中短時間內保證不同CPU上運行的進程並發執行的正確性。當持有這些鎖時,內核不應該被搶占。
內核正在執行調度程序Scheler。搶占的原因就是為了進行新的調度,沒有理由將調度程序搶佔掉再運行調度程序。
內核正在對每個CPU「私有」的數據結構操作(Per-CPU date structures)。在SMP中,對於per-CPU數據結構未用spinlocks保護,因為這些數據結構隱含地被保護了(不同的CPU有不一樣的per-CPU數據,其他CPU上運行的進程不會用到另一個CPU的per-CPU數據)。但是如果允許搶占,但一個進程被搶占後重新調度,有可能調度到其他的CPU上去,這時定義的Per-CPU變數就會有問題,這時應禁搶占。

2. linux內核態和linux用戶態上常見的臨界區保護手段有哪些,他們適合在哪些場景下使用

大部分都在用spin lock自旋鎖。而且他也很通用。不過小語句,類似以i++之類還是用原子操作比較好點。

3. 請教linux下用戶態進程調度問題

在進行Linux系統操作的時候,有時候會遇到一次用戶態進程死循環,即系統反應遲鈍、進程掛死等問題,那麼遇到這些問題又該如何解決呢?下面小編就給大家介紹下一次用戶態進程死循環的問題該如何處理。
Linux下如何處理一次用戶態進程死循環問題
1、問題現象
業務進程(用戶態多線程程序)掛死,操作系統反應遲鈍,系統日誌沒有任何異常。從進程的內核態堆棧看,看似所有線程都卡在了內核態的如下堆棧流程中:
[root@vmc116 ~]# cat /proc/27007/task/11825/stack
[《ffffffff8100baf6》] retint_careful+0x14/0x32
[《ffffffffffffffff》] 0xffffffffffffffff
2、問題分析
1)內核堆棧分析
從內核堆棧看,所有進程都阻塞在 retint_careful上,這個是中斷返回過程中的流程,代碼(匯編)如下:
entry_64.S
代碼如下:
ret_from_intr:
DISABLE_INTERRUPTS(CLBR_NONE)
TRACE_IRQS_OFF
decl PER_CPU_VAR(irq_count)
/* Restore saved previous stack */
popq %rsi
CFI_DEF_CFA rsi,SS+8-RBP /* reg/off reset after def_cfa_expr */
leaq ARGOFFSET-RBP(%rsi), %rsp
CFI_DEF_CFA_REGISTER rsp
CFI_ADJUST_CFA_OFFSET RBP-ARGOFFSET
。。。
retint_careful:
CFI_RESTORE_STATE
bt $TIF_NEED_RESCHED,%edx
jnc retint_signal
TRACE_IRQS_ON
ENABLE_INTERRUPTS(CLBR_NONE)
pushq_cfi %rdi
SCHEDULE_USER
popq_cfi %rdi
GET_THREAD_INFO(%rcx)
DISABLE_INTERRUPTS(CLBR_NONE)
TRACE_IRQS_OFF
jmp retint_check
這其實是用戶態進程在用戶態被中斷打斷後,從中斷返回的流程,結合retint_careful+0x14/0x32,進行反匯編,可以確認阻塞的點其實就在
SCHEDULE_USER
這其實就是調用schele()進行調度,也就是說當進程走到中斷返回的流程中時,發現需要調度(設置了TIF_NEED_RESCHED),於是在這里發生了調度。
有一個疑問:為什麼在堆棧中看不到schele()這一級的棧幀呢?
因為這里是匯編直接調用的,沒有進行相關棧幀壓棧和上下文保存操作。
2)進行狀態信息分析
從top命令結果看,相關線程實際一直處於R狀態,CPU幾乎完全耗盡,而且絕大部分都消耗在用戶態:
[root@vmc116 ~]# top
top - 09:42:23 up 16 days, 2:21, 23 users, load average: 84.08, 84.30, 83.62
Tasks: 1037 total, 85 running, 952 sleeping, 0 stopped, 0 zombie
Cpu(s): 97.6%us, 2.2%sy, 0.2%ni, 0.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 32878852k total, 32315464k used, 563388k free, 374152k buffers
Swap: 35110904k total, 38644k used, 35072260k free, 28852536k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
27074 root 20 0 5316m 163m 14m R 10.2 0.5 321:06.17 z_itask_templat
27084 root 20 0 5316m 163m 14m R 10.2 0.5 296:23.37 z_itask_templat
27085 root 20 0 5316m 163m 14m R 10.2 0.5 337:57.26 z_itask_templat
27095 root 20 0 5316m 163m 14m R 10.2 0.5 327:31.93 z_itask_templat
27102 root 20 0 5316m 163m 14m R 10.2 0.5 306:49.44 z_itask_templat
27113 root 20 0 5316m 163m 14m R 10.2 0.5 310:47.41 z_itask_templat
25730 root 20 0 5316m 163m 14m R 10.2 0.5 283:03.37 z_itask_templat
30069 root 20 0 5316m 163m 14m R 10.2 0.5 283:49.67 z_itask_templat
13938 root 20 0 5316m 163m 14m R 10.2 0.5 261:24.46 z_itask_templat
16326 root 20 0 5316m 163m 14m R 10.2 0.5 150:24.53 z_itask_templat
6795 root 20 0 5316m 163m 14m R 10.2 0.5 100:26.77 z_itask_templat
27063 root 20 0 5316m 163m 14m R 9.9 0.5 337:18.77 z_itask_templat
27065 root 20 0 5316m 163m 14m R 9.9 0.5 314:24.17 z_itask_templat
27068 root 20 0 5316m 163m 14m R 9.9 0.5 336:32.78 z_itask_templat
27069 root 20 0 5316m 163m 14m R 9.9 0.5 338:55.08 z_itask_templat
27072 root 20 0 5316m 163m 14m R 9.9 0.5 306:46.08 z_itask_templat
27075 root 20 0 5316m 163m 14m R 9.9 0.5 316:49.51 z_itask_templat
。。。
3)進程調度信息
從相關線程的調度信息看:
[root@vmc116 ~]# cat /proc/27007/task/11825/schedstat
15681811525768 129628804592612 3557465
[root@vmc116 ~]# cat /proc/27007/task/11825/schedstat
15682016493013 129630684625241 3557509
[root@vmc116 ~]# cat /proc/27007/task/11825/schedstat
15682843570331 129638127548315 3557686
[root@vmc116 ~]# cat /proc/27007/task/11825/schedstat
15683323640217 129642447477861 3557793
[root@vmc116 ~]# cat /proc/27007/task/11825/schedstat
15683698477621 129645817640726 3557875
發現相關線程的調度統計一直在增加,說明相關線程一直是在被調度運行的,結合其狀態也一直是R,推測很可能在用戶態發生了死循環(或者非睡眠死鎖)。
這里又有問題:為什麼從top看每個線程的CPU佔用率只有10%左右,而不是通常看到的死循環進程導致的100%的佔用率?
因為線程數很多,而且優先順序都一樣,根據CFS調度演算法,會平均分配時間片,不會讓其中一個線程獨佔CPU。結果為多個線程間輪流調度,消耗掉了所有的cpu。。
另一個問題:為什麼這種情況下,內核沒有檢測到softlockup?
因為業務進程的優先順序不高,不會影響watchdog內核線程(最高優先順序的實時線程)的調度,所以不會產生softlockup的情況。
再一個問題:為什麼每次查看線程堆棧時,總是阻塞在retint_careful,而不是其它地方?
因為這里(中斷返回的時候)正是調度的時機點,在其它時間點不能發生調度(不考慮其它情況~),而我們查看線程堆棧的行為,也必須依賴於進程調度,所以我們每次查看堆棧時,正是查看堆棧的進程(cat命令)得到調度的時候,這時正是中斷返回的時候,所以正好看到的阻塞點為retint_careful。
4)用戶態分析
從上面的分析看,推測應該是用戶態發生了死鎖。
用戶態確認方法:
部署debug信息,然後gdb attach相關進程,確認堆棧,並結合代碼邏輯分析。
最終確認該問題確為用戶態進程中產生了死循環。

4. linux 文件鎖,系統調用和庫函數之間的關系

系統調用:是操作系統為用戶態運行的進程和硬體設備(如CPU、磁碟、列印機等)進行交互提供的一組介面,即就是設置在應用程序和硬體設備之間的一個介面層。可以說是操作系統留給用戶程序的一個介面。再來說一下,linux內核是單內核,結構緊湊,執行速度快,各個模塊之間是直接調用的關系。放眼望整個linux系統,從上到下依次是用戶進程->linux內核->硬體。其中系統調用介面是位於Linux內核中的,如果再稍微細分一下的話,整個linux系統從上到下可以是:用戶進程->系統調用介面->linux內核子系統->硬體,也就是說Linux內核包括了系統調用介面和內核子系統兩部分;或者從下到上可以是:物理硬體->OS內核->OS服務->應用程序,其中操作系統起到「承上啟下」的關鍵作用,向下管理物理硬體,向上為操作系服務和應用程序提供介面,這里的介面就是系統調用了。 一般地,操作系統為了考慮實現的難度和管理的方便,它只提供一少部分的系統調用,這些系統調用一般都是由C和匯編混合編寫實現的,其介面用C來定義,而具體的實現則是匯編,這樣的好處就是執行效率高,而且,極大的方便了上層調用。

庫函數:顧名思義是把函數放到庫里。是把一些常用到的函數編完放到一個文件里,供別人用。別人用的時候把它所在的文件名用#include<>加到裡面就可以了。一般是放到lib文件里的。一般是指編譯器提供的可在c源程序中調用的函數。可分為兩類,一類是c語言標准規定的庫函數,一類是編譯器特定的庫函數。(由於版權原因,庫函數的源代碼一般是不可見的,但在頭文件中你可以看到它對外的介面)

5. 自旋鎖 是用於線程同步還是linux內核同步

自旋鎖在線程同步和linux內核同步中都有,但在用戶態使用的比較少,在內核使用的比較多

6. linux中程序處於停止態可以被喚醒嗎

在Linux中,休眠主要分三個主要的步驟:
1) 凍結用戶態進程和內核態任務
2) 調用注冊的設備的suspend的回調函數, 順序是按照注冊順序
3) 休眠核心設備和使CPU進入休眠態, 凍結進程是內核把進程列表中所有的進程的狀態都設置為停止,並且保存下所有進程的上下文.
當這些進程被解凍的時候,他們是不知道自己被凍結過的,只是簡單的繼續執行。
如何讓Linux進入休眠呢?用戶可以通過讀寫sys文件/sys /power/state 是實現控制系統進入休眠. 比如
# echo mem > /sys/power/state
命令系統進入休眠. 也可以使用

# cat /sys/power/state
來得到內核支持哪幾種休眠方式.
1. 相關代碼

• kernel/kernel/power/main.c
• kernel/arch/arm/mach-xxx/pm.c
• kernel/driver/base/power/main.c

接下來讓我們詳細的看一下Linux是怎麼休眠/喚醒的:
用戶對於/sys/power/state 的讀寫會調用到 kernel/kernel/power/main.c中的state_store(),
用戶可以寫入 const char * const pm_states[] 中定義的字元串, 比如"mem", "standby"。

const char *const pm_states[PM_SUSPEND_MAX] = {
#ifdef CONFIG_EARLYSUSPEND
[PM_SUSPEND_ON] = "on",
#endif
[PM_SUSPEND_STANDBY] = "standby",
[PM_SUSPEND_MEM] = "mem",
};
常見有standby(suspend to RAM)、mem(suspend to RAM)和disk(suspend to disk),只是standby耗電更多,返回到正常工作狀態的時間更短。

然後state_store()會調用enter_state()<註:這是經典Linux調用流程, 在Android系統中,
Kernel將調用request_suspend_state,而不是enter_state>,它首先會檢查一些狀態參數,然後同步文件系統。

2. 准備, 凍結進程
當進入到suspend_prepare()中以後, 它會給suspend分配一個虛擬終端來輸出信息, 然後廣播一個系統要進入suspend的Notify,
關閉掉用戶態的helper進程, 然後一次調用suspend_freeze_processes()凍結所有的進程, 這里會保存所有進程當前的狀態,
也許有一些進程會拒絕進入凍結狀態, 當有這樣的進程存在的時候, 會導致凍結失敗,此函數就會放棄凍結進程,並且解凍剛才凍結的所有進程。

3. 讓外設進入休眠
現在, 所有的進程(也包括workqueue/kthread) 都已經停止了,內核態人物有可能在停止的時候握有一些信號量,
所以如果這時候在外設裡面去解鎖這個信號量有可能會發生死鎖,所以在外設的suspend()函數裡面作lock/unlock鎖要非常小心,
這里建議設計的時候就不要在suspend()裡面等待鎖。而且因為suspend的時候,有一些Log是無法輸出的,所以一旦出現問題,非常難調試。

然後kernel在這里會嘗試釋放一些內存。

最後會調用suspend_devices_and_enter()來把所有的外設休眠, 在這個函數中,
如果平台注冊了suspend_ops(通常是在板級定義中定義和注冊,在kernel/arch/arm/mach-xx/pm.c中調用suspend_set_ops),
這里就會調用 suspend_ops->begin(); 然後調用dpm_suspend_start,他們會依次調用驅動的suspend() 回調來休眠掉所有的設備。

當所有的設備休眠以後, suspend_ops->prepare()會被調用, 這個函數通常會作一些准備工作來讓板機進入休眠。
接下來Linux,在多核的CPU中的非啟動CPU會被關掉,通過注釋看到是避免這些其他的CPU造成race condio,接下來的以後只有一個CPU在運行了。

suspend_ops 是板級的電源管理操作, 通常注冊在文件 arch/arch/mach-xxx/pm.c 中.

接下來, suspend_enter()會被調用, 這個函數會關閉arch irq, 調用 device_power_down(), 它會調用suspend_late()函數,
這個函數是系統真正進入休眠最後調用的函數,通常會在這個函數中作最後的檢查。 如果檢查沒問題, 接下來休眠所有的系統設備和匯流排,
並且調用 suspend_pos->enter() 來使CPU進入省電狀態,這時就已經休眠了。代碼的執行也就停在這里了。

三、Linux Resume流程

如果在休眠中系統被中斷或者其他事件喚醒,接下來的代碼就會開始執行,這個喚醒的順序是和休眠的循序相反的,
所以系統設備和匯流排會首先喚醒,使能系統中斷,使能休眠時候停止掉的非啟動CPU, 以及調用suspend_ops->finish(),
而且在suspend_devices_and_enter()函數中也會繼續喚醒每個設備,使能虛擬終端, 最後調用 suspend_ops->end()。

在返回到enter_state()函數中的,當 suspend_devices_and_enter() 返回以後,外設已經喚醒了,
但是進程和任務都還是凍結狀態, 這里會調用suspend_finish()來解凍這些進程和任務, 而且發出Notify來表示系統已經從suspend狀態退出, 喚醒終端。

到這里,所有的休眠和喚醒就已經完畢了,系統繼續運行了。

7. 求助:linux 用戶態 線程同步中信號量,互斥

你好,
1.信號量和自旋鎖一般都用於互斥.
2.信號量一般進行上下文切換,可休眠,但不可中斷.
3.自旋鎖可中斷(中斷臨界區無獲鎖操作),不可休眠.
4.信號量互斥,一般臨界區TIME(sem)較長; 自旋鎖,一般臨界區TIME(lock)較短.

8. linux pthread 信號量 佔用資源嗎

glibc提供的pthread互斥信號量可以用在進程內部,也可以用在進程間,可以在初始化時通過pthread_mutexattr_setpshared介面設置該信號量屬性,表示是進程內還是進程間。進程內的使用較為簡單,本文的總結主要是針對進程間的,進程內的也可以參考,其代碼實現原理是類似的。
一、實現原理
pthread mutex的實現是非常輕量級的,採用原子操作+futex系統調用。
在沒有競爭的情況下,即鎖空閑時,任務獲取信號量只需要通過原子操作鎖的狀態值,把值置為佔有,再記錄其他一些俄信息(owner,計數,如果使能回收功能則串入任務的信號量回收鏈表等),然後就返回了。
如果在獲取鎖時發現被佔用了,如果調用者需要睡眠等待,這時候會觸發futex系統調用,由內核繼續處理,內核會讓調用任務睡眠,並在適當時候喚醒(超時或者鎖狀態為可用)。
佔用鎖的任務釋放鎖時,如果沒有任務等待這把鎖,只需要把鎖狀態置為空閑即可。如果發現有其他任務在等待此鎖,則觸發futex系統調用,由內核喚醒等待任務。
由此可見,在沒有競爭的情況下,mutex只需要在用戶態操作鎖狀態值,無須陷入內核,是非常高效的。
獲取到鎖的任務沒有陷入內核,那麼當鎖支持優先順序翻轉時,高優先順序任務等待這把鎖,正常處理必須提升佔用鎖的任務優先順序。內核又是怎麼知道是哪個任務佔用了鎖呢?實現上,復用了鎖的狀態值,該值在空閑態時為0,非空閑態則保存了鎖的持有者ID,即PID,內核態通過PID就知道是那個任務了。
二、內核對鎖的管理
內核維護了一個hash鏈表,每把鎖都被插入到hash鏈表中去,hash值的計算如下(參考get_futex_key):1,如果是進程內的鎖,則通
過鎖的虛擬地址+任務mm指針值+鎖在頁內偏移;2,如果是進程間的鎖,則會獲取鎖虛擬地址對應物理地址的page描述符,由page描述符構造
hash值。
這樣計算的原因是進程間的鎖在各個進程內虛擬地址可能是不同的,但都映射到同一個物理地址,對應同一個page描述符。所以,內
核使用它來定位是否同一個鎖。
這里對進程間互斥鎖計算hash值的方法,給進程間共享鎖的使用設置了一個隱患條件。下面描述這個問題。

三、進程間互斥信號量的使用限制:必須在系統管理的內存上定義mutex結構,而不能在用戶reserved的共享內存上定義mutex結構。
鎖要實現進程間互斥,必須各個進程都能看到這個鎖,因此,鎖結構必須放在共享內存上。
獲取系統的共享內存通過System V的API介面創建:shmget, shmat,shmdt。但是shmget的參數需要一個id值,各進程映射同一塊共享內存需要同樣的ID值。如果各個進程需要共享的共享內存比較多,如幾千上萬個,ID值如果管理?shmget的man幫助和一些示例代碼給出的是通過ftok函數把一個文件轉為ID值(實際就是把文件對應的INODE轉為ID值),但實際應用中,如果需要的共享內存個數較多,難道創建成千上萬個文件來使用?而且怎麼保證文件在進程的生命周期內不會被刪除或者重建?
當時開發的系統還存在另外一種共享內存,就是我們通過remap_pfn_range實現的,自己管理了這塊內存的申請釋放。申請介面參數為字元串,相同的字元串表示同一塊內存。因此,傾向於使用自己管理的共享內存存放mutex結構。但在使用中,發現這種方法達不到互斥的效果。為什麼?
原因是自己管理的共享內存在內核是通過remap_pfn_range實現的,內核會把這塊內存置為reserved,表示非內核管理,獲取鎖的HASH值時,查找不到page結構,返回失敗了。最後的解決方法還是通過shmget申請共享內存,但不是通過ftok獲取ID,而是通過字元串轉為ID值並處理沖突。

四、進程間互斥信號量回收問題。
假設進程P1獲取了進程間信號量,異常退出了,還沒有釋放信號量,這時候其他進程想來獲取信號量,能獲取的到嗎?
或者進程P1獲取了信號量後,其他進程獲取不到進入了睡眠後,P1異常退出了,誰來負責喚醒睡眠的進程?
好在系統設計上已經考慮了這一點。
只要在信號量初始化時調用pthread_mutexattr_setrobust_np設置支持信號量回收機制,然後,在獲取信號量時,如果原來佔有信號量的進程退出了,系統將會返回EOWNERDEAD,判斷是這個返回值後,調用pthread_mutex_consistent_np完成信號量owner的切換工作即可。
其原理如下:
任務創建時,會注冊一個robust list(用戶態鏈表)到內核的任務控制塊TCB中期,獲取了信號量時,會把信號量掛入鏈表。進程復位時,內核會遍歷此鏈表(內核必須非常小心,因為此時的鏈表信息可能不可靠了,可不能影響到內核),置上ownerdead的標志到鎖狀態,並喚醒等待在此信號量鏈表上的進程。
五、pthread介面使用說明
pthread_mutex_init: 根據指定的屬性初始化一個mutex,狀態為空閑。
pthread_mutex_destroy: 刪除一個mutex
pthread_mutex_lock/trylock/timedlock/unlock: 獲取鎖、釋放鎖。沒有競爭關系的情況下在用戶態只需要置下鎖的狀態值即返回了,無須陷入內核。但是timedlock的入參為超時時間,一般需要調用系統API獲取,會導致陷入內核,性能較差,實現上,可先trylock,失敗了再timedlock。
pthread_mutexattr_init:配置初始化
pthread_mutexattr_destroy:刪除配置初始化介面申請的資源
pthread_mutexattr_setpshared:設置mutex是否進程間共享
pthread_mutexattr_settype:設置類型,如遞歸調用,錯誤檢測等。
pthread_mutexattr_setprotocol:設置是否支持優先順序翻轉
pthread_mutexattr_setprioceiling:設置獲取信號量的任務運行在最高優先順序。
每個set介面都有對應的get介面。

六、pthread結構變數說明

struct __pthread_mutex_s
{
int __lock; ----31bit:這個鎖是否有等待者;30bit:這個鎖的owner是否已經掛掉了。其他bit位:0鎖狀態空閑,非0為持有鎖的任務PID;
unsigned int __count; ----獲取鎖的次數,支持嵌套調用,每次獲取到鎖值加1,釋放減1。
int __owner; ----鎖的owner
unsigned int __nusers; ----使用鎖的任務個數,通常為1(被佔用)或0(空閑)
int __kind;----鎖的屬性,如遞歸調用,優先順序翻轉等。
int __spins; ----SMP下,嘗試獲取鎖的次數,盡量不進入內核。
__pthread_list_t __list; ----把鎖插入回收鏈表,如果支持回收功能,每次獲取鎖時要插入任務控制塊的回收鏈表。
}__data;

9. linux中哪些無關賬號需要鎖定

linux中需要鎖定賬號的情況為:

用戶在指定時間內輸入錯誤密碼的次數達到了相應的次數,賬戶鎖定策略就會將該用戶禁用。

linux對賬戶的鎖定功能比windows的要更加廣泛,強大,windows組策略中的限制,只是在系統層面的限制。

而linux藉助pam(Pluggable Authentication Moles,插件式認證模塊)的強大,不單止可以系統層面實現,還能在各中支持pam的應用中實現這種安全鎖定策略。

linux中PAM通過提供一些動態鏈接庫和一套統一的API,將系統提供的服務和該服務的認證方式分開,使得系統管理員可以靈活地根據需要給不同的服務配置不同的認證方式而無需更改服務程序,同時也便於向系統中添加新的認證手段。

PAM最初是集成在Solaris中,目前已移植到其它系統中,如Linux、SunOS、HP-UX9.0等。

PAM的配置是通過單個配置文件/etc/pam.conf。RedHat還支持另外一種配置方式,即通過配置目錄/etc/pam.d/,且這種的優先順序要高於單個配置文件的方式。

(9)linux用戶態鎖擴展閱讀:

在 Linux 中鎖定、解鎖和檢查給定用戶帳戶的狀態的操作:

找到同時有「password」和「pam_unix.so」欄位並且附加有「remember=5」的那行,它表示禁止使用最近用過的5個密碼(己使用過的密碼會被保存在/etc/security/opasswd下面)。

找到同時有「password」和「pam_cracklib.so」欄位並且附加有「minlen=10」的那行,它表示最小密碼長度為(10-類型數量)。這里的「類型數量」表示不同的字元類型數量。PAM提供4種類型符號作為密碼(大寫字母、小寫字母、數字和標點符號)。

如果密碼同時用上了這4種類型的符號,並且你的minlen設為10,那麼最短的密碼長度允許是6個字元。

使用配置目錄/etc/pam.d/,該目錄下的每個文件的名字對應服務名,例如ftp服務對應文件/etc/pam.d/ftp。

如果名為xxxx的服務所對應的配置文件/etc/pam.d/xxxx不存 在,則該服務將使用默認的配置文件/etc/pam.d/other。每個文件由如下格式的文本行所構成:

mole-typecontrol-flagmole-patharguments;每個欄位的含義和/etc/pam.conf中的相同。

密碼復雜度通過/etc/pam.d/system-auth這個文件來實現的。

閱讀全文

與linux用戶態鎖相關的資料

熱點內容
linux切換root命令 瀏覽:280
c編譯之後界面一閃而過怎麼辦 瀏覽:877
怎麼看ic卡是否加密 瀏覽:722
lgplc編程講座 瀏覽:806
cnc手動編程銑圓 瀏覽:720
cad中幾種命令的意思 瀏覽:324
oraclelinux安裝目錄 瀏覽:133
安卓系統可以安裝編譯器嗎 瀏覽:570
javajson實體類 瀏覽:690
板加密鋼筋是否取代原鋼筋 瀏覽:66
學習編程的思路 瀏覽:230
app易語言post怎麼學 瀏覽:965
地梁的箍筋加密區位置 瀏覽:302
二分法排序程序及編譯結果 瀏覽:679
日語命令形和禁止型 瀏覽:285
安裝軟體用管理員解壓 瀏覽:505
編譯原理代碼塊 瀏覽:400
小孩可以用壓縮面膜嗎 瀏覽:14
錐形倒角怎麼計演算法 瀏覽:883
java合並鏈表 瀏覽:508