SyscallManager may now be executed asynchronously
This is required for instance when reading from STDIO, but the stdio
buffer is empty. In this case, the system call handling must wait until
the user has typed something into the console - which has to be done
on the GUI thread.
MODIFY
src/processorhandler.cpp
src/processorhandler.cpp
@@ -195,18 +195,12 @@ QString ProcessorHandler::parseInstrAt(const uint32_t addr) const {
}
void ProcessorHandler::asyncTrap() {
- QMetaObject::invokeMethod(this, "handleTrap", Qt::AutoConnection);
- m_sem.acquire();
-}
-
-void ProcessorHandler::handleTrap() {
- // Trapping to the execution environment must be done in the GUI thread. If this is not the case, something has gone
- // horribly wrong!
- Q_ASSERT(QThread::currentThread() == this->thread());
-
+ QtConcurrent::run([=] {
const unsigned int function = m_currentProcessor->getRegister(currentISA()->syscallReg());
m_syscallManager->execute(function);
m_sem.release();
+ });
+ m_sem.acquire();
}
void ProcessorHandler::checkProcessorFinished() {

MODIFY
src/processorhandler.h
src/processorhandler.h
@@ -162,19 +162,11 @@ public slots:
private slots:
/**
* @brief asyncTrap
- * Connects to the processors system call request interface. Will emit a queued requestHandleTrap() request to
- * execute handleTrap(). This queued request facilitates control flow crossing from the simulator thread to the GUI
- * thread.
+ * Connects to the processors system call request interface. Will concurrently run the systemcall manager to handle
+ * the requested functionality, and return once the system call was handled.
*/
void asyncTrap();
- /**
- * @brief handleTrap
- * Will handle a queued request initialized from asyncTrap to perform whatever is required of the supporting
- * execution environment
- */
- void handleTrap();
-
private:
ProcessorHandler();

MODIFY
src/syscall/ripes_syscall.h
src/syscall/ripes_syscall.h
#pragma once
+#include <QAbstractEventDispatcher>
+#include <QApplication>
#include <QMessageBox>
#include <QString>
+#include <QThread>
+
#include <functional>
#include <map>
#include <memory>
@@ -51,6 +55,12 @@ protected:
const std::map<unsigned, QString> m_returnDescriptions;
};
+/**
+ * @brief The SyscallManager class
+ *
+ * It is expected that the syscallManager can be called outside of the main GUI thread. As such, all syscalls who
+ * require GUI interaction must handle this explicitely.
+ */
class SyscallManager {
public:
/**
@@ -59,9 +69,11 @@ public:
*/
void execute(int id) {
if (m_syscalls.count(id) == 0) {
+ postToGUIThread([=] {
QMessageBox::warning(nullptr, "Error",
"Unknown system call: " + QString::number(id) +
"\nRefer to \"Help->System calls\" for a list of support system calls.");
+ });
} else {
m_syscalls.at(id)->execute();
}
@@ -70,6 +82,18 @@ public:
const std::map<int, std::unique_ptr<Syscall>>& getSyscalls() const { return m_syscalls; }
protected:
+ /**
+ * @brief postToGUIThread
+ * Schedules the execution of @param fun in the GUI thread.
+ * @param connection type.
+ */
+ template <typename F>
+ static void postToGUIThread(F&& fun, Qt::ConnectionType type = Qt::BlockingQueuedConnection) {
+ auto* obj = QAbstractEventDispatcher::instance(qApp->thread());
+ Q_ASSERT(obj);
+ QMetaObject::invokeMethod(obj, std::forward<F>(fun), type);
+ }
+
SyscallManager() {}
std::map<int, std::unique_ptr<Syscall>> m_syscalls;
};

SyscallManager may now be executed asynchronously

This is required for instance when reading from STDIO, but the stdio
buffer is empty. In this case, the system call handling must wait until
the user has typed something into the console - which has to be done
on the GUI thread.