summaryrefslogblamecommitdiffstats
path: root/testsuite/thread01/test_main.c
blob: 643a6ad94ce054c808e968b40279f3048831c863 (plain) (tree)















































































































































































































































































































                                                                                
/*
 * Copyright (c) 2013 embedded brains GmbH.  All rights reserved.
 *
 *  embedded brains GmbH
 *  Dornierstr. 4
 *  82178 Puchheim
 *  Germany
 *  <rtems@embedded-brains.de>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <machine/rtems-bsd-config.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>

#include <rtems/bsd/sys/types.h>
#include <rtems/bsd/sys/param.h>
#include <sys/proc.h>
#include <sys/kthread.h>
#include <sys/errno.h>

#include <rtems.h>
#include <rtems/libcsupport.h>
#include <rtems/score/threaddispatch.h>
#include <rtems/score/wkspace.h>

#define TEST_NAME "LIBBSD THREAD 1"

#define TEST_KTHREAD_ADD ((void *) 0xdeadbeef)

static rtems_id main_task_id;

static char test_kproc_name[] = "kproc";

static struct kproc_desc test_kproc_start_desc;

static char test_kthread_name[] = "kthread";

static struct kthread_desc test_kthread_start_desc;

static void
test_curthread(const char *name)
{
	struct thread *td_0 = rtems_bsd_get_curthread_or_null();
	struct thread *td_1 = rtems_bsd_get_curthread_or_wait_forever();
	struct thread *td_2 = curthread;

	assert(td_0 != NULL);
	assert(td_0 == td_1);
	assert(td_0 == td_2);
	assert(strcmp(&td_0->td_name[0], name) == 0);
}

static void
wake_up_main_thread(void)
{
	rtems_status_code sc;

	sc = rtems_event_transient_send(main_task_id);
	assert(sc == RTEMS_SUCCESSFUL);
}

static void
wait_for_worker_thread(void)
{
	rtems_status_code sc;

	sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
	assert(sc == RTEMS_SUCCESSFUL);
}

static void
non_bsd_thread(rtems_task_argument arg)
{
	rtems_status_code sc;

	test_curthread("");
	wake_up_main_thread();

	sc = rtems_task_delete(RTEMS_SELF);
	assert(sc == RTEMS_SUCCESSFUL);
}

static void
test_non_bsd_thread(void)
{
	rtems_status_code sc;
	rtems_id task_id;
	rtems_resource_snapshot snapshot;

	rtems_resource_snapshot_take(&snapshot);

	sc = rtems_task_create(
		rtems_build_name('T', 'A', 'S', 'K'),
		RTEMS_MINIMUM_PRIORITY,
		RTEMS_MINIMUM_STACK_SIZE,
		RTEMS_DEFAULT_MODES,
		RTEMS_DEFAULT_ATTRIBUTES,
		&task_id
	);
	assert(sc == RTEMS_SUCCESSFUL);

	sc = rtems_task_start(task_id, non_bsd_thread, 0);
	assert(sc == RTEMS_SUCCESSFUL);

	wait_for_worker_thread();

	assert(rtems_resource_snapshot_check(&snapshot));
}

static void
test_kproc_start_proc(void)
{
	test_curthread(&test_kproc_name[0]);
	wake_up_main_thread();
	kproc_exit(0);
}

static void
test_kproc_start(void)
{
	rtems_resource_snapshot snapshot;
	struct proc *pr = NULL;
	struct kproc_desc *kpd = &test_kproc_start_desc;

	puts("test kproc_start()");

	rtems_resource_snapshot_take(&snapshot);

	kpd->arg0 = &test_kproc_name[0];
	kpd->func = test_kproc_start_proc,
	kpd->global_procpp = &pr;

	kproc_start(kpd);
	wait_for_worker_thread();

	assert(pr != NULL);

	assert(rtems_resource_snapshot_check(&snapshot));
}

static void
test_kthread_start_thread(void)
{
	test_curthread(&test_kthread_name[0]);
	wake_up_main_thread();
	kthread_exit();
}

static void
test_kthread_start(void)
{
	rtems_resource_snapshot snapshot;
	struct thread *td = NULL;
	struct kthread_desc *ktd = &test_kthread_start_desc;

	puts("test kthread_start()");

	rtems_resource_snapshot_take(&snapshot);

	ktd->arg0 = &test_kthread_name[0];
	ktd->func = test_kthread_start_thread,
	ktd->global_threadpp = &td;

	kthread_start(ktd);
	wait_for_worker_thread();

	assert(td != NULL);

	assert(rtems_resource_snapshot_check(&snapshot));
}

static void
test_kthread_add_thread(void *arg)
{
	test_curthread(&test_kthread_name[0]);

	assert(arg == TEST_KTHREAD_ADD);

	wake_up_main_thread();
	kthread_exit();
}

static void
test_kthread_add(void)
{
	rtems_resource_snapshot snapshot;
	uintptr_t take_away;
	void *greedy;

	puts("test kthread_add()");

	greedy = rtems_workspace_greedy_allocate_all_except_largest(&take_away);

	rtems_resource_snapshot_take(&snapshot);

	assert(rtems_configuration_get_unified_work_area());

	while (take_away > 0) {
		struct thread *td = NULL;
		void *away;
		int eno;

		/*
		 * FIXME: This direct workspace access is a hack to get
		 * reasonable test run times with RTEMS_DEBUG enabled.
		 */
		_Thread_Disable_dispatch();
		away = _Workspace_Allocate(take_away);
		_Thread_Enable_dispatch();

		eno = kthread_add(
			test_kthread_add_thread,
			TEST_KTHREAD_ADD,
			NULL,
			&td,
			0,
			0,
			"%s",
			&test_kthread_name[0]
		);

		_Thread_Disable_dispatch();
		_Workspace_Free(away);
		_Thread_Enable_dispatch();

		if (eno == 0) {
			wait_for_worker_thread();
			assert(td != NULL);

			take_away = 0;
		} else {
			assert(eno == ENOMEM);
			assert(rtems_resource_snapshot_check(&snapshot));

			--take_away;
		}
	}

	rtems_workspace_greedy_free(greedy);
}

static void
test_rtems_bsd_get_curthread_or_null(void)
{
	rtems_resource_snapshot snapshot;
	void *greedy;

	puts("test rtems_bsd_get_curthread_or_null()");

	rtems_resource_snapshot_take(&snapshot);

	greedy = rtems_workspace_greedy_allocate(NULL, 0);
	assert(rtems_bsd_get_curthread_or_null() == NULL);
	rtems_workspace_greedy_free(greedy);

	rtems_resource_snapshot_take(&snapshot);
}

static void
test_main(void)
{
	rtems_status_code sc;
	rtems_task_priority prio = RTEMS_MAXIMUM_PRIORITY - 1;

	main_task_id = rtems_task_self();

	sc = rtems_task_set_priority(RTEMS_SELF, prio, &prio);
	assert(sc == RTEMS_SUCCESSFUL);

	test_non_bsd_thread();
	test_kproc_start();
	test_kthread_start();
	test_kthread_add();
	test_rtems_bsd_get_curthread_or_null();

	puts("*** END OF " TEST_NAME " TEST ***");
	exit(0);
}

#include <rtems/bsd/test/default-init.h>