38 using Device_type = DEV;
39 using Client_type = Virtio_client<Device_type>;
47 void handle_irq() { _parent->schedule(); }
52 Irq_object _irq_handler;
56 cxx::unique_ptr<Pending_request> pending;
62 Context(Client_type *client) : client(client), device_busy(
false), cost(0)
65 bool same_notification_domain(Client_type
const *c)
const
66 {
return c->notification_domain() == client->notification_domain(); }
69 using Queue_type = std::vector<cxx::unique_ptr<Context>>;
70 using Iterator_type =
typename Queue_type::const_iterator;
74 : _irq_handler(
this), _registry(registry), _next(_clients.cend())
77 "Registering device notify IRQ object.");
87 ->unmap(_irq_handler.obj_cap().fpage(),
102 void add_client(Client_type *client)
104 Dbg::trace().printf(
"Adding client %p to request scheduler.\n", client);
107 client->set_device_notify_irq(
108 L4::cap_cast<L4::Irq>(_irq_handler.obj_cap()));
110 client->set_client_invalidate_cb([
this, client](
bool fail_pending) {
111 client_invalidate(client, fail_pending);
114 client->set_client_idle_cb([
this, client]() { client_idle(client); });
116 _clients.push_back(cxx::make_unique<Context>(client));
117 _next = _clients.cend();
120 void remove_client(Client_type *client)
122 Dbg::trace().printf(
"Removing client %p from request scheduler.\n", client);
123 _clients.erase(std::remove_if(_clients.begin(), _clients.end(),
124 [client](cxx::unique_ptr<Context> &c) {
125 return c->client == client;
127 _next = _clients.cend();
130 Queue_type
const &clients()
135 void client_invalidate(Client_type *client,
bool fail_pending)
137 for (
auto &c : _clients)
138 if (c->client == client)
140 c->device_busy =
false;
145 c->pending->fail_request();
152 void client_idle(Client_type *client)
154 bool resched =
false;
155 for (
auto &c : _clients)
156 if (c->device_busy && c->same_notification_domain(client))
158 c->device_busy =
false;
168 L4::cap_cast<L4::Irq>(this->_irq_handler.obj_cap())->trigger();
181 bool handle_pending(Context *c)
183 auto cost =
get_cost(*(c->pending));
187 Dbg::trace().printf(
"Preempting client %p (cost=%zu+%zu, weight=%zu)\n",
188 c->client, c->cost, cost,
get_weight(c->client));
199 int ret = c->pending->handle_request();
202 c->device_busy =
true;
211 c->pending.release();
231 bool schedule_client(Context *c)
238 "Skipping pending request of client %p (busy).\n", c->client);
242 Dbg::trace().printf(
"Handling pending request of client %p.\n",
247 return handle_pending(c);
250 if (c->client->check_for_new_requests())
252 auto req = c->client->get_request();
255 Dbg::trace().printf(
"Scheduling request from client %p.\n",
257 c->pending = c->client->start_request(cxx::move(req));
264 return handle_pending(c);
289 if (_clients.empty())
292 if (_next == _clients.cend())
293 _next = _clients.cbegin();
297 Iterator_type start(_next);
298 bool recheck =
false;
301 bool progress = schedule_client(_next->get());
305 if (!progress || ((*_next)->cost >=
get_weight((*_next)->client)))
308 if (_next == _clients.cend())
309 _next = _clients.cbegin();