diff --git a/repos/gems/run/tcp_terminal.run b/repos/gems/run/tcp_terminal.run
index 5eb3bbee0d..0a61f9e14a 100644
--- a/repos/gems/run/tcp_terminal.run
+++ b/repos/gems/run/tcp_terminal.run
@@ -62,9 +62,8 @@ set config {
-
-
-
+
+
@@ -87,7 +86,7 @@ install_config $config
set boot_modules {
core ld.lib.so init timer
nic_drv
- libc.lib.so lwip.lib.so libc_pipe.lib.so
+ libc.lib.so pthread.lib.so lwip.lib.so libc_pipe.lib.so
tcp_terminal
test-terminal_echo
}
diff --git a/repos/gems/src/server/tcp_terminal/main.cc b/repos/gems/src/server/tcp_terminal/main.cc
index b024ea8a08..9e185983cd 100644
--- a/repos/gems/src/server/tcp_terminal/main.cc
+++ b/repos/gems/src/server/tcp_terminal/main.cc
@@ -19,10 +19,12 @@
#include
#include
#include
-#include
#include
#include
+#include
+#include
+
/* socket API */
#include
#include
@@ -242,6 +244,11 @@ class Open_socket_pool
*/
Genode::List _list;
+ /**
+ * Thread doing the select
+ */
+ pthread_t _select;
+
/**
* Number of currently open sockets
*/
@@ -261,11 +268,26 @@ class Open_socket_pool
::write(sync_pipe_fds[1], &c, sizeof(c));
}
+ static void * entry(void *arg) {
+ Open_socket_pool * pool = reinterpret_cast(arg);
+
+ for (;;)
+ pool->watch_sockets_for_incoming_data();
+
+ return nullptr;
+ }
+
public:
- Open_socket_pool() : _count(0)
+ Open_socket_pool(Genode::Env &env)
+ : _count(0)
{
pipe(sync_pipe_fds);
+
+ if (pthread_create(&_select, nullptr, entry, this)) {
+ class Startup_select_thread_failed : Genode::Exception { };
+ throw Startup_select_thread_failed();
+ }
}
void insert(Open_socket *s)
@@ -366,9 +388,9 @@ class Open_socket_pool
};
-Open_socket_pool *open_socket_pool()
+Open_socket_pool *open_socket_pool(Genode::Env * env = nullptr)
{
- static Open_socket_pool inst;
+ static Open_socket_pool inst(*env);
return &inst;
}
@@ -390,153 +412,159 @@ Open_socket::~Open_socket()
namespace Terminal {
+ class Session_component;
+ class Root_component;
+};
- class Session_component : public Genode::Rpc_object,
- public Open_socket
- {
- private:
-
- Genode::Attached_ram_dataspace _io_buffer;
-
- public:
-
- Session_component(Genode::size_t io_buffer_size, int tcp_port)
- :
- Open_socket(tcp_port),
- _io_buffer(Genode::env()->ram_session(), io_buffer_size)
- { }
-
- /********************************
- ** Terminal session interface **
- ********************************/
-
- Size size() { return Size(0, 0); }
-
- bool avail()
- {
- return !read_buffer_empty();
- }
-
- Genode::size_t _read(Genode::size_t dst_len)
- {
- Genode::size_t num_bytes =
- read_buffer(_io_buffer.local_addr(),
- Genode::min(_io_buffer.size(), dst_len));
-
- /*
- * If read buffer was in use, look if more data is buffered in
- * the TCP/IP stack.
- */
- if (num_bytes)
- open_socket_pool()->update_sockets_to_watch();
-
- return num_bytes;
- }
-
- Genode::size_t _write(Genode::size_t num_bytes)
- {
- /* sanitize argument */
- num_bytes = Genode::min(num_bytes, _io_buffer.size());
-
- /* write data to socket, assuming that it won't block */
- ssize_t written_bytes = ::write(sd(),
- _io_buffer.local_addr(),
- num_bytes);
-
- if (written_bytes < 0) {
- Genode::error("write error, dropping data");
- return 0;
- }
-
- return written_bytes;
- }
-
- Genode::Dataspace_capability _dataspace()
- {
- return _io_buffer.cap();
- }
-
- void read_avail_sigh(Genode::Signal_context_capability sigh)
- {
- Open_socket::read_avail_sigh(sigh);
- }
-
- void connected_sigh(Genode::Signal_context_capability sigh)
- {
- Open_socket::connected_sigh(sigh);
- }
-
- Genode::size_t read(void *buf, Genode::size_t) { return 0; }
- Genode::size_t write(void const *buf, Genode::size_t) { return 0; }
- };
-
-
- class Root_component : public Genode::Root_component
- {
- protected:
-
- Session_component *_create_session(const char *args)
- {
- using namespace Genode;
-
- /*
- * XXX read I/O buffer size from args
- */
- Genode::size_t io_buffer_size = 4096;
-
- try {
- Session_label const label = label_from_args(args);
- Session_policy policy(label);
-
- unsigned tcp_port = 0;
- policy.attribute("port").value(&tcp_port);
- return new (md_alloc())
- Session_component(io_buffer_size, tcp_port);
-
- } catch (Xml_node::Nonexistent_attribute) {
- error("Missing \"port\" attribute in policy definition");
- throw Root::Unavailable();
- } catch (Session_policy::No_policy_defined) {
- error("Invalid session request, no matching policy");
- throw Root::Unavailable();
- }
- }
-
- public:
-
- /**
- * Constructor
- */
- Root_component(Genode::Rpc_entrypoint *ep,
- Genode::Allocator *md_alloc)
- :
- Genode::Root_component(ep, md_alloc)
- { }
- };
-}
-
-
-int main()
+class Terminal::Session_component : public Genode::Rpc_object,
+ public Open_socket
{
- using namespace Genode;
+ private:
- Genode::log("--- TCP terminal started ---");
+ Genode::Attached_ram_dataspace _io_buffer;
- /* initialize entry point that serves the root interface */
- enum { STACK_SIZE = 4*4096 };
- static Cap_connection cap;
- static Rpc_entrypoint ep(&cap, STACK_SIZE, "terminal_ep");
+ public:
- static Sliced_heap sliced_heap(env()->ram_session(), env()->rm_session());
+ Session_component(Genode::Env &env, Genode::size_t io_buffer_size, int tcp_port)
+ :
+ Open_socket(tcp_port),
+ _io_buffer(env.ram(), env.rm(), io_buffer_size)
+ { }
+
+ /********************************
+ ** Terminal session interface **
+ ********************************/
+
+ Size size() { return Size(0, 0); }
+
+ bool avail()
+ {
+ return !read_buffer_empty();
+ }
+
+ Genode::size_t _read(Genode::size_t dst_len)
+ {
+ Genode::size_t num_bytes =
+ read_buffer(_io_buffer.local_addr(),
+ Genode::min(_io_buffer.size(), dst_len));
+
+ /*
+ * If read buffer was in use, look if more data is buffered in
+ * the TCP/IP stack.
+ */
+ if (num_bytes)
+ open_socket_pool()->update_sockets_to_watch();
+
+ return num_bytes;
+ }
+
+ Genode::size_t _write(Genode::size_t num_bytes)
+ {
+ /* sanitize argument */
+ num_bytes = Genode::min(num_bytes, _io_buffer.size());
+
+ /* write data to socket, assuming that it won't block */
+ ssize_t written_bytes = ::write(sd(),
+ _io_buffer.local_addr(),
+ num_bytes);
+
+ if (written_bytes < 0) {
+ Genode::error("write error, dropping data");
+ return 0;
+ }
+
+ return written_bytes;
+ }
+
+ Genode::Dataspace_capability _dataspace()
+ {
+ return _io_buffer.cap();
+ }
+
+ void read_avail_sigh(Genode::Signal_context_capability sigh)
+ {
+ Open_socket::read_avail_sigh(sigh);
+ }
+
+ void connected_sigh(Genode::Signal_context_capability sigh)
+ {
+ Open_socket::connected_sigh(sigh);
+ }
+
+ Genode::size_t read(void *buf, Genode::size_t) { return 0; }
+ Genode::size_t write(void const *buf, Genode::size_t) { return 0; }
+};
+
+
+class Terminal::Root_component : public Genode::Root_component
+{
+ private:
+
+ Genode::Env &_env;
+
+ protected:
+
+ Session_component *_create_session(const char *args)
+ {
+ using namespace Genode;
+
+ /*
+ * XXX read I/O buffer size from args
+ */
+ Genode::size_t io_buffer_size = 4096;
+
+ try {
+ Session_label const label = label_from_args(args);
+ Session_policy policy(label);
+
+ unsigned tcp_port = 0;
+ policy.attribute("port").value(&tcp_port);
+ return new (md_alloc())
+ Session_component(_env, io_buffer_size, tcp_port);
+
+ } catch (Xml_node::Nonexistent_attribute) {
+ error("Missing \"port\" attribute in policy definition");
+ throw Root::Unavailable();
+ } catch (Session_policy::No_policy_defined) {
+ error("Invalid session request, no matching policy");
+ throw Root::Unavailable();
+ }
+ }
+
+ public:
+
+ /**
+ * Constructor
+ */
+ Root_component(Genode::Env &env, Genode::Allocator &md_alloc)
+ :
+ Genode::Root_component(&env.ep().rpc_ep(),
+ &md_alloc),
+ _env(env)
+ { }
+};
+
+
+struct Main
+{
+ Genode::Env &_env;
+
+ Genode::Sliced_heap _sliced_heap { _env.ram(), _env.rm() };
/* create root interface for service */
- static Terminal::Root_component root(&ep, &sliced_heap);
+ Terminal::Root_component _root { _env, _sliced_heap };
- /* announce service at our parent */
- env()->parent()->announce(ep.manage(&root));
+ Main(Genode::Env &env) : _env(env)
+ {
+ Genode::log("--- TCP terminal started ---");
- for (;;)
- open_socket_pool()->watch_sockets_for_incoming_data();
+ /* start thread blocking in select */
+ open_socket_pool(&_env);
- return 0;
-}
+ /* announce service at our parent */
+ _env.parent().announce(env.ep().manage(_root));
+
+ }
+};
+
+void Libc::Component::construct(Libc::Env &env) { static Main main(env); }
diff --git a/repos/gems/src/server/tcp_terminal/target.mk b/repos/gems/src/server/tcp_terminal/target.mk
index a107693c8b..3a9d7d7356 100644
--- a/repos/gems/src/server/tcp_terminal/target.mk
+++ b/repos/gems/src/server/tcp_terminal/target.mk
@@ -1,3 +1,3 @@
TARGET = tcp_terminal
SRC_CC = main.cc
-LIBS = posix libc_lwip_nic_dhcp libc_pipe
+LIBS = libc pthread libc_lwip_nic_dhcp libc_pipe
diff --git a/repos/ports/run/noux_net_netcat.run b/repos/ports/run/noux_net_netcat.run
index 1d85bed51d..ff3e218937 100644
--- a/repos/ports/run/noux_net_netcat.run
+++ b/repos/ports/run/noux_net_netcat.run
@@ -164,7 +164,7 @@ install_config $config
# generic modules
set boot_modules {
core init timer tcp_terminal nic_bridge
- ld.lib.so noux_net libc.lib.so libm.lib.so libc_pipe.lib.so
+ ld.lib.so noux_net libc.lib.so libm.lib.so libc_pipe.lib.so pthread.lib.so
libc_resolv.lib.so libc_noux.lib.so lwip.lib.so noux_netcat.tar
}