usb c-api: manage lifetime of session handles

Fix genodelabs/genode#4602
This commit is contained in:
Stefan Kalkowski 2022-09-06 18:04:00 +02:00 committed by Norman Feske
parent 3d26ce9f8d
commit f2c52d1570

View File

@ -46,6 +46,24 @@ struct Device {
}; };
class Session_id
{
private:
genode_usb_session_handle_t const _id;
unsigned _ref_cnt { 0 };
public:
Session_id(genode_usb_session_handle_t id) : _id(id) {}
genode_usb_session_handle_t id() { return _id; }
void inc() { _ref_cnt++; }
void dec() { _ref_cnt--; }
bool used() { return _ref_cnt; }
};
class Root; class Root;
@ -62,7 +80,7 @@ class genode_usb_session : public Usb::Session_rpc_object
::Root & _root; ::Root & _root;
genode_shared_dataspace * _ds; genode_shared_dataspace * _ds;
Signal_context_capability _sigh_state_cap {}; Signal_context_capability _sigh_state_cap {};
genode_usb_session_handle_t _id; Session_id & _id;
Session_label const _label; Session_label const _label;
List_element<genode_usb_session> _le { this }; List_element<genode_usb_session> _le { this };
@ -79,8 +97,8 @@ class genode_usb_session : public Usb::Session_rpc_object
genode_usb_session(::Root & root, genode_usb_session(::Root & root,
genode_shared_dataspace * ds, genode_shared_dataspace * ds,
Env & env, Env & env,
Session_id & id,
Signal_context_capability cap, Signal_context_capability cap,
genode_usb_session_handle_t id,
Session_label label); Session_label label);
virtual ~genode_usb_session() {} virtual ~genode_usb_session() {}
@ -143,17 +161,7 @@ class Root : public Root_component<genode_usb_session>
{ {
private: private:
enum { MAX_DEVICES = 32 }; enum { MAX_DEVICES = 32, MAX_SESSIONS = MAX_DEVICES };
struct Id_allocator : Bit_allocator<16>
{
genode_usb_session_handle_t alloc()
{
/* we can downcast here, because we only use 16 bits */
return (genode_usb_session_handle_t)
Bit_allocator<16>::alloc();
}
};
Env & _env; Env & _env;
Signal_context_capability _sigh_cap; Signal_context_capability _sigh_cap;
@ -161,8 +169,8 @@ class Root : public Root_component<genode_usb_session>
Signal_handler<Root> _config_handler { _env.ep(), *this, Signal_handler<Root> _config_handler { _env.ep(), *this,
&Root::_announce_service }; &Root::_announce_service };
Reporter _config_reporter { _env, "config" }; Reporter _config_reporter { _env, "config" };
Constructible<Session_id> _session_ids[MAX_SESSIONS];
Constructible<Device> _devices[MAX_DEVICES]; Constructible<Device> _devices[MAX_DEVICES];
Id_allocator _id_alloc {};
bool _announced { false }; bool _announced { false };
Constructible<Expanding_reporter> _device_reporter {}; Constructible<Expanding_reporter> _device_reporter {};
@ -244,6 +252,8 @@ class Root : public Root_component<genode_usb_session>
* Acknowledge requests from sessions without device * Acknowledge requests from sessions without device
*/ */
void handle_empty_sessions(); void handle_empty_sessions();
void decrement_session_id(genode_usb_session_handle_t id);
}; };
@ -446,37 +456,39 @@ bool genode_usb_session::request(genode_usb_request_callbacks & req, void * data
+ offset); + offset);
packets[idx].construct(p); packets[idx].construct(p);
_id.inc(); /* increment the session ids usage */
switch (p.type) { switch (p.type) {
case Packet_descriptor::STRING: case Packet_descriptor::STRING:
req.string_fn((genode_usb_request_string*)&p.string, req.string_fn((genode_usb_request_string*)&p.string,
_id, idx, addr, p.size(), data); _id.id(), idx, addr, p.size(), data);
break; break;
case Packet_descriptor::CTRL: case Packet_descriptor::CTRL:
req.urb_fn({ CTRL, &p.control }, _id, idx, addr, p.size(), data); req.urb_fn({ CTRL, &p.control }, _id.id(), idx, addr, p.size(), data);
break; break;
case Packet_descriptor::BULK: case Packet_descriptor::BULK:
req.urb_fn({ BULK, &p.transfer }, _id, idx, addr, p.size(), data); req.urb_fn({ BULK, &p.transfer }, _id.id(), idx, addr, p.size(), data);
break; break;
case Packet_descriptor::IRQ: case Packet_descriptor::IRQ:
req.urb_fn({ IRQ, &p.transfer }, _id, idx, addr, p.size(), data); req.urb_fn({ IRQ, &p.transfer }, _id.id(), idx, addr, p.size(), data);
break; break;
case Packet_descriptor::ISOC: case Packet_descriptor::ISOC:
req.urb_fn({ ISOC, &p.transfer }, _id, idx, addr, p.size(), data); req.urb_fn({ ISOC, &p.transfer }, _id.id(), idx, addr, p.size(), data);
break; break;
case Packet_descriptor::ALT_SETTING: case Packet_descriptor::ALT_SETTING:
req.altsetting_fn(p.interface.number, p.interface.alt_setting, req.altsetting_fn(p.interface.number, p.interface.alt_setting,
_id, idx, data); _id.id(), idx, data);
break; break;
case Packet_descriptor::CONFIG: case Packet_descriptor::CONFIG:
req.config_fn(p.number, _id, idx, data); req.config_fn(p.number, _id.id(), idx, data);
break; break;
case Packet_descriptor::RELEASE_IF: case Packet_descriptor::RELEASE_IF:
warning("Release interface gets ignored!"); warning("Release interface gets ignored!");
_id.dec();
packets[idx].destruct(); packets[idx].destruct();
break; break;
case Packet_descriptor::FLUSH_TRANSFERS: case Packet_descriptor::FLUSH_TRANSFERS:
req.flush_fn(p.number, _id, idx, data); req.flush_fn(p.number, _id.id(), idx, data);
break; break;
}; };
@ -514,8 +526,8 @@ void genode_usb_session::handle_response(genode_usb_request_handle_t id,
genode_usb_session::genode_usb_session(::Root & root, genode_usb_session::genode_usb_session(::Root & root,
genode_shared_dataspace * ds, genode_shared_dataspace * ds,
Env & env, Env & env,
Session_id & id,
Signal_context_capability cap, Signal_context_capability cap,
genode_usb_session_handle_t id,
Session_label const label) Session_label const label)
: :
Usb::Session_rpc_object(genode_shared_dataspace_capability(ds), Usb::Session_rpc_object(genode_shared_dataspace_capability(ds),
@ -526,6 +538,8 @@ genode_usb_session::genode_usb_session(::Root & root,
_label(label) _label(label)
{ {
_tx.sigh_packet_avail(cap); _tx.sigh_packet_avail(cap);
id.inc();
} }
@ -574,9 +588,18 @@ genode_usb_session * ::Root::_create_session(const char * args,
throw Insufficient_ram_quota(); throw Insufficient_ram_quota();
} }
unsigned i = 0;
for (; i < MAX_SESSIONS; i++)
if (!_session_ids[i]->used())
break;
if (i >= MAX_SESSIONS) {
warning("Maximum of sessions reached!");
throw Service_denied();
}
genode_shared_dataspace * ds = _callbacks->alloc_fn(tx_buf_size); genode_shared_dataspace * ds = _callbacks->alloc_fn(tx_buf_size);
genode_usb_session * ret = new (md_alloc()) genode_usb_session * ret = new (md_alloc())
genode_usb_session(*this, ds, _env, _sigh_cap, _id_alloc.alloc(), label); genode_usb_session(*this, ds, _env, *_session_ids[i], _sigh_cap, label);
_sessions.insert(&ret->_le); _sessions.insert(&ret->_le);
if (!ret) throw Service_denied(); if (!ret) throw Service_denied();
@ -602,11 +625,10 @@ void ::Root::_destroy_session(genode_usb_session * session)
} }
}); });
genode_usb_session_handle_t id = session->_id; session->_id.dec();
genode_shared_dataspace * ds = session->_ds; genode_shared_dataspace * ds = session->_ds;
_sessions.remove(&session->_le); _sessions.remove(&session->_le);
Genode::destroy(md_alloc(), session); Genode::destroy(md_alloc(), session);
_id_alloc.free((addr_t)id);
_callbacks->free_fn(ds); _callbacks->free_fn(ds);
} }
@ -765,7 +787,7 @@ genode_usb_session_handle_t ::Root::session(genode_usb_bus_num_t bus,
session = d.usb_session; session = d.usb_session;
}); });
return session ? session->_id : 0; return session ? session->_id.id() : 0;
} }
@ -775,7 +797,7 @@ void ::Root::session(genode_usb_session_handle_t id, FUNC const & fn)
genode_usb_session * session = nullptr; genode_usb_session * session = nullptr;
_for_each_session([&] (genode_usb_session & s) { _for_each_session([&] (genode_usb_session & s) {
if (s._id == id) session = &s; if (s._id.id() == id) session = &s;
}); });
/* /*
@ -816,13 +838,22 @@ void ::Root::handle_empty_sessions()
} }
void ::Root::decrement_session_id(genode_usb_session_handle_t id)
{
if (id > 0 && id <= MAX_SESSIONS)
_session_ids[id-1]->dec();
}
::Root::Root(Env & env, Allocator & alloc, Signal_context_capability cap) ::Root::Root(Env & env, Allocator & alloc, Signal_context_capability cap)
: :
Root_component<genode_usb_session>(env.ep(), alloc), Root_component<genode_usb_session>(env.ep(), alloc),
_env(env), _sigh_cap(cap) _env(env), _sigh_cap(cap)
{ {
/* Reserve id zero which is invalid */ /* Reserve id zero which is invalid */
_id_alloc.alloc(); for (unsigned i = 0; i < MAX_SESSIONS; i++)
_session_ids[i].construct((genode_usb_session_handle_t)(i+1));
_config.sigh(_config_handler); _config.sigh(_config_handler);
} }
@ -896,6 +927,8 @@ extern "C" void genode_usb_ack_request(genode_usb_session_handle_t session_id,
_usb_root->session(session_id, [&] (genode_usb_session & session) { _usb_root->session(session_id, [&] (genode_usb_session & session) {
session.handle_response(request_id, callback, callback_data); }); session.handle_response(request_id, callback, callback_data); });
_usb_root->decrement_session_id(session_id);
} }