summaryrefslogtreecommitdiff
path: root/include/libcamera/base
diff options
context:
space:
mode:
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__ */