Giacomo Travaglini has uploaded this change for review. (
https://gem5-review.googlesource.com/c/public/gem5/+/43164 )
Change subject: dev: Factor functionalities out of the Terminal device
......................................................................
dev: Factor functionalities out of the Terminal device
The Terminal device is implementing some useful functionalities
we could use for other purposes.
It is mainly a serial device with circular buffers and a listening
socket. With this patch I am moving the circular buffers and IPC logic
(socket listener) out of the class into a new CircularPipe object;
decoupling the simulated object (a serial device) to its communication
mechanism.
We could reuse this newly created class to establish buffered
communications from everywhere in gem5
Change-Id: I1ede897568a8292f485404fc014defe28ce12deb
Signed-off-by: Giacomo Travaglini <[email protected]>
---
M src/base/SConscript
A src/base/circular_pipe.cc
A src/base/circular_pipe.hh
M src/dev/serial/terminal.cc
M src/dev/serial/terminal.hh
5 files changed, 387 insertions(+), 248 deletions(-)
diff --git a/src/base/SConscript b/src/base/SConscript
index 1190b93..e2a5c3e 100644
--- a/src/base/SConscript
+++ b/src/base/SConscript
@@ -37,6 +37,7 @@
Source('imgwriter.cc')
Source('bmpwriter.cc')
Source('channel_addr.cc')
+Source('circular_pipe.cc')
Source('cprintf.cc', add_tags='gtest lib')
GTest('cprintf.test', 'cprintf.test.cc')
Executable('cprintftime', 'cprintftime.cc', 'cprintf.cc')
diff --git a/src/base/circular_pipe.cc b/src/base/circular_pipe.cc
new file mode 100644
index 0000000..ddceb12
--- /dev/null
+++ b/src/base/circular_pipe.cc
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2019, 2021 Arm Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "base/circular_pipe.hh"
+
+#include "base/atomicio.hh"
+#include "base/trace.hh"
+#include "sim/eventq.hh"
+
+/*
+ * Poll event for the listen socket
+ */
+CircularPipe::ListenEvent::ListenEvent(CircularPipe *l, int fd, int e)
+ : PollEvent(fd, e), pipe(l)
+{
+}
+
+void
+CircularPipe::ListenEvent::process(int revent)
+{
+ pipe->accept();
+}
+
+/*
+ * Poll event for the data socket
+ */
+CircularPipe::DataEvent::DataEvent(CircularPipe *l, int fd, int e)
+ : PollEvent(fd, e), pipe(l)
+{
+}
+
+void
+CircularPipe::DataEvent::process(int revent)
+{
+ // As a consequence of being called from the PollQueue, we might
+ // have been called from a different thread. Migrate to "our"
+ // thread.
+ EventQueue::ScopedMigration migrate(pipe->evQueue);
+
+ if (revent & POLLIN)
+ pipe->data();
+ else if (revent & POLLNVAL)
+ pipe->detach();
+}
+
+/*
+ * Terminal code
+ */
+CircularPipe::CircularPipe(int port, EventQueue *eq, const std::string
&_name,
+ ssize_t tx_size, ssize_t rx_size)
+ : listenEvent(NULL), dataEvent(NULL), evQueue(eq),
+ number(port), data_fd(-1), pipeName(_name),
+ txbuf(tx_size), rxbuf(rx_size)
+#if TRACING_ON == 1
+ , linebuf(16384)
+#endif
+{
+ if (port)
+ listen(port);
+}
+
+CircularPipe::~CircularPipe()
+{
+ if (data_fd != -1)
+ ::close(data_fd);
+
+ if (listenEvent)
+ delete listenEvent;
+
+ if (dataEvent)
+ delete dataEvent;
+}
+
+void
+CircularPipe::listen(int port)
+{
+ if (ListenSocket::allDisabled()) {
+ warn_once("Sockets disabled, not accepting %s connections",
pipeName);
+ return;
+ }
+
+ while (!listener.listen(port, true)) {
+ port++;
+ }
+
+ ccprintf(std::cerr, "%s: Listening for connections on port %d\n",
+ pipeName, port);
+
+ listenEvent = new ListenEvent(this, listener.getfd(), POLLIN);
+ pollQueue.schedule(listenEvent);
+}
+
+void
+CircularPipe::accept()
+{
+ if (!listener.islistening())
+ panic("%s: cannot accept a connection if not listening!",
pipeName);
+
+ int fd = listener.accept(true);
+ if (data_fd != -1) {
+ char message[] = "terminal already attached!\n";
+ atomic_write(fd, message, sizeof(message));
+ ::close(fd);
+ return;
+ }
+
+ data_fd = fd;
+ dataEvent = new DataEvent(this, data_fd, POLLIN);
+ pollQueue.schedule(dataEvent);
+
+ std::stringstream stream;
+ ccprintf(stream, "==== m5 terminal: %s %d ====", pipeName, number);
+
+ // we need an actual carriage return followed by a newline for the
+ // terminal
+ stream << "\r\n";
+
+ write((const uint8_t *)stream.str().c_str(), stream.str().size());
+
+ DPRINTFN("attach %s %d\n", pipeName, number);
+ char buf[1024];
+ for (size_t i = 0; i < txbuf.size(); i += sizeof(buf)) {
+ const size_t chunk_len(std::min(txbuf.size() - i, sizeof(buf)));
+ txbuf.peek(buf, i, chunk_len);
+ write((const uint8_t *)buf, chunk_len);
+ }
+}
+
+void
+CircularPipe::detach()
+{
+ if (data_fd != -1) {
+ ::close(data_fd);
+ data_fd = -1;
+ }
+
+ pollQueue.remove(dataEvent);
+ delete dataEvent;
+ dataEvent = NULL;
+
+ DPRINTFN("detach %s %d\n", pipeName, number);
+}
+
+void
+CircularPipe::data()
+{
+ uint8_t buf[1024];
+ int len;
+
+ len = read(buf, sizeof(buf));
+ if (len) {
+ rxbuf.write((char *)buf, len);
+ notifyRx();
+ }
+}
+
+size_t
+CircularPipe::read(uint8_t *buf, size_t len)
+{
+ if (data_fd < 0)
+ panic("%s not properly attached.\n", pipeName);
+
+ ssize_t ret;
+ do {
+ ret = ::read(data_fd, buf, len);
+ } while (ret == -1 && errno == EINTR);
+
+
+ if (ret < 0)
+ DPRINTFN("Read failed.\n");
+
+ if (ret <= 0) {
+ detach();
+ return 0;
+ }
+
+ return ret;
+}
+
+// Terminal output.
+size_t
+CircularPipe::write(const uint8_t *buf, size_t len)
+{
+ if (data_fd < 0)
+ panic("%s not properly attached.\n", pipeName);
+
+ ssize_t ret = atomic_write(data_fd, buf, len);
+ if (ret < len)
+ detach();
+
+ return ret;
+}
+
+void
+CircularPipe::sendChar(uint8_t c)
+{
+ txbuf.write(&c, 1);
+
+ if (data_fd >= 0)
+ write(c);
+}
+
+std::string
+CircularPipe::txDump()
+{
+ const ssize_t size = txbuf.size();
+ std::unique_ptr<char[]> buf(new char[size]);
+
+ txbuf.peek(buf.get(), 0, size);
+
+ return std::string(buf.get(), size);
+}
diff --git a/src/base/circular_pipe.hh b/src/base/circular_pipe.hh
new file mode 100644
index 0000000..f02f261
--- /dev/null
+++ b/src/base/circular_pipe.hh
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2019, 2021 Arm Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DEV_CIRCULAR_PIPE_HH__
+#define __DEV_CIRCULAR_PIPE_HH__
+
+#include <iostream>
+
+#include "base/callback.hh"
+#include "base/circlebuf.hh"
+#include "base/pollevent.hh"
+#include "base/socket.hh"
+
+class EventQueue;
+
+class CircularPipe
+{
+ protected:
+ class ListenEvent : public PollEvent
+ {
+ protected:
+ CircularPipe *pipe;
+
+ public:
+ ListenEvent(CircularPipe *t, int fd, int e);
+ void process(int revent);
+ };
+
+ friend class ListenEvent;
+ ListenEvent *listenEvent;
+
+ class DataEvent : public PollEvent
+ {
+ protected:
+ CircularPipe *pipe;
+
+ public:
+ DataEvent(CircularPipe *t, int fd, int e);
+ void process(int revent);
+ };
+
+ friend class DataEvent;
+ DataEvent *dataEvent;
+ EventQueue *evQueue;
+
+ protected:
+ int number;
+ int data_fd;
+ const std::string pipeName;
+
+ public:
+ CircularPipe(int port, EventQueue *eq, const std::string &name,
+ ssize_t tx_size=16384, ssize_t rx_size=16384);
+ ~CircularPipe();
+
+ protected:
+ ListenSocket listener;
+
+ void listen(int port);
+ void accept();
+
+ protected:
+ virtual void notifyRx() {}
+
+ CircleBuf<char> txbuf;
+ CircleBuf<char> rxbuf;
+#if TRACING_ON == 1
+ CircleBuf<char> linebuf;
+#endif
+
+ public:
+ void data();
+ void read(uint8_t &c) { read(&c, 1); }
+ size_t read(uint8_t *buf, size_t len);
+ void write(uint8_t c) { write(&c, 1); }
+ size_t write(const uint8_t *buf, size_t len);
+ void detach();
+
+ void sendChar(uint8_t c);
+ std::string txDump();
+};
+
+#endif // __DEV_CIRCULAR_PIPE_HH__
diff --git a/src/dev/serial/terminal.cc b/src/dev/serial/terminal.cc
index d85cf1f..570a173 100644
--- a/src/dev/serial/terminal.cc
+++ b/src/dev/serial/terminal.cc
@@ -63,7 +63,6 @@
#include <sstream>
#include <string>
-#include "base/atomicio.hh"
#include "base/logging.hh"
#include "base/output.hh"
#include "base/socket.hh"
@@ -74,69 +73,14 @@
#include "dev/serial/uart.hh"
/*
- * Poll event for the listen socket
- */
-Terminal::ListenEvent::ListenEvent(Terminal *t, int fd, int e)
- : PollEvent(fd, e), term(t)
-{
-}
-
-void
-Terminal::ListenEvent::process(int revent)
-{
- term->accept();
-}
-
-/*
- * Poll event for the data socket
- */
-Terminal::DataEvent::DataEvent(Terminal *t, int fd, int e)
- : PollEvent(fd, e), term(t)
-{
-}
-
-void
-Terminal::DataEvent::process(int revent)
-{
- // As a consequence of being called from the PollQueue, we might
- // have been called from a different thread. Migrate to "our"
- // thread.
- EventQueue::ScopedMigration migrate(term->eventQueue());
-
- if (revent & POLLIN)
- term->data();
- else if (revent & POLLNVAL)
- term->detach();
-}
-
-/*
* Terminal code
*/
Terminal::Terminal(const Params &p)
- : SerialDevice(p), listenEvent(NULL), dataEvent(NULL),
- number(p.number), data_fd(-1), txbuf(16384), rxbuf(16384),
+ : SerialDevice(p), CircularPipe(p.port, eventQueue(), name()),
outfile(terminalDump(p))
-#if TRACING_ON == 1
- , linebuf(16384)
-#endif
{
if (outfile)
outfile->stream()->setf(std::ios::unitbuf);
-
- if (p.port)
- listen(p.port);
-}
-
-Terminal::~Terminal()
-{
- if (data_fd != -1)
- ::close(data_fd);
-
- if (listenEvent)
- delete listenEvent;
-
- if (dataEvent)
- delete dataEvent;
}
OutputStream *
@@ -156,133 +100,6 @@
}
}
-///////////////////////////////////////////////////////////////////////
-// socket creation and terminal attach
-//
-
-void
-Terminal::listen(int port)
-{
- if (ListenSocket::allDisabled()) {
- warn_once("Sockets disabled, not accepting terminal connections");
- return;
- }
-
- while (!listener.listen(port, true)) {
- DPRINTF(Terminal,
- ": can't bind address terminal port %d inuse PID %d\n",
- port, getpid());
- port++;
- }
-
- ccprintf(std::cerr, "%s: Listening for connections on port %d\n",
- name(), port);
-
- listenEvent = new ListenEvent(this, listener.getfd(), POLLIN);
- pollQueue.schedule(listenEvent);
-}
-
-void
-Terminal::accept()
-{
- if (!listener.islistening())
- panic("%s: cannot accept a connection if not listening!", name());
-
- int fd = listener.accept(true);
- if (data_fd != -1) {
- char message[] = "terminal already attached!\n";
- atomic_write(fd, message, sizeof(message));
- ::close(fd);
- return;
- }
-
- data_fd = fd;
- dataEvent = new DataEvent(this, data_fd, POLLIN);
- pollQueue.schedule(dataEvent);
-
- std::stringstream stream;
- ccprintf(stream, "==== m5 terminal: Terminal %d ====", number);
-
- // we need an actual carriage return followed by a newline for the
- // terminal
- stream << "\r\n";
-
- write((const uint8_t *)stream.str().c_str(), stream.str().size());
-
- DPRINTFN("attach terminal %d\n", number);
- char buf[1024];
- for (size_t i = 0; i < txbuf.size(); i += sizeof(buf)) {
- const size_t chunk_len(std::min(txbuf.size() - i, sizeof(buf)));
- txbuf.peek(buf, i, chunk_len);
- write((const uint8_t *)buf, chunk_len);
- }
-}
-
-void
-Terminal::detach()
-{
- if (data_fd != -1) {
- ::close(data_fd);
- data_fd = -1;
- }
-
- pollQueue.remove(dataEvent);
- delete dataEvent;
- dataEvent = NULL;
-
- DPRINTFN("detach terminal %d\n", number);
-}
-
-void
-Terminal::data()
-{
- uint8_t buf[1024];
- int len;
-
- len = read(buf, sizeof(buf));
- if (len) {
- rxbuf.write((char *)buf, len);
- notifyInterface();
- }
-}
-
-size_t
-Terminal::read(uint8_t *buf, size_t len)
-{
- if (data_fd < 0)
- panic("Terminal not properly attached.\n");
-
- ssize_t ret;
- do {
- ret = ::read(data_fd, buf, len);
- } while (ret == -1 && errno == EINTR);
-
-
- if (ret < 0)
- DPRINTFN("Read failed.\n");
-
- if (ret <= 0) {
- detach();
- return 0;
- }
-
- return ret;
-}
-
-// Terminal output.
-size_t
-Terminal::write(const uint8_t *buf, size_t len)
-{
- if (data_fd < 0)
- panic("Terminal not properly attached.\n");
-
- ssize_t ret = atomic_write(data_fd, buf, len);
- if (ret < len)
- detach();
-
- return ret;
-}
-
uint8_t
Terminal::readData()
{
@@ -321,10 +138,7 @@
}
#endif
- txbuf.write(&c, 1);
-
- if (data_fd >= 0)
- write(c);
+ sendChar(c);
if (outfile)
outfile->stream()->put((char)c);
@@ -333,3 +147,9 @@
isprint(c) ? c : ' ', (int)c);
}
+
+void
+Terminal::notifyRx()
+{
+ notifyInterface();
+}
diff --git a/src/dev/serial/terminal.hh b/src/dev/serial/terminal.hh
index 31c8ed9..9b9b8d8 100644
--- a/src/dev/serial/terminal.hh
+++ b/src/dev/serial/terminal.hh
@@ -49,6 +49,7 @@
#include "base/callback.hh"
#include "base/circlebuf.hh"
+#include "base/circular_pipe.hh"
#include "base/pollevent.hh"
#include "base/socket.hh"
#include "dev/serial/serial.hh"
@@ -58,75 +59,23 @@
class OutputStream;
class TerminalListener;
-class Terminal : public SerialDevice
+class Terminal : public SerialDevice, public CircularPipe
{
- protected:
- class ListenEvent : public PollEvent
- {
- protected:
- Terminal *term;
-
- public:
- ListenEvent(Terminal *t, int fd, int e);
- void process(int revent);
- };
-
- friend class ListenEvent;
- ListenEvent *listenEvent;
-
- class DataEvent : public PollEvent
- {
- protected:
- Terminal *term;
-
- public:
- DataEvent(Terminal *t, int fd, int e);
- void process(int revent);
- };
-
- friend class DataEvent;
- DataEvent *dataEvent;
-
- protected:
- int number;
- int data_fd;
-
public:
typedef TerminalParams Params;
Terminal(const Params &p);
- ~Terminal();
OutputStream * terminalDump(const TerminalParams &p);
- protected:
- ListenSocket listener;
-
- void listen(int port);
- void accept();
-
- protected:
- CircleBuf<char> txbuf;
- CircleBuf<char> rxbuf;
- OutputStream *outfile;
-#if TRACING_ON == 1
- CircleBuf<char> linebuf;
-#endif
-
- public:
- ///////////////////////
- // Terminal Interface
-
- void data();
-
- void read(uint8_t &c) { read(&c, 1); }
- size_t read(uint8_t *buf, size_t len);
- void write(uint8_t c) { write(&c, 1); }
- size_t write(const uint8_t *buf, size_t len);
- void detach();
-
- public: // SerialDevice interface
+ // Serial Device interface
uint8_t readData() override;
void writeData(uint8_t c) override;
bool dataAvailable() const override { return !rxbuf.empty(); }
+
+ // CircularPipe interface
+ void notifyRx() override;
+
+ protected:
+ OutputStream *outfile;
};
#endif // __DEV_TERMINAL_HH__
--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/43164
To unsubscribe, or for help writing mail filters, visit
https://gem5-review.googlesource.com/settings
Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: I1ede897568a8292f485404fc014defe28ce12deb
Gerrit-Change-Number: 43164
Gerrit-PatchSet: 1
Gerrit-Owner: Giacomo Travaglini <[email protected]>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list -- [email protected]
To unsubscribe send an email to [email protected]
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s