linux 終端下敲ctrl-c時,到底發生了什么?(轉)


通過telnet登錄到單板,然后按ctrl-c會發生什么情況,流程是怎么樣的?

在分析之前,先介紹tty的相關知識。
我們可以認為,所有跟輸入輸出相關的操作,最終都由tty來接管。
舉例來說,當我們敲 ls /dev時得到

[cpp]  view plaincopy
  1. ls /dev/ -l  
  2. total 0  
  3. crw-------  1 root root     10, 235  8月 16 13:08 autofs  
  4. drwxr-xr-x  2 root root         720  8月 16 13:08 block  
  5. drwxr-xr-x  2 root root          80  8月 16 13:08 bsg  
  6. crw-rw----  1 root disk     10, 234  8月 16 13:08 btrfs-control  
  7. drwxr-xr-x  3 root root          60  8月 16 13:08 bus  
  8. lrwxrwxrwx  1 root root           3  8月 16 13:08 cdrom -> sr0  
  9. drwxr-xr-x  2 root root        3760  8月 16 13:08 char  
  10. crw-------  1 root root      5,   1  8月 16 13:09 console  
  11. lrwxrwxrwx  1 root root          11  8月 16 13:08 core -> /proc/kcore  
  12. drwxr-xr-x  2 root root          60  8月 16 13:08 cpu  
  13. crw-------  1 root root     10,  60  8月 16 13:08 cpu_dma_latency  
  14. crw-------  1 root root     10, 203  8月 16 13:08 cuse  
  15. drwxr-xr-x  5 root root         100  8月 16 13:08 disk  
  16. drwxr-xr-x  2 root root         100  8月 16 13:08 dri  
  17. lrwxrwxrwx  1 root root           3  8月 16 13:08 dvd -> sr0  
  18. crw-------  1 root root     10,  61  8月 16 13:08 ecryptfs  
  19. crw-rw----  1 root video    29,   0  8月 16 13:08 fb0  
  20. lrwxrwxrwx  1 root root          13  8月 16 13:08 fd -> /proc/self/fd  
  21. crw-rw-rw-  1 root root      1,   7  8月 16 13:08 full  
  22. crw-rw-rw-  1 root root     10, 229  8月 16 13:08 fuse  
  23. crw-------  1 root root    249,   0  8月 16 13:08 hidraw0  
  24. crw-------  1 root root    249,   1  8月 16 13:08 hidraw1  
  25. crw-------  1 root root    249,   2  8月 16 13:08 hidraw2  
  26. crw-------  1 root root     10, 228  8月 16 13:08 hpet  
  27. drwxr-xr-x  2 root root           0  8月 16 13:08 hugepages  
  28. crw-------  1 root root     10, 183  8月 16 13:08 hwrng  
  29. lrwxrwxrwx  1 root root          25  8月 16 13:08 initctl -> /run/systemd/initctl/fifo  
  30. drwxr-xr-x  4 root root         320  8月 16 13:08 input  
  31. crw-r--r--  1 root root      1,  11  8月 16 13:08 kmsg  
  32. lrwxrwxrwx  1 root root          28  8月 16 13:08 log -> /run/systemd/journal/dev-log  
  33. brw-rw----  1 root disk      7,   0  8月 16 13:08 loop0  
  34. brw-rw----  1 root disk      7,   1  8月 16 13:08 loop1  
  35. brw-rw----  1 root disk      7,   2  8月 16 13:08 loop2  
  36. brw-rw----  1 root disk      7,   3  8月 16 13:08 loop3  
  37. brw-rw----  1 root disk      7,   4  8月 16 13:08 loop4  
  38. brw-rw----  1 root disk      7,   5  8月 16 13:08 loop5  
  39. brw-rw----  1 root disk      7,   6  8月 16 13:08 loop6  
  40. brw-rw----  1 root disk      7,   7  8月 16 13:08 loop7  
  41. crw-rw----  1 root disk     10, 237  8月 16 13:08 loop-control  
  42. drwxr-xr-x  2 root root          60  8月 16 13:08 mapper  
  43. crw-------  1 root root     10, 227  8月 16 13:08 mcelog  
  44. crw-------  1 root root    250,   0  8月 16 13:08 mei0  
  45. crw-r-----  1 root kmem      1,   1  8月 16 13:08 mem  
  46. crw-------  1 root root     10,  57  8月 16 13:08 memory_bandwidth  
  47. drwxrwxrwt  2 root root          40  8月 16 13:08 mqueue  
  48. drwxr-xr-x  2 root root          60  8月 16 13:08 net  
  49. crw-------  1 root root     10,  59  8月 16 13:08 network_latency  
  50. crw-------  1 root root     10,  58  8月 16 13:08 network_throughput  
  51. crw-rw-rw-  1 root root      1,   3  8月 16 13:08 null  
  52. crw-r-----  1 root kmem      1,   4  8月 16 13:08 port  
  53. crw-------  1 root root    108,   0  8月 16 13:08 ppp  
  54. crw-------  1 root root     10,   1  8月 16 13:08 psaux  
  55. crw-rw-rw-  1 root tty       5,   2  8月 16 13:44 ptmx  
  56. drwxr-xr-x  2 root root           0  8月 16 13:08 pts  
  57. brw-rw----  1 root disk      1,   0  8月 16 13:08 ram0  
  58. brw-rw----  1 root disk      1,   1  8月 16 13:08 ram1  
  59. brw-rw----  1 root disk      1,  10  8月 16 13:08 ram10  
  60. brw-rw----  1 root disk      1,  11  8月 16 13:08 ram11  
  61. brw-rw----  1 root disk      1,  12  8月 16 13:08 ram12  
  62. brw-rw----  1 root disk      1,  13  8月 16 13:08 ram13  
  63. brw-rw----  1 root disk      1,  14  8月 16 13:08 ram14  
  64. brw-rw----  1 root disk      1,  15  8月 16 13:08 ram15  
  65. brw-rw----  1 root disk      1,   2  8月 16 13:08 ram2  
  66. brw-rw----  1 root disk      1,   3  8月 16 13:08 ram3  
  67. brw-rw----  1 root disk      1,   4  8月 16 13:08 ram4  
  68. brw-rw----  1 root disk      1,   5  8月 16 13:08 ram5  
  69. brw-rw----  1 root disk      1,   6  8月 16 13:08 ram6  
  70. brw-rw----  1 root disk      1,   7  8月 16 13:08 ram7  
  71. brw-rw----  1 root disk      1,   8  8月 16 13:08 ram8  
  72. brw-rw----  1 root disk      1,   9  8月 16 13:08 ram9  
  73. crw-rw-rw-  1 root root      1,   8  8月 16 13:08 random  
  74. crw-rw-r--+ 1 root root     10,  62  8月 16 13:08 rfkill  
  75. lrwxrwxrwx  1 root root           4  8月 16 13:08 rtc -> rtc0  
  76. crw-------  1 root root    253,   0  8月 16 13:08 rtc0  
  77. brw-rw----  1 root disk      8,   0  8月 16 13:08 sda  
  78. brw-rw----  1 root disk      8,   1  8月 16 13:08 sda1  
  79. brw-rw----  1 root disk      8,   2  8月 16 13:08 sda2  
  80. brw-rw----  1 root disk      8,   3  8月 16 13:08 sda3  
  81. brw-rw----  1 root disk      8,   4  8月 16 13:08 sda4  
  82. brw-rw----  1 root disk      8,   5  8月 16 13:08 sda5  
  83. brw-rw----  1 root disk      8,   6  8月 16 13:08 sda6  
  84. brw-rw----  1 root disk      8,   7  8月 16 13:08 sda7  
  85. brw-rw----  1 root disk      8,   8  8月 16 13:08 sda8  
  86. crw-rw----  1 root disk     21,   0  8月 16 13:08 sg0  
  87. crw-rw----+ 1 root cdrom    21,   1  8月 16 13:08 sg1  
  88. drwxrwxrwt  2 root root         120  8月 16 13:08 shm  
  89. crw-------  1 root root     10, 231  8月 16 13:08 snapshot  
  90. drwxr-xr-x  3 root root         200  8月 16 13:08 snd  
  91. brw-rw----+ 1 root cdrom    11,   0  8月 16 13:08 sr0  
  92. lrwxrwxrwx  1 root root          15  8月 16 13:08 stderr -> /proc/self/fd/2  
  93. lrwxrwxrwx  1 root root          15  8月 16 13:08 stdin -> /proc/self/fd/0  
  94. lrwxrwxrwx  1 root root          15  8月 16 13:08 stdout -> /proc/self/fd/1  
  95. crw-rw-rw-  1 root tty       5,   0  8月 16 13:08 tty  
  96. crw--w----  1 root tty       4,   0  8月 16 13:08 tty0  
  97. crw--w----  1 root tty       4,   1  8月 16 13:08 tty1  
  98. crw--w----  1 root tty       4,  10  8月 16 13:08 tty10  
  99. crw--w----  1 root tty       4,  11  8月 16 13:08 tty11  
  100. crw--w----  1 root tty       4,  12  8月 16 13:08 tty12  
  101. crw--w----  1 root tty       4,  13  8月 16 13:08 tty13  
  102. crw--w----  1 root tty       4,  14  8月 16 13:08 tty14  
  103. crw--w----  1 root tty       4,  15  8月 16 13:08 tty15  
  104. crw--w----  1 root tty       4,  16  8月 16 13:08 tty16  
  105. crw--w----  1 root tty       4,  17  8月 16 13:08 tty17  
  106. crw--w----  1 root tty       4,  18  8月 16 13:08 tty18  
  107. crw--w----  1 root tty       4,  19  8月 16 13:08 tty19  
  108. crw--w----  1 root tty       4,   2  8月 16 13:08 tty2  
  109. crw--w----  1 root tty       4,  20  8月 16 13:08 tty20  
  110. crw--w----  1 root tty       4,  21  8月 16 13:08 tty21  
  111. crw--w----  1 root tty       4,  22  8月 16 13:08 tty22  
  112. crw--w----  1 root tty       4,  23  8月 16 13:08 tty23  
  113. crw--w----  1 root tty       4,  24  8月 16 13:08 tty24  
  114. crw--w----  1 root tty       4,  25  8月 16 13:08 tty25  
  115. crw--w----  1 root tty       4,  26  8月 16 13:08 tty26  
  116. crw--w----  1 root tty       4,  27  8月 16 13:08 tty27  
  117. crw--w----  1 root tty       4,  28  8月 16 13:08 tty28  
  118. crw--w----  1 root tty       4,  29  8月 16 13:08 tty29  
  119. crw--w----  1 root tty       4,   3  8月 16 13:08 tty3  
  120. crw--w----  1 root tty       4,  30  8月 16 13:08 tty30  
  121. crw--w----  1 root tty       4,  31  8月 16 13:08 tty31  
  122. crw--w----  1 root tty       4,  32  8月 16 13:08 tty32  
  123. crw--w----  1 root tty       4,  33  8月 16 13:08 tty33  
  124. crw--w----  1 root tty       4,  34  8月 16 13:08 tty34  
  125. crw--w----  1 root tty       4,  35  8月 16 13:08 tty35  
  126. crw--w----  1 root tty       4,  36  8月 16 13:08 tty36  
  127. crw--w----  1 root tty       4,  37  8月 16 13:08 tty37  
  128. crw--w----  1 root tty       4,  38  8月 16 13:08 tty38  
  129. crw--w----  1 root tty       4,  39  8月 16 13:08 tty39  
  130. crw--w----  1 root tty       4,   4  8月 16 13:08 tty4  
  131. crw--w----  1 root tty       4,  40  8月 16 13:08 tty40  
  132. crw--w----  1 root tty       4,  41  8月 16 13:08 tty41  
  133. crw--w----  1 root tty       4,  42  8月 16 13:08 tty42  
  134. crw--w----  1 root tty       4,  43  8月 16 13:08 tty43  
  135. crw--w----  1 root tty       4,  44  8月 16 13:08 tty44  
  136. crw--w----  1 root tty       4,  45  8月 16 13:08 tty45  
  137. crw--w----  1 root tty       4,  46  8月 16 13:08 tty46  
  138. crw--w----  1 root tty       4,  47  8月 16 13:08 tty47  
  139. crw--w----  1 root tty       4,  48  8月 16 13:08 tty48  
  140. crw--w----  1 root tty       4,  49  8月 16 13:08 tty49  
  141. crw--w----  1 root tty       4,   5  8月 16 13:08 tty5  
  142. crw--w----  1 root tty       4,  50  8月 16 13:08 tty50  
  143. crw--w----  1 root tty       4,  51  8月 16 13:08 tty51  
  144. crw--w----  1 root tty       4,  52  8月 16 13:08 tty52  
  145. crw--w----  1 root tty       4,  53  8月 16 13:08 tty53  
  146. crw--w----  1 root tty       4,  54  8月 16 13:08 tty54  
  147. crw--w----  1 root tty       4,  55  8月 16 13:08 tty55  
  148. crw--w----  1 root tty       4,  56  8月 16 13:08 tty56  
  149. crw--w----  1 root tty       4,  57  8月 16 13:08 tty57  
  150. crw--w----  1 root tty       4,  58  8月 16 13:08 tty58  
  151. crw--w----  1 root tty       4,  59  8月 16 13:08 tty59  
  152. crw--w----  1 root tty       4,   6  8月 16 13:08 tty6  
  153. crw--w----  1 root tty       4,  60  8月 16 13:08 tty60  
  154. crw--w----  1 root tty       4,  61  8月 16 13:08 tty61  
  155. crw--w----  1 root tty       4,  62  8月 16 13:08 tty62  
  156. crw--w----  1 root tty       4,  63  8月 16 13:08 tty63  
  157. crw--w----  1 root tty       4,   7  8月 16 13:08 tty7  
  158. crw--w----  1 root tty       4,   8  8月 16 13:08 tty8  
  159. crw--w----  1 root tty       4,   9  8月 16 13:08 tty9  
  160. crw-------  1 root root      5,   3  8月 16 13:08 ttyprintk  
  161. crw-rw----  1 root dialout   4,  64  8月 16 13:08 ttyS0  
  162. crw-rw----  1 root dialout   4,  65  8月 16 13:08 ttyS1  
  163. crw-rw----  1 root dialout   4,  74  8月 16 13:08 ttyS10  
  164. crw-rw----  1 root dialout   4,  75  8月 16 13:08 ttyS11  
  165. crw-rw----  1 root dialout   4,  76  8月 16 13:08 ttyS12  
  166. crw-rw----  1 root dialout   4,  77  8月 16 13:08 ttyS13  
  167. crw-rw----  1 root dialout   4,  78  8月 16 13:08 ttyS14  
  168. crw-rw----  1 root dialout   4,  79  8月 16 13:08 ttyS15  
  169. crw-rw----  1 root dialout   4,  80  8月 16 13:08 ttyS16  
  170. crw-rw----  1 root dialout   4,  81  8月 16 13:08 ttyS17  
  171. crw-rw----  1 root dialout   4,  82  8月 16 13:08 ttyS18  
  172. crw-rw----  1 root dialout   4,  83  8月 16 13:08 ttyS19  
  173. crw-rw----  1 root dialout   4,  66  8月 16 13:08 ttyS2  
  174. crw-rw----  1 root dialout   4,  84  8月 16 13:08 ttyS20  
  175. crw-rw----  1 root dialout   4,  85  8月 16 13:08 ttyS21  
  176. crw-rw----  1 root dialout   4,  86  8月 16 13:08 ttyS22  
  177. crw-rw----  1 root dialout   4,  87  8月 16 13:08 ttyS23  
  178. crw-rw----  1 root dialout   4,  88  8月 16 13:08 ttyS24  
  179. crw-rw----  1 root dialout   4,  89  8月 16 13:08 ttyS25  
  180. crw-rw----  1 root dialout   4,  90  8月 16 13:08 ttyS26  
  181. crw-rw----  1 root dialout   4,  91  8月 16 13:08 ttyS27  
  182. crw-rw----  1 root dialout   4,  92  8月 16 13:08 ttyS28  
  183. crw-rw----  1 root dialout   4,  93  8月 16 13:08 ttyS29  
  184. crw-rw----  1 root dialout   4,  67  8月 16 13:08 ttyS3  
  185. crw-rw----  1 root dialout   4,  94  8月 16 13:08 ttyS30  
  186. crw-rw----  1 root dialout   4,  95  8月 16 13:08 ttyS31  
  187. crw-rw----  1 root dialout   4,  68  8月 16 13:08 ttyS4  
  188. crw-rw----  1 root dialout   4,  69  8月 16 13:08 ttyS5  
  189. crw-rw----  1 root dialout   4,  70  8月 16 13:08 ttyS6  
  190. crw-rw----  1 root dialout   4,  71  8月 16 13:08 ttyS7  
  191. crw-rw----  1 root dialout   4,  72  8月 16 13:08 ttyS8  
  192. crw-rw----  1 root dialout   4,  73  8月 16 13:08 ttyS9  
  193. crw-------  1 root root     10, 239  8月 16 13:08 uhid  
  194. crw-------  1 root root     10, 223  8月 16 13:08 uinput  
  195. crw-rw-rw-  1 root root      1,   9  8月 16 13:08 urandom  
  196. crw-rw----  1 root tty       7,   0  8月 16 13:08 vcs  
  197. crw-rw----  1 root tty       7,   1  8月 16 13:08 vcs1  
  198. crw-rw----  1 root tty       7,   2  8月 16 13:08 vcs2  
  199. crw-rw----  1 root tty       7,   3  8月 16 13:08 vcs3  
  200. crw-rw----  1 root tty       7,   4  8月 16 13:08 vcs4  
  201. crw-rw----  1 root tty       7,   5  8月 16 13:08 vcs5  
  202. crw-rw----  1 root tty       7,   6  8月 16 13:08 vcs6  
  203. crw-rw----  1 root tty       7,   7  8月 16 13:08 vcs7  
  204. crw-rw----  1 root tty       7, 128  8月 16 13:08 vcsa  
  205. crw-rw----  1 root tty       7, 129  8月 16 13:08 vcsa1  
  206. crw-rw----  1 root tty       7, 130  8月 16 13:08 vcsa2  
  207. crw-rw----  1 root tty       7, 131  8月 16 13:08 vcsa3  
  208. crw-rw----  1 root tty       7, 132  8月 16 13:08 vcsa4  
  209. crw-rw----  1 root tty       7, 133  8月 16 13:08 vcsa5  
  210. crw-rw----  1 root tty       7, 134  8月 16 13:08 vcsa6  
  211. crw-rw----  1 root tty       7, 135  8月 16 13:08 vcsa7  
  212. drwxr-xr-x  2 root root          60  8月 16 13:08 vfio  
  213. crw-------  1 root root     10,  63  8月 16 13:08 vga_arbiter  
  214. crw-------  1 root root     10, 137  8月 16 13:08 vhci  
  215. crw-------  1 root root     10, 238  8月 16 13:08 vhost-net  
  216. prw-r-----  1 root adm            0  8月 16 13:08 xconsole  
  217. crw-rw-rw-  1 root root      1,   5  8月 16 13:08 zero  


另外還可以通過 /proc/tty/drivers得到tty相關驅動信息

 

[cpp]  view plaincopy
  1. cat /proc/tty/drivers  
  2. /dev/tty             /dev/tty        5       0 system:/dev/tty  
  3. /dev/console         /dev/console    5       1 system:console  
  4. /dev/ptmx            /dev/ptmx       5       2 system  
  5. /dev/vc/0            /dev/vc/0       4       0 system:vtmaster  
  6. ttyprintk            /dev/ttyprintk   5       3 console  
  7. serial               /dev/ttyS       4 64-111 serial  
  8. pty_slave            /dev/pts      136 0-1048575 pty:slave  
  9. pty_master           /dev/ptm      128 0-1048575 pty:master  
  10. unknown              /dev/tty        4 1-63 console  

 

tty  控制終端,control terminal 這個是跟進程相關的,可以理解為一個指針,指向具體的tty終端設備。

     進程可以通過open /dev/tty來獲取當前進程使用的tty終端具體是哪個,例如是ptmx,還是pts/2,還是

tty2,或者是ttyS0
     linux shell下tty命令的可以查看當前進程的控制終端。例如:
     [root@ dev]# tty
     /dev/pts/10
     具體的實現是靠ttyname(0)
     即返回當前進程的標准輸入,對應的tty終端設備是哪個。

     另外通過ps -ax可以查看系統所有進程的控制終端,如:

 

[cpp]  view plaincopy
  1. root       781  0.0  0.0  20052  2088 tty1     Ss+  13:08   0:00 /sbin/agetty --noclear tty1 linux  

 


ptmx 偽終端主
pts  偽終端從
tty0-tty63  虛擬終端,也叫虛擬控制台終端,virtual console ternimal 通常情況下是6個,這里我們查看
的服務器有63個
tty0可以理解為指針
ttyS0-ttyS3 串口終端 

剛才說到,/proc/pid/stat的第7個字段是進程控制終端的設備號,可以根據此設備號得到具體的設備名。

 

[cpp]  view plaincopy
  1. tty_nr = new_encode_dev(tty_devnum(sig->tty));  
  2. seq_put_decimal_ll(m, ' ', tty_nr);  

例如:

 

 

[cpp]  view plaincopy
  1. cat /proc/781/stat  
  2. 81 (agetty) S 1 781 781 1025 781 4194560 180 35 0 0 0 0 0 0 20 0 1 0 2778 20533248 522 18446744073709551615 4194304 4227700 140728752939200 140728752928472 139843305755776 0 0 6 0 18446744071579591276 0 0 17 2 0 0 0 0 0 6327824 6329216 20836352 140728752942807 140728752942841 140728752942841 140728752943083 0  

即1025,十六進為0x401 ,主設備號為高4字節4,次設備號為低字節1,

 

對照/proc/tty/drivers得到

[cpp]  view plaincopy
  1. unknown              /dev/tty        4 1-63 console  

 

即tty1。再根據ps -ax | grep 781得到

 

[cpp]  view plaincopy
  1. /# ps -ax | grep 781  
  2.   781 tty1     Ss+    0:00 /sbin/agetty --noclear tty1 linux  


確實是吻合的。

 

 

扯遠了,下面來看telnet的流程

26912 ?        Ss     0:00 busybox telnetd
當用戶通過telnet客戶端連接telnetd后
26912 ?        Ss     0:00 busybox telnetd
27030 ?        Ss     0:00 login -- chenyu
27038 pts/6    Ss+    0:00 -bash

可以看出telnetd先fork出gettty並執行login,登錄成功后則再fork出實際的bash,

這個bash用的是偽終端pts/6,

以下數據的PPid字段可以證明:
Name:   busybox
PPid:   1

Name:   login
Pid:    27030
PPid:   26912

Name:   bash
Pid:    27038
PPid:   27030

bash並不知道這個pts/6具體是個什么設備,只知道往里面讀寫。
每次在telnet客戶端,敲一個字符,就會把數據發給telnetd,telnetd再操作ptmx通過
tty displine將數據格式化傳遞給pts/6,然后bash從pts/6收到數據進行處理,再寫回pts/6,
傳給ptmx,由telnetd將數據再傳遞回telnet客戶端。 可以通過每次在telnet客戶端
敲一個字符,telnetd的調度次數就增加2,來大體驗證這個流程(telnetd收到客戶端數據被喚醒,bash通過
偽終端把數據寫回喚醒telnetd,一共兩次喚醒)

具體的telnet流程圖如下:





說完了telnetd的原理,再來看看在telnet客戶端敲ctrl-c時,系統會發生什么。
首先可以明確的是,ctrl-c傳遞到telnetd后,會通過寫偽終端主設備ptmx的方式傳遞給從設備進而傳給bash。
那么,到底是telnetd,還是bash端會處理這個ctrl-c?

實際上我們可以這么理解,在直接登錄shell時,沒有telnetd這一層,

應該是shell進程本身被ctrl-c鍵盤中斷打斷,

然后再驅動里通過tty收到了此特殊字符,然后在接收流程里,決定是否給當前進程shell發SIG信號。
那么我們就認為telnetd不過是一個中轉站,具體的數據處理還是要靠bash來完成。

因此當bash從pts/6收到ctrl-c特殊字符后,會進行特殊處理。來看這段代碼:
首先,不管是偽終端,還是串口,亦或是控制台,接收到字符后都要推送給tty displine 的接收函數
n_tty_receive_buf做進一步處理。n_tty_receive_buf的數據來源是tty->buf。
這個tty->buf的來源,要么是偽終端主設備pty_write寫入的數據,要么是中斷往里面寫入的數據。

如果是偽終端pty_write
static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c)
{
     //得到從設備
struct tty_struct *to = tty->link;


if (tty->stopped)
return 0;


if (c > 0) {
/* Stuff the data into the input queue of the other end */
     //讓從設備強行收數據,即將buf數據傳遞給從設備的tty->buf
c = tty_insert_flip_string(to, buf, c);
/* And shovel */
if (c) {
            //將從設備的tty->buf臨時緩沖數據提交給displine處理,即提交給tty->read_buf
            //供用戶空間使用
             //這個一般是通過schedule_work來完成
tty_flip_buffer_push(to);
tty_wakeup(tty);
}
}
return c;
}

如果是串口中斷,則是
serial8250_interrupt->serial8250_handle_port->receive_chars->
uart_insert_char->tty_insert_flip_char 將串口數據拷貝到tty->buf中之后,
再tty_flip_buffer_push(tty);將數據推送給displine處理

因此可以看出,串口和偽終端的不同之處在於,數據來源不同,一個是tty_write寫入的,
一個是串口中斷接受到的。
所以,我們在串口,或者是在telnet下,敲ctrl-c,實際上都會走到tty_flip_buffer_push,
進行數據的分析和接受。具體的特殊字符解析,應該也是在tty_flip_buffer_push之后的步驟完成。

那下面我們來看tty_flip_buffer_push
* This routine is called out of the software interrupt to flush data
* from the buffer chain to the line discipline.


最終調到到receive_buf->n_tty_receive_buf->n_tty_receive_break->
isig(SIGINT, tty, 1);->
if (tty->pgrp)
kill_pgrp(tty->pgrp, sig, 1);

即向進程組發送INT信號。

 

 

有了上面的知識鋪墊,我們來看一個實際的問題。

我們先說明,這是一個busybox 1.13版本的bug,后來已經在高版本修復。

故障現象是這樣的:

mips32&64  busybox 1.13 kernel 2.6.32

在串口終端執行如下腳本:

./tftp -r file_256M -g 192.168.1.1

 'echo 1'

然后在tftp下載過程中,按ctrl-c

那么tftp進程將變成Z

故障的場景:
1)# ./test.sh之后 ash fork生成一個sh, 這個sh嘗試按行解析test.sh,每讀取一行就fork一個新進程並exec去執行。 然后sh通過waitpid等待子進程的完成。  正常情況下,兩條命令順序執行完,一切都結束的很好。

2)如果sh在waitpid過程中,即等待tftp完成的過程中,正好收到了SIGINT信號,那么sh就被人從阻塞狀態里喚醒。

do_wait繼續進入輪詢檢查到tftp不是為Z(因為這個時候tftp還沒得到調度),所以不會回收tftp,然后退出系統調用返回用戶態

時檢查到有pending的SIGINT,於是get_signal_to_deliever,

由於sh注冊了SIGINT信號的處理函數onsig,因此不會do_group_exit
3)onsig執行完之后,再解析下一條命令`echo 1` , 由於sh發現這條命令是引號包起來的,   說明是一個子命令,因此sh再次fork一個進程sh_2,去執行echo 1,並且通過管道pipe_wait等待   sh_2的echo 1的結果
4)sh_2在解析echo 1的過程中,需要獲取tty串口的信息,由於這個時候控制終端tty串口已經被sh占有,所以sh_2    就會一直阻塞在tty_read,造成與sh的互鎖。
因此問題出在,第3步sh如果收到了SIGINT信號,就不應該繼續執行下一條echo 1指令了,而是整個進程退出 后面的一系列問題都是錯誤的流程導致的錯誤的結果。

附出問題時的阻塞現場

941 root      3840 S    -/bin/ash 
  955 root      3840 S    /bin/sh 
  969 root      3792 S    /bin/sh ./test.sh    //即上文的sh
  970 root         0 Z    [tftp]
  971 root      3792 S    /bin/sh ./test.sh    //sh收到ctrl-c后不做處理,繼續fork,嘗試解析echo 1字符
  972 root      3856 R    ps 

(gdb) attach 969
The target endianness is set automatically (currently big endian)
[New Thread 969]
0x0000000120013370 in read ()
(gdb) bt
#0  0x0000000120013370 in read ()
#1  0x00000001200fe9d4 in safe_read (fd=3, buf=0xffffa53bf8, count=128)
    at libbb/read.c:27
#2  0x00000001200fea68 in nonblock_safe_read (fd=3, buf=0xffffa53bf8, 
    count=128) at libbb/read.c:75
#3  0x000000012018fd3c in expbackq (cmd=0x120341b48, quoted=0, quotes=0)
    at shell/ash.c:5557
#4  0x0000000120190580 in argstr (p=0x120341b6b "", flag=68, var_str_list=0x0)
    at shell/ash.c:5783
#5  0x0000000120193574 in expandarg (arg=0x120341b70, arglist=0xffffa53e40, 
    flag=4) at shell/ash.c:6829
#6  0x0000000120198304 in evalcommand (cmd=0x120341b90, flags=0)
    at shell/ash.c:8813
#7  0x0000000120196474 in evaltree (n=0x120341b90, flags=0)
    at shell/ash.c:8005
#8  0x000000012019fd6c in cmdloop (top=1) at shell/ash.c:11739
#9  0x00000001201a46e8 in ash_main (argc=2, argv=0xffffa54408)
    at shell/ash.c:13743
#10 0x00000001200fa098 in run_applet_no_and_exit (applet_no=219, 
    argv=0xffffa54408) at libbb/appletlib.c:747
#11 0x00000001200fa10c in run_applet_and_exit (name=0xffffa57f61 "sh", 
    argv=0xffffa54408) at libbb/appletlib.c:754
#12 0x00000001200fa24c in main (argc=2, argv=0xffffa54408)
    at libbb/appletlib.c:791
(gdb) detach 
Ending debugging.
(gdb) attach 971
[New Thread 971]
0x0000000120013370 in read ()
(gdb) bt
#0  0x0000000120013370 in read ()
#1  0x00000001200fe9d4 in safe_read (fd=0, buf=0x12031cd08, count=8191)
    at libbb/read.c:27
#2  0x00000001200fea68 in nonblock_safe_read (fd=0, buf=0x12031cd08, 
    count=8191) at libbb/read.c:75
#3  0x0000000120199148 in preadfd () at shell/ash.c:9139
#4  0x00000001201994d8 in preadbuffer () at shell/ash.c:9258
#5  0x000000012019972c in pgetc () at shell/ash.c:9314
#6  0x000000012019f078 in xxreadtoken () at shell/ash.c:11365
#7  0x000000012019f3a8 in readtoken () at shell/ash.c:11499
#8  0x000000012019f64c in parsecmd (interact=0) at shell/ash.c:11576
#9  0x000000012019fc80 in cmdloop (top=1) at shell/ash.c:11724
#10 0x00000001201a46e8 in ash_main (argc=2, argv=0xffffa54408)
    at shell/ash.c:13743
#11 0x00000001200fa098 in run_applet_no_and_exit (applet_no=219, 
    argv=0xffffa54408) at libbb/appletlib.c:747
#12 0x00000001200fa10c in run_applet_and_exit (name=0xffffa57f61 "sh", 
    argv=0xffffa54408) at libbb/appletlib.c:754
#13 0x00000001200fa24c in main (argc=2, argv=0xffffa54408)
    at libbb/appletlib.c:791
(gdb) 

http://blog.csdn.net/chenyu105/article/details/7738388

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM