summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2022-12-12 15:04:49 +0200
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2022-12-12 15:51:39 +0200
commite653f4c13e32225c2d1c304f3e6c44ff4efbdfe9 (patch)
tree721956a4c96200a87a4b8ddd84d3ac6b1f167dc0 /utils
parentb026e4a6a0a620ce994938c3d1babd3f3df4a47e (diff)
Documentation: contributing: Add commit message guidelines
All developers, whether junior or experienced, can benefit from improving their commit message writing skills. Add a paragraph to the contribution documentation to explain this, with a link to a good guide. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>
Diffstat (limited to 'utils')
0 files changed, 0 insertions, 0 deletions
5' href='#n105'>105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (C) 2019, Google Inc.
 *
 * event_loop.cpp - 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(const std::function<void()> &func)
{
	{
		std::unique_lock<std::mutex> locker(lock_);
		calls_.push_back(func);
	}

	event_base_once(base_, -1, EV_TIMEOUT, dispatchCallback, this, nullptr);
}

void EventLoop::addFdEvent(int fd, EventType type,
			   const std::function<void()> &callback)
{
	std::unique_ptr<Event> event = std::make_unique<Event>(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,
			      const std::function<void()> &callback)
{
	std::unique_ptr<Event> event = std::make_unique<Event>(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(const std::function<void()> &callback)
	: callback_(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_();
}