Linux preempt-rt

Check our new training course

Real-Time Linux with PREEMPT_RT

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

Bootlin logo

Elixir Cross Referencer

/*
 * Copyright (c) 2019 Peter Bigot Consulting, LLC
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <ztest.h>
#include <sys/notify.h>

static uint32_t get_extflags(const struct sys_notify *anp)
{
	uint32_t flags = anp->flags & SYS_NOTIFY_EXTENSION_MASK;

	return flags >> SYS_NOTIFY_EXTENSION_POS;
}

static void set_extflags(struct sys_notify *anp,
			 uint32_t flags)
{
	anp->flags = (anp->flags & ~SYS_NOTIFY_EXTENSION_MASK)
		     | (flags << SYS_NOTIFY_EXTENSION_POS);
}

static void callback(struct sys_notify *anp,
		     int *resp)
{
	zassert_equal(sys_notify_fetch_result(anp, resp), 0,
		      "failed callback fetch");
}

static void test_validate(void)
{
	struct sys_notify notify = {
		.flags = 0,
	};

	zassert_equal(sys_notify_validate(NULL), -EINVAL,
		      "accepted null pointer");
	zassert_equal(sys_notify_validate(&notify), -EINVAL,
		      "accepted bad method");
}


static void test_spinwait(void)
{
	int rc;
	int set_res = 423;
	int res;
	sys_notify_generic_callback cb;
	struct sys_notify notify;
	uint32_t xflags = 0x1234;

	memset(&notify, 0xac, sizeof(notify));
	rc = sys_notify_validate(&notify);
	zassert_equal(rc, -EINVAL,
		      "invalid not diagnosed");

	sys_notify_init_spinwait(&notify);
	rc = sys_notify_validate(&notify);
	zassert_equal(rc, 0,
		      "init_spinwait invalid");

	zassert_false(sys_notify_uses_callback(&notify),
		      "uses callback");

	zassert_equal(notify.flags, SYS_NOTIFY_METHOD_SPINWAIT,
		      "flags mismatch");

	set_extflags(&notify, xflags);
	zassert_equal(sys_notify_get_method(&notify),
		      SYS_NOTIFY_METHOD_SPINWAIT,
		      "method corrupted");
	zassert_equal(get_extflags(&notify), xflags,
		      "xflags extract failed");

	rc = sys_notify_fetch_result(&notify, &res);
	zassert_equal(rc, -EAGAIN,
		      "spinwait ready too soon");

	zassert_not_equal(notify.flags, 0,
			  "flags cleared");

	cb = sys_notify_finalize(&notify, set_res);
	zassert_equal(cb, (sys_notify_generic_callback)NULL,
		      "callback not null");
	zassert_equal(notify.flags, 0,
		      "flags not cleared");

	rc = sys_notify_fetch_result(&notify, &res);
	zassert_equal(rc, 0,
		      "spinwait not ready");
	zassert_equal(res, set_res,
		      "result not set");
}

static void test_signal(void)
{
#ifdef CONFIG_POLL
	int rc;
	int set_res = 423;
	int res;
	struct k_poll_signal sig;
	sys_notify_generic_callback cb;
	struct sys_notify notify;
	uint32_t xflags = 0x1234;

	memset(&notify, 0xac, sizeof(notify));
	rc = sys_notify_validate(&notify);
	zassert_equal(rc, -EINVAL,
		      "invalid not diagnosed");

	k_poll_signal_init(&sig);
	k_poll_signal_check(&sig, &rc, &res);
	zassert_equal(rc, 0,
		      "signal set");

	sys_notify_init_signal(&notify, &sig);
	notify.method.signal = NULL;
	rc = sys_notify_validate(&notify);
	zassert_equal(rc, -EINVAL,
		      "null signal not invalid");

	memset(&notify, 0xac, sizeof(notify));
	sys_notify_init_signal(&notify, &sig);
	rc = sys_notify_validate(&notify);
	zassert_equal(rc, 0,
		      "init_spinwait invalid");

	zassert_false(sys_notify_uses_callback(&notify),
		      "uses callback");

	zassert_equal(notify.flags, SYS_NOTIFY_METHOD_SIGNAL,
		      "flags mismatch");
	zassert_equal(notify.method.signal, &sig,
		      "signal pointer mismatch");

	set_extflags(&notify, xflags);
	zassert_equal(sys_notify_get_method(&notify),
		      SYS_NOTIFY_METHOD_SIGNAL,
		      "method corrupted");
	zassert_equal(get_extflags(&notify), xflags,
		      "xflags extract failed");

	rc = sys_notify_fetch_result(&notify, &res);
	zassert_equal(rc, -EAGAIN,
		      "spinwait ready too soon");

	zassert_not_equal(notify.flags, 0,
			  "flags cleared");

	cb = sys_notify_finalize(&notify, set_res);
	zassert_equal(cb, (sys_notify_generic_callback)NULL,
		      "callback not null");
	zassert_equal(notify.flags, 0,
		      "flags not cleared");
	k_poll_signal_check(&sig, &rc, &res);
	zassert_equal(rc, 1,
		      "signal not set");
	zassert_equal(res, set_res,
		      "signal result wrong");

	rc = sys_notify_fetch_result(&notify, &res);
	zassert_equal(rc, 0,
		      "signal not ready");
	zassert_equal(res, set_res,
		      "result not set");
#endif /* CONFIG_POLL */
}

static void test_callback(void)
{
	int rc;
	int set_res = 423;
	int res;
	sys_notify_generic_callback cb;
	struct sys_notify notify;
	uint32_t xflags = 0x8765432;

	memset(&notify, 0xac, sizeof(notify));
	rc = sys_notify_validate(&notify);
	zassert_equal(rc, -EINVAL,
		      "invalid not diagnosed");

	sys_notify_init_callback(&notify, callback);
	notify.method.callback = NULL;
	rc = sys_notify_validate(&notify);
	zassert_equal(rc, -EINVAL,
		      "null callback not invalid");

	memset(&notify, 0xac, sizeof(notify));
	sys_notify_init_callback(&notify, callback);
	rc = sys_notify_validate(&notify);
	zassert_equal(rc, 0,
		      "init_spinwait invalid");

	zassert_true(sys_notify_uses_callback(&notify),
		     "not using callback");

	zassert_equal(notify.flags, SYS_NOTIFY_METHOD_CALLBACK,
		      "flags mismatch");
	zassert_equal(notify.method.callback,
		      (sys_notify_generic_callback)callback,
		      "callback mismatch");

	set_extflags(&notify, xflags);
	zassert_equal(sys_notify_get_method(&notify),
		      SYS_NOTIFY_METHOD_CALLBACK,
		      "method corrupted");
	zassert_equal(get_extflags(&notify), xflags,
		      "xflags extract failed");

	rc = sys_notify_fetch_result(&notify, &res);
	zassert_equal(rc, -EAGAIN,
		      "callback ready too soon");

	zassert_not_equal(notify.flags, 0,
			  "flags cleared");

	cb = sys_notify_finalize(&notify, set_res);
	zassert_equal(cb, (sys_notify_generic_callback)callback,
		      "callback wrong");
	zassert_equal(notify.flags, 0,
		      "flags not cleared");

	res = ~set_res;
	((sys_notify_generic_callback)cb)(&notify, &res);
	zassert_equal(res, set_res,
		      "result not set");
}

void test_main(void)
{
	ztest_test_suite(sys_notify_api,
			 ztest_unit_test(test_validate),
			 ztest_unit_test(test_spinwait),
			 ztest_unit_test(test_signal),
			 ztest_unit_test(test_callback));
	ztest_run_test_suite(sys_notify_api);
}