Skip to content

Commit

Permalink
Fix multiple open monitors and install default html in cmake
Browse files Browse the repository at this point in the history
Signed-off-by: Mark Burton <mburton@quicinc.com>
  • Loading branch information
markfoodyburton committed Oct 25, 2024
1 parent bec1a33 commit ca5923a
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 66 deletions.
36 changes: 23 additions & 13 deletions qemu-components/qmp/include/qmp.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@ class qmp : public sc_core::sc_module

public:
cci::cci_param<std::string> p_qmp_str;
cci::cci_param<bool> p_monitor;

qmp(const sc_core::sc_module_name& name, sc_core::sc_object* o): qmp(name, *(dynamic_cast<QemuInstance*>(o))) {}
qmp(const sc_core::sc_module_name& n, QemuInstance& inst)
: sc_core::sc_module(n)
, p_qmp_str("qmp_str", "", "qmp options string, i.e. unix:./qmp-sock,server,wait=off")
, qmp_socket("qmp_socket")
, p_monitor("monitor", true, "use the HMP monitor (true, default) - or QMP (false) ")
{
SCP_TRACE(())("qmp constructor");
if (p_qmp_str.get_value().empty()) {
Expand All @@ -51,7 +53,11 @@ class qmp : public sc_core::sc_module
// unlink(socket_path.c_str());
}
// https://qemu-project.gitlab.io/qemu/interop/qemu-qmp-ref.html
inst.add_arg("-qmp");
if (p_monitor) {
inst.add_arg("-monitor");
} else {
inst.add_arg("-qmp");
}
inst.add_arg(p_qmp_str.get_value().c_str());

qmp_socket.register_b_transport(this, &qmp::b_transport);
Expand All @@ -67,17 +73,19 @@ class qmp : public sc_core::sc_module
* is, otherwise wrap it as a human monitor command */
buffer = buffer + std::string(data, length);
if (data[length - 1] == '\n' || data[length - 1] == '\r') {
buffer.erase(std::remove_if(buffer.begin(), buffer.end(), [](char c) { return c == '\r' || c == '\n'; }),
buffer.end());
std::string msg;
if (buffer[0] != '{') {
msg = R"("{ "execute": "human-monitor-command", "arguments": { "command-line": ")" + buffer +
R"(" } }")";
} else {
msg = buffer;
if (!p_monitor) {
buffer.erase(
std::remove_if(buffer.begin(), buffer.end(), [](char c) { return c == '\r' || c == '\n'; }),
buffer.end());
if (buffer[0] != '{') {
SCP_WARN(())
("Wrapping raw HMP command {} on QMP interface, consider selecting monitor mode", buffer);
buffer = R"("{ "execute": "human-monitor-command", "arguments": { "command-line": ")" + buffer +
R"(" } }")";
}
}
if (m_sockfd > 0) {
send(m_sockfd, msg.c_str(), msg.length(), 0);
send(m_sockfd, buffer.c_str(), buffer.length(), 0);
}
buffer = "";
}
Expand Down Expand Up @@ -128,9 +136,11 @@ class qmp : public sc_core::sc_module
SCP_ERR(())("Unable to connect to QMP socket");
}

std::string msg = R"({ "execute": "qmp_capabilities", "arguments": { "enable": ["oob"] } })";
if (write(m_sockfd, msg.c_str(), msg.size()) == -1) {
SCP_ERR(())("Can't send initialization command");
if (!p_monitor) {
std::string msg = R"({ "execute": "qmp_capabilities", "arguments": { "enable": ["oob"] } })";
if (write(m_sockfd, msg.c_str(), msg.size()) == -1) {
SCP_ERR(())("Can't send initialization command");
}
}
}
};
Expand Down
1 change: 0 additions & 1 deletion systemc-components/common/include/qkmultithread.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ class tlm_quantumkeeper_multithread : public gs::tlm_quantumkeeper_extended

// only NONE, RUNNING and STOPPED will be used by the model, the rest are for debug
enum jobstates { NONE = 0, RUNNING = 1, STOPPED = 2, SYSC_WAITING = 4, EXT_WAITING = 8, ILLEGAL = 12 } status;

// MAKE THIS INTO A CCI_PARAM, and provide to_json in the 'normal' way !!!!!

// this function provided only for debug.
Expand Down
6 changes: 6 additions & 0 deletions systemc-components/monitor/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
gs_create_dymod(monitor)

add_custom_command(TARGET monitor POST_BUILD
COMMAND ${CMAKE_COMMAND} -E create_symlink
${CMAKE_CURRENT_SOURCE_DIR}/static/monitor.html $<TARGET_FILE_DIR:monitor>/monitor.html)

install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/static/monitor.html DESTINATION bin)
30 changes: 21 additions & 9 deletions systemc-components/monitor/include/monitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <ports/biflow-socket.h>

#define MAX_ASIO_BUF_LEN (1024ULL * 16ULL)
#define MAX_BUFFER 1000

namespace gs {

Expand All @@ -47,11 +48,11 @@ class monitor : public sc_core::sc_module

class biflow_ws
{
public:
crow::websocket::connection* m_conn=nullptr;
public:
std::vector<crow::websocket::connection*> m_conns;
biflow_socket<biflow_ws> socket;
std::string buffer;
const char *name;
const char* name;

public:
void bind(biflow_bindable& other)
Expand All @@ -66,9 +67,9 @@ class monitor : public sc_core::sc_module
char* ptr = (char*)txn.get_data_ptr();
std::string data(ptr, txn.get_data_length());
buffer = (buffer + data);
if (buffer.size()>1000) buffer=buffer.substr(buffer.size()-1000);
if (m_conn) {
m_conn->send_text(data);
if (buffer.size() > MAX_BUFFER) buffer = buffer.substr(buffer.size() - MAX_BUFFER);
for (auto conn : m_conns) {
conn->send_text(data);
}
}
void enqueue(std::string data)
Expand All @@ -77,13 +78,24 @@ class monitor : public sc_core::sc_module
socket.enqueue(c);
}
}
biflow_ws(gs::biflow_multibindable& o, const char *n): socket(sc_core::sc_gen_unique_name("monitor_biflow_backend")), name(n)
biflow_ws(gs::biflow_multibindable& o, const char* n)
: socket(sc_core::sc_gen_unique_name("monitor_biflow_backend")), name(n)
{
socket.register_b_transport(this, &biflow_ws::b_transport);
bind(o);
}
void set_conn(crow::websocket::connection* c) { m_conn = c; m_conn->send_text(buffer);}
void clear_conn(){m_conn=nullptr;}
void set_conn(crow::websocket::connection* c)
{
m_conns.push_back(c);
c->send_text(buffer);
}
void clear_conn(crow::websocket::connection* c)
{
auto i = std::find(m_conns.begin(), m_conns.end(), c);
if (i != m_conns.end()) {
m_conns.erase(i);
}
}
};
std::map<std::string, std::unique_ptr<biflow_ws>> biflows;

Expand Down
49 changes: 44 additions & 5 deletions systemc-components/monitor/src/monitor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,29 @@ platform["monitor_0"] = {
*/

#include <monitor.h>
#include "monitor.h"
#include <module_factory_registery.h>
#include <vector>
#include <functional>
#include <exception>
#include <cciutils.h>
#include <algorithm>

/*
* pre declaration for getexepath
* NB this has to be done like this because of a nasty conflicting #def in libgen.h
*/
std::string getexepath();

namespace gs {

template <unsigned int BUSWIDTH>
monitor<BUSWIDTH>::monitor(const sc_core::sc_module_name& nm)
: sc_core::sc_module(nm)
, p_server_port("server_port", 18080, "monitor server port number")
, p_html_doc_template_dir_path("html_doc_template_dir_path", "",
, p_html_doc_template_dir_path("html_doc_template_dir_path", getexepath(),
"path to a template directory where HTML document to call the REST API exist")
, p_html_doc_name("html_doc_name", "", "name of a HTML document to call the REST API")
, p_html_doc_name("html_doc_name", "monitor.html", "name of a HTML document to call the REST API")
, p_use_html_presentation("use_html_presentation", true, "use HTML document to present the REST API")
{
SCP_DEBUG(()) << "monitor constructor";
Expand Down Expand Up @@ -331,11 +337,11 @@ void monitor<BUSWIDTH>::init_monitor()
})
.onclose([&](crow::websocket::connection& conn, const std::string& reason) {
auto b = (static_cast<std::unique_ptr<biflow_ws>*>(conn.userdata()));
(*b)->clear_conn();
(*b)->clear_conn(&conn);
})
.onerror([&](crow::websocket::connection& conn, const std::string& reason) {
auto b = (static_cast<std::unique_ptr<biflow_ws>*>(conn.userdata()));
(*b)->clear_conn();
(*b)->clear_conn(&conn);
});
m_app_future = m_app.loglevel(crow::LogLevel::Error).port(p_server_port.get_value()).multithreaded().run_async();
}
Expand Down Expand Up @@ -375,4 +381,37 @@ template class monitor<64>;
} // namespace gs
typedef gs::monitor<32> monitor;

/* Helper function to get the executable path
* This needs to be at the end of this file, to prevent conflicts with 'basename' which seems to be
* defined in libgen.h
*/
#include <unistd.h>
#include <libgen.h>
#if defined(__APPLE__)
#include <mach-o/dyld.h>
#endif

std::string getexepath()
{
char result[1024] = { 0 };
#ifdef __APPLE__
uint32_t size = sizeof(result);
if (_NSGetExecutablePath(result, &size) != 0) {
std::cerr << "error executing _NSGetExecutablePath() in python-binder-bench.h" << std::endl;
exit(EXIT_FAILURE);
}
return std::string(dirname(result));
#elif __linux__
ssize_t count = readlink("/proc/self/exe", result, 1024);
if (count < 0) {
std::cerr << "error executing readlink() in python-binder-bench.h: " << strerror(errno) << std::endl;
exit(EXIT_FAILURE);
}
return std::string(dirname(result), count);

#else
#error monitor supports only Mac OS and linux for now!
#endif
}

void module_register() { GSC_MODULE_REGISTER_C(monitor); }
85 changes: 47 additions & 38 deletions systemc-components/monitor/static/monitor.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@

<head>
<title>Monitor</title>

<script src="https://cdn.jsdelivr.net/npm/@xterm/xterm@5.5.0/lib/xterm.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@xterm/xterm@5.5.0/css/xterm.min.css">
<script src="https://cdn.jsdelivr.net/npm/@xterm/addon-fit@0.10.0/lib/addon-fit.min.js"></script>

</head>

Expand All @@ -18,10 +20,9 @@
<select id="biflowsDropdown">
<option value="" disabled selected>Select a biflow</option>
</select>
<textarea id="wslog" cols=100 rows=50>
</textarea>
<a href="https://qemu-project.gitlab.io/qemu/interop/qemu-qmp-ref.html">for QEMU QMP, see Reference Manual</a>


<div id="terminal" style="min-width:400px; width: 80% ; height:400px;"></div>

<br>
<br>
<h3>QK Status</h3>
Expand Down Expand Up @@ -70,31 +71,42 @@ <h3>Registers</h3>

<script>

var sock;
var savedtext = "";
var term;

var term = new window.Terminal({
cursorBlink: false,
cursorInactiveStyle: "outline"
});
term.open(document.getElementById('terminal'));
term.onData((data) => { sock.send(data) });
var fitAddon = new FitAddon.FitAddon();
term.loadAddon(fitAddon);

function populateBiFlows(data) {
const dropdown = document.getElementById('biflowsDropdown');
const dropdown = document.getElementById('biflowsDropdown');

data.biflows.forEach(biflow => {
const option = document.createElement('option');
option.value = biflow;
option.textContent = biflow;
dropdown.appendChild(option);
});
data.biflows.forEach(biflow => {
const option = document.createElement('option');
option.value = biflow;
option.textContent = biflow;
dropdown.appendChild(option);
});

// Set up WebSocket connection when a biflow is selected
dropdown.addEventListener('change', function () {
const selectedBiflow = this.value;
if (selectedBiflow) {
openWebSocket(selectedBiflow);
}
});
// Set up WebSocket connection when a biflow is selected
dropdown.addEventListener('change', function () {
const selectedBiflow = this.value;
if (sock) sock.close();
if (selectedBiflow) {
term.reset();
openWebSocket(selectedBiflow);
fitAddon.fit();
}
});
}
var sock;
var savedtext = "";

function openWebSocket(biflowName) {
savedtext = "";
var t = document.getElementById('wslog');
t.value = "";

sock = new WebSocket("ws://" + location.host + "/biflow/" + biflowName);
sock.onopen = () => {
Expand All @@ -105,21 +117,10 @@ <h3>Registers</h3>
}
sock.onclose = (e) => {
console.log('close websocket', e)
savedtext = "";
var t = document.getElementById('wslog');
t.value = "";
}
sock.onmessage = (e) => {
var t = document.getElementById('wslog');
t.value = t.value + e.data;//+"\n";
savedtext = t.value;
t.scrollTop = t.scrollHeight;
term.write(e.data);
}
document.getElementById('wslog').addEventListener('input', function () {
var t = event.target;
sock.send(t.value.substring(savedtext.length));
t.value = savedtext; // drop the new chars, to prevent echo.
}, false);
}

document.getElementById('reset').onclick = () => {
Expand All @@ -140,8 +141,6 @@ <h3>Registers</h3>
} catch (error) {
const statusElement = document.getElementById('sc_time');
statusElement.textContent = "Not connected";
//console.error('Error fetching flag:', error);
// document.getElementById('status').textContent = 'Error fetching data';
}
}

Expand Down Expand Up @@ -387,6 +386,16 @@ <h3>Registers</h3>

// Fetch top-level objects on page load
window.onload = fetchObjects;

window.addEventListener('resize', () => {
console.log("Here");

const container = document.getElementById('terminal');
console.log('Container dimensions:', container.clientWidth, container.clientHeight);
console.log('Terminal rows:', term.rows, 'columns:', term.cols);
fitAddon.fit();
term.refresh(0, -term.rows - 1);
});
</script>

</body>
Expand Down

0 comments on commit ca5923a

Please sign in to comment.