dol: initial dol commit
[jump.git] / dol / src / dol / visitor / hdsd / scd / scd_chan_wrapper.cpp
diff --git a/dol/src/dol/visitor/hdsd/scd/scd_chan_wrapper.cpp b/dol/src/dol/visitor/hdsd/scd/scd_chan_wrapper.cpp
new file mode 100644 (file)
index 0000000..2629240
--- /dev/null
@@ -0,0 +1,201 @@
+#include "scd_chan_wrapper.h"
+
+#include <cassert>
+#include <cstdio>
+
+#include "scd_logging.h"
+
+
+scd_chan_wrapper::scd_chan_wrapper(scd_simulator& sim, const std::string& name,
+        sc_prim_channel& chan):
+    _sim(sim), _name(name), _is_initialized(false),
+    _is_writing(false), _is_reading(false)
+{
+    try
+    {
+        _chan_in = &dynamic_cast<scd_rem_chan_in_if&>(chan);
+    } catch (std::bad_cast e)
+    {
+        _chan_in = NULL;
+    }
+
+    try
+    {
+        _chan_out = &dynamic_cast<scd_rem_chan_out_if&>(chan);
+    } catch (std::bad_cast e)
+    {
+        _chan_out = NULL;
+    }
+
+    if (_chan_in == NULL && _chan_out == NULL)
+        scd_warn("channel \"" + _name + "\" is not a remote channel");
+}
+
+
+scd_chan_wrapper::~scd_chan_wrapper()
+{
+    if ( _is_initialized )
+    {
+        _sim.get_poller().remove_handler(*this);
+        _socket->close();
+        delete _socket;
+    }
+}
+
+
+bool scd_chan_wrapper::is_initialized() const { return _is_initialized; }
+
+
+const std::string& scd_chan_wrapper::get_name() const { return _name; }
+
+
+void scd_chan_wrapper::connect(scd_socket* sock)
+{
+    assert(!_is_initialized);
+
+    _socket = sock;
+    _is_initialized = true;
+
+    sock_ev flags = SOCK_EV_CLOSE;
+    if (_chan_in != NULL)
+    {
+        flags |= SOCK_EV_READ;
+        _is_reading = true;
+    }
+    _sim.get_poller().register_handler(*this, flags);
+
+} // connect()
+
+
+void scd_chan_wrapper::process()
+{
+    // check if channel has data to send
+    if (_chan_out != NULL && _is_initialized )
+    {
+        if (!_is_writing && _socket->is_valid() && _chan_out->available() > 0 )
+        {
+            // register write event
+            sock_ev events;
+            _sim.get_poller().get_ev(*this, events);
+            events |= SOCK_EV_WRITE;
+            _sim.get_poller().set_ev( *this, events );
+            _is_writing = true;
+        }
+    }
+
+    // check if channel has data to read
+    if (_chan_in != NULL && _is_initialized )
+    {
+        if (!_is_reading && _socket->is_valid() && _chan_in->free() > 0 )
+        {
+            // register read event
+            sock_ev events;
+            _sim.get_poller().get_ev(*this, events);
+            events |= SOCK_EV_READ;
+            _sim.get_poller().set_ev( *this, events );
+            _is_reading = true;
+        }
+    }
+
+} // process()
+
+
+void scd_chan_wrapper::close()
+{
+    if (_is_initialized)
+        _socket->close();
+
+} // close()
+
+
+void scd_chan_wrapper::handle_sock_ev(sock_ev events)
+{
+    if (events & SOCK_EV_CLOSE)
+    {
+        scd_debug("channel \"" + _name + "\" closed connection");
+        _sim.get_poller().set_ev(*this, 0);
+        _sim.get_cont_man().set_fail();
+        close();
+        return;
+    } // end close event
+
+    if (events & SOCK_EV_READ)
+    {
+        _read_event();
+    }
+
+    if (events & SOCK_EV_WRITE)
+    {
+        _write_event();
+    }
+
+} // handle_sock_ev()
+
+
+const scd_socket& scd_chan_wrapper::get_sock() { return *_socket; }
+
+
+void scd_chan_wrapper::_read_event()
+{
+    size_t free = _chan_in->free();
+
+    /* receive portions as long as they can be received */
+    size_t recv = 0xFF; //dummy
+    while ( free != 0 && recv != 0)
+    {
+        free = ( free < SCD_CHAN_BUFLEN ) ? free : SCD_CHAN_BUFLEN ;
+        recv = _socket->recv(_buf, free);
+        if (recv != 0)
+            _chan_in->receive(_buf, recv);
+        free = _chan_in->free();
+    }
+
+    if (free == 0)
+    {
+        sock_ev events;
+        _sim.get_poller().get_ev(*this, events);
+        events &= ~SOCK_EV_READ;
+        _sim.get_poller().set_ev(*this, events );
+        _is_reading = false;
+        return;
+    }
+
+    if (!_socket->is_valid())
+    {
+        scd_debug("channel \"" + _name + "\" closed connection");
+        _sim.get_poller().set_ev(*this, 0);
+        _sim.get_cont_man().set_fail();
+        return;
+    }
+
+} // end _read_event()
+
+
+void scd_chan_wrapper::_write_event()
+{
+    /* send portions as long as they can be sent */
+    size_t sent = 0xFF; //dummy
+    while ( sent )
+    {
+        sent = _socket->send( _chan_out->send(), _chan_out->available() );
+        if (sent != 0)
+            _chan_out->remove(sent);
+    }
+
+    if (_chan_out->available() == 0)
+    {
+        sock_ev events;
+        _sim.get_poller().get_ev(*this, events);
+        events &= ~SOCK_EV_WRITE;
+        _sim.get_poller().set_ev(*this, events );
+        _is_writing = false;
+        return;
+    }
+
+    if (!_socket->is_valid())
+    {
+        scd_debug("channel \"" + _name + "\" closed connection");
+        _sim.get_poller().set_ev(*this, 0);
+        _sim.get_cont_man().set_fail();
+    }
+}