summaryrefslogtreecommitdiff
path: root/src/cam/event_loop.h
AgeCommit message (Collapse)Author
2022-05-23cam: event_loop: Add timer events to event loopEric Curtin
Extend the EventLoop class to support periodic timer events. This can be used to run tasks periodically, such as handling the event loop of SDL. Signed-off-by: Eric Curtin <ecurtin@redhat.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Tested-by: Jacopo Mondi <jacopo@jmondi.org> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
2022-05-23cam: event_loop: Rename addEvent to addFdEventEric Curtin
With the addition of addTimerEvent, the naming of addEvent is specific to the management of an fd, while the naming is generic. Update the name to make the naming scheme consistent in specifying the type of event to be added. Signed-off-by: Eric Curtin <ecurtin@redhat.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Tested-by: Jacopo Mondi <jacopo@jmondi.org> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
2021-11-24cam: Convert to pragma onceKieran Bingham
Remove the verbose #ifndef/#define/#endif pattern for maintaining header idempotency, and replace it with a simple #pragma once. This simplifies the headers, and prevents redundant changes when header files get moved. Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Jean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com>
2021-08-05cam: event_loop: Add support for file descriptor eventsLaurent Pinchart
Extend the EventLoop class to support watching file descriptors for read and write events. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se> Reviewed-by: Paul Elder <paul.elder@ideasonboard.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>
2021-02-05cam: event_loop: Execute events in the libevent loopNiklas Söderlund
Cam uses libevent to deal with threads and idle loop while still implementing its own event queue. This creates issues when the event loop is terminated as it might get stuck in the idle loop if exit() is called while the thread is busy with dispatchCalls(). Solve this by removing the custom event execution and instead injecting the calls as events to the base event loop. Reported-by: Sebastian Fricke <sebastian.fricke@posteo.net> Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
2021-02-05cam: event_loop: Rename event_ to base_Niklas Söderlund
The 'event' variable name is usually used for events added to the base event loop, not the loop itself. Rename the struct event_base member to base_ as a preparation for future work adding events to the loop. There is no functional change. Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
2020-11-15cam: event_loop: Add deferred calls supportLaurent Pinchart
Add a deferred cals queue to the EventLoop class to support queuing calls from a different thread and processing them in the event loop's thread. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
2020-11-15cam: Use libevent to implement event loopLaurent Pinchart
To prepare for removal of the EventDispatcher from the libcamera public API, switch to libevent to handle the event loop. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
2019-11-08libcamera: Remove unneeded semicolonsLaurent Pinchart
Comply with the coding style by removing lots of unneeded semicolons. Fix a few other coding style violations on the lines touched by those fixes. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2019-01-25cam: Add event loopLaurent Pinchart
Add a simple event loop to the cam application and use it in the main() function, with an example of how to handle SIGINT to gracefully stop the loop. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
236' href='#n236'>236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
 * Copyright (C) 2020, Google Inc.
 *
 * span.h - C++20 std::span<> implementation for C++11
 */

#pragma once

#include <array>
#include <iterator>
#include <limits>
#include <stddef.h>
#include <type_traits>

namespace libcamera {

static constexpr std::size_t dynamic_extent = std::numeric_limits<std::size_t>::max();

template<typename T, std::size_t Extent = dynamic_extent>
class Span;

namespace details {

template<typename U>
struct is_array : public std::false_type {
};

template<typename U, std::size_t N>
struct is_array<std::array<U, N>> : public std::true_type {
};

template<typename U>
struct is_span : public std::false_type {
};

template<typename U, std::size_t Extent>
struct is_span<Span<U, Extent>> : public std::true_type {
};

} /* namespace details */

namespace utils {

template<typename C>
constexpr auto size(const C &c) -> decltype(c.size())
{
	return c.size();
}

template<typename C>
constexpr auto data(const C &c) -> decltype(c.data())
{
	return c.data();
}

template<typename C>
constexpr auto data(C &c) -> decltype(c.data())
{
	return c.data();
}

template<class T, std::size_t N>
constexpr T *data(T (&array)[N]) noexcept
{
	return array;
}

template<std::size_t I, typename T>
struct tuple_element;

template<std::size_t I, typename T, std::size_t N>
struct tuple_element<I, Span<T, N>> {
	using type = T;
};

template<typename T>
struct tuple_size;

template<typename T, std::size_t N>
struct tuple_size<Span<T, N>> : public std::integral_constant<std::size_t, N> {
};

template<typename T>
struct tuple_size<Span<T, dynamic_extent>>;

} /* namespace utils */

template<typename T, std::size_t Extent>
class Span
{
public:
	using element_type = T;
	using value_type = typename std::remove_cv_t<T>;
	using size_type = std::size_t;
	using difference_type = std::ptrdiff_t;
	using pointer = T *;
	using const_pointer = const T *;
	using reference = T &;
	using const_reference = const T &;
	using iterator = pointer;
	using const_iterator = const_pointer;
	using reverse_iterator = std::reverse_iterator<iterator>;
	using const_reverse_iterator = std::reverse_iterator<const_iterator>;

	static constexpr std::size_t extent = Extent;

	template<bool Dependent = false,
		 typename = std::enable_if_t<Dependent || Extent == 0>>
	constexpr Span() noexcept
		: data_(nullptr)
	{
	}

	explicit constexpr Span(pointer ptr, [[maybe_unused]] size_type count)
		: data_(ptr)
	{
	}

	explicit constexpr Span(pointer first, [[maybe_unused]] pointer last)
		: data_(first)
	{
	}

	template<std::size_t N>
	constexpr Span(element_type (&arr)[N],
		       std::enable_if_t<std::is_convertible<std::remove_pointer_t<decltype(utils::data(arr))> (*)[],
							    element_type (*)[]>::value &&
					N == Extent,
					std::nullptr_t> = nullptr) noexcept
		: data_(arr)
	{
	}

	template<std::size_t N>
	constexpr Span(std::array<value_type, N> &arr,
		       std::enable_if_t<std::is_convertible<std::remove_pointer_t<decltype(utils::data(arr))> (*)[],
							    element_type (*)[]>::value &&
					N == Extent,
					std::nullptr_t> = nullptr) noexcept
		: data_(arr.data())
	{
	}

	template<std::size_t N>
	constexpr Span(const std::array<value_type, N> &arr,
		       std::enable_if_t<std::is_convertible<std::remove_pointer_t<decltype(utils::data(arr))> (*)[],
							    element_type (*)[]>::value &&
					N == Extent,
					std::nullptr_t> = nullptr) noexcept
		: data_(arr.data())
	{
	}

	template<class Container>
	explicit constexpr Span(Container &cont,
				std::enable_if_t<!details::is_span<Container>::value &&
						 !details::is_array<Container>::value &&
						 !std::is_array<Container>::value &&
						 std::is_convertible<std::remove_pointer_t<decltype(utils::data(cont))> (*)[],
								     element_type (*)[]>::value,
						 std::nullptr_t> = nullptr)
		: data_(utils::data(cont))
	{
	}

	template<class Container>
	explicit constexpr Span(const Container &cont,
				std::enable_if_t<!details::is_span<Container>::value &&
						 !details::is_array<Container>::value &&
						 !std::is_array<Container>::value &&
						 std::is_convertible<std::remove_pointer_t<decltype(utils::data(cont))> (*)[],
								     element_type (*)[]>::value,
						 std::nullptr_t> = nullptr)
		: data_(utils::data(cont))
	{
		static_assert(utils::size(cont) == Extent, "Size mismatch");
	}

	template<class U, std::size_t N>
	explicit constexpr Span(const Span<U, N> &s,
				std::enable_if_t<std::is_convertible<U (*)[], element_type (*)[]>::value &&
						 N == Extent,
						 std::nullptr_t> = nullptr) noexcept
		: data_(s.data())
	{
	}

	constexpr Span(const Span &other) noexcept = default;
	constexpr Span &operator=(const Span &other) noexcept = default;

	constexpr iterator begin() const { return data(); }
	constexpr const_iterator cbegin() const { return begin(); }
	constexpr iterator end() const { return data() + size(); }
	constexpr const_iterator cend() const { return end(); }
	constexpr reverse_iterator rbegin() const { return reverse_iterator(end()); }
	constexpr const_reverse_iterator crbegin() const { return rbegin(); }
	constexpr reverse_iterator rend() const { return reverse_iterator(begin()); }
	constexpr const_reverse_iterator crend() const { return rend(); }

	constexpr reference front() const { return *data(); }
	constexpr reference back() const { return *(data() + size() - 1); }
	constexpr reference operator[](size_type idx) const { return data()[idx]; }
	constexpr pointer data() const noexcept { return data_; }

	constexpr size_type size() const noexcept { return Extent; }
	constexpr size_type size_bytes() const noexcept { return size() * sizeof(element_type); }
	constexpr bool empty() const noexcept { return size() == 0; }

	template<std::size_t Count>
	constexpr Span<element_type, Count> first() const
	{
		static_assert(Count <= Extent, "Count larger than size");
		return Span<element_type, Count>{ data(), Count };
	}

	constexpr Span<element_type, dynamic_extent> first(std::size_t Count) const
	{
		return Span<element_type, dynamic_extent>{ data(), Count };
	}

	template<std::size_t Count>
	constexpr Span<element_type, Count> last() const
	{
		static_assert(Count <= Extent, "Count larger than size");
		return Span<element_type, Count>{ data() + size() - Count, Count };
	}

	constexpr Span<element_type, dynamic_extent> last(std::size_t Count) const
	{
		return Span<element_type, dynamic_extent>{ data() + size() - Count, Count };
	}

	template<std::size_t Offset, std::size_t Count = dynamic_extent>
	constexpr Span<element_type, Count != dynamic_extent ? Count : Extent - Offset> subspan() const
	{
		static_assert(Offset <= Extent, "Offset larger than size");
		static_assert(Count == dynamic_extent || Count + Offset <= Extent,
			      "Offset + Count larger than size");
		return Span<element_type, Count != dynamic_extent ? Count : Extent - Offset>{
			data() + Offset,
			Count == dynamic_extent ? size() - Offset : Count
		};
	}

	constexpr Span<element_type, dynamic_extent>
	subspan(std::size_t Offset, std::size_t Count = dynamic_extent) const
	{
		return Span<element_type, dynamic_extent>{
			data() + Offset,
			Count == dynamic_extent ? size() - Offset : Count
		};
	}

private:
	pointer data_;
};

template<typename T>
class Span<T, dynamic_extent>
{
public:
	using element_type = T;
	using value_type = typename std::remove_cv_t<T>;
	using size_type = std::size_t;
	using difference_type = std::ptrdiff_t;
	using pointer = T *;
	using const_pointer = const T *;
	using reference = T &;
	using const_reference = const T &;
	using iterator = T *;
	using const_iterator = const T *;
	using reverse_iterator = std::reverse_iterator<iterator>;
	using const_reverse_iterator = std::reverse_iterator<const_iterator>;

	static constexpr std::size_t extent = dynamic_extent;

	constexpr Span() noexcept
		: data_(nullptr), size_(0)
	{
	}

	constexpr Span(pointer ptr, size_type count)
		: data_(ptr), size_(count)
	{
	}

	constexpr Span(pointer first, pointer last)
		: data_(first), size_(last - first)
	{
	}

	template<std::size_t N>
	constexpr Span(element_type (&arr)[N],
		       std::enable_if_t<std::is_convertible<std::remove_pointer_t<decltype(utils::data(arr))> (*)[],
							    element_type (*)[]>::value,
					std::nullptr_t> = nullptr) noexcept
		: data_(arr), size_(N)
	{
	}

	template<std::size_t N>
	constexpr Span(std::array<value_type, N> &arr,
		       std::enable_if_t<std::is_convertible<std::remove_pointer_t<decltype(utils::data(arr))> (*)[],
							    element_type (*)[]>::value,
					std::nullptr_t> = nullptr) noexcept
		: data_(utils::data(arr)), size_(N)
	{
	}

	template<std::size_t N>
	constexpr Span(const std::array<value_type, N> &arr) noexcept
		: data_(utils::data(arr)), size_(N)
	{
	}

	template<class Container>
	constexpr Span(Container &cont,
		       std::enable_if_t<!details::is_span<Container>::value &&
					!details::is_array<Container>::value &&
					!std::is_array<Container>::value &&
					std::is_convertible<std::remove_pointer_t<decltype(utils::data(cont))> (*)[],
							    element_type (*)[]>::value,
					std::nullptr_t> = nullptr)
		: data_(utils::data(cont)), size_(utils::size(cont))
	{
	}

	template<class Container>
	constexpr Span(const Container &cont,
		       std::enable_if_t<!details::is_span<Container>::value &&
					!details::is_array<Container>::value &&
					!std::is_array<Container>::value &&
					std::is_convertible<std::remove_pointer_t<decltype(utils::data(cont))> (*)[],
							    element_type (*)[]>::value,
					std::nullptr_t> = nullptr)
		: data_(utils::data(cont)), size_(utils::size(cont))
	{
	}

	template<class U, std::size_t N>
	constexpr Span(const Span<U, N> &s,
		       std::enable_if_t<std::is_convertible<U (*)[], element_type (*)[]>::value,
					std::nullptr_t> = nullptr) noexcept
		: data_(s.data()), size_(s.size())
	{
	}

	constexpr Span(const Span &other) noexcept = default;

	constexpr Span &operator=(const Span &other) noexcept
	{
		data_ = other.data_;
		size_ = other.size_;
		return *this;
	}

	constexpr iterator begin() const { return data(); }
	constexpr const_iterator cbegin() const { return begin(); }
	constexpr iterator end() const { return data() + size(); }
	constexpr const_iterator cend() const { return end(); }
	constexpr reverse_iterator rbegin() const { return reverse_iterator(end()); }
	constexpr const_reverse_iterator crbegin() const { return rbegin(); }
	constexpr reverse_iterator rend() const { return reverse_iterator(begin()); }
	constexpr const_reverse_iterator crend() const { return rend(); }

	constexpr reference front() const { return *data(); }
	constexpr reference back() const { return *(data() + size() - 1); }
	constexpr reference operator[](size_type idx) const { return data()[idx]; }
	constexpr pointer data() const noexcept { return data_; }

	constexpr size_type size() const noexcept { return size_; }
	constexpr size_type size_bytes() const noexcept { return size() * sizeof(element_type); }
	constexpr bool empty() const noexcept { return size() == 0; }

	template<std::size_t Count>
	constexpr Span<element_type, Count> first() const
	{
		return Span<element_type, Count>{ data(), Count };
	}

	constexpr Span<element_type, dynamic_extent> first(std::size_t Count) const
	{
		return { data(), Count };
	}

	template<std::size_t Count>
	constexpr Span<element_type, Count> last() const
	{
		return Span<element_type, Count>{ data() + size() - Count, Count };
	}

	constexpr Span<element_type, dynamic_extent> last(std::size_t Count) const
	{
		return Span<element_type, dynamic_extent>{ data() + size() - Count, Count };
	}

	template<std::size_t Offset, std::size_t Count = dynamic_extent>
	constexpr Span<element_type, Count> subspan() const
	{
		return Span<element_type, Count>{
			data() + Offset,
			Count == dynamic_extent ? size() - Offset : Count
		};
	}

	constexpr Span<element_type, dynamic_extent>
	subspan(std::size_t Offset, std::size_t Count = dynamic_extent) const
	{
		return Span<element_type, dynamic_extent>{
			data() + Offset,
			Count == dynamic_extent ? size() - Offset : Count
		};
	}

private:
	pointer data_;
	size_type size_;
};

} /* namespace libcamera */