[libcamera-devel] [PATCH 2/4] libcamera: event_dispatcher_poll: Handle interrupted ppoll() calls

Laurent Pinchart laurent.pinchart at ideasonboard.com
Wed Jan 23 17:43:38 CET 2019


Hi Kieran,

On Wed, Jan 23, 2019 at 11:30:25AM +0000, Kieran Bingham wrote:
> On 23/01/2019 08:59, Laurent Pinchart wrote:
> > The ppoll() call can be interrupted if a signal is delivered. Handle the
> > EINTR error code gracefully by restarting the call. This fixes the
> > event-dispatcher test failure.
> 
> Two discussion points below - but otherwise:
> 
> Reviewed-by: Kieran Bingham <kieran.bingham at ideasonboard.com>
> 
> > Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> > ---
> >  src/libcamera/event_dispatcher_poll.cpp       | 58 +++++++++++--------
> >  src/libcamera/include/event_dispatcher_poll.h |  1 +
> >  2 files changed, 34 insertions(+), 25 deletions(-)
> > 
> > diff --git a/src/libcamera/event_dispatcher_poll.cpp b/src/libcamera/event_dispatcher_poll.cpp
> > index eefac54ca6da..6e0609c34ddc 100644
> > --- a/src/libcamera/event_dispatcher_poll.cpp
> > +++ b/src/libcamera/event_dispatcher_poll.cpp
> > @@ -128,32 +128,11 @@ void EventDispatcherPoll::processEvents()
> >  	for (auto notifier : notifiers_)
> >  		pollfds.push_back({ notifier.first, notifier.second.events(), 0 });
> >  
> > -	/* Compute the timeout. */
> > -	Timer *nextTimer = !timers_.empty() ? timers_.front() : nullptr;
> > -	struct timespec timeout;
> > -
> > -	if (nextTimer) {
> > -		clock_gettime(CLOCK_MONOTONIC, &timeout);
> > -		uint64_t now = timeout.tv_sec * 1000000000ULL + timeout.tv_nsec;
> > -
> > -		if (nextTimer->deadline() > now) {
> > -			uint64_t delta = nextTimer->deadline() - now;
> > -			timeout.tv_sec = delta / 1000000000ULL;
> > -			timeout.tv_nsec = delta % 1000000000ULL;
> > -		} else {
> > -			timeout.tv_sec = 0;
> > -			timeout.tv_nsec = 0;
> > -		}
> > -
> > -		LOG(Event, Debug)
> > -			<< "timeout " << timeout.tv_sec << "."
> > -			<< std::setfill('0') << std::setw(9)
> > -			<< timeout.tv_nsec;
> > -	}
> > -
> >  	/* Wait for events and process notifiers and timers. */
> > -	ret = ppoll(pollfds.data(), pollfds.size(),
> > -		    nextTimer ? &timeout : nullptr, nullptr);
> > +	do {
> > +		ret = poll(&pollfds);
> 
> Eeep - you almost caught me here ... :
> 
> 	int poll(struct pollfd *fds, nfds_t nfds, int timeout);
> 
> No problem conflicting with the std library namespace I hope?

No, the compiler will pick the right one, and if me ever need to call
the libc function, we can write ::poll().

> > +	} while (ret == -1 && errno == EINTR);
> > +
> >  	if (ret < 0) {
> >  		ret = -errno;
> >  		LOG(Event, Warning) << "poll() failed with " << strerror(-ret);
> > @@ -178,6 +157,35 @@ short EventDispatcherPoll::EventNotifierSetPoll::events() const
> >  	return events;
> >  }
> >  
> > +int EventDispatcherPoll::poll(std::vector<struct pollfd> *pollfds)
> > +{
> > +	/* Compute the timeout. */
> > +	Timer *nextTimer = !timers_.empty() ? timers_.front() : nullptr;
> > +	struct timespec timeout;
> > +
> > +	if (nextTimer) {
> > +		clock_gettime(CLOCK_MONOTONIC, &timeout);
> > +		uint64_t now = timeout.tv_sec * 1000000000ULL + timeout.tv_nsec;
> > +
> > +		if (nextTimer->deadline() > now) {
> > +			uint64_t delta = nextTimer->deadline() - now;
> > +			timeout.tv_sec = delta / 1000000000ULL;
> > +			timeout.tv_nsec = delta % 1000000000ULL;
> > +		} else {
> > +			timeout.tv_sec = 0;
> > +			timeout.tv_nsec = 0;
> > +		}
> > +
> > +		LOG(Event, Debug)
> > +			<< "timeout " << timeout.tv_sec << "."
> > +			<< std::setfill('0') << std::setw(9)
> > +			<< timeout.tv_nsec;
> > +	}
> > +
> > +	return ppoll(pollfds->data(), pollfds->size(),
> > +		     nextTimer ? &timeout : nullptr, nullptr);
> 
> I see comparisons (particularly from a table in Michael Kerrisk's kernel
> interface book) looking at how epoll is much better than poll/select
> when there are more than about 10 fds to consider...
> 
> I wonder how many FDs we'll end up monitoring in our event code...
> Especially as external code will likely use our event loop.
> 
> One day it might be worth looking at the comparisons, but I don't think
> today is that day.

That's a good point. Out of scope for this patch as you mentioned, but a
good point. If someone wants to have a good, be my guest :-)

> > +}
> > +
> >  void EventDispatcherPoll::processNotifiers(const std::vector<struct pollfd> &pollfds)
> >  {
> >  	static const struct {
> > diff --git a/src/libcamera/include/event_dispatcher_poll.h b/src/libcamera/include/event_dispatcher_poll.h
> > index a41926e11a11..ac3efde082b4 100644
> > --- a/src/libcamera/include/event_dispatcher_poll.h
> > +++ b/src/libcamera/include/event_dispatcher_poll.h
> > @@ -41,6 +41,7 @@ private:
> >  	std::map<int, EventNotifierSetPoll> notifiers_;
> >  	std::list<Timer *> timers_;
> >  
> > +	int poll(std::vector<struct pollfd> *pollfds);
> >  	void processNotifiers(const std::vector<struct pollfd> &pollfds);
> >  	void processTimers();
> >  };

-- 
Regards,

Laurent Pinchart


More information about the libcamera-devel mailing list