dde_linux: preserve Io_signal_handler for IRQs

Do not construct/destruct signal handlers for interrupts dynamically,
but only the Irq session to prevent a deadlock.

Fix #4272
This commit is contained in:
Stefan Kalkowski 2021-09-29 16:32:47 +02:00 committed by Norman Feske
parent 6ae55d490b
commit f4cb5cc299
3 changed files with 37 additions and 55 deletions

View File

@ -59,39 +59,19 @@ class Lx_kit::Device : List<Device>::Element
: idx{idx}, addr(addr), size(size) {} : idx{idx}, addr(addr), size(size) {}
}; };
struct Irq_handler
{
private:
Irq_handler(Irq_handler const &);
Irq_handler &operator = (Irq_handler const &);
Platform::Device::Irq _irq;
Io_signal_handler<Irq_handler> _handler;
unsigned _number;
void _handle();
public:
Irq_handler(Platform::Device & dev,
Platform::Device::Irq::Index idx,
unsigned number);
void ack() { _irq.ack(); }
};
struct Irq : List<Irq>::Element struct Irq : List<Irq>::Element
{ {
using Index = Platform::Device::Irq::Index; using Index = Platform::Device::Irq::Index;
Index idx; Index idx;
unsigned number; unsigned number;
Io_signal_handler<Irq> handler;
Constructible<Irq_handler> handler {}; Constructible<Platform::Device::Irq> session {};
Irq(unsigned idx, unsigned number) Irq(Entrypoint & ep, unsigned idx, unsigned number);
: idx{idx}, number(number) {}
void handle();
}; };
struct Clock : List<Clock>::Element struct Clock : List<Clock>::Element
@ -104,7 +84,8 @@ class Lx_kit::Device : List<Device>::Element
: idx(idx), name(name), lx_clock{0} {} : idx(idx), name(name), lx_clock{0} {}
}; };
Device(Platform::Connection & plat, Device(Entrypoint & ep,
Platform::Connection & plat,
Xml_node & xml, Xml_node & xml,
Heap & heap); Heap & heap);
@ -156,7 +137,9 @@ class Lx_kit::Device_list : List<Device>
void for_each(FN const & fn) { void for_each(FN const & fn) {
for (Device * d = first(); d; d = d->next()) fn(*d); } for (Device * d = first(); d; d = d->next()) fn(*d); }
Device_list(Heap & heap, Platform::Connection & platform); Device_list(Entrypoint & ep,
Heap & heap,
Platform::Connection & platform);
}; };
#endif /* _LX_KIT__DEVICE_H_ */ #endif /* _LX_KIT__DEVICE_H_ */

View File

@ -48,7 +48,7 @@ struct Lx_kit::Env
Mem_allocator memory { env, heap, platform, CACHED }; Mem_allocator memory { env, heap, platform, CACHED };
Mem_allocator uncached_memory { env, heap, platform, UNCACHED }; Mem_allocator uncached_memory { env, heap, platform, UNCACHED };
Scheduler scheduler { }; Scheduler scheduler { };
Device_list devices { heap, platform }; Device_list devices { env.ep(), heap, platform };
Lx_kit::Timeout timeout { timer, scheduler }; Lx_kit::Timeout timeout { timer, scheduler };
unsigned int last_irq { 0 }; unsigned int last_irq { 0 };

View File

@ -27,29 +27,23 @@ bool Device::Io_mem::match(addr_t addr, size_t size)
} }
/************************* /****************
** Device::Irq_handler ** ** Device::Irq**
*************************/ ****************/
void Device::Irq_handler::_handle() void Device::Irq::handle()
{ {
env().last_irq = _number; env().last_irq = number;
env().scheduler.unblock_irq_handler(); env().scheduler.unblock_irq_handler();
env().scheduler.schedule(); env().scheduler.schedule();
} }
Device::Irq_handler::Irq_handler(Platform::Device & dev, Device::Irq::Irq(Entrypoint & ep, unsigned idx, unsigned number)
Platform::Device::Irq::Index idx,
unsigned number)
: :
_irq(dev, idx), idx{idx},
_handler(Lx_kit::env().env.ep(), *this, &Irq_handler::_handle), number(number),
_number(number) handler(ep, *this, &Irq::handle) { }
{
_irq.sigh_omit_initial_signal(_handler);
_irq.ack();
}
/************ /************
@ -132,13 +126,15 @@ bool Device::irq_unmask(unsigned number)
if (irq.number != number) if (irq.number != number)
return; return;
ret = true;
enable(); enable();
if (irq.handler.constructed()) if (irq.session.constructed())
return; return;
irq.handler.construct(*_pdev, irq.idx, number); irq.session.construct(*_pdev, irq.idx);
ret = true; irq.session->sigh_omit_initial_signal(irq.handler);
irq.session->ack();
}); });
return ret; return ret;
@ -153,7 +149,7 @@ void Device::irq_mask(unsigned number)
_for_each_irq([&] (Irq & irq) { _for_each_irq([&] (Irq & irq) {
if (irq.number != number) if (irq.number != number)
return; return;
irq.handler.destruct(); irq.session.destruct();
}); });
} }
@ -165,9 +161,9 @@ void Device::irq_ack(unsigned number)
return; return;
_for_each_irq([&] (Irq & irq) { _for_each_irq([&] (Irq & irq) {
if (irq.number != number) if (irq.number != number || !irq.session.constructed())
return; return;
irq.handler->ack(); irq.session->ack();
}); });
} }
@ -196,7 +192,8 @@ void Device::enable()
} }
Device::Device(Platform::Connection & plat, Device::Device(Entrypoint & ep,
Platform::Connection & plat,
Xml_node & xml, Xml_node & xml,
Heap & heap) Heap & heap)
: :
@ -213,7 +210,7 @@ Device::Device(Platform::Connection & plat,
i = 0; i = 0;
xml.for_each_sub_node("irq", [&] (Xml_node node) { xml.for_each_sub_node("irq", [&] (Xml_node node) {
_irqs.insert(new (heap) Irq(i++, node.attribute_value("number", 0U))); _irqs.insert(new (heap) Irq(ep, i++, node.attribute_value("number", 0U)));
}); });
i = 0; i = 0;
@ -228,13 +225,15 @@ Device::Device(Platform::Connection & plat,
** Device_list ** ** Device_list **
*****************/ *****************/
Device_list::Device_list(Heap & heap, Platform::Connection & platform) Device_list::Device_list(Entrypoint & ep,
Heap & heap,
Platform::Connection & platform)
: :
_platform(platform) _platform(platform)
{ {
_platform.with_xml([&] (Xml_node & xml) { _platform.with_xml([&] (Xml_node & xml) {
xml.for_each_sub_node("device", [&] (Xml_node node) { xml.for_each_sub_node("device", [&] (Xml_node node) {
insert(new (heap) Device(_platform, node, heap)); insert(new (heap) Device(ep, _platform, node, heap));
}); });
}); });
} }