dev-arm: Move GICv3 (Re)Ditributor address in Realview.py
[gem5.git] / src / dev / net / ethertap.cc
index ca19b4884f1c4152c7ebbd63e3cbf2c19430a8c0..552296d5c89aebb1c7377e9e6c916d4b23ae43f3 100644 (file)
@@ -79,11 +79,20 @@ class TapEvent : public PollEvent
   public:
     TapEvent(EtherTapBase *_tap, int fd, int e)
         : PollEvent(fd, e), tap(_tap) {}
-    virtual void process(int revent) { tap->recvReal(revent); }
+
+    void
+    process(int revent) override
+    {
+        // Ensure that our event queue is active. It may not be since we get
+        // here from the PollQueue whenever a real packet happens to arrive.
+        EventQueue::ScopedMigration migrate(tap->eventQueue());
+
+        tap->recvReal(revent);
+    }
 };
 
 EtherTapBase::EtherTapBase(const Params *p)
-    : EtherObject(p), buflen(p->bufsz), dump(p->dump), event(NULL),
+    : SimObject(p), buflen(p->bufsz), dump(p->dump), event(NULL),
       interface(NULL),
       txEvent([this]{ retransmit(); }, "EtherTapBase retransmit")
 {
@@ -150,15 +159,12 @@ EtherTapBase::stopPolling()
 }
 
 
-EtherInt*
-EtherTapBase::getEthPort(const std::string &if_name, int idx)
+Port &
+EtherTapBase::getPort(const std::string &if_name, PortID idx)
 {
-    if (if_name == "tap") {
-        if (interface->getPeer())
-            panic("Interface already connected to\n");
-        return interface;
-    }
-    return NULL;
+    if (if_name == "tap")
+        return *interface;
+    return SimObject::getPort(if_name, idx);
 }
 
 bool
@@ -397,7 +403,7 @@ EtherTapStub::sendReal(const void *data, size_t len)
 
 EtherTap::EtherTap(const Params *p) : EtherTapBase(p)
 {
-    int fd = open(p->tun_clone_device.c_str(), O_RDWR);
+    int fd = open(p->tun_clone_device.c_str(), O_RDWR | O_NONBLOCK);
     if (fd < 0)
         panic("Couldn't open %s.\n", p->tun_clone_device);
 
@@ -429,18 +435,39 @@ EtherTap::recvReal(int revent)
     if (!(revent & POLLIN))
         return;
 
-    ssize_t ret = read(tap, buffer, buflen);
-    if (ret < 0)
-        panic("Failed to read from tap device.\n");
+    ssize_t ret;
+    while ((ret = read(tap, buffer, buflen))) {
+        if (ret < 0) {
+            if (errno == EAGAIN)
+                break;
+            panic("Failed to read from tap device.\n");
+        }
 
-    sendSimulated(buffer, ret);
+        sendSimulated(buffer, ret);
+    }
 }
 
 bool
 EtherTap::sendReal(const void *data, size_t len)
 {
-    if (write(tap, data, len) != len)
-        panic("Failed to write data to tap device.\n");
+    int n;
+    pollfd pfd[1];
+    pfd->fd = tap;
+    pfd->events = POLLOUT;
+
+    // `tap` is a nonblock fd. Here we try to write until success, and use
+    // poll to make a blocking wait.
+    while ((n = write(tap, data, len)) != len) {
+        if (errno != EAGAIN)
+            panic("Failed to write data to tap device.\n");
+        pfd->revents = 0;
+        int ret = poll(pfd, 1, -1);
+        // timeout is set to inf, we shouldn't get 0 in any case.
+        assert(ret != 0);
+        if (ret == -1 || (ret == 1 && (pfd->revents & POLLERR))) {
+            panic("Failed when polling to write data to tap device.\n");
+        }
+    }
     return true;
 }