/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2019, Google Inc. * * process.cpp - Process object */ #include "libcamera/internal/process.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /** * \file process.h * \brief Process object */ namespace libcamera { LOG_DEFINE_CATEGORY(Process) /** * \class ProcessManager * \brief Manager of processes * * The ProcessManager singleton keeps track of all created Process instances, * and manages the signal handling involved in terminating processes. */ namespace { void sigact(int signal, siginfo_t *info, void *ucontext) { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-result" /* * We're in a signal handler so we can't log any message, and we need * to continue anyway. */ char data = 0; write(ProcessManager::instance()->writePipe(), &data, sizeof(data)); #pragma GCC diagnostic pop const struct sigaction &oldsa = ProcessManager::instance()->oldsa(); if (oldsa.sa_flags & SA_SIGINFO) { oldsa.sa_sigaction(signal, info, ucontext); } else { if (oldsa.sa_handler != SIG_IGN && oldsa.sa_handler != SIG_DFL) oldsa.sa_handler(signal); } } } /* namespace */ void ProcessManager::sighandler() { char data; ssize_t ret = read(pipe_[0].get(), &data, sizeof(data)); if (ret < 0) { LOG(Process, Error) << "Failed to read byte from signal handler pipe"; return; } for (auto it = processes_.begin(); it != processes_.end(); ) { Process *process = *it; int wstatus; pid_t pid = waitpid(process->pid_, &wstatus, WNOHANG); if (process->pid_ != pid) { ++it; continue; } it = processes_.erase(it); process->died(wstatus); } } /** * \brief Register process with process manager * \param[in] proc Process to register * * This function registers the \a proc with the process manager. It * shall be called by the parent process after successfully forking, in * order to let the parent signal process termination. */ void ProcessManager::registerProcess(Process *proc) { processes_.push_back(proc); } ProcessManager *ProcessManager::self_ = nullptr; /** * \brief Construct a ProcessManager instance * * The ProcessManager class is meant to only be instantiated once, by the * CameraManager. */ ProcessManager::ProcessManager() { if (self_) LOG(Process, Fatal) << "Multiple ProcessManager objects are not allowed"; sigaction(SIGCHLD, NULL, &oldsa_); struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_sigaction = &sigact; memcpy(&sa.sa_mask, &oldsa_.sa_mask, sizeof(sa.sa_mask)); sigaddset(&sa.sa_mask, SIGCHLD); sa.sa_flags = oldsa_.sa_flags | SA_SIGINFO; sigaction(SIGCHLD, &sa, NULL); int pipe[2]; if (pipe2(pipe, O_CLOEXEC | O_DIRECT | O_NONBLOCK)) LOG(Process, Fatal) << "Failed to initialize pipe for signal handling"; pipe_[0] = UniqueFD(pipe[0]); pipe_[1] = UniqueFD(pipe[1]); sigEvent_ = new EventNotifier(pipe_[0].get(), EventNotifier::Read); sigEvent_->activated.connect(this, &ProcessManager::sighandler); self_ = this; } ProcessManager::~ProcessManager() { sigaction(SIGCHLD, &oldsa_, NULL); delete sigEvent_; self_ = nullptr; } /** * \brief Retrieve the Process manager instance * * The ProcessManager is constructed by the CameraManager. This function shall * be used to retrieve the single instance of the manager. * * \return The Process manager instance */ ProcessManager *ProcessManager::instance() { return self_; } /** * \brief Retrieve the Process manager's write pipe * * This function is meant only to be used by the static signal handler. * * \return Pipe for writing */ int ProcessManager::writePipe() const { return pipe_[1].get(); } /** * \brief Retrive the old signal action data * * This function is meant only to be used by the static signal handler. * * \return The old signal action data */ const struct sigaction &ProcessManager::oldsa() const { return oldsa_; } /** * \class Process * \brief Process object * * The Process class models a process, and simplifies spawning new processes * and monitoring the exiting of a process. */ /** * \enum Process::ExitStatus * \brief Exit status of process * \var Process::NotExited * The process hasn't exited yet * \var Process::NormalExit * The process exited normally, either via exit() or returning from main * \var Process::SignalExit * The process was terminated by a signal (this includes crashing) */ Process::Process() : pid_(-1), running_(false), exitStatus_(NotExited), exitCode_(0) { } Process::~Process() { kill(); /* \todo wait for child process to exit */ } /** * \brief Fork and exec a process, and close fds * \param[in] path Path to executable * \param[in] args Arguments to pass to executable (optional) * \param[in] fds Vector of file descriptors to keep open (optional) * * Fork a process, and exec the executable specified by path. Prior to * exec'ing, but after forking, all file descriptors except for those * specified in fds will be closed. * * All indexes of args will be incremented by 1 before being fed to exec(), * so args[0] should not need to be equal to path. * * \return Zero on successful fork, exec, and closing the file descriptors, * or a negative error code otherwise */ int Process::start(const std::string &path, const std::vector &args, const std::vector &fds) { int ret; if (running_) return 0; int childPid = fork(); if (childPid == -1) { ret = -errno; LOG(Process, Error) << "Failed to fork: " << strerror(-ret); return ret; } else if (childPid) { pid_ = childPid; ProcessManager::instance()->registerProcess(this); running_ = true; return 0; } else { if (isolate()) _exit(EXIT_FAILURE); closeAllFdsExcept(fds); const c/* SPDX-License-Identifier: BSD-2-Clause */ /* * Copyright (C) 2019-2021, Raspberry Pi (Trading) Limited * * sdn.cpp - SDN (spatial denoise) control algorithm */ #include "libcamera/internal/log.h" #include "../denoise_status.h" #include "../noise_status.h" #include "sdn.hpp" using namespace RPiController; using namespace libcamera; LOG_DEFINE_CATEGORY(RPiSdn) // Calculate settings for the spatial denoise block using the noise profile in // the image metadata. #define NAME "rpi.sdn" Sdn::Sdn(Controller *controller) : DenoiseAlgorithm(controller), mode_(DenoiseMode::ColourOff) { } char const *Sdn::Name() const { return NAME; } void Sdn::Read(boost::property_tree::ptree const &params) { deviation_ = params.get<double>("deviation", 3.2); strength_ = params.get<double>("strength", 0.75); } void Sdn::Initialise() {} void Sdn::Prepare(Metadata *image_metadata) { struct NoiseStatus noise_status = {}; noise_status.noise_slope = 3.0; // in case no metadata if (image_metadata->Get("noise.status", noise_status) != 0) LOG(RPiSdn, Warning) << "no noise profile found"; LOG(RPiSdn, Debug) << "Noise profile: constant " << noise_status.noise_constant << " slope " << noise_status.noise_slope; struct DenoiseStatus status; status.noise_constant = noise_status.noise_constant * deviation_; status.noise_slope = noise_status.noise_slope * deviation_; status.strength = strength_; status.mode = static_cast<std::underlying_type_t<DenoiseMode>>(mode_); image_metadata->Set("denoise.status", status); LOG(RPiSdn, Debug) << "programmed constant " << status.noise_constant << " slope " << status.noise_slope << " strength " << status.strength; } void Sdn::SetMode(DenoiseMode mode) { // We only distinguish between off and all other modes. mode_ = mode; } // Register algorithm with the system. static Algorithm *Create(Controller *controller) { return (Algorithm *)new Sdn(controller); } static RegisterAlgorithm reg(NAME, &Create);