summaryrefslogtreecommitdiff
path: root/test/ipc
AgeCommit message (Collapse)Author
2020-05-16libcamera: Move internal headers to include/libcamera/internal/Laurent Pinchart
The libcamera internal headers are located in src/libcamera/include/. The directory is added to the compiler headers search path with a meson include_directories() directive, and internal headers are included with (e.g. for the internal semaphore.h header) #include "semaphore.h" All was well, until libcxx decided to implement the C++20 synchronization library. The __threading_support header gained a #include <semaphore.h> to include the pthread's semaphore support. As include_directories() adds src/libcamera/include/ to the compiler search path with -I, the internal semaphore.h is included instead of the pthread version. Needless to say, the compiler isn't happy. Three options have been considered to fix this issue: - Use -iquote instead of -I. The -iquote option instructs gcc to only consider the header search path for headers included with the "" version. Meson unfortunately doesn't support this option. - Rename the internal semaphore.h header. This was deemed to be the beginning of a long whack-a-mole game, where namespace clashes with system libraries would appear over time (possibly dependent on particular system configurations) and would need to be constantly fixed. - Move the internal headers to another directory to create a unique namespace through path components. This causes lots of churn in all the existing source files through the all project. The first option would be best, but isn't available to us due to missing support in meson. Even if -iquote support was added, we would need to fix the problem before a new version of meson containing the required support would be released. The third option is thus the only practical solution available. Bite the bullet, and do it, moving headers to include/libcamera/internal/. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Acked-by: Jacopo Mondi <jacopo@jmondi.org>
2020-05-13licenses: License all meson files under CC0-1.0Laurent Pinchart
In an attempt to clarify the license terms of all files in the libcamera project, the build system files deserve particular attention. While they describe how the binaries are created, they are not themselves transformed into any part of binary distributions of the software, and thus don't influence the copyright on the binary packages. They are however subject to copyright, and thus influence the distribution terms of the source packages. Most of the meson.build files would not meet the threshold of originality criteria required for copyright protection. Some of the more complex meson.build files may be eligible for copyright protection. To avoid any ambiguity and uncertainty, state our intent to not assert copyrights on the build system files by putting them in the public domain with the CC0-1.0 license. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Acked-by: Giulio Benetti <giulio.benetti@micronovasrl.com> Acked-by: Jacopo Mondi <jacopo@jmondi.org> Acked-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Acked-by: Naushir Patuck <naush@raspberrypi.com> Acked-by: Nicolas Dufresne <nicolas.dufresne@collabora.com> Acked-by: Niklas Söderlund <niklas.soderlund@ragnatech.se> Acked-by: Paul Elder <paul.elder@ideasonboard.com> Acked-by: Show Liu <show.liu@linaro.org>
2019-08-19test: Get event dispatcher from current threadLaurent Pinchart
For all tests that don't otherwise require access to the camera manager, get the event dispatcher from the current thread instead of the camera manager. This prepares for the removal of CameraManager::instance(). Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
2019-08-19test: unixsocket: Fix typo in error messageLaurent Pinchart
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
2019-07-04test: Allow self-contained tests to run in parallelNiklas Söderlund
The IPA, IPC and Stream tests are self-contained so they can run in parallel. Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
2019-07-02test: ipc: unix: Add test for IPCUnixSocketNiklas Söderlund
Test that the IPC supports sending data and file descriptors over the IPC medium. To be able to execute the test two parts are needed, one to drive the test and act as the libcamera (master) and a one to act as the IPA (slave). The master drives the testing posting requests to the slave to process and sometimes respond to. A few different tests are performed. - Master sends an array to the slave which responds with a reversed copy of the array. The master verifies that a reversed array is returned. - Master tries to send an empty message making sure that the send call fails. - Master sends a list of file descriptors and ask the slave to calculate and respond with the sum of the size of the files. The master verifies that the calculated size is correct. - Master sends a pre-computed size and a list of file descriptors and asks the slave to verify that the pre-computed size matches the sum of the size of the file descriptors. - Master sends two file descriptors and asks the slave to join the file contents in a new file and respond with its file descriptor. The master then verifies that the content of the returned file descriptor matches the order of the original two files. Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
/a> 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
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
 * Copyright (C) 2020, Google Inc.
 *
 * file.cpp - File I/O operations
 */

#include "file.h"

#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include "log.h"

/**
 * \file file.h
 * \brief File I/O operations
 */

namespace libcamera {

LOG_DEFINE_CATEGORY(File);

/**
 * \class File
 * \brief Interface for I/O operations on files
 *
 * The File class provides an interface to perform I/O operations on files. It
 * wraps opening, closing and mapping files in memory, and handles the cleaning
 * of allocated resources.
 *
 * File instances are usually constructed with a file name, but the name can be
 * set later through the setFileName() function. Instances are not automatically
 * opened when constructed, and shall be opened explictly with open().
 *
 * Files can be mapped to the process memory with map(). Mapped regions can be
 * unmapped manually with munmap(), and are automatically unmapped when the File
 * is destroyed or when it is used to reference another file with setFileName().
 */

/**
 * \enum File::MapFlag
 * \brief Flags for the File::map() function
 * \var File::MapNoOption
 * \brief No option (used as default value)
 * \var File::MapPrivate
 * \brief The memory region is mapped as private, changes are not reflected in
 * the file constents
 */

/**
 * \enum File::OpenMode
 * \brief Mode in which a file is opened
 * \var File::NotOpen
 * \brief The file is not open
 * \var File::ReadOnly
 * \brief The file is open for reading
 * \var File::WriteOnly
 * \brief The file is open for writing
 * \var File::ReadWrite
 * \brief The file is open for reading and writing
 */

/**
 * \brief Construct a File to represent the file \a name
 * \param[in] name The file name
 *
 * Upon construction the File object is closed and shall be opened with open()
 * before performing I/O operations.
 */
File::File(const std::string &name)
	: name_(name), fd_(-1), mode_(NotOpen), error_(0)
{
}

/**
 * \brief Construct a File without an associated name
 *
 * Before being used for any purpose, the file name shall be set with
 * setFileName().
 */
File::File()
	: fd_(-1), mode_(NotOpen), error_(0)
{
}

/**
 * \brief Destroy a File instance
 *
 * Any memory mapping associated with the File is unmapped, and the File is
 * closed if it is open.
 */
File::~File()
{
	unmapAll();
	close();
}

/**
 * \fn const std::string &File::fileName() const
 * \brief Retrieve the file name
 * \return The file name
 */

/**
 * \brief Set the name of the file
 * \param[in] name The name of the file
 *
 * The \a name can contain an absolute path, a relative path or no path at all.
 * Calling this function on an open file results in undefined behaviour.
 *
 * Any memory mapping associated with the File is unmapped.
 */
void File::setFileName(const std::string &name)
{
	if (isOpen()) {
		LOG(File, Error)
			<< "Can't set file name on already open file " << name_;
		return;
	}

	unmapAll();

	name_ = name;
}

/**
 * \brief Check if the file specified by fileName() exists
 *
 * This function checks if the file specified by fileName() exists. The File
 * instance doesn't need to be open to check for file existence, and this
 * function may return false even if the file is open, if it was deleted from
 * the file system.
 *
 * \return True if the the file exists, false otherwise
 */
bool File::exists() const
{
	return exists(name_);
}

/**
 * \brief Open the file in the given mode
 * \param[in] mode The open mode
 *
 * This function opens the file specified by fileName() in \a mode. If the file
 * doesn't exist and the mode is WriteOnly or ReadWrite, this
 * function will attempt to create the file.
 *
 * The error() status is updated.
 *
 * \return True on success, false otherwise
 */
bool File::open(File::OpenMode mode)
{
	if (isOpen()) {
		LOG(File, Error) << "File " << name_ << " is already open";
		return false;
	}

	int flags = (mode & ReadWrite) - 1;

	fd_ = ::open(name_.c_str(), flags);
	if (fd_ < 0) {
		error_ = -errno;
		return false;
	}

	mode_ = mode;
	error_ = 0;
	return true;
}

/**
 * \fn bool File::isOpen() const
 * \brief Check if the file is open
 * \return True if the file is open, false otherwise
 */

/**
 * \fn OpenMode File::openMode() const
 * \brief Retrieve the file open mode
 * \return The file open mode
 */

/**
 * \brief Close the file
 *
 * This function closes the File. If the File is not open, it performs no
 * operation. Memory mappings created with map() are not destroyed when the
 * file is closed.
 */
void File::close()
{
	if (fd_ == -1)
		return;

	::close(fd_);
	fd_ = -1;
	mode_ = NotOpen;
}

/**
 * \fn int File::error() const
 * \brief Retrieve the file error status
 *
 * This function retrieves the error status from the last file open or I/O
 * operation. The error status is a negative number as defined by errno.h. If
 * no error occurred, this function returns 0.
 *
 * \return The file error status
 */

/**
 * \brief Retrieve the file size
 *
 * This function retrieves the size of the file on the filesystem. The File
 * instance shall be open to retrieve its size. The error() status is not
 * modified, error codes are returned directly on failure.
 *
 * \return The file size in bytes on success, or a negative error code otherwise
 */
ssize_t File::size() const
{
	if (!isOpen())
		return -EINVAL;

	struct stat st;
	int ret = fstat(fd_, &st);
	if (ret < 0)
		return -errno;

	return st.st_size;
}

/**
 * \brief Map a region of the file in the process memory
 * \param[in] offset The region offset within the file
 * \param[in] size The region sise
 * \param[in] flags The mapping flags
 *
 * This function maps a region of \a size bytes of the file starting at \a
 * offset into the process memory. The File instance shall be open, but may be
 * closed after mapping the region. Mappings stay valid when the File is
 * closed, and are destroyed automatically when the File is deleted.
 *
 * If \a size is a negative value, this function maps the region starting at \a
 * offset until the end of the file.
 *
 * The mapping memory protection is controlled by the file open mode, unless \a
 * flags contains MapPrivate in which case the region is mapped in read/write
 * mode.
 *
 * The error() status is updated.
 *
 * \return The mapped memory on success, or an empty span otherwise
 */
Span<uint8_t> File::map(off_t offset, ssize_t size, enum File::MapFlag flags)
{
	if (!isOpen()) {
		error_ = -EBADF;
		return {};
	}

	if (size < 0) {
		size = File::size();
		if (size < 0) {
			error_ = size;
			return {};
		}

		size -= offset;
	}

	int mmapFlags = flags & MapPrivate ? MAP_PRIVATE : MAP_SHARED;

	int prot = 0;
	if (mode_ & ReadOnly)
		prot |= PROT_READ;
	if (mode_ & WriteOnly)
		prot |= PROT_WRITE;
	if (flags & MapPrivate)
		prot |= PROT_WRITE;

	void *map = mmap(NULL, size, prot, mmapFlags, fd_, offset);
	if (map == MAP_FAILED) {
		error_ = -errno;
		return {};
	}

	maps_.emplace(map, size);

	error_ = 0;
	return { static_cast<uint8_t *>(map), static_cast<size_t>(size) };
}

/**
 * \brief Unmap a region mapped with map()
 * \param[in] addr The region address
 *
 * The error() status is updated.
 *
 * \return True on success, or false if an error occurs
 */
bool File::unmap(uint8_t *addr)
{
	auto iter = maps_.find(static_cast<void *>(addr));
	if (iter == maps_.end()) {
		error_ = -ENOENT;
		return false;
	}

	int ret = munmap(addr, iter->second);
	if (ret < 0) {
		error_ = -errno;
		return false;
	}

	maps_.erase(iter);

	error_ = 0;
	return true;
}

void File::unmapAll()
{
	for (const auto &map : maps_)
		munmap(map.first, map.second);

	maps_.clear();
}

/**
 * \brief Check if the file specified by \a name exists
 * \param[in] name The file name
 * \return True if the file exists, false otherwise
 */
bool File::exists(const std::string &name)
{
	struct stat st;
	int ret = stat(name.c_str(), &st);
	if (ret < 0)
		return false;

	return true;
}

} /* namespace libcamera */