歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> 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
這其實就是調用schedule()進行調度,也就是說當進程走到中斷返回的流程中時,發現需要調度(設置了TIF_NEED_RESCHED),於是在這裡發生了調度。
有一個疑問:為什麼在堆棧中看不到schedule()這一級的棧幀呢?
因為這裡是匯編直接調用的,沒有進行相關棧幀壓棧和上下文保存操作。

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相關進程,確認堆棧,並結合代碼邏輯分析。
最終確認該問題確為用戶態進程中產生了死循環。

以上就是linux系統中一次用戶態進程死循環案例的分析過程,謝謝閱讀,希望能幫到大家,請繼續關注腳本之家,我們會努力分享更多優秀的文章。

Copyright © Linux教程網 All Rights Reserved