Boot Linux faster!

Check our new training course

Boot Linux faster!

Check our new training course
and Creative Commons CC-BY-SA
lecture and lab materials

Bootlin logo

Elixir Cross Referencer

/*
 * Copyright (c) 2019 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <ztest.h>
#include <zephyr.h>
#include <sys/fdtable.h>
#include <errno.h>

/* The thread will test that the refcounting of fd object will
 * work as expected.
 */
static struct k_thread fd_thread;
static int shared_fd;

#define VTABLE_INIT ((const struct fd_op_vtable *)1)

K_THREAD_STACK_DEFINE(fd_thread_stack, CONFIG_ZTEST_STACKSIZE +
		      CONFIG_TEST_EXTRA_STACKSIZE);

void test_z_reserve_fd(void)
{
	int fd = z_reserve_fd(); /* function being tested */

	zassert_true(fd >= 0, "fd < 0");

	z_free_fd(fd);
}

void test_z_get_fd_obj_and_vtable(void)
{
	const struct fd_op_vtable *vtable;

	int fd = z_reserve_fd();
	zassert_true(fd >= 0, "fd < 0");

	int *obj;
	obj = z_get_fd_obj_and_vtable(fd, &vtable); /* function being tested */

	zassert_is_null(obj, "obj is not NULL");

	z_free_fd(fd);
}

void test_z_get_fd_obj(void)
{
	int fd = z_reserve_fd();
	zassert_true(fd >= 0, "fd < 0");

	int err = -1;
	const struct fd_op_vtable *vtable = 0;
	const struct fd_op_vtable *vtable2 = vtable+1;

	int *obj = z_get_fd_obj(fd, vtable, err); /* function being tested */

	/* take branch -- if (_check_fd(fd) < 0) */
	zassert_is_null(obj, "obj not is NULL");

	obj = (void *)1;
	vtable = (const struct fd_op_vtable *)1;

	/* This will set obj and vtable properly */
	z_finalize_fd(fd, obj, vtable);

	obj = z_get_fd_obj(-1, vtable, err); /* function being tested */

	zassert_equal_ptr(obj, NULL, "obj is not NULL when fd < 0");
	zassert_equal(errno, EBADF, "fd: out of bounds error");

	/* take branch -- if (vtable != NULL && fd_entry->vtable != vtable) */
	obj = z_get_fd_obj(fd, vtable2, err); /* function being tested */

	zassert_equal_ptr(obj, NULL, "obj is not NULL - vtable doesn't match");
	zassert_equal(errno, err, "vtable matches");

	z_free_fd(fd);
}

void test_z_finalize_fd(void)
{
	const struct fd_op_vtable *vtable;

	int fd = z_reserve_fd();
	zassert_true(fd >= 0, NULL);

	int *obj = z_get_fd_obj_and_vtable(fd, &vtable);

	const struct fd_op_vtable *original_vtable = vtable;
	int *original_obj = obj;

	z_finalize_fd(fd, obj, vtable); /* function being tested */

	obj = z_get_fd_obj_and_vtable(fd, &vtable);

	zassert_equal_ptr(obj, original_obj, "obj is different after finalizing");
	zassert_equal_ptr(vtable, original_vtable, "vtable is different after finalizing");

	z_free_fd(fd);
}

void test_z_alloc_fd(void)
{
	const struct fd_op_vtable *vtable = NULL;
	int *obj = NULL;

	int fd = z_alloc_fd(obj, vtable); /* function being tested */
	zassert_true(fd >= 0, NULL);

	obj = z_get_fd_obj_and_vtable(fd, &vtable);

	zassert_equal_ptr(obj, NULL, "obj is different after allocating");
	zassert_equal_ptr(vtable, NULL, "vtable is different after allocating");

	z_free_fd(fd);
}

void test_z_free_fd(void)
{
	const struct fd_op_vtable *vtable = NULL;

	int fd = z_reserve_fd();
	zassert_true(fd >= 0, NULL);

	z_free_fd(fd); /* function being tested */

	int *obj = z_get_fd_obj_and_vtable(fd, &vtable);

	zassert_equal_ptr(obj, NULL, "obj is not NULL after freeing");
}

static void test_cb(void *fd_ptr)
{
	int fd = POINTER_TO_INT(fd_ptr);
	const struct fd_op_vtable *vtable;
	int *obj;

	obj = z_get_fd_obj_and_vtable(fd, &vtable);

	zassert_not_null(obj, "obj is null");
	zassert_not_null(vtable, "vtable is null");

	z_free_fd(fd);

	obj = z_get_fd_obj_and_vtable(fd, &vtable);
	zassert_is_null(obj, "obj is still there");
	zassert_equal(errno, EBADF, "fd was found");
}

void test_z_fd_multiple_access(void)
{
	const struct fd_op_vtable *vtable = VTABLE_INIT;
	void *obj = (void *)vtable;

	shared_fd = z_reserve_fd();
	zassert_true(shared_fd >= 0, "fd < 0");

	z_finalize_fd(shared_fd, obj, vtable);

	k_thread_create(&fd_thread, fd_thread_stack,
			K_THREAD_STACK_SIZEOF(fd_thread_stack),
			(k_thread_entry_t)test_cb,
			INT_TO_POINTER(shared_fd), NULL, NULL,
			CONFIG_ZTEST_THREAD_PRIORITY, 0, K_NO_WAIT);

	k_thread_join(&fd_thread, K_FOREVER);

	/* should be null since freed in the other thread */
	obj = z_get_fd_obj_and_vtable(shared_fd, &vtable);
	zassert_is_null(obj, "obj is still there");
	zassert_equal(errno, EBADF, "fd was found");
}

void test_main(void)
{
	ztest_test_suite(test_fdtable,
			 ztest_unit_test(test_z_reserve_fd),
			 ztest_unit_test(test_z_get_fd_obj_and_vtable),
			 ztest_unit_test(test_z_get_fd_obj),
			 ztest_unit_test(test_z_finalize_fd),
			 ztest_unit_test(test_z_alloc_fd),
			 ztest_unit_test(test_z_free_fd),
			 ztest_unit_test(test_z_fd_multiple_access)
		);
	ztest_run_test_suite(test_fdtable);
}