libcamera: event_dispatcher: Add interrupt() function
The new interrupt() function allows interrupting in-progress blocking processEvents() calls. This is useful to stop running event loops. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
This commit is contained in:
parent
d370c1b46e
commit
4d470eb37f
4 changed files with 46 additions and 1 deletions
|
@ -26,6 +26,8 @@ public:
|
||||||
virtual void unregisterTimer(Timer *timer) = 0;
|
virtual void unregisterTimer(Timer *timer) = 0;
|
||||||
|
|
||||||
virtual void processEvents() = 0;
|
virtual void processEvents() = 0;
|
||||||
|
|
||||||
|
virtual void interrupt() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace libcamera */
|
} /* namespace libcamera */
|
||||||
|
|
|
@ -104,4 +104,14 @@ EventDispatcher::~EventDispatcher()
|
||||||
* it before returning.
|
* it before returning.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \fn EventDispatcher::interrupt()
|
||||||
|
* \brief Interrupt any running processEvents() call as soon as possible
|
||||||
|
*
|
||||||
|
* Calling this function interrupts any blocking processEvents() call in
|
||||||
|
* progress. The processEvents() function will return as soon as possible,
|
||||||
|
* after processing pending timers and events. If processEvents() isn't in
|
||||||
|
* progress, it will be interrupted immediately the next time it gets called.
|
||||||
|
*/
|
||||||
|
|
||||||
} /* namespace libcamera */
|
} /* namespace libcamera */
|
||||||
|
|
|
@ -8,7 +8,10 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/eventfd.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <libcamera/event_notifier.h>
|
#include <libcamera/event_notifier.h>
|
||||||
#include <libcamera/timer.h>
|
#include <libcamera/timer.h>
|
||||||
|
@ -43,10 +46,18 @@ static const char *notifierType(EventNotifier::Type type)
|
||||||
|
|
||||||
EventDispatcherPoll::EventDispatcherPoll()
|
EventDispatcherPoll::EventDispatcherPoll()
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Create the event fd. Failures are fatal as we can't implement an
|
||||||
|
* interruptible dispatcher without the fd.
|
||||||
|
*/
|
||||||
|
eventfd_ = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
|
||||||
|
if (eventfd_ < 0)
|
||||||
|
LOG(Event, Fatal) << "Unable to create eventfd";
|
||||||
}
|
}
|
||||||
|
|
||||||
EventDispatcherPoll::~EventDispatcherPoll()
|
EventDispatcherPoll::~EventDispatcherPoll()
|
||||||
{
|
{
|
||||||
|
close(eventfd_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventDispatcherPoll::registerEventNotifier(EventNotifier *notifier)
|
void EventDispatcherPoll::registerEventNotifier(EventNotifier *notifier)
|
||||||
|
@ -123,11 +134,13 @@ void EventDispatcherPoll::processEvents()
|
||||||
|
|
||||||
/* Create the pollfd array. */
|
/* Create the pollfd array. */
|
||||||
std::vector<struct pollfd> pollfds;
|
std::vector<struct pollfd> pollfds;
|
||||||
pollfds.reserve(notifiers_.size());
|
pollfds.reserve(notifiers_.size() + 1);
|
||||||
|
|
||||||
for (auto notifier : notifiers_)
|
for (auto notifier : notifiers_)
|
||||||
pollfds.push_back({ notifier.first, notifier.second.events(), 0 });
|
pollfds.push_back({ notifier.first, notifier.second.events(), 0 });
|
||||||
|
|
||||||
|
pollfds.push_back({ eventfd_, POLLIN, 0 });
|
||||||
|
|
||||||
/* Wait for events and process notifiers and timers. */
|
/* Wait for events and process notifiers and timers. */
|
||||||
do {
|
do {
|
||||||
ret = poll(&pollfds);
|
ret = poll(&pollfds);
|
||||||
|
@ -137,12 +150,20 @@ void EventDispatcherPoll::processEvents()
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
LOG(Event, Warning) << "poll() failed with " << strerror(-ret);
|
LOG(Event, Warning) << "poll() failed with " << strerror(-ret);
|
||||||
} else if (ret > 0) {
|
} else if (ret > 0) {
|
||||||
|
processInterrupt(pollfds.back());
|
||||||
|
pollfds.pop_back();
|
||||||
processNotifiers(pollfds);
|
processNotifiers(pollfds);
|
||||||
}
|
}
|
||||||
|
|
||||||
processTimers();
|
processTimers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EventDispatcherPoll::interrupt()
|
||||||
|
{
|
||||||
|
uint64_t value = 1;
|
||||||
|
write(eventfd_, &value, sizeof(value));
|
||||||
|
}
|
||||||
|
|
||||||
short EventDispatcherPoll::EventNotifierSetPoll::events() const
|
short EventDispatcherPoll::EventNotifierSetPoll::events() const
|
||||||
{
|
{
|
||||||
short events = 0;
|
short events = 0;
|
||||||
|
@ -186,6 +207,15 @@ int EventDispatcherPoll::poll(std::vector<struct pollfd> *pollfds)
|
||||||
nextTimer ? &timeout : nullptr, nullptr);
|
nextTimer ? &timeout : nullptr, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EventDispatcherPoll::processInterrupt(const struct pollfd &pfd)
|
||||||
|
{
|
||||||
|
if (!pfd.revents & POLLIN)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint64_t value;
|
||||||
|
read(eventfd_, &value, sizeof(value));
|
||||||
|
}
|
||||||
|
|
||||||
void EventDispatcherPoll::processNotifiers(const std::vector<struct pollfd> &pollfds)
|
void EventDispatcherPoll::processNotifiers(const std::vector<struct pollfd> &pollfds)
|
||||||
{
|
{
|
||||||
static const struct {
|
static const struct {
|
||||||
|
|
|
@ -31,6 +31,7 @@ public:
|
||||||
void unregisterTimer(Timer *timer);
|
void unregisterTimer(Timer *timer);
|
||||||
|
|
||||||
void processEvents();
|
void processEvents();
|
||||||
|
void interrupt();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct EventNotifierSetPoll {
|
struct EventNotifierSetPoll {
|
||||||
|
@ -40,8 +41,10 @@ private:
|
||||||
|
|
||||||
std::map<int, EventNotifierSetPoll> notifiers_;
|
std::map<int, EventNotifierSetPoll> notifiers_;
|
||||||
std::list<Timer *> timers_;
|
std::list<Timer *> timers_;
|
||||||
|
int eventfd_;
|
||||||
|
|
||||||
int poll(std::vector<struct pollfd> *pollfds);
|
int poll(std::vector<struct pollfd> *pollfds);
|
||||||
|
void processInterrupt(const struct pollfd &pfd);
|
||||||
void processNotifiers(const std::vector<struct pollfd> &pollfds);
|
void processNotifiers(const std::vector<struct pollfd> &pollfds);
|
||||||
void processTimers();
|
void processTimers();
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue