diff options
Diffstat (limited to 'src/libcamera/base')
-rw-r--r-- | src/libcamera/base/backtrace.cpp | 14 | ||||
-rw-r--r-- | src/libcamera/base/bound_method.cpp | 3 | ||||
-rw-r--r-- | src/libcamera/base/class.cpp | 2 | ||||
-rw-r--r-- | src/libcamera/base/event_dispatcher.cpp | 2 | ||||
-rw-r--r-- | src/libcamera/base/event_dispatcher_poll.cpp | 2 | ||||
-rw-r--r-- | src/libcamera/base/event_notifier.cpp | 8 | ||||
-rw-r--r-- | src/libcamera/base/file.cpp | 7 | ||||
-rw-r--r-- | src/libcamera/base/flags.cpp | 2 | ||||
-rw-r--r-- | src/libcamera/base/log.cpp | 56 | ||||
-rw-r--r-- | src/libcamera/base/meson.build | 7 | ||||
-rw-r--r-- | src/libcamera/base/message.cpp | 2 | ||||
-rw-r--r-- | src/libcamera/base/mutex.cpp | 2 | ||||
-rw-r--r-- | src/libcamera/base/object.cpp | 57 | ||||
-rw-r--r-- | src/libcamera/base/semaphore.cpp | 6 | ||||
-rw-r--r-- | src/libcamera/base/shared_fd.cpp | 2 | ||||
-rw-r--r-- | src/libcamera/base/signal.cpp | 5 | ||||
-rw-r--r-- | src/libcamera/base/thread.cpp | 19 | ||||
-rw-r--r-- | src/libcamera/base/timer.cpp | 12 | ||||
-rw-r--r-- | src/libcamera/base/unique_fd.cpp | 2 | ||||
-rw-r--r-- | src/libcamera/base/utils.cpp | 70 |
20 files changed, 232 insertions, 48 deletions
diff --git a/src/libcamera/base/backtrace.cpp b/src/libcamera/base/backtrace.cpp index 483492c3..0b04629c 100644 --- a/src/libcamera/base/backtrace.cpp +++ b/src/libcamera/base/backtrace.cpp @@ -2,7 +2,7 @@ /* * Copyright (C) 2021, Ideas on Board Oy * - * backtrace.h - Call stack backtraces + * Call stack backtraces */ #include <libcamera/base/backtrace.h> @@ -191,10 +191,22 @@ __attribute__((__noinline__)) bool Backtrace::unwindTrace() { #if HAVE_UNWIND +/* + * unw_getcontext() for ARM32 is an inline assembly function using the stmia + * instruction to store SP and PC. This is considered by clang-11 as deprecated, + * and generates a warning. + */ +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winline-asm" +#endif unw_context_t uc; int ret = unw_getcontext(&uc); if (ret) return false; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif unw_cursor_t cursor; ret = unw_init_local(&cursor, &uc); diff --git a/src/libcamera/base/bound_method.cpp b/src/libcamera/base/bound_method.cpp index 3ecec51c..322029a8 100644 --- a/src/libcamera/base/bound_method.cpp +++ b/src/libcamera/base/bound_method.cpp @@ -2,11 +2,12 @@ /* * Copyright (C) 2019, Google Inc. * - * bound_method.cpp - Method bind and invocation + * Method bind and invocation */ #include <libcamera/base/bound_method.h> #include <libcamera/base/message.h> +#include <libcamera/base/object.h> #include <libcamera/base/semaphore.h> #include <libcamera/base/thread.h> diff --git a/src/libcamera/base/class.cpp b/src/libcamera/base/class.cpp index 9c2d9f21..61998398 100644 --- a/src/libcamera/base/class.cpp +++ b/src/libcamera/base/class.cpp @@ -2,7 +2,7 @@ /* * Copyright (C) 2020, Google Inc. * - * class.cpp - Utilities and helpers for classes + * Utilities and helpers for classes */ #include <libcamera/base/class.h> diff --git a/src/libcamera/base/event_dispatcher.cpp b/src/libcamera/base/event_dispatcher.cpp index 4be89e81..5f4a5cb4 100644 --- a/src/libcamera/base/event_dispatcher.cpp +++ b/src/libcamera/base/event_dispatcher.cpp @@ -2,7 +2,7 @@ /* * Copyright (C) 2019, Google Inc. * - * event_dispatcher.cpp - Event dispatcher + * Event dispatcher */ #include <libcamera/base/event_dispatcher.h> diff --git a/src/libcamera/base/event_dispatcher_poll.cpp b/src/libcamera/base/event_dispatcher_poll.cpp index 7238a316..b737ca7a 100644 --- a/src/libcamera/base/event_dispatcher_poll.cpp +++ b/src/libcamera/base/event_dispatcher_poll.cpp @@ -2,7 +2,7 @@ /* * Copyright (C) 2019, Google Inc. * - * event_dispatcher_poll.cpp - Poll-based event dispatcher + * Poll-based event dispatcher */ #include <libcamera/base/event_dispatcher_poll.h> diff --git a/src/libcamera/base/event_notifier.cpp b/src/libcamera/base/event_notifier.cpp index fd93c087..495c281d 100644 --- a/src/libcamera/base/event_notifier.cpp +++ b/src/libcamera/base/event_notifier.cpp @@ -2,12 +2,13 @@ /* * Copyright (C) 2019, Google Inc. * - * event_notifier.cpp - File descriptor event notifier + * File descriptor event notifier */ #include <libcamera/base/event_notifier.h> #include <libcamera/base/event_dispatcher.h> +#include <libcamera/base/log.h> #include <libcamera/base/message.h> #include <libcamera/base/thread.h> @@ -20,6 +21,8 @@ namespace libcamera { +LOG_DECLARE_CATEGORY(Event) + /** * \class EventNotifier * \brief Notify of activity on a file descriptor @@ -104,6 +107,9 @@ EventNotifier::~EventNotifier() */ void EventNotifier::setEnabled(bool enable) { + if (!assertThreadBound("EventNotifier can't be enabled from another thread")) + return; + if (enabled_ == enable) return; diff --git a/src/libcamera/base/file.cpp b/src/libcamera/base/file.cpp index fb3e276d..2b83a517 100644 --- a/src/libcamera/base/file.cpp +++ b/src/libcamera/base/file.cpp @@ -2,7 +2,7 @@ /* * Copyright (C) 2020, Google Inc. * - * file.cpp - File I/O operations + * File I/O operations */ #include <libcamera/base/file.h> @@ -163,6 +163,9 @@ bool File::exists() const * attempt to create the file with initial permissions set to 0666 (modified by * the process' umask). * + * The file is opened with the O_CLOEXEC flag, and will be closed automatically + * when a new binary is executed with one of the exec(3) functions. + * * The error() status is updated. * * \return True on success, false otherwise @@ -178,7 +181,7 @@ bool File::open(File::OpenMode mode) if (mode & OpenModeFlag::WriteOnly) flags |= O_CREAT; - fd_ = UniqueFD(::open(name_.c_str(), flags, 0666)); + fd_ = UniqueFD(::open(name_.c_str(), flags | O_CLOEXEC, 0666)); if (!fd_.isValid()) { error_ = -errno; return false; diff --git a/src/libcamera/base/flags.cpp b/src/libcamera/base/flags.cpp index 3e4320ac..9981f2ed 100644 --- a/src/libcamera/base/flags.cpp +++ b/src/libcamera/base/flags.cpp @@ -2,7 +2,7 @@ /* * Copyright (C) 2020, Google Inc. * - * flags.cpp - Type-safe enum-based bitfields + * Type-safe enum-based bitfields */ #include <libcamera/base/flags.h> diff --git a/src/libcamera/base/log.cpp b/src/libcamera/base/log.cpp index 5c359a22..3a656b8f 100644 --- a/src/libcamera/base/log.cpp +++ b/src/libcamera/base/log.cpp @@ -2,7 +2,7 @@ /* * Copyright (C) 2018, Google Inc. * - * log.cpp - Logging infrastructure + * Logging infrastructure */ #include <libcamera/base/log.h> @@ -21,6 +21,7 @@ #include <libcamera/logging.h> #include <libcamera/base/backtrace.h> +#include <libcamera/base/mutex.h> #include <libcamera/base/thread.h> #include <libcamera/base/utils.h> @@ -314,10 +315,11 @@ private: friend LogCategory; void registerCategory(LogCategory *category); + LogCategory *findCategory(const char *name) const; static bool destroyed_; - std::unordered_set<LogCategory *> categories_; + std::vector<LogCategory *> categories_; std::list<std::pair<std::string, LogSeverity>> levels_; std::shared_ptr<LogOutput> output_; @@ -568,7 +570,7 @@ void Logger::logSetLevel(const char *category, const char *level) return; for (LogCategory *c : categories_) { - if (!strcmp(c->name(), category)) { + if (c->name() == category) { c->setSeverity(severity); break; } @@ -707,12 +709,12 @@ LogSeverity Logger::parseLogLevel(const std::string &level) * \brief Register a log category with the logger * \param[in] category The log category * - * Log categories must have unique names. If a category with the same name - * already exists this function performs no operation. + * Log categories must have unique names. It is invalid to call this function + * if a log category with the same name already exists. */ void Logger::registerCategory(LogCategory *category) { - categories_.insert(category); + categories_.push_back(category); const std::string &name = category->name(); for (const std::pair<std::string, LogSeverity> &level : levels_) { @@ -737,6 +739,22 @@ void Logger::registerCategory(LogCategory *category) } /** + * \brief Find an existing log category with the given name + * \param[in] name Name of the log category + * \return The pointer to the found log category or nullptr if not found + */ +LogCategory *Logger::findCategory(const char *name) const +{ + if (auto it = std::find_if(categories_.begin(), categories_.end(), + [name](auto c) { return c->name() == name; }); + it != categories_.end()) { + return *it; + } + + return nullptr; +} + +/** * \enum LogSeverity * Log message severity * \var LogDebug @@ -761,13 +779,35 @@ void Logger::registerCategory(LogCategory *category) */ /** + * \brief Create a new LogCategory or return an existing one + * \param[in] name Name of the log category + * + * Create and return a new LogCategory with the given name if such a category + * does not yet exist, or return the existing one. + * + * \return The pointer to the LogCategory + */ +LogCategory *LogCategory::create(const char *name) +{ + static Mutex mutex_; + MutexLocker locker(mutex_); + LogCategory *category = Logger::instance()->findCategory(name); + + if (!category) { + category = new LogCategory(name); + Logger::instance()->registerCategory(category); + } + + return category; +} + +/** * \brief Construct a log category * \param[in] name The category name */ LogCategory::LogCategory(const char *name) : name_(name), severity_(LogSeverity::LogInfo) { - Logger::instance()->registerCategory(this); } /** @@ -804,7 +844,7 @@ void LogCategory::setSeverity(LogSeverity severity) */ const LogCategory &LogCategory::defaultCategory() { - static const LogCategory *category = new LogCategory("default"); + static const LogCategory *category = LogCategory::create("default"); return *category; } diff --git a/src/libcamera/base/meson.build b/src/libcamera/base/meson.build index 7030ad1f..7a7fd7e4 100644 --- a/src/libcamera/base/meson.build +++ b/src/libcamera/base/meson.build @@ -22,8 +22,8 @@ libcamera_base_sources = files([ 'utils.cpp', ]) -libdw = cc.find_library('libdw', required : false) -libunwind = cc.find_library('libunwind', required : false) +libdw = dependency('libdw', required : false) +libunwind = dependency('libunwind', required : false) if cc.has_header_symbol('execinfo.h', 'backtrace') config_h.set('HAVE_BACKTRACE', 1) @@ -38,9 +38,9 @@ if libunwind.found() endif libcamera_base_deps = [ - dependency('threads'), libatomic, libdw, + libthreads, libunwind, ] @@ -51,6 +51,7 @@ libcamera_base_args = [ '-DLIBCAMERA_BASE_PRIVATE' ] libcamera_base_lib = shared_library('libcamera-base', [libcamera_base_sources, libcamera_base_headers], version : libcamera_version, + soversion : libcamera_soversion, name_prefix : '', install : true, cpp_args : libcamera_base_args, diff --git a/src/libcamera/base/message.cpp b/src/libcamera/base/message.cpp index 2da2a7ed..098faac6 100644 --- a/src/libcamera/base/message.cpp +++ b/src/libcamera/base/message.cpp @@ -2,7 +2,7 @@ /* * Copyright (C) 2019, Google Inc. * - * message.cpp - Message queue support + * Message queue support */ #include <libcamera/base/message.h> diff --git a/src/libcamera/base/mutex.cpp b/src/libcamera/base/mutex.cpp index e34e8618..2a4542c4 100644 --- a/src/libcamera/base/mutex.cpp +++ b/src/libcamera/base/mutex.cpp @@ -2,7 +2,7 @@ /* * Copyright (C) 2021, Google Inc. * - * mutex.cpp - Mutex classes with clang thread safety annotation + * Mutex classes with clang thread safety annotation */ #include <libcamera/base/mutex.h> diff --git a/src/libcamera/base/object.cpp b/src/libcamera/base/object.cpp index 92cecd22..745d2565 100644 --- a/src/libcamera/base/object.cpp +++ b/src/libcamera/base/object.cpp @@ -2,7 +2,7 @@ /* * Copyright (C) 2019, Google Inc. * - * object.cpp - Base object + * Base object */ #include <libcamera/base/object.h> @@ -40,8 +40,9 @@ LOG_DEFINE_CATEGORY(Object) * Object class. * * Deleting an object from a thread other than the one the object is bound to is - * unsafe, unless the caller ensures that the object isn't processing any - * message concurrently. + * unsafe, unless the caller ensures that the object's thread is stopped and no + * parent or child of the object gets deleted concurrently. See + * Object::~Object() for more information. * * Object slots connected to signals will also run in the context of the * object's thread, regardless of whether the signal is emitted in the same or @@ -84,9 +85,20 @@ Object::Object(Object *parent) * Object instances shall be destroyed from the thread they are bound to, * otherwise undefined behaviour may occur. If deletion of an Object needs to * be scheduled from a different thread, deleteLater() shall be used. + * + * As an exception to this rule, Object instances may be deleted from a + * different thread if the thread the instance is bound to is stopped through + * the whole duration of the object's destruction, *and* the parent and children + * of the object do not get deleted concurrently. The caller is responsible for + * fulfilling those requirements. + * + * In all cases Object instances shall be deleted before the Thread they are + * bound to. */ Object::~Object() { + ASSERT(Thread::current() == thread_ || !thread_->isRunning()); + /* * Move signals to a private list to avoid concurrent iteration and * deletion of items from Signal::disconnect(). @@ -116,8 +128,9 @@ Object::~Object() * event loop that the object belongs to. This ensures the object is destroyed * from the right context, as required by the libcamera threading model. * - * If this function is called before the thread's event loop is started, the - * object will be deleted when the event loop starts. + * If this function is called before the thread's event loop is started or after + * it has stopped, the object will be deleted when the event loop (re)starts. If + * this never occurs, the object will be leaked. * * Deferred deletion can be used to control the destruction context with shared * pointers. An object managed with shared pointers is deleted when the last @@ -213,6 +226,35 @@ void Object::message(Message *msg) } /** + * \fn Object::assertThreadBound() + * \brief Check if the caller complies with thread-bound constraints + * \param[in] message The message to be printed on error + * + * This function verifies the calling constraints required by the \threadbound + * definition. It shall be called at the beginning of member functions of an + * Object subclass that are explicitly marked as thread-bound in their + * documentation. + * + * If the thread-bound constraints are not met, the function prints \a message + * as an error message. For debug builds, it additionally causes an assertion + * error. + * + * \todo Verify the thread-bound requirements for functions marked as + * thread-bound at the class level. + * + * \return True if the call is thread-bound compliant, false otherwise + */ +bool Object::assertThreadBound(const char *message) +{ + if (Thread::current() == thread_) + return true; + + LOG(Object, Error) << message; + ASSERT(false); + return false; +} + +/** * \fn R Object::invokeMethod() * \brief Invoke a method asynchronously on an Object instance * \param[in] func The object method to invoke @@ -259,11 +301,12 @@ void Object::message(Message *msg) * Moving an object that has a parent is not allowed, and causes undefined * behaviour. * - * \context This function is thread-bound. + * \context This function is \threadbound. */ void Object::moveToThread(Thread *thread) { - ASSERT(Thread::current() == thread_); + if (!assertThreadBound("Object can't be moved from another thread")) + return; if (thread_ == thread) return; diff --git a/src/libcamera/base/semaphore.cpp b/src/libcamera/base/semaphore.cpp index 4fe30293..862f3b31 100644 --- a/src/libcamera/base/semaphore.cpp +++ b/src/libcamera/base/semaphore.cpp @@ -2,7 +2,7 @@ /* * Copyright (C) 2019, Google Inc. * - * semaphore.cpp - General-purpose counting semaphore + * General-purpose counting semaphore */ #include <libcamera/base/semaphore.h> @@ -56,7 +56,9 @@ unsigned int Semaphore::available() void Semaphore::acquire(unsigned int n) { MutexLocker locker(mutex_); - cv_.wait(locker, [&] { return available_ >= n; }); + cv_.wait(locker, [&]() LIBCAMERA_TSA_REQUIRES(mutex_) { + return available_ >= n; + }); available_ -= n; } diff --git a/src/libcamera/base/shared_fd.cpp b/src/libcamera/base/shared_fd.cpp index c711cf57..7afc8ca5 100644 --- a/src/libcamera/base/shared_fd.cpp +++ b/src/libcamera/base/shared_fd.cpp @@ -2,7 +2,7 @@ /* * Copyright (C) 2019, Google Inc. * - * shared_fd.cpp - File descriptor wrapper with shared ownership + * File descriptor wrapper with shared ownership */ #include <libcamera/base/shared_fd.h> diff --git a/src/libcamera/base/signal.cpp b/src/libcamera/base/signal.cpp index a46386a0..b782e050 100644 --- a/src/libcamera/base/signal.cpp +++ b/src/libcamera/base/signal.cpp @@ -2,12 +2,13 @@ /* * Copyright (C) 2019, Google Inc. * - * signal.cpp - Signal & slot implementation + * Signal & slot implementation */ #include <libcamera/base/signal.h> #include <libcamera/base/mutex.h> +#include <libcamera/base/object.h> /** * \file base/signal.h @@ -74,7 +75,7 @@ SignalBase::SlotList SignalBase::slots() * * Signals and slots are a language construct aimed at communication between * objects through the observer pattern without the need for boilerplate code. - * See http://doc.qt.io/qt-5/signalsandslots.html for more information. + * See http://doc.qt.io/qt-6/signalsandslots.html for more information. * * Signals model events that can be observed from objects unrelated to the event * source. Slots are functions that are called in response to a signal. Signals diff --git a/src/libcamera/base/thread.cpp b/src/libcamera/base/thread.cpp index 6bda9d14..72733431 100644 --- a/src/libcamera/base/thread.cpp +++ b/src/libcamera/base/thread.cpp @@ -2,7 +2,7 @@ /* * Copyright (C) 2019, Google Inc. * - * thread.cpp - Thread support + * Thread support */ #include <libcamera/base/thread.h> @@ -18,6 +18,7 @@ #include <libcamera/base/log.h> #include <libcamera/base/message.h> #include <libcamera/base/mutex.h> +#include <libcamera/base/object.h> /** * \page thread Thread Support @@ -151,7 +152,7 @@ private: friend class ThreadMain; Thread *thread_; - bool running_; + bool running_ LIBCAMERA_TSA_GUARDED_BY(mutex_); pid_t tid_; Mutex mutex_; @@ -370,6 +371,12 @@ void Thread::run() void Thread::finishThread() { + /* + * Objects may have been scheduled for deletion right before the thread + * exited. Ensure they get deleted now, before the thread stops. + */ + dispatchMessages(Message::Type::DeferredDelete); + data_->mutex_.lock(); data_->running_ = false; data_->mutex_.unlock(); @@ -422,11 +429,15 @@ bool Thread::wait(utils::duration duration) { MutexLocker locker(data_->mutex_); + auto isRunning = ([&]() LIBCAMERA_TSA_REQUIRES(data_->mutex_) { + return !data_->running_; + }); + if (duration == utils::duration::max()) - data_->cv_.wait(locker, [&]() { return !data_->running_; }); + data_->cv_.wait(locker, isRunning); else hasFinished = data_->cv_.wait_for(locker, duration, - [&]() { return !data_->running_; }); + isRunning); } if (thread_.joinable()) diff --git a/src/libcamera/base/timer.cpp b/src/libcamera/base/timer.cpp index 74b060af..7b0f3725 100644 --- a/src/libcamera/base/timer.cpp +++ b/src/libcamera/base/timer.cpp @@ -2,7 +2,7 @@ /* * Copyright (C) 2019, Google Inc. * - * timer.cpp - Generic timer + * Generic timer */ #include <libcamera/base/timer.h> @@ -85,10 +85,8 @@ void Timer::start(std::chrono::milliseconds duration) */ void Timer::start(std::chrono::steady_clock::time_point deadline) { - if (Thread::current() != thread()) { - LOG(Timer, Error) << "Timer " << this << " << can't be started from another thread"; + if (!assertThreadBound("Timer can't be started from another thread")) return; - } deadline_ = deadline; @@ -114,13 +112,11 @@ void Timer::start(std::chrono::steady_clock::time_point deadline) */ void Timer::stop() { - if (!isRunning()) + if (!assertThreadBound("Timer can't be stopped from another thread")) return; - if (Thread::current() != thread()) { - LOG(Timer, Error) << "Timer " << this << " can't be stopped from another thread"; + if (!isRunning()) return; - } unregisterTimer(); } diff --git a/src/libcamera/base/unique_fd.cpp b/src/libcamera/base/unique_fd.cpp index 83d6919c..d0649e4d 100644 --- a/src/libcamera/base/unique_fd.cpp +++ b/src/libcamera/base/unique_fd.cpp @@ -2,7 +2,7 @@ /* * Copyright (C) 2021, Google Inc. * - * unique_fd.cpp - File descriptor wrapper that owns a file descriptor + * File descriptor wrapper that owns a file descriptor */ #include <libcamera/base/unique_fd.h> diff --git a/src/libcamera/base/utils.cpp b/src/libcamera/base/utils.cpp index 6a307940..ccb31063 100644 --- a/src/libcamera/base/utils.cpp +++ b/src/libcamera/base/utils.cpp @@ -2,12 +2,13 @@ /* * Copyright (C) 2019, Google Inc. * - * utils.cpp - Miscellaneous utility functions + * Miscellaneous utility functions */ #include <libcamera/base/utils.h> #include <iomanip> +#include <locale.h> #include <sstream> #include <stdlib.h> #include <string.h> @@ -463,6 +464,73 @@ std::string toAscii(const std::string &str) * \a b */ +#if HAVE_LOCALE_T + +namespace { + +/* + * RAII wrapper around locale_t instances, to support global locale instances + * without leaking memory. + */ +class Locale +{ +public: + Locale(const char *locale) + { + locale_ = newlocale(LC_ALL_MASK, locale, static_cast<locale_t>(0)); + } + + ~Locale() + { + freelocale(locale_); + } + + locale_t locale() { return locale_; } + +private: + locale_t locale_; +}; + +Locale cLocale("C"); + +} /* namespace */ + +#endif /* HAVE_LOCALE_T */ + +/** + * \brief Convert a string to a double independently of the current locale + * \param[in] nptr The string to convert + * \param[out] endptr Pointer to trailing portion of the string after conversion + * + * This function is a locale-independent version of the std::strtod() function. + * It behaves as the standard function, but uses the "C" locale instead of the + * current locale. + * + * \return The converted value, if any, or 0.0 if the conversion failed. + */ +double strtod(const char *__restrict nptr, char **__restrict endptr) +{ +#if HAVE_LOCALE_T + return strtod_l(nptr, endptr, cLocale.locale()); +#else + /* + * If the libc implementation doesn't provide locale object support, + * assume that strtod() is locale-independent. + */ + return ::strtod(nptr, endptr); +#endif +} + +/** + * \fn to_underlying(Enum e) + * \brief Convert an enumeration to its underlygin type + * \param[in] e Enumeration value to convert + * + * This function is equivalent to the C++23 std::to_underlying(). + * + * \return The value of e converted to its underlying type + */ + } /* namespace utils */ #ifndef __DOXYGEN__ |