• 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

  • 相关阅读:
    java 字符串split有很多坑,使用时请小心!!
    Java并发编程:线程池的使用
    java自带线程池和队列详细讲解
    merge into的用法
    Oracle中如何使用REGEXP_SUBSTR函数
    oracle分组统计某列逗号隔开数据
    oracle一列中的数据有多个手机号码用逗号隔开,我如何分别取出来?
    css box-shadow使用---转
    201706问题记录
    201705问题记录
  • 原文地址:https://www.cnblogs.com/softidea/p/4986369.html
Copyright © 2020-2023  润新知