opencontainers / runc

CLI tool for spawning and running containers according to the OCI specification
https://www.opencontainers.org/
Apache License 2.0
11.93k stars 2.12k forks source link

runc doesn't pass SIGINT to underlying process #1624

Open qingyunha opened 7 years ago

qingyunha commented 7 years ago

I think signal handler is here.

    for s := range h.signals {
        switch s {
        case unix.SIGWINCH:
            // Ignore errors resizing, as above.
            _ = tty.resize()
        case unix.SIGCHLD:
            exits, err := h.reap()
            if err != nil {
                logrus.Error(err)
            }
            for _, e := range exits {
                logrus.WithFields(logrus.Fields{
                    "pid":    e.pid,
                    "status": e.status,
                }).Debug("process exited")
                if e.pid == pid1 {
                    // call Wait() on the process even though we already have the exit
                    // status because we must ensure that any of the go specific process
                    // fun such as flushing pipes are complete before we return.
                    process.Wait()
                    if h.notifySocket != nil {
                        h.notifySocket.Close()
                    }
                    return e.status, nil
                }
            }
        default:
            logrus.Debugf("sending signal to process %s", s)
            if err := unix.Kill(pid1, s.(syscall.Signal)); err != nil {
                logrus.Error(err)
            }
        }
    }

so the SIGINT will send to pid1. Right?

But when I run runc --log /dev/stderr --debug run xxx, then kill -SIGINT runc. I didn't see log sending signal to process as I expected. runc just exit and leave container process running in some case.

Other signals than SIGINT will do that. I am confused about this, please help me.

qingyunha commented 7 years ago

the strace output when I kill SIGTTIN and SIGINT

[pid  7031] --- SIGTTIN {si_signo=SIGTTIN, si_code=SI_USER, si_pid=7065, si_uid=0} ---                                                                                                        
[pid  7031] rt_sigreturn({mask=[SYS]})  = 202                                                                                                                                                 
[pid  7032] sched_yield()               = 0                                                                                                                                                   
[pid  7032] epoll_wait(4,  <unfinished ...>                                                                                                                                                   
[pid  7033] epoll_wait(4,  <unfinished ...>                                                                                                                                                   
[pid  7032] <... epoll_wait resumed> [], 128, 0) = 0                                           
[pid  7044] fcntl(3, F_GETFL <unfinished ...>  
[pid  7033] <... epoll_wait resumed> [], 128, 0) = 0
[pid  7044] <... fcntl resumed> )       = 0x109c01 (flags O_WRONLY|O_APPEND|O_NONBLOCK|O_SYNC|O_LARGEFILE)                                                                                    
[pid  7044] fcntl(3, F_SETFL, O_WRONLY|O_APPEND|O_SYNC|O_LARGEFILE) = 0
[pid  7044] ioctl(3, TCGETS, {B38400 opost -isig -icanon -echo ...}) = 0
[pid  7044] write(3, "\33[37mDEBU\33[0m[0054] sending sign"..., 67) = 67
[pid  7044] kill(7039, SIGTTIN)         = 0                                                    
[pid  7044] epoll_wait(4, [{EPOLLOUT, {u32=258010880, u64=140707681595136}}], 128, 0) = 1
[pid  7036] <... epoll_wait resumed> [{EPOLLIN|EPOLLOUT, {u32=7, u64=7}}], 128, -1) = 1
[pid  7036] epoll_wait(9,  <unfinished ...>    
[pid  7044] epoll_wait(4, [], 128, 0)   = 0                                                    
[pid  7044] read(7,  <unfinished ...>          
[pid  7033] epoll_wait(4,  <unfinished ...>    
[pid  7044] <... read resumed> "get signal stopped (tty input)\n", 32768) = 31
[pid  7033] <... epoll_wait resumed> [], 128, 0) = 0
[pid  7044] write(1, "get signal stopped (tty input)\n", 31) = 31
[pid  7044] read(7, 0xc4201ca000, 32768) = -1 EAGAIN (Resource temporarily unavailable)
[pid  7044] epoll_wait(4, [{EPOLLOUT, {u32=258010880, u64=140707681595136}}], 128, 0) = 1
[pid  7032] epoll_wait(4, [], 128, 0)   = 0    
[pid  7044] epoll_wait(4, [], 128, 0)   = 0    

[pid  7031] --- SIGINT {si_signo=SIGINT, si_code=SI_USER, si_pid=7072, si_uid=0} ---
[pid  7031] rt_sigreturn({mask=[SYS]} <unfinished ...>
[pid  7032] epoll_wait(4, [], 128, 0)   = 0
[pid  7044] epoll_wait(4, [], 128, 0)   = 0
[pid  7033] ioctl(0, SNDCTL_TMR_START or TCSETS, {B38400 opost isig icanon echo ...} <unfinished ...>
[pid  7031] <... rt_sigreturn resumed> ) = 202
[pid  7033] <... ioctl resumed> )       = 0
[pid  7033] exit_group(0 <unfinished ...>
[pid  7034] <... read resumed> <unfinished ...>) = ?
[pid  7033] <... exit_group resumed>)   = ?
[pid  7034] +++ exited with 0 +++
[pid  7035] +++ exited with 0 +++
[pid  7036] <... epoll_wait resumed> <unfinished ...>) = ?
[pid  7033] +++ exited with 0 +++
[pid  7044] +++ exited with 0 +++
[pid  7036] +++ exited with 0 +++
[pid  7032] +++ exited with 0 +++
+++ exited with 0 +++
qingyunha commented 6 years ago

There is another signal handler in https://github.com/opencontainers/runc/blob/master/tty.go#L105 that cause runc exit immediately.