[libcamera-devel] [PATCH v2 06/11] libcamera: Add event notification infrastructure
Jacopo Mondi
jacopo at jmondi.org
Tue Jan 8 10:43:43 CET 2019
Hi Laurent,
a few minor things on comments, otherwise
Reviewed-by: Jacopo Mondi <jacopo at jmondi.org>
On Tue, Jan 08, 2019 at 01:11:46AM +0200, Laurent Pinchart wrote:
> Add three new classes, EventDispatcher, EventNotifier and Timer, that
> define APIs for file descriptor event notification and timers. The
> implementation of the EventDispatcher is meant to be provided to
> libcamera by the application.
>
> The event dispatcher is integrated twith the camera manager to implement
> automatic registration of timers and events.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> Reviewed-by: Niklas Söderlund <niklas.soderlund at ragnatech.se>
> ---
> Changes since v1:
>
> - Rename EventNotifier::isEnabled() to EventNotifier::enabled()
> - Fix typo in documentation
> ---
> include/libcamera/camera_manager.h | 7 ++
> include/libcamera/event_dispatcher.h | 33 ++++++++
> include/libcamera/event_notifier.h | 42 ++++++++++
> include/libcamera/libcamera.h | 1 +
> include/libcamera/meson.build | 3 +
> include/libcamera/timer.h | 37 ++++++++
> src/libcamera/camera_manager.cpp | 42 +++++++++-
> src/libcamera/event_dispatcher.cpp | 103 +++++++++++++++++++++++
> src/libcamera/event_notifier.cpp | 121 +++++++++++++++++++++++++++
> src/libcamera/meson.build | 3 +
> src/libcamera/timer.cpp | 105 +++++++++++++++++++++++
> 11 files changed, 496 insertions(+), 1 deletion(-)
> create mode 100644 include/libcamera/event_dispatcher.h
> create mode 100644 include/libcamera/event_notifier.h
> create mode 100644 include/libcamera/timer.h
> create mode 100644 src/libcamera/event_dispatcher.cpp
> create mode 100644 src/libcamera/event_notifier.cpp
> create mode 100644 src/libcamera/timer.cpp
>
> diff --git a/include/libcamera/camera_manager.h b/include/libcamera/camera_manager.h
> index e14da0f893b3..15e7c162032a 100644
> --- a/include/libcamera/camera_manager.h
> +++ b/include/libcamera/camera_manager.h
> @@ -14,6 +14,7 @@ namespace libcamera {
>
> class Camera;
> class DeviceEnumerator;
> +class EventDispatcher;
> class PipelineHandler;
>
> class CameraManager
> @@ -27,13 +28,19 @@ public:
>
> static CameraManager *instance();
>
> + void setEventDispatcher(EventDispatcher *dispatcher);
> + EventDispatcher *eventDispatcher();
> +
> private:
> CameraManager();
> CameraManager(const CameraManager &) = delete;
> void operator=(const CameraManager &) = delete;
> + ~CameraManager();
>
> DeviceEnumerator *enumerator_;
> std::vector<PipelineHandler *> pipes_;
> +
> + EventDispatcher *dispatcher_;
> };
>
> } /* namespace libcamera */
> diff --git a/include/libcamera/event_dispatcher.h b/include/libcamera/event_dispatcher.h
> new file mode 100644
> index 000000000000..c20518c6866d
> --- /dev/null
> +++ b/include/libcamera/event_dispatcher.h
> @@ -0,0 +1,33 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2019, Google Inc.
> + *
> + * event_dispatcher.h - Event dispatcher
> + */
> +#ifndef __LIBCAMERA_EVENT_DISPATCHER_H__
> +#define __LIBCAMERA_EVENT_DISPATCHER_H__
> +
> +#include <vector>
> +
> +namespace libcamera {
> +
> +class EventNotifier;
> +class Timer;
> +
> +class EventDispatcher
> +{
> +public:
> + virtual ~EventDispatcher();
> +
> + virtual void registerEventNotifier(EventNotifier *notifier) = 0;
> + virtual void unregisterEventNotifier(EventNotifier *notifier) = 0;
> +
> + virtual void registerTimer(Timer *timer) = 0;
> + virtual void unregisterTimer(Timer *timer) = 0;
> +
> + virtual void processEvents() = 0;
> +};
> +
> +} /* namespace libcamera */
> +
> +#endif /* __LIBCAMERA_EVENT_DISPATCHER_H__ */
> diff --git a/include/libcamera/event_notifier.h b/include/libcamera/event_notifier.h
> new file mode 100644
> index 000000000000..1e9b6da1340c
> --- /dev/null
> +++ b/include/libcamera/event_notifier.h
> @@ -0,0 +1,42 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2019, Google Inc.
> + *
> + * event_notifier.h - File descriptor event notifier
> + */
> +#ifndef __LIBCAMERA_EVENT_NOTIFIER_H__
> +#define __LIBCAMERA_EVENT_NOTIFIER_H__
> +
> +#include <libcamera/signal.h>
> +
> +namespace libcamera {
> +
> +class EventNotifier
> +{
> +public:
> + enum Type {
> + Read,
> + Write,
> + Exception,
> + };
> +
> + EventNotifier(int fd, Type type);
> + virtual ~EventNotifier();
> +
> + Type type() const { return type_; }
> + int fd() const { return fd_; }
> +
> + bool enabled() const { return enabled_; }
> + void setEnabled(bool enable);
> +
> + Signal<EventNotifier *> activated;
> +
> +private:
> + int fd_;
> + Type type_;
> + bool enabled_;
> +};
> +
> +} /* namespace libcamera */
> +
> +#endif /* __LIBCAMERA_EVENT_NOTIFIER_H__ */
> diff --git a/include/libcamera/libcamera.h b/include/libcamera/libcamera.h
> index f9556a8bce62..785babefa1c8 100644
> --- a/include/libcamera/libcamera.h
> +++ b/include/libcamera/libcamera.h
> @@ -9,5 +9,6 @@
>
> #include <libcamera/camera.h>
> #include <libcamera/camera_manager.h>
> +#include <libcamera/event_dispatcher.h>
>
> #endif /* __LIBCAMERA_LIBCAMERA_H__ */
> diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
> index 6f87689ea528..d7cb55ba4a49 100644
> --- a/include/libcamera/meson.build
> +++ b/include/libcamera/meson.build
> @@ -1,8 +1,11 @@
> libcamera_api = files([
> 'camera.h',
> 'camera_manager.h',
> + 'event_dispatcher.h',
> + 'event_notifier.h',
> 'libcamera.h',
> 'signal.h',
> + 'timer.h',
> ])
>
> install_headers(libcamera_api,
> diff --git a/include/libcamera/timer.h b/include/libcamera/timer.h
> new file mode 100644
> index 000000000000..97dcc01f493d
> --- /dev/null
> +++ b/include/libcamera/timer.h
> @@ -0,0 +1,37 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2019, Google Inc.
> + *
> + * timer.h - Generic timer
> + */
> +#ifndef __LIBCAMERA_TIMER_H__
> +#define __LIBCAMERA_TIMER_H__
> +
> +#include <cstdint>
> +
> +#include <libcamera/signal.h>
> +
> +namespace libcamera {
> +
> +class Timer
> +{
> +public:
> + Timer();
> +
> + void start(unsigned int msec);
> + void stop();
> + bool isRunning() const;
> +
> + unsigned int interval() const { return interval_; }
> + uint64_t deadline() const { return deadline_; }
> +
> + Signal<Timer *> timeout;
> +
> +private:
> + unsigned int interval_;
> + uint64_t deadline_;
> +};
> +
> +} /* namespace libcamera */
> +
> +#endif /* __LIBCAMERA_TIMER_H__ */
> diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp
> index 1a9d2f38e3b9..cbfd977f1e3c 100644
> --- a/src/libcamera/camera_manager.cpp
> +++ b/src/libcamera/camera_manager.cpp
> @@ -6,8 +6,10 @@
> */
>
> #include <libcamera/camera_manager.h>
> +#include <libcamera/event_dispatcher.h>
>
> #include "device_enumerator.h"
> +#include "log.h"
> #include "pipeline_handler.h"
>
> /**
> @@ -37,10 +39,15 @@
> namespace libcamera {
>
> CameraManager::CameraManager()
> - : enumerator_(nullptr)
> + : enumerator_(nullptr), dispatcher_(nullptr)
> {
> }
>
> +CameraManager::~CameraManager()
> +{
> + delete dispatcher_;
> +}
> +
> /**
> * \brief Start the camera manager
> *
> @@ -176,4 +183,37 @@ CameraManager *CameraManager::instance()
> return &manager;
> }
>
> +/**
> + * \brief Set the event dispatcher
> + * \param dispatcher Pointer to the event dispatcher
> + *
> + * libcamera requires an event dispatcher to integrate event notification and
> + * timers with the application event loop. Applications shall call this function
> + * once and only once before the camera manager is started with start() to set
> + * the event dispatcher.
> + *
> + * The CameraManager takes ownership of the event dispatcher and will delete it
> + * when the application terminates.
> + */
> +void CameraManager::setEventDispatcher(EventDispatcher *dispatcher)
> +{
> + if (dispatcher_) {
> + LOG(Warning) << "Event dispatcher is already set";
> + return;
> + }
> +
> + dispatcher_ = dispatcher;
> +}
> +
> +/**
> + * \fn CameraManager::eventDispatcher()
Not needed, as the comment applies to the function just after the
comment block.
> + * \brief Retrieve the event dispatcher
> + * \return Pointer to the event dispatcher, or nullptr if no event dispatcher
> + * has been set
> + */
> +EventDispatcher *CameraManager::eventDispatcher()
> +{
> + return dispatcher_;
> +}
> +
> } /* namespace libcamera */
> diff --git a/src/libcamera/event_dispatcher.cpp b/src/libcamera/event_dispatcher.cpp
> new file mode 100644
> index 000000000000..b893ab046985
> --- /dev/null
> +++ b/src/libcamera/event_dispatcher.cpp
> @@ -0,0 +1,103 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2019, Google Inc.
> + *
> + * event_dispatcher.cpp - Event dispatcher
> + */
> +
> +#include <libcamera/event_dispatcher.h>
> +
> +/**
> + * \file event_dispatcher.h
> + */
> +
> +namespace libcamera {
> +
> +/**
> + * \class EventDispatcher
> + * \brief Interface to manage the libcamera events and timers
> + *
> + * The EventDispatcher class allows the integration of the application event
> + * loop with libcamera by abstracting how events and timers are managed and
> + * processed.
> + *
> + * To listen to events, libcamera creates EventNotifier instances and register
s/register/registers ?
> + * them with the dispatcher with registerEventNotifier(). The event notifier
> + * \ref EventNotifier::activated signal is then emitted by the dispatcher
> + * whenever the event is detected.
> + *
> + * To set timers, libcamera creates Timer instances and register them with the
s/register/registers ?
> + * dispatcher with registerTimer(). The timer \ref Timer::timeout signal is then
> + * emitted by the dispatcher when the timer times out.
> + */
> +
> +EventDispatcher::~EventDispatcher()
> +{
> +}
> +
> +/**
> + * \fn EventDispatcher::registerEventNotifier()
> + * \brief Register an event notifier
> + * \param notifier The event notifier to register
> + *
> + * Once the \a notifier is registered with the dispatcher, the dispatcher will
> + * emit the notifier \ref EventNotifier::activated signal whenever a
> + * corresponding event is detected on the notifier's file descriptor. The event
> + * is monitored until the notifier is unregistered with
> + * unregisterEventNotifier().
> + *
> + * Registering multiple notifiers for the same file descriptor and event type is
> + * not allowed and results in undefined behaviour.
> + */
> +
> +/**
> + * \fn EventDispatcher::unregisterEventNotifier()
> + * \brief Unregister an event notifier
> + * \param notifier The event notifier to unregister
> + *
> + * After this function returns the \a notifier is guaranteed not to emit the
> + * \ref EventNotifier::activated signal.
> + *
> + * If the notifier isn't registered, this function performs no operation.
> + */
> +
> +/**
> + * \fn EventDispatcher::registerTimer()
> + * \brief Register a timer
> + * \param timer The timer to register
> + *
> + * Once the \a timer is registered with the dispatcher, the dispatcher will emit
> + * the timer \ref Timer::timeout signal when the timer times out. The timer can
> + * be unregistered with unregisterTimer() before it times out, in which case the
> + * signal will not be emitted.
> + *
> + * When the \a timer times out, it is automatically unregistered by the
> + * dispatcher and can be registered back as early as from the \ref Timer::timeout
> + * signal handlers.
> + *
> + * Registering the same timer multiple times is not allowed and results in
> + * undefined behaviour.
> + */
> +
> +/**
> + * \fn EventDispatcher::unregisterTimer()
> + * \brief Unregister a timer
> + * \param timer The timer to unregister
> + *
> + * After this function returns the \a timer is guaranteed not to emit the
> + * \ref Timer::timeout signal.
> + *
> + * If the timer isn't registered, this function performs no operation.
> + */
> +
> +/**
> + * \fn EventDispatcher::processEvents()
> + * \brief Wait for and process pending events
> + *
> + * This function processes all pending events associated with registered event
> + * notifiers and timers and signals the corresponding EventNotifier and Timer
> + * objects. If no events are pending, it waits for the first event and processes
> + * it before returning.
> + */
> +
> +} /* namespace libcamera */
> diff --git a/src/libcamera/event_notifier.cpp b/src/libcamera/event_notifier.cpp
> new file mode 100644
> index 000000000000..8dc45a546a11
> --- /dev/null
> +++ b/src/libcamera/event_notifier.cpp
> @@ -0,0 +1,121 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2019, Google Inc.
> + *
> + * event_notifier.cpp - File descriptor event notifier
> + */
> +
> +#include <libcamera/camera_manager.h>
> +#include <libcamera/event_dispatcher.h>
> +#include <libcamera/event_notifier.h>
> +
> +/**
> + * \file event_notifier.h
> + * \brief Event notifier
Event notifier for file descriptor events ?
> + */
> +
> +namespace libcamera {
> +
> +/**
> + * \class EventNotifier
> + * \brief Notify of activity on a file descriptor
> + *
> + * The EventNotifier models a file descriptor event source that can be
> + * monitored. It is created with the file descriptor to be monitored and the
> + * type of event, and is enabled by default. It will emit the \ref activated
> + * signal whenever an event of the monitored type occurs on the file descriptor.
> + *
> + * Supported type of events are EventNotifier::Read, EventNotifier::Write and
> + * EventNotifier::Exception. The type is specified when constructing the
> + * notifier, and can be retrieved using the type() function. To listen to
> + * multiple event types on the same file descriptor multiple notifiers must be
> + * created.
> + *
> + * The notifier can be disabled with the setEnable() function. When the notifier
> + * is disabled it ignores events and does not emit the \ref activated signal.
> + * The notifier can then be re-enabled with the setEnable() function.
> + *
> + * Creating multiple notifiers of the same type for the same file descriptor is
> + * not allowed and results in undefined behaviour.
> + *
> + * Notifier events are detected and dispatched from the
> + * EventDispatcher::processEvents() function.
> + */
> +
> +/**
> + * \enum EventNotifier::Type
> + * Type of file descriptor event to listen for.
> + * \var EventNotifier::Read
> + * Data is available to be read from the file descriptor
> + * \var EventNotifier::Write
> + * Data can be written to the file descriptor
> + * \var EventNotifier::Exception
> + * An exception has occurred on the file descriptor
> + */
> +
> +/**
> + * \brief Construct an event notifier with a file descriptor and event type
> + * \param fd The file descriptor to monitor
> + * \param type The event type to monitor
> + */
> +EventNotifier::EventNotifier(int fd, Type type)
> + : fd_(fd), type_(type), enabled_(false)
> +{
> + setEnabled(true);
> +}
> +
> +EventNotifier::~EventNotifier()
> +{
> + setEnabled(false);
> +}
> +
> +/**
> + * \fn EventNotifier::type()
> + * \brief Retrive the type of the event being monitored
> + * \return The type of the event
> + */
> +
> +/**
> + * \fn EventNotifier::fd()
> + * \brief Retrive the file descriptor being monitored
> + * \return The file descriptor
> + */
> +
> +/**
> + * \fn EventNotifier::enabled()
> + * \brief Retrieve the notifier state
> + * \return true if the notifier is enabled, or false otherwise
s/true/True ?
> + * \sa setEnable()
> + */
> +
> +/**
> + * \brief Enable or disable the notifier
> + * \param enable true to enable the notifier, false to disable it
s/true/True ?
> + *
> + * This function enables or disables the notifier. A disabled notifier ignores
> + * events and does not emit the \ref activated signal.
> + */
> +void EventNotifier::setEnabled(bool enable)
> +{
> + if (enabled_ == enable)
> + return;
> +
> + enabled_ = enable;
> +
> + EventDispatcher *dispatcher = CameraManager::instance()->eventDispatcher();
> + if (enable)
> + dispatcher->registerEventNotifier(this);
> + else
> + dispatcher->unregisterEventNotifier(this);
> +}
> +
> +/**
> + * \var EventNotifier::activated
> + * \brief Signal emitted when the event occurs
> + *
> + * This signal is emitted when the event \ref type() occurs on the file
> + * descriptor monitored by the notifier. The notifier pointer is passed as a
> + * parameter.
> + */
> +
> +} /* namespace libcamera */
> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
> index 3ec86e75b57e..61fb93205b34 100644
> --- a/src/libcamera/meson.build
> +++ b/src/libcamera/meson.build
> @@ -2,11 +2,14 @@ libcamera_sources = files([
> 'camera.cpp',
> 'camera_manager.cpp',
> 'device_enumerator.cpp',
> + 'event_dispatcher.cpp',
> + 'event_notifier.cpp',
> 'log.cpp',
> 'media_device.cpp',
> 'media_object.cpp',
> 'pipeline_handler.cpp',
> 'signal.cpp',
> + 'timer.cpp',
> ])
>
> libcamera_headers = files([
> diff --git a/src/libcamera/timer.cpp b/src/libcamera/timer.cpp
> new file mode 100644
> index 000000000000..57c49aa2ef36
> --- /dev/null
> +++ b/src/libcamera/timer.cpp
> @@ -0,0 +1,105 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2019, Google Inc.
> + *
> + * timer.cpp - Generic timer
> + */
> +
> +#include <time.h>
> +
> +#include <libcamera/camera_manager.h>
> +#include <libcamera/event_dispatcher.h>
> +#include <libcamera/timer.h>
> +
> +#include "log.h"
> +
> +/**
> + * \file timer.h
> + * \brief Generic timer
> + */
> +
> +namespace libcamera {
> +
> +/**
> + * \class Timer
> + * \brief Single-shot timer interface
> + *
> + * The Timer class models a single-shot timer that is started with start() and
> + * emits the \ref timeout signal when it times out.
> + *
> + * Once started the timer will run until it times out. It can be stopped with
> + * stop(), and once it times out or is stopped, can be started again with
> + * start().
> + */
> +
> +/**
> + * \brief Construct a timer
> + */
> +Timer::Timer()
> +{
> +}
> +
> +/**
> + * \brief Start or restart the timer with a timeout of \a msec
> + * \param msec The timer duration in milliseconds
> + *
> + * If the timer is already running it will be stopped and restarted.
> + */
> +void Timer::start(unsigned int msec)
> +{
> + struct timespec tp;
> + clock_gettime(CLOCK_MONOTONIC, &tp);
> +
> + interval_ = msec;
> + deadline_ = tp.tv_sec * 1000000000ULL + tp.tv_nsec + msec * 1000000;
> +
> + LOG(Debug) << "Starting timer " << this << " with interval " << msec
> + << ": deadline " << deadline_;
> +
> + CameraManager::instance()->eventDispatcher()->registerTimer(this);
> +}
> +
> +/**
> + * \brief Stop the timer
> + *
> + * After this function returns the timer is guaranteed not to emit the
> + * \ref timeout signal.
> + *
> + * If the timer is not running this function performs no operation.
> + */
> +void Timer::stop()
> +{
> + CameraManager::instance()->eventDispatcher()->unregisterTimer(this);
> +
> + deadline_ = 0;
> +}
> +
> +/**
> + * \brief
Empty brief. I know, there's not much to say on this function...
> + * \return true if the timer is running, false otherwise
s/true/True ?
> + */
> +bool Timer::isRunning() const
> +{
> + return deadline_ != 0;
> +}
> +
> +/**
> + * \fn Timer::interval()
> + * \brief Retrieve the timer interval
> + * \return The timer interval in milliseconds
> + */
> +
> +/**
> + * \fn Timer::deadline()
> + * \brief Retrieve the timer deadline
> + * \return The timer deadline in nanoseconds
> + */
> +
> +/**
> + * \var Timer::timeout
> + * \brief Signal emitted when the timer times out
> + *
> + * The timer pointer is passed as a parameter.
> + */
> +
> +} /* namespace libcamera */
Thanks
j
> --
> Regards,
>
> Laurent Pinchart
>
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel at lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://lists.libcamera.org/pipermail/libcamera-devel/attachments/20190108/38f165cb/attachment-0001.sig>
More information about the libcamera-devel
mailing list