Index: test/tools/lldb-mi/TestMiExit.py =================================================================== --- test/tools/lldb-mi/TestMiExit.py +++ test/tools/lldb-mi/TestMiExit.py @@ -28,7 +28,6 @@ # Test -gdb-exit: try to exit and check that program is finished self.runCmd("-gdb-exit") - self.runCmd("") #FIXME hangs here on Linux; extra return is needed self.expect("\^exit") import pexpect self.expect(pexpect.EOF) Index: tools/lldb-mi/MICmnStreamStdinLinux.h =================================================================== --- tools/lldb-mi/MICmnStreamStdinLinux.h +++ tools/lldb-mi/MICmnStreamStdinLinux.h @@ -69,4 +69,5 @@ const MIuint m_constBufferSize; FILE *m_pStdin; MIchar *m_pCmdBuffer; + bool m_waitForInput; }; Index: tools/lldb-mi/MICmnStreamStdinLinux.cpp =================================================================== --- tools/lldb-mi/MICmnStreamStdinLinux.cpp +++ tools/lldb-mi/MICmnStreamStdinLinux.cpp @@ -20,10 +20,8 @@ //-- // Third Party Headers: -#if defined(__APPLE__) #include #include // For STDIN_FILENO -#endif // defined( __APPLE__ ) #include // For std::strerror() // In-house headers: @@ -43,6 +41,7 @@ : m_constBufferSize(1024) , m_pStdin(nullptr) , m_pCmdBuffer(nullptr) + , m_waitForInput(true) { } @@ -153,28 +152,43 @@ bool CMICmnStreamStdinLinux::InputAvailable(bool &vwbAvail) { -#if defined(__APPLE__) // The code below is needed on OSX where lldb-mi hangs when doing -exec-run. - // The hang seems to come from calling fgets and fileno from different thread. - // Although this problem was not observed on Linux. + // Similar behavior has been observed on other systems too. See + // http://llvm.org/bugs/show_bug.cgi?id=22411 // A solution based on 'ioctl' was initially committed but it seems to make // lldb-mi takes much more processor time. The solution based on 'select' works // well but it seems to slow the execution of lldb-mi tests a lot on Linux. - // As a result, this code is #defined to run only on OSX. + // The reason for delay was behavior of select in multithreaded app. + // The man pages for select suggest that closing a fd which is monitored + // by select from another thread has no effect. It effectively caused the + // application to block in select forever and test cases timed out. + // To fix this issue, I have introduced the a timeout using 5th arg of select. It + // gives us chance to see if other thread has asked us to stop waiting for + // input by setting m_waitForInput to false. fd_set setOfStdin; - FD_ZERO(&setOfStdin); - FD_SET(STDIN_FILENO, &setOfStdin); + struct timeval tv; - // Wait while input would be available - if (::select(STDIN_FILENO + 1, &setOfStdin, nullptr, nullptr, nullptr) == -1) + while (m_waitForInput) { - vwbAvail = false; - return MIstatus::failure; + FD_ZERO(&setOfStdin); + FD_SET(STDIN_FILENO, &setOfStdin); + tv.tv_sec = 1; + tv.tv_usec = 0; + int ret = ::select(STDIN_FILENO + 1, &setOfStdin, nullptr, nullptr, &tv); + if (ret == 0) // Timeout. Loop back if m_waitForInput is true + continue; + else if (ret == -1) // Error condition. Return + { + vwbAvail = false; + return MIstatus::failure; + } + else // Have some valid input + { + vwbAvail = true; + return MIstatus::success; + } } - -#endif // defined( __APPLE__ ) - vwbAvail = true; - return MIstatus::success; + return MIstatus::failure; } //++ ------------------------------------------------------------------------------------ @@ -221,5 +235,5 @@ void CMICmnStreamStdinLinux::InterruptReadLine(void) { - fclose(stdin); + m_waitForInput = false; }