zoukankan      html  css  js  c++  java
  • linux 终端下敲ctrl-c时,到底发生了什么?(转)

    通过telnet登录到单板,然后按ctrl-c会发生什么情况,流程是怎么样的?

    在分析之前,先介绍tty的相关知识。
    我们可以认为,所有跟输入输出相关的操作,最终都由tty来接管。
    举例来说,当我们敲 ls /dev时得到

    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相关驱动信息

    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可以查看系统所有进程的控制终端,如:

    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个字段是进程控制终端的设备号,可以根据此设备号得到具体的设备名。

    1. tty_nr = new_encode_dev(tty_devnum(sig->tty));  
    2. seq_put_decimal_ll(m, ' ', tty_nr);  

    例如:

    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得到

    1. unknown              /dev/tty        4 1-63 console  

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

    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

  • 相关阅读:
    php多态
    ssl certificate problem: self signed certificate in certificate chain
    test plugin
    open specific port on ubuntu
    junit vs testng
    jersey rest service
    toast master
    use curl to test java webservice
    update folder access
    elk
  • 原文地址:https://www.cnblogs.com/softidea/p/4986369.html
Copyright © 2011-2022 走看看