diff --git a/repos/os/include/suoritin/client.h b/repos/os/include/suoritin/client.h new file mode 100644 index 0000000000..1acd0e93c7 --- /dev/null +++ b/repos/os/include/suoritin/client.h @@ -0,0 +1,38 @@ +/* + * \brief Suoritin - Task-based CPU Client Interface + * \author Michael Müller + * \date 2023-07-12 + */ + +/* + * Copyright (C) 2010-2020 Genode Labs GmbH + * Copyright (C) 2023 Michael Müller, Osnabrück University + * + * This file is part of EalánOS, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ +#pragma once + +#include +#include +#include + +struct Tukija::Suoritin::Client : Genode::Rpc_client +{ + explicit Client(Genode::Capability session) + : Rpc_client(session) { } + + void create_channel() override + { + call(); + } + + void register_worker(Genode::Thread::Name const &name, Genode::Thread_capability cap) override + { + call(name, cap); + } + + Capability interface_cap() override { + return call(); + } +}; \ No newline at end of file diff --git a/repos/os/include/suoritin/connection.h b/repos/os/include/suoritin/connection.h new file mode 100644 index 0000000000..48eefff1d6 --- /dev/null +++ b/repos/os/include/suoritin/connection.h @@ -0,0 +1,46 @@ +/* + * \brief Suoritin - Task-based CPU Connection + * \author Michael Müller + * \date 2023-07-12 + */ + +/* + * Copyright (C) 2010-2020 Genode Labs GmbH + * Copyright (C) 2023 Michael Müller, Osnabrück University + * + * This file is part of EalánOS, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ +#pragma once + +#include +#include + +namespace Tukija { + namespace Suoritin { + struct Connection; + } +} + +struct Tukija::Suoritin::Connection : Genode::Connection, Tukija::Suoritin::Client +{ + enum + { + RAM_QUOTA = 32768UL + }; + + Connection(Genode::Env &env, const char *label="", Genode::Affinity const &affinity = Genode::Affinity()) + : Genode::Connection(env, session(env.parent(), affinity, "ram_quota=%u, cap_quota=%u, label=\"%s\"", RAM_QUOTA, CAP_QUOTA, label)), Tukija::Suoritin::Client(cap()) {} + + void create_channel() override { + Tukija::Suoritin::Client::create_channel(); + } + + void register_worker(Genode::Thread::Name const &name, Genode::Thread_capability cap) override { + Tukija::Suoritin::Client::register_worker(name, cap); + } + + Tukija::Suoritin::Capability interface_cap() override { + return Tukija::Suoritin::Client::interface_cap(); + } +}; \ No newline at end of file diff --git a/repos/os/include/suoritin/session.h b/repos/os/include/suoritin/session.h new file mode 100644 index 0000000000..4a20c9b9e8 --- /dev/null +++ b/repos/os/include/suoritin/session.h @@ -0,0 +1,101 @@ +/* + * \brief Suoritin - Task-based CPU Service + * \author Michael Müller + * \date 2023-07-12 + */ + +/* + * Copyright (C) 2010-2020 Genode Labs GmbH + * Copyright (C) 2023 Michael Müller, Osnabrück University + * + * This file is part of EalánOS, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ +#pragma once + +#include +#include +#include +#include + +namespace Tukija { + namespace Suoritin { + struct Session; + struct Client; + class Capability; + + struct Channel; + struct Worker; + typedef Genode::Registry> Channel_list; + typedef Genode::Registry> Worker_registry; + } +} + +class Tukija::Suoritin::Capability +{ + private: + Genode::Ram_dataspace_capability _worker_space; + Genode::Ram_dataspace_capability _channel_space; + + public: + Capability(Genode::Ram_dataspace_capability worker_space, Genode::Ram_dataspace_capability channel_space) : _worker_space(worker_space), _channel_space(channel_space) {} + + Genode::Ram_dataspace_capability worker_interface() { return _worker_space; } + Genode::Ram_dataspace_capability channel_space() { return _channel_space; } +}; + +struct Tukija::Suoritin::Worker : Genode::Interface +{ + Genode::Thread_capability _cap{}; + Genode::Thread::Name _name{}; +}; + +struct Tukija::Suoritin::Channel : Genode::Interface +{ + unsigned long _id{0}; + unsigned long _length{0}; + unsigned long _occupancy{0}; +}; + +struct Tukija::Suoritin::Session : Genode::Session +{ + static const char *service_name() { return "TASKING"; } + + enum + { + CAP_QUOTA = 6 + }; + + /** + * @brief List of all channels, i.e. worker queues, of the client cell + * + */ + Channel_list _channels{}; + + /** + * @brief List of worker threads for this client + * + */ + Worker_registry _workers{}; + + virtual ~Session() { } + + /************************ + ** internal interface ** + ************************/ + Channel_list &channels() { return _channels; } + Worker_registry &workers() { return _workers; } + + /******************************** + ** Suoritin session interface ** + ********************************/ + virtual void create_channel() = 0; + virtual void register_worker(Genode::Thread::Name const &name, Genode::Thread_capability cap) = 0; + virtual Capability interface_cap() = 0; + + GENODE_RPC(Rpc_create_channel, void, create_channel); + GENODE_RPC(Rpc_register_worker, void, register_worker, Genode::Thread::Name const&, Genode::Thread_capability); + GENODE_RPC(Rpc_suoritin_cap, Tukija::Suoritin::Capability, interface_cap); + + GENODE_RPC_INTERFACE(Rpc_create_channel, Rpc_register_worker, Rpc_suoritin_cap); +}; \ No newline at end of file diff --git a/repos/os/src/hoitaja/suoritin/component.cc b/repos/os/src/hoitaja/suoritin/component.cc new file mode 100644 index 0000000000..0c2096776d --- /dev/null +++ b/repos/os/src/hoitaja/suoritin/component.cc @@ -0,0 +1,131 @@ +/* Genode includes */ +#include +#include +#include +#include +#include + +#include +#include +#include + + + +namespace Tukija { + namespace Suoritin { + class Session_component; + template class Allocator; + } +} + +template +class Tukija::Suoritin::Allocator : public Genode::Allocator +{ + using size_t = Genode::size_t; + +private: + Genode::Region_map::Local_addr _dataspace{}; + size_t _interface_size; + Genode::Region_map::Local_addr _pos {_dataspace}; + +public: + Allocator(Genode::Env &env, Genode::Ram_dataspace_capability *_interface_cap, size_t interface_size) : _interface_size(interface_size) + { + *_interface_cap = env.ram().alloc(interface_size); + _dataspace = static_cast(env.rm().attach(*_interface_cap)); + } + + Alloc_result try_alloc(size_t) override + { + T *pos = _pos; + if (pos >= static_cast(_dataspace) + _interface_size) + return Alloc_result(Genode::Ram_allocator::Alloc_error::OUT_OF_RAM); + + pos++; + return Alloc_result(static_cast(pos)); + } + + void free(void *, size_t) override + { } + + size_t overhead(size_t) const override { return 0; } + + bool need_size_for_free() const override { return false; } + + T *interface() { return _dataspace; } +}; + +class Tukija::Suoritin::Session_component : public Genode::Session_object +{ + private: + Genode::Affinity _affinity; + Genode::Env &_env; + Genode::Ram_dataspace_capability _workers_interface_cap{}; + Genode::Ram_dataspace_capability _channels_interface_cap{}; + + Allocator> _worker_allocator; + Allocator> _channel_allocator; + + unsigned long no_channels{0}; + unsigned long no_workers{0}; + + template + void construct(FUNC const &fn, Allocator> &alloc, Genode::Registry> ®istry) { + T* object = nullptr; + + try { + try { + object = new (alloc) Genode::Registered(registry); + fn(object); + } catch (Genode::Allocator::Out_of_memory) { + Genode::error("Out of RAM on registering worker."); + throw; + } + } catch (...) { + if (object) + destroy(alloc, object); + Genode::error("Exception caught registering worker"); + throw; + } + } + + + public: + Session_component(Genode::Rpc_entrypoint &session_ep, + Genode::Session::Resources const &resources, + Genode::Session::Label const &label, + Genode::Session::Diag const &diag, + Genode::Env &env, + Genode::Affinity &affinity) + : Session_object(session_ep, resources, label, diag), _affinity(affinity.space().total() ? affinity : Genode::Affinity(Genode::Affinity::Space(1,1), Genode::Affinity::Location(0,0,1,1))), + _env(env), _worker_allocator(env, &_workers_interface_cap, _affinity.space().total()*sizeof(Genode::Registered)), + _channel_allocator(env, &_channels_interface_cap, _affinity.space().total()*sizeof(Genode::Registered)) + { + } + + void create_channel() override + { + try { + construct([&](Channel *) {}, _channel_allocator, _channels); + } + catch (...) + { + Genode::error("Faild to create channel"); + } + } + void register_worker(Genode::Thread::Name const &name, Genode::Thread_capability cap) override { + try { + construct([&](Worker *worker) + { worker->_cap = cap; + worker->_name = name; }, _worker_allocator, _workers); + } + catch (...) + { + Genode::error("Failed to register worker"); + } + } + + Capability interface_cap() override { + return Capability{_workers_interface_cap, _channels_interface_cap}; + } +}; \ No newline at end of file