/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2018, Google Inc. * * byte_stream_buffer.cpp - ByteStreamBuffer tests */ #include #include #include "libcamera/internal/byte_stream_buffer.h" #include "test.h" using namespace std; using namespace libcamera; class ByteStreamBufferTest : public Test { protected: int run() { std::array data; unsigned int i; uint32_t value; int ret; /* * Write mode. */ ByteStreamBuffer wbuf(data.data(), data.size()); if (wbuf.base() != data.data() || wbuf.size() != data.size() || wbuf.offset() != 0 || wbuf.overflow()) { cerr << "Write buffer incorrectly constructed" << endl; return TestFail; } /* Test write. */ value = 0x12345678; ret = wbuf.write(&value); if (ret || wbuf.offset() != 4 || wbuf.overflow() || *reinterpret_cast(data.data()) != 0x12345678) { cerr << "Write failed on write buffer" << endl; return TestFail; } /* Test write carve out. */ ByteStreamBuffer wco = wbuf.carveOut(10); if (wco.base() != wbuf.base() + 4 || wco.size() != 10 || wco.offset() != 0 || wco.overflow() || wbuf.offset() != 14 || wbuf.overflow()) { cerr << "Carving out write buffer failed" << endl; return TestFail; } /* Test write on the carved out buffer. */ value = 0x87654321; ret = wco.write(&value); if (ret || wco.offset() != 4 || wco.overflow() || *reinterpret_cast(data.data() + 4) != 0x87654321) { cerr << "Write failed on carve out buffer" << endl; return TestFail; } if (wbuf.offset() != 14 || wbuf.overflow()) { cerr << "Write on carve out buffer modified write buffer" << endl; return TestFail; } /* Test read, this should fail. */ ret = wbuf.read(&value); if (!ret || wbuf.overflow()) { cerr << "Read should fail on write buffer" << endl; return TestFail; } /* Test overflow on carved out buffer. */ for (i = 0; i < 2; ++i) { ret = wco.write(&value); if (ret < 0) break; } if (i != 1 || !wco.overflow() || !wbuf.overflow()) { cerr << "Write on carve out buffer failed to overflow" << endl; return TestFail; } /* Test reinitialization of the buffer. */ wbuf = ByteStreamBuffer(data.data(), data.size()); if (wbuf.overflow() || wbuf.base() != data.data() || wbuf.offset() != 0) { cerr << "Write buffer reinitialization failed" << endl; return TestFail; } /* * Read mode. */ ByteStreamBuffer rbuf(const_cast(data.data()), data.size()); if (rbuf.base() != data.data() || rbuf.size() != data.size() || rbuf.offset() != 0 || rbuf.overflow()) { cerr << "Read buffer incorrectly constructed" << endl; return TestFail; } /* Test read. */ value = 0; ret = rbuf.read(&value); if (ret || rbuf.offset() != 4 || rbuf.overflow() || value != 0x12345678) { cerr << "Write failed on write buffer" << endl; return TestFail; } /* Test read carve out. */ ByteStreamBuffer rco = rbuf.carveOut(10); if (rco.base() != rbuf.base() + 4 || rco.size() != 10 || rco.offset() != 0 || rco.overflow() || rbuf.offset() != 14 || rbuf.overflow()) { cerr << "Carving out read buffer failed" << endl; return TestFail; } /* Test read on the carved out buffer. */ value = 0; ret = rco.read(&value); if (ret || rco.offset() != 4 || rco.overflow() || value != 0x87654321) { cerr << "Read failed on carve out buffer" << endl; return TestFail; } if (rbuf.offset() != 14 || rbuf.overflow()) { cerr << "Read on carve out buffer modified read buffer" << endl; return TestFail; } /* Test write, this should fail. */ ret = rbuf.write(&value); if (!ret || rbuf.overflow()) { cerr << "Write should fail on read buffer" << endl; return TestFail; } /* Test overflow on carved out buffer. */ for (i = 0; i < 2; ++i) { ret = rco.read(&value); if (ret < 0) break; } if (i != 1 || !rco.overflow() || !rbuf.overflow()) { cerr << "Read on carve out buffer failed to overflow" << endl; return TestFail; } /* Test reinitialization of the buffer. */ rbuf = ByteStreamBuffer(const_cast(data.data()), data.size()); if (rbuf.overflow() || rbuf.base() != data.data() || rbuf.offset() != 0) { cerr << "Read buffer reinitialization failed" << endl; return TestFail; } return TestPass; } }; TEST_REGISTER(ByteStreamBufferTest) ref='#n39'>39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 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_();
}