/*
 * Copyright (c) 2019 Nordic Semiconductor
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @file
 * @brief Test log immediate
 *
 */


#include <tc_util.h>
#include <stdbool.h>
#include <zephyr.h>
#include <ztest.h>
#include <logging/log_backend.h>
#include <logging/log_ctrl.h>
#include <logging/log.h>

#define LOG_MODULE_NAME test
LOG_MODULE_REGISTER(LOG_MODULE_NAME);

#define STACK_SIZE (1024 + CONFIG_TEST_EXTRA_STACKSIZE)

#define NUM_THREADS 5

K_THREAD_STACK_ARRAY_DEFINE(stacks, NUM_THREADS, STACK_SIZE);
static struct k_thread threads[NUM_THREADS];
static k_tid_t tids[NUM_THREADS];


/* Thread entry point, used for multiple threads. Thread is logging some data
 * (data length varies for each thread) and sleeps. Threads have different
 * priorities so on wakeup other thread will be preempted, interrupting logging.
 */
static void thread_func(void *p1, void *p2, void *p3)
{
	intptr_t id = (intptr_t)p1;
	int buf_len = 8*id + 8;
	u8_t *buf = alloca(buf_len);

	while (1) {
		LOG_INF("test string printed %d %d %p", 1, 2, k_current_get());
		LOG_HEXDUMP_INF(buf, buf_len, "data:");
		k_sleep(20+id);
	}
}

/*
 * Test create number of threads with different priorities. Each thread logs
 * data and sleeps. This creates environment where multiple threads are
 * preempted during logging (in immediate mode). Test checks that system does
 * not hit any assert or other fault during frequent preemptions.
 */
static void test_log_immediate_preemption(void)
{
	for (intptr_t i = 0; i < NUM_THREADS; i++) {
		tids[i] = k_thread_create(&threads[i], stacks[i], STACK_SIZE,
				thread_func, (void *)i, NULL, NULL,
				k_thread_priority_get(k_current_get()) + i,
				0, K_MSEC(10));
	}
	k_sleep(3000);

	for (int i = 0; i < NUM_THREADS; i++) {
		k_thread_abort(tids[i]);
	}
	zassert_true(true, "");
}

/*test case main entry*/
void test_main(void)
{
	ztest_test_suite(test_log_immediate,
			 ztest_unit_test(test_log_immediate_preemption));
	ztest_run_test_suite(test_log_immediate);
}
