Fix deadlock when stopping execution while trapping for I/O
Before, when trapping for I/O (reading stdin), if the user selected
to stop running the program, a deadlock would occur.
With this commit, the wait condition on the stdin stream has been
modified to also accept a timeout + abort flag.
MODIFY
src/processorhandler.cpp
src/processorhandler.cpp
@@ -209,10 +209,14 @@ void ProcessorHandler::checkProcessorFinished() {
}
void ProcessorHandler::stop() {
- if (m_runWatcher.isRunning())
+ if (m_runWatcher.isRunning()) {
m_stopRunningFlag = true;
+ // We might be currently trapping for user I/O. Signal to abort the trap, in this avoiding a deadlock.
+ SystemIO::abortSyscall(true);
+ }
m_runWatcher.waitForFinished();
m_stopRunningFlag = false;
+ SystemIO::abortSyscall(false);
}
bool ProcessorHandler::isExecutableAddress(uint32_t address) const {

MODIFY
src/syscall/file.h
src/syscall/file.h
@@ -83,13 +83,15 @@ public:
int retLength = SystemIO::readFromFile(fd, buffer, length);
BaseSyscall::setRet(0, retLength);
+ if (retLength != -1) {
// copy bytes from returned buffer into memory
- const char* dataptr = buffer.constData(); // QString::data contains a possible null termination '\0' character
- // (present if reading from stdin and not from a file)
+ const char* dataptr = buffer.constData(); // QString::data contains a possible null termination '\0'
+ // character (present if reading from stdin and not from a file)
while (retLength-- > 0) {
ProcessorHandler::get()->writeMem(byteAddress++, *dataptr++, sizeof(char));
}
}
+ }
};
template <typename BaseSyscall>

MODIFY
src/syscall/systemio.cpp
src/syscall/systemio.cpp
@@ -10,4 +10,5 @@ std::map<int, QFile> SystemIO::FileIOData::files;
QByteArray SystemIO::FileIOData::s_stdinBuffer;
QMutex SystemIO::FileIOData::s_stdioMutex;
QWaitCondition SystemIO::FileIOData::s_stdinBufferEmpty;
+bool SystemIO::s_abortSyscall = false;
} // namespace Ripes

MODIFY
src/syscall/systemio.h
src/syscall/systemio.h
@@ -61,6 +61,9 @@ private:
// String used for description of file error
static QString s_fileErrorString; // = ("File operation OK");
+ // Flag used for aborting waiting for I/O
+ static bool s_abortSyscall;
+
// Standard I/O Channels
enum STDIO { STDIN = 0, STDOUT = 1, STDERR = 2, STDIO_END };
@@ -325,11 +328,19 @@ public:
while (myBuffer.size() == 0) {
// Lock the stdio objects and try to read from stdio. If no data is present, wait until so.
FileIOData::s_stdioMutex.lock();
- myBuffer = InputStream.read(lengthRequested).toUtf8();
- if (myBuffer.size() == 0) {
- FileIOData::s_stdinBufferEmpty.wait(&FileIOData::s_stdioMutex);
+ while (myBuffer.size() == 0) {
+ /** We spin on a wait condition with a timeout. The timeout is required to ensure that we may
+ * observe any abort flags (ie. if execution is stopped while waiting for IO */
+ const bool dataInStdinStrm = FileIOData::s_stdinBufferEmpty.wait(&FileIOData::s_stdioMutex, 100);
+ if (s_abortSyscall) {
+ FileIOData::s_stdioMutex.unlock();
+ s_abortSyscall = false;
+ return -1;
}
+ if (dataInStdinStrm) {
myBuffer = InputStream.read(lengthRequested).toUtf8();
+ }
+ }
FileIOData::s_stdioMutex.unlock();
}
} else {
@@ -389,6 +400,7 @@ public:
static void printString(const QString& string) { emit get().doPrint(string); }
static void reset() { FileIOData::resetFiles(); }
+ static void abortSyscall(bool state) { s_abortSyscall = state; }
signals:
void doPrint(const QString&);

Fix deadlock when stopping execution while trapping for I/O

Before, when trapping for I/O (reading stdin), if the user selected
to stop running the program, a deadlock would occur.
With this commit, the wait condition on the stdin stream has been
modified to also accept a timeout + abort flag.