summaryrefslogtreecommitdiff
path: root/include/libcamera/base
diff options
context:
space:
mode:
authorKieran Bingham <kieran.bingham@ideasonboard.com>2021-06-15 16:15:12 +0100
committerKieran Bingham <kieran.bingham@ideasonboard.com>2021-06-25 16:11:08 +0100
commit27aff949fbc1b9aabfc594bbfd6f94be55a086ec (patch)
tree9ddbc2462a685a6db3ed33f09ed7a493376439d6 /include/libcamera/base
parent6410d1d37c1ea9d1d168840a7ba063facb0bc9d6 (diff)
libcamera/base: Move extended base functionality
Move the functionality for the following components to the new base support library: - BoundMethod - EventDispatcher - EventDispatcherPoll - Log - Message - Object - Signal - Semaphore - Thread - Timer While it would be preferable to see these split to move one component per commit, these components are all interdependent upon each other, which leaves us with one big change performing the move for all of them. Reviewed-by: Hirokazu Honda <hiroh@chromium.org> Reviewed-by: Paul Elder <paul.elder@ideasonboard.com> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Diffstat (limited to 'include/libcamera/base')
-rw-r--r--include/libcamera/base/bound_method.h239
-rw-r--r--include/libcamera/base/event_dispatcher.h35
-rw-r--r--include/libcamera/base/event_dispatcher_poll.h58
-rw-r--r--include/libcamera/base/log.h130
-rw-r--r--include/libcamera/base/meson.build10
-rw-r--r--include/libcamera/base/message.h71
-rw-r--r--include/libcamera/base/object.h71
-rw-r--r--include/libcamera/base/semaphore.h34
-rw-r--r--include/libcamera/base/signal.h132
-rw-r--r--include/libcamera/base/thread.h76
-rw-r--r--include/libcamera/base/timer.h49
11 files changed, 905 insertions, 0 deletions
diff --git a/include/libcamera/base/bound_method.h b/include/libcamera/base/bound_method.h
new file mode 100644
index 00000000..282f9b58
--- /dev/null
+++ b/include/libcamera/base/bound_method.h
@@ -0,0 +1,239 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * bound_method.h - Method bind and invocation
+ */
+#ifndef __LIBCAMERA_BASE_BOUND_METHOD_H__
+#define __LIBCAMERA_BASE_BOUND_METHOD_H__
+
+#include <memory>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+namespace libcamera {
+
+class Object;
+
+enum ConnectionType {
+ ConnectionTypeAuto,
+ ConnectionTypeDirect,
+ ConnectionTypeQueued,
+ ConnectionTypeBlocking,
+};
+
+class BoundMethodPackBase
+{
+public:
+ virtual ~BoundMethodPackBase() = default;
+};
+
+template<typename R, typename... Args>
+class BoundMethodPack : public BoundMethodPackBase
+{
+public:
+ BoundMethodPack(const Args &... args)
+ : args_(args...)
+ {
+ }
+
+ std::tuple<typename std::remove_reference_t<Args>...> args_;
+ R ret_;
+};
+
+template<typename... Args>
+class BoundMethodPack<void, Args...> : public BoundMethodPackBase
+{
+public:
+ BoundMethodPack(const Args &... args)
+ : args_(args...)
+ {
+ }
+
+ std::tuple<typename std::remove_reference_t<Args>...> args_;
+};
+
+class BoundMethodBase
+{
+public:
+ BoundMethodBase(void *obj, Object *object, ConnectionType type)
+ : obj_(obj), object_(object), connectionType_(type)
+ {
+ }
+ virtual ~BoundMethodBase() = default;
+
+ template<typename T, typename std::enable_if_t<!std::is_same<Object, T>::value> * = nullptr>
+ bool match(T *obj) { return obj == obj_; }
+ bool match(Object *object) { return object == object_; }
+
+ Object *object() const { return object_; }
+
+ virtual void invokePack(BoundMethodPackBase *pack) = 0;
+
+protected:
+ bool activatePack(std::shared_ptr<BoundMethodPackBase> pack,
+ bool deleteMethod);
+
+ void *obj_;
+ Object *object_;
+
+private:
+ ConnectionType connectionType_;
+};
+
+template<typename R, typename... Args>
+class BoundMethodArgs : public BoundMethodBase
+{
+public:
+ using PackType = BoundMethodPack<R, Args...>;
+
+private:
+ template<std::size_t... I>
+ void invokePack(BoundMethodPackBase *pack, std::index_sequence<I...>)
+ {
+ PackType *args = static_cast<PackType *>(pack);
+ args->ret_ = invoke(std::get<I>(args->args_)...);
+ }
+
+public:
+ BoundMethodArgs(void *obj, Object *object, ConnectionType type)
+ : BoundMethodBase(obj, object, type) {}
+
+ void invokePack(BoundMethodPackBase *pack) override
+ {
+ invokePack(pack, std::make_index_sequence<sizeof...(Args)>{});
+ }
+
+ virtual R activate(Args... args, bool deleteMethod = false) = 0;
+ virtual R invoke(Args... args) = 0;
+};
+
+template<typename... Args>
+class BoundMethodArgs<void, Args...> : public BoundMethodBase
+{
+public:
+ using PackType = BoundMethodPack<void, Args...>;
+
+private:
+ template<std::size_t... I>
+ void invokePack(BoundMethodPackBase *pack, std::index_sequence<I...>)
+ {
+ /* args is effectively unused when the sequence I is empty. */
+ PackType *args [[gnu::unused]] = static_cast<PackType *>(pack);
+ invoke(std::get<I>(args->args_)...);
+ }
+
+public:
+ BoundMethodArgs(void *obj, Object *object, ConnectionType type)
+ : BoundMethodBase(obj, object, type) {}
+
+ void invokePack(BoundMethodPackBase *pack) override
+ {
+ invokePack(pack, std::make_index_sequence<sizeof...(Args)>{});
+ }
+
+ virtual void activate(Args... args, bool deleteMethod = false) = 0;
+ virtual void invoke(Args... args) = 0;
+};
+
+template<typename T, typename R, typename... Args>
+class BoundMethodMember : public BoundMethodArgs<R, Args...>
+{
+public:
+ using PackType = typename BoundMethodArgs<R, Args...>::PackType;
+
+ BoundMethodMember(T *obj, Object *object, R (T::*func)(Args...),
+ ConnectionType type = ConnectionTypeAuto)
+ : BoundMethodArgs<R, Args...>(obj, object, type), func_(func)
+ {
+ }
+
+ bool match(R (T::*func)(Args...)) const { return func == func_; }
+
+ R activate(Args... args, bool deleteMethod = false) override
+ {
+ if (!this->object_) {
+ T *obj = static_cast<T *>(this->obj_);
+ return (obj->*func_)(args...);
+ }
+
+ auto pack = std::make_shared<PackType>(args...);
+ bool sync = BoundMethodBase::activatePack(pack, deleteMethod);
+ return sync ? pack->ret_ : R();
+ }
+
+ R invoke(Args... args) override
+ {
+ T *obj = static_cast<T *>(this->obj_);
+ return (obj->*func_)(args...);
+ }
+
+private:
+ R (T::*func_)(Args...);
+};
+
+template<typename T, typename... Args>
+class BoundMethodMember<T, void, Args...> : public BoundMethodArgs<void, Args...>
+{
+public:
+ using PackType = typename BoundMethodArgs<void, Args...>::PackType;
+
+ BoundMethodMember(T *obj, Object *object, void (T::*func)(Args...),
+ ConnectionType type = ConnectionTypeAuto)
+ : BoundMethodArgs<void, Args...>(obj, object, type), func_(func)
+ {
+ }
+
+ bool match(void (T::*func)(Args...)) const { return func == func_; }
+
+ void activate(Args... args, bool deleteMethod = false) override
+ {
+ if (!this->object_) {
+ T *obj = static_cast<T *>(this->obj_);
+ return (obj->*func_)(args...);
+ }
+
+ auto pack = std::make_shared<PackType>(args...);
+ BoundMethodBase::activatePack(pack, deleteMethod);
+ }
+
+ void invoke(Args... args) override
+ {
+ T *obj = static_cast<T *>(this->obj_);
+ return (obj->*func_)(args...);
+ }
+
+private:
+ void (T::*func_)(Args...);
+};
+
+template<typename R, typename... Args>
+class BoundMethodStatic : public BoundMethodArgs<R, Args...>
+{
+public:
+ BoundMethodStatic(R (*func)(Args...))
+ : BoundMethodArgs<R, Args...>(nullptr, nullptr, ConnectionTypeAuto),
+ func_(func)
+ {
+ }
+
+ bool match(R (*func)(Args...)) const { return func == func_; }
+
+ R activate(Args... args, [[maybe_unused]] bool deleteMethod = false) override
+ {
+ return (*func_)(args...);
+ }
+
+ R invoke(Args...) override
+ {
+ return R();
+ }
+
+private:
+ R (*func_)(Args...);
+};
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_BASE_BOUND_METHOD_H__ */
diff --git a/include/libcamera/base/event_dispatcher.h b/include/libcamera/base/event_dispatcher.h
new file mode 100644
index 00000000..045df27f
--- /dev/null
+++ b/include/libcamera/base/event_dispatcher.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * event_dispatcher.h - Event dispatcher
+ */
+#ifndef __LIBCAMERA_BASE_EVENT_DISPATCHER_H__
+#define __LIBCAMERA_BASE_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;
+
+ virtual void interrupt() = 0;
+};
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_BASE_EVENT_DISPATCHER_H__ */
diff --git a/include/libcamera/base/event_dispatcher_poll.h b/include/libcamera/base/event_dispatcher_poll.h
new file mode 100644
index 00000000..ae2a3f04
--- /dev/null
+++ b/include/libcamera/base/event_dispatcher_poll.h
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * event_dispatcher_poll.h - Poll-based event dispatcher
+ */
+#ifndef __LIBCAMERA_BASE_EVENT_DISPATCHER_POLL_H__
+#define __LIBCAMERA_BASE_EVENT_DISPATCHER_POLL_H__
+
+#include <list>
+#include <map>
+#include <vector>
+
+#include <libcamera/base/event_dispatcher.h>
+
+struct pollfd;
+
+namespace libcamera {
+
+class EventNotifier;
+class Timer;
+
+class EventDispatcherPoll final : public EventDispatcher
+{
+public:
+ EventDispatcherPoll();
+ ~EventDispatcherPoll();
+
+ void registerEventNotifier(EventNotifier *notifier);
+ void unregisterEventNotifier(EventNotifier *notifier);
+
+ void registerTimer(Timer *timer);
+ void unregisterTimer(Timer *timer);
+
+ void processEvents();
+ void interrupt();
+
+private:
+ struct EventNotifierSetPoll {
+ short events() const;
+ EventNotifier *notifiers[3];
+ };
+
+ int poll(std::vector<struct pollfd> *pollfds);
+ void processInterrupt(const struct pollfd &pfd);
+ void processNotifiers(const std::vector<struct pollfd> &pollfds);
+ void processTimers();
+
+ std::map<int, EventNotifierSetPoll> notifiers_;
+ std::list<Timer *> timers_;
+ int eventfd_;
+
+ bool processingEvents_;
+};
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_BASE_EVENT_DISPATCHER_POLL_H__ */
diff --git a/include/libcamera/base/log.h b/include/libcamera/base/log.h
new file mode 100644
index 00000000..b93c947a
--- /dev/null
+++ b/include/libcamera/base/log.h
@@ -0,0 +1,130 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2018, Google Inc.
+ *
+ * log.h - Logging infrastructure
+ */
+#ifndef __LIBCAMERA_BASE_LOG_H__
+#define __LIBCAMERA_BASE_LOG_H__
+
+#include <chrono>
+#include <sstream>
+
+#include <libcamera/base/class.h>
+#include <libcamera/base/utils.h>
+
+namespace libcamera {
+
+enum LogSeverity {
+ LogInvalid = -1,
+ LogDebug = 0,
+ LogInfo,
+ LogWarning,
+ LogError,
+ LogFatal,
+};
+
+class LogCategory
+{
+public:
+ explicit LogCategory(const char *name);
+
+ const char *name() const { return name_; }
+ LogSeverity severity() const { return severity_; }
+ void setSeverity(LogSeverity severity);
+
+ static const LogCategory &defaultCategory();
+
+private:
+ const char *name_;
+ LogSeverity severity_;
+};
+
+#define LOG_DECLARE_CATEGORY(name) \
+extern const LogCategory &_LOG_CATEGORY(name)();
+
+#define LOG_DEFINE_CATEGORY(name) \
+const LogCategory &_LOG_CATEGORY(name)() \
+{ \
+ /* The instance will be deleted by the Logger destructor. */ \
+ static LogCategory *category = new LogCategory(#name); \
+ return *category; \
+}
+
+class LogMessage
+{
+public:
+ LogMessage(const char *fileName, unsigned int line,
+ const LogCategory &category, LogSeverity severity);
+
+ LogMessage(LogMessage &&);
+ ~LogMessage();
+
+ std::ostream &stream() { return msgStream_; }
+
+ const utils::time_point &timestamp() const { return timestamp_; }
+ LogSeverity severity() const { return severity_; }
+ const LogCategory &category() const { return category_; }
+ const std::string &fileInfo() const { return fileInfo_; }
+ const std::string msg() const { return msgStream_.str(); }
+
+private:
+ LIBCAMERA_DISABLE_COPY(LogMessage)
+
+ void init(const char *fileName, unsigned int line);
+
+ std::ostringstream msgStream_;
+ const LogCategory &category_;
+ LogSeverity severity_;
+ utils::time_point timestamp_;
+ std::string fileInfo_;
+};
+
+class Loggable
+{
+public:
+ virtual ~Loggable();
+
+protected:
+ virtual std::string logPrefix() const = 0;
+
+ LogMessage _log(const LogCategory *category, LogSeverity severity,
+ const char *fileName = __builtin_FILE(),
+ unsigned int line = __builtin_LINE()) const;
+};
+
+LogMessage _log(const LogCategory *category, LogSeverity severity,
+ const char *fileName = __builtin_FILE(),
+ unsigned int line = __builtin_LINE());
+
+#ifndef __DOXYGEN__
+#define _LOG_CATEGORY(name) logCategory##name
+
+#define _LOG1(severity) \
+ _log(nullptr, Log##severity).stream()
+#define _LOG2(category, severity) \
+ _log(&_LOG_CATEGORY(category)(), Log##severity).stream()
+
+/*
+ * Expand the LOG() macro to _LOG1() or _LOG2() based on the number of
+ * arguments.
+ */
+#define _LOG_MACRO(_1, _2, NAME, ...) NAME
+#define LOG(...) _LOG_MACRO(__VA_ARGS__, _LOG2, _LOG1)(__VA_ARGS__)
+#else /* __DOXYGEN___ */
+#define LOG(category, severity)
+#endif /* __DOXYGEN__ */
+
+#ifndef NDEBUG
+#define ASSERT(condition) static_cast<void>(({ \
+ if (!(condition)) \
+ LOG(Fatal) << "assertion \"" #condition "\" failed in " \
+ << __func__ << "()"; \
+}))
+#else
+#define ASSERT(condition) static_cast<void>(false && (condition))
+#endif
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_BASE_LOG_H__ */
diff --git a/include/libcamera/base/meson.build b/include/libcamera/base/meson.build
index 2db756c5..7a858dcb 100644
--- a/include/libcamera/base/meson.build
+++ b/include/libcamera/base/meson.build
@@ -3,7 +3,17 @@
libcamera_base_include_dir = libcamera_include_dir / 'base'
libcamera_base_headers = files([
+ 'bound_method.h',
'class.h',
+ 'event_dispatcher.h',
+ 'event_dispatcher_poll.h',
+ 'log.h',
+ 'message.h',
+ 'object.h',
+ 'semaphore.h',
+ 'signal.h',
+ 'thread.h',
+ 'timer.h',
'utils.h',
])
diff --git a/include/libcamera/base/message.h b/include/libcamera/base/message.h
new file mode 100644
index 00000000..5d2a9f04
--- /dev/null
+++ b/include/libcamera/base/message.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * message.h - Message queue support
+ */
+#ifndef __LIBCAMERA_BASE_MESSAGE_H__
+#define __LIBCAMERA_BASE_MESSAGE_H__
+
+#include <atomic>
+
+#include <libcamera/base/bound_method.h>
+
+namespace libcamera {
+
+class BoundMethodBase;
+class Object;
+class Semaphore;
+class Thread;
+
+class Message
+{
+public:
+ enum Type {
+ None = 0,
+ InvokeMessage = 1,
+ ThreadMoveMessage = 2,
+ DeferredDelete = 3,
+ UserMessage = 1000,
+ };
+
+ Message(Type type);
+ virtual ~Message();
+
+ Type type() const { return type_; }
+ Object *receiver() const { return receiver_; }
+
+ static Type registerMessageType();
+
+private:
+ friend class Thread;
+
+ Type type_;
+ Object *receiver_;
+
+ static std::atomic_uint nextUserType_;
+};
+
+class InvokeMessage : public Message
+{
+public:
+ InvokeMessage(BoundMethodBase *method,
+ std::shared_ptr<BoundMethodPackBase> pack,
+ Semaphore *semaphore = nullptr,
+ bool deleteMethod = false);
+ ~InvokeMessage();
+
+ Semaphore *semaphore() const { return semaphore_; }
+
+ void invoke();
+
+private:
+ BoundMethodBase *method_;
+ std::shared_ptr<BoundMethodPackBase> pack_;
+ Semaphore *semaphore_;
+ bool deleteMethod_;
+};
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_BASE_MESSAGE_H__ */
diff --git a/include/libcamera/base/object.h b/include/libcamera/base/object.h
new file mode 100644
index 00000000..5c385ab4
--- /dev/null
+++ b/include/libcamera/base/object.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * object.h - Base object
+ */
+#ifndef __LIBCAMERA_BASE_OBJECT_H__
+#define __LIBCAMERA_BASE_OBJECT_H__
+
+#include <list>
+#include <memory>
+#include <vector>
+
+#include <libcamera/base/bound_method.h>
+
+namespace libcamera {
+
+class Message;
+template<typename... Args>
+class Signal;
+class SignalBase;
+class Thread;
+
+class Object
+{
+public:
+ Object(Object *parent = nullptr);
+ virtual ~Object();
+
+ void deleteLater();
+
+ void postMessage(std::unique_ptr<Message> msg);
+
+ template<typename T, typename R, typename... FuncArgs, typename... Args,
+ typename std::enable_if_t<std::is_base_of<Object, T>::value> * = nullptr>
+ R invokeMethod(R (T::*func)(FuncArgs...), ConnectionType type,
+ Args... args)
+ {
+ T *obj = static_cast<T *>(this);
+ auto *method = new BoundMethodMember<T, R, FuncArgs...>(obj, this, func, type);
+ return method->activate(args..., true);
+ }
+
+ Thread *thread() const { return thread_; }
+ void moveToThread(Thread *thread);
+
+ Object *parent() const { return parent_; }
+
+protected:
+ virtual void message(Message *msg);
+
+private:
+ friend class SignalBase;
+ friend class Thread;
+
+ void notifyThreadMove();
+
+ void connect(SignalBase *signal);
+ void disconnect(SignalBase *signal);
+
+ Object *parent_;
+ std::vector<Object *> children_;
+
+ Thread *thread_;
+ std::list<SignalBase *> signals_;
+ unsigned int pendingMessages_;
+};
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_BASE_OBJECT_H__ */
diff --git a/include/libcamera/base/semaphore.h b/include/libcamera/base/semaphore.h
new file mode 100644
index 00000000..c8e62e3e
--- /dev/null
+++ b/include/libcamera/base/semaphore.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * semaphore.h - General-purpose counting semaphore
+ */
+#ifndef __LIBCAMERA_BASE_SEMAPHORE_H__
+#define __LIBCAMERA_BASE_SEMAPHORE_H__
+
+#include <condition_variable>
+
+#include <libcamera/base/thread.h>
+
+namespace libcamera {
+
+class Semaphore
+{
+public:
+ Semaphore(unsigned int n = 0);
+
+ unsigned int available();
+ void acquire(unsigned int n = 1);
+ bool tryAcquire(unsigned int n = 1);
+ void release(unsigned int n = 1);
+
+private:
+ Mutex mutex_;
+ std::condition_variable cv_;
+ unsigned int available_;
+};
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_BASE_SEMAPHORE_H__ */
diff --git a/include/libcamera/base/signal.h b/include/libcamera/base/signal.h
new file mode 100644
index 00000000..c2521769
--- /dev/null
+++ b/include/libcamera/base/signal.h
@@ -0,0 +1,132 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * signal.h - Signal & slot implementation
+ */
+#ifndef __LIBCAMERA_BASE_SIGNAL_H__
+#define __LIBCAMERA_BASE_SIGNAL_H__
+
+#include <functional>
+#include <list>
+#include <type_traits>
+#include <vector>
+
+#include <libcamera/base/bound_method.h>
+#include <libcamera/base/object.h>
+
+namespace libcamera {
+
+class SignalBase
+{
+public:
+ void disconnect(Object *object);
+
+protected:
+ using SlotList = std::list<BoundMethodBase *>;
+
+ void connect(BoundMethodBase *slot);
+ void disconnect(std::function<bool(SlotList::iterator &)> match);
+
+ SlotList slots();
+
+private:
+ SlotList slots_;
+};
+
+template<typename... Args>
+class Signal : public SignalBase
+{
+public:
+ ~Signal()
+ {
+ disconnect();
+ }
+
+#ifndef __DOXYGEN__
+ template<typename T, typename R, typename std::enable_if_t<std::is_base_of<Object, T>::value> * = nullptr>
+ void connect(T *obj, R (T::*func)(Args...),
+ ConnectionType type = ConnectionTypeAuto)
+ {
+ Object *object = static_cast<Object *>(obj);
+ SignalBase::connect(new BoundMethodMember<T, R, Args...>(obj, object, func, type));
+ }
+
+ template<typename T, typename R, typename std::enable_if_t<!std::is_base_of<Object, T>::value> * = nullptr>
+#else
+ template<typename T, typename R>
+#endif
+ void connect(T *obj, R (T::*func)(Args...))
+ {
+ SignalBase::connect(new BoundMethodMember<T, R, Args...>(obj, nullptr, func));
+ }
+
+ template<typename R>
+ void connect(R (*func)(Args...))
+ {
+ SignalBase::connect(new BoundMethodStatic<R, Args...>(func));
+ }
+
+ void disconnect()
+ {
+ SignalBase::disconnect([]([[maybe_unused]] SlotList::iterator &iter) {
+ return true;
+ });
+ }
+
+ template<typename T>
+ void disconnect(T *obj)
+ {
+ SignalBase::disconnect([obj](SlotList::iterator &iter) {
+ return (*iter)->match(obj);
+ });
+ }
+
+ template<typename T, typename R>
+ void disconnect(T *obj, R (T::*func)(Args...))
+ {
+ SignalBase::disconnect([obj, func](SlotList::iterator &iter) {
+ BoundMethodArgs<R, Args...> *slot =
+ static_cast<BoundMethodArgs<R, Args...> *>(*iter);
+
+ if (!slot->match(obj))
+ return false;
+
+ /*
+ * If the object matches the slot, the slot is
+ * guaranteed to be a member slot, so we can safely
+ * cast it to BoundMethodMember<T, Args...> to match
+ * func.
+ */
+ return static_cast<BoundMethodMember<T, R, Args...> *>(slot)->match(func);
+ });
+ }
+
+ template<typename R>
+ void disconnect(R (*func)(Args...))
+ {
+ SignalBase::disconnect([func](SlotList::iterator &iter) {
+ BoundMethodArgs<R, Args...> *slot =
+ static_cast<BoundMethodArgs<R, Args...> *>(*iter);
+
+ if (!slot->match(nullptr))
+ return false;
+
+ return static_cast<BoundMethodStatic<R, Args...> *>(slot)->match(func);
+ });
+ }
+
+ void emit(Args... args)
+ {
+ /*
+ * Make a copy of the slots list as the slot could call the
+ * disconnect operation, invalidating the iterator.
+ */
+ for (BoundMethodBase *slot : slots())
+ static_cast<BoundMethodArgs<void, Args...> *>(slot)->activate(args...);
+ }
+};
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_BASE_SIGNAL_H__ */
diff --git a/include/libcamera/base/thread.h b/include/libcamera/base/thread.h
new file mode 100644
index 00000000..2ed18d49
--- /dev/null
+++ b/include/libcamera/base/thread.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * thread.h - Thread support
+ */
+#ifndef __LIBCAMERA_BASE_THREAD_H__
+#define __LIBCAMERA_BASE_THREAD_H__
+
+#include <memory>
+#include <mutex>
+#include <sys/types.h>
+#include <thread>
+
+#include <libcamera/base/message.h>
+#include <libcamera/base/signal.h>
+#include <libcamera/base/utils.h>
+
+namespace libcamera {
+
+class EventDispatcher;
+class Message;
+class Object;
+class ThreadData;
+class ThreadMain;
+
+using Mutex = std::mutex;
+using MutexLocker = std::unique_lock<std::mutex>;
+
+class Thread
+{
+public:
+ Thread();
+ virtual ~Thread();
+
+ void start();
+ void exit(int code = 0);
+ bool wait(utils::duration duration = utils::duration::max());
+
+ bool isRunning();
+
+ Signal<Thread *> finished;
+
+ static Thread *current();
+ static pid_t currentId();
+
+ EventDispatcher *eventDispatcher();
+
+ void dispatchMessages(Message::Type type = Message::Type::None);
+
+protected:
+ int exec();
+ virtual void run();
+
+private:
+ void startThread();
+ void finishThread();
+
+ void postMessage(std::unique_ptr<Message> msg, Object *receiver);
+ void removeMessages(Object *receiver);
+
+ friend class Object;
+ friend class ThreadData;
+ friend class ThreadMain;
+
+ void moveObject(Object *object);
+ void moveObject(Object *object, ThreadData *currentData,
+ ThreadData *targetData);
+
+ std::thread thread_;
+ ThreadData *data_;
+};
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_BASE_THREAD_H__ */
diff --git a/include/libcamera/base/timer.h b/include/libcamera/base/timer.h
new file mode 100644
index 00000000..e79e85f1
--- /dev/null
+++ b/include/libcamera/base/timer.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * timer.h - Generic timer
+ */
+#ifndef __LIBCAMERA_BASE_TIMER_H__
+#define __LIBCAMERA_BASE_TIMER_H__
+
+#include <chrono>
+#include <stdint.h>
+
+#include <libcamera/base/object.h>
+#include <libcamera/base/signal.h>
+
+namespace libcamera {
+
+class Message;
+
+class Timer : public Object
+{
+public:
+ Timer(Object *parent = nullptr);
+ ~Timer();
+
+ void start(unsigned int msec) { start(std::chrono::milliseconds(msec)); }
+ void start(std::chrono::milliseconds duration);
+ void start(std::chrono::steady_clock::time_point deadline);
+ void stop();
+ bool isRunning() const;
+
+ std::chrono::steady_clock::time_point deadline() const { return deadline_; }
+
+ Signal<Timer *> timeout;
+
+protected:
+ void message(Message *msg) override;
+
+private:
+ void registerTimer();
+ void unregisterTimer();
+
+ bool running_;
+ std::chrono::steady_clock::time_point deadline_;
+};
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_BASE_TIMER_H__ */