From 5d1b48d6114b8c9666f0c8b916f871af97b0a761 Mon Sep 17 00:00:00 2001 From: Alexander Gerasiov Date: Tue, 3 Jul 2018 14:27:12 +0300 Subject: [PATCH] console_linux: Fix race: lock Cond before Signal. Possible race: Thread1: Thread2: line 178: Read() -> EAGAIN ... line 110: EpollWait() ... line 124: signalRead() ... ... line 191: Wait() ... line 110: EpollWait() Thread2 (epoll) sends signalRead() (via sync.Cond) but Thread1 is not waiting yet. Then it starts to wait, but no more signals will arrive (because Thread2 is sleeping in EpollWait() on edge-triggered epoll. To prevent this race one should held Lock when sending signalRead(). The same situation goes with Write loop. Bug was reported to docker: https://github.com/docker/for-linux/issues/353 Signed-off-by: Alexander Gerasiov --- console_linux.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/console_linux.go b/console_linux.go index efefcb1..42274e1 100644 --- a/console_linux.go +++ b/console_linux.go @@ -262,10 +262,14 @@ func (ec *EpollConsole) Shutdown(close func(int) error) error { // signalRead signals that the console is readable. func (ec *EpollConsole) signalRead() { + ec.readc.L.Lock() ec.readc.Signal() + ec.readc.L.Unlock() } // signalWrite signals that the console is writable. func (ec *EpollConsole) signalWrite() { + ec.writec.L.Lock() ec.writec.Signal() + ec.writec.L.Unlock() }