libcamera/src/apps/common/event_loop.cpp
Barnabás Pőcze b1b99f4d66 apps: common: event_loop: Take callbacks by rvalue ref
Using a const lvalue reference to `std::function<>` is not ideal
because it forces a copy to happen. Use an rvalue reference and
`std::move()` to avoid that.

Signed-off-by: Barnabás Pőcze <pobrn@protonmail.com>
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
2025-02-27 17:29:28 +01:00

150 lines
3 KiB
C++

/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2019, Google Inc.
*
* cam - Event loop
*/
#include "event_loop.h"
#include <assert.h>
#include <event2/event.h>
#include <event2/thread.h>
#include <iostream>
EventLoop *EventLoop::instance_ = nullptr;
EventLoop::EventLoop()
{
assert(!instance_);
evthread_use_pthreads();
base_ = event_base_new();
instance_ = this;
}
EventLoop::~EventLoop()
{
instance_ = nullptr;
events_.clear();
event_base_free(base_);
libevent_global_shutdown();
}
EventLoop *EventLoop::instance()
{
return instance_;
}
int EventLoop::exec()
{
exitCode_ = -1;
event_base_loop(base_, EVLOOP_NO_EXIT_ON_EMPTY);
return exitCode_;
}
void EventLoop::exit(int code)
{
exitCode_ = code;
event_base_loopbreak(base_);
}
void EventLoop::callLater(std::function<void()> &&func)
{
{
std::unique_lock<std::mutex> locker(lock_);
calls_.push_back(std::move(func));
}
event_base_once(base_, -1, EV_TIMEOUT, dispatchCallback, this, nullptr);
}
void EventLoop::addFdEvent(int fd, EventType type,
std::function<void()> &&callback)
{
std::unique_ptr<Event> event = std::make_unique<Event>(std::move(callback));
short events = (type & Read ? EV_READ : 0)
| (type & Write ? EV_WRITE : 0)
| EV_PERSIST;
event->event_ = event_new(base_, fd, events, &EventLoop::Event::dispatch,
event.get());
if (!event->event_) {
std::cerr << "Failed to create event for fd " << fd << std::endl;
return;
}
int ret = event_add(event->event_, nullptr);
if (ret < 0) {
std::cerr << "Failed to add event for fd " << fd << std::endl;
return;
}
events_.push_back(std::move(event));
}
void EventLoop::addTimerEvent(const std::chrono::microseconds period,
std::function<void()> &&callback)
{
std::unique_ptr<Event> event = std::make_unique<Event>(std::move(callback));
event->event_ = event_new(base_, -1, EV_PERSIST, &EventLoop::Event::dispatch,
event.get());
if (!event->event_) {
std::cerr << "Failed to create timer event" << std::endl;
return;
}
struct timeval tv;
tv.tv_sec = period.count() / 1000000ULL;
tv.tv_usec = period.count() % 1000000ULL;
int ret = event_add(event->event_, &tv);
if (ret < 0) {
std::cerr << "Failed to add timer event" << std::endl;
return;
}
events_.push_back(std::move(event));
}
void EventLoop::dispatchCallback([[maybe_unused]] evutil_socket_t fd,
[[maybe_unused]] short flags, void *param)
{
EventLoop *loop = static_cast<EventLoop *>(param);
loop->dispatchCall();
}
void EventLoop::dispatchCall()
{
std::function<void()> call;
{
std::unique_lock<std::mutex> locker(lock_);
if (calls_.empty())
return;
call = calls_.front();
calls_.pop_front();
}
call();
}
EventLoop::Event::Event(std::function<void()> &&callback)
: callback_(std::move(callback)), event_(nullptr)
{
}
EventLoop::Event::~Event()
{
event_del(event_);
event_free(event_);
}
void EventLoop::Event::dispatch([[maybe_unused]] int fd,
[[maybe_unused]] short events, void *arg)
{
Event *event = static_cast<Event *>(arg);
event->callback_();
}