Commit 7c9e4445 authored by yoogx's avatar yoogx

* Added a user-level scheduler to allow for step-by-step simulation

        Part of issue #5
parent fe11ed47
......@@ -194,10 +194,12 @@ AC_OUTPUT([
src/drivers/configuration/Makefile
src/monitoring/Makefile
src/monitoring/cheddar_scheduling/Makefile
src/simulator/Makefile
include/Makefile
include/drivers/Makefile
include/drivers/configuration/Makefile
include/monitoring/Makefile
include/simulator/Makefile
examples/Makefile
examples/aadlv1/Makefile
examples/aadlv1/d3.1.3-1/Makefile
......@@ -245,5 +247,3 @@ AC_OUTPUT([
share/config/gumstix-rtems/Makefile
support/Makefile
])
......@@ -15,7 +15,7 @@
* Define some values that are dependant of the
* underlying executive.
*/
#if defined(POSIX) || defined (XENO_POSIX)
#if defined(POSIX) || defined (XENO_POSIX) || defined (SIMULATOR)
#include <stdlib.h>
#include <stdio.h>
#define __PO_HI_MAIN_NAME main
......@@ -65,6 +65,13 @@
#define __PO_HI_MAX_PRIORITY sched_get_priority_max(SCHED_FIFO)
#define __PO_HI_MIN_PRIORITY sched_get_priority_min(SCHED_FIFO)
#define __PO_HI_DEFAULT_PRIORITY ((sched_get_priority_min(SCHED_FIFO) + sched_get_priority_max(SCHED_FIFO))/2)
#elif defined (SIMULATOR)
#include <po_hi_time.h>
#define __PO_HI_MAX_PRIORITY 255
#define __PO_HI_MIN_PRIORITY 1
#define __PO_HI_DEFAULT_PRIORITY 128
#elif defined(_WIN32)
#include <inttypes.h>
#include <po_hi_time.h>
......
AUTOMAKE_OPTIONS = no-dependencies
SUBDIRS=
EXTRA_DIST = $(srcdir)/um_threads.h
CLEANFILES = *~
hsrc = ${shell $(CYGPATH_U) '$(OCARINA_RUNTIME)/polyorb-hi-c/include'}
install-data-local:
$(INSTALL) -d $(DESTDIR)$(hsrc)
for f in $(EXTRA_DIST) $(CONFIG_HEADER); do \
$(INSTALL) -m 444 $$f $(DESTDIR)$(hsrc) ; \
done
uninstall-local:
rm -rf $(DESTDIR)$(hsrc)
/******************************************************************************
* User-mode thread library
*
* This library relies on <ucontext.h> to define a limited runtime to
* support threads and various scheduling policies.
******************************************************************************/
#ifndef __UM_THREADS_H__
#define __UM_THREADS_H__
#include<ucontext.h>
#include<deployment.h>
#include<po_hi_task.h>
#include<po_hi_time.h>
#include<stdint.h>
#define STACKSIZE (128 * 1024) /* Default stack size */
#define INTERVAL 700 /* timer interval in microseconds */
/******************************************************************************/
/* Thread entities */
typedef uint32_t um_thread_id; /* id of a thread */
typedef uint32_t stack_size_t; /* stack size of a thread */
typedef uint32_t priority_t; /* priority */
typedef enum { IDLE, READY, RUNNING } thread_state_t;
typedef struct { /* thread control block */
ucontext_t um_context;
um_thread_id tid;
stack_size_t stack_size;
priority_t priority;
thread_state_t state;
} um_thread_t;
um_thread_id um_thread_create
(void (*function)(void),
stack_size_t stack_size,
priority_t priority);
/* um_thread_create: helper function to create a thread context
* - initialize the context,
* - setup the new stack,
* - signal mask,
* - function to execute
*/
/*
* Create a periodic task.
*
* The task created have the identifier given by the first
* parameter. It is created according to the period created
* with __po_hi_* functions (like __po_hi_milliseconds())
* and priority parameters (use the OS priority). The task execute
* periodically start_routine.
*
* This function returns SUCCESS if there is no error. Else,
* it returns the negative value ERROR_CREATE_TASK.
*/
int um_thread_sim_create
(void* (*function)(void),
stack_size_t stack_size,
priority_t priority,
const __po_hi_task_id po_hi_id);
void um_thread_yield (void);
/* um_thread_yield: relinquish CPU */
ucontext_t *get_context (um_thread_id tid);
ucontext_t *get_current_context (void);
um_thread_id get_current_context_id (void);
/******************************************************************************/
/* Scheduler */
typedef um_thread_id (* scheduler_function) (void);
void configure_scheduler (scheduler_function s);
void start_scheduler (void);
void scheduler(void);
/******************************************************************************/
#endif /* __UM_THREADS_H__ */
......@@ -39,7 +39,7 @@ ifneq ($(USER_LD),)
LD=$(USER_LD)
endif
CFLAGS=$(USER_CFLAGS) $(TARGET_CFLAGS)
CFLAGS=$(TARGET_CFLAGS) $(USER_CFLAGS)
CPPFLAGS=$(CFLAGS) $(USER_CPPFLAGS)
LDFLAGS=$(TARGET_LDFLAGS) $(USER_LDFLAGS)
......@@ -206,6 +206,7 @@ ifeq ($(MONITORING), true)
MONITORING_OBJS = trace_manager.o remote_configuration.o
PO_HI_CPPOBJS += $(MONITORING_OBJS)
PO_HI_OBJS += um_threads.o
INCLUDE += -I$(RUNTIME_PATH)/src \
-I$(RUNTIME_PATH)/src/monitoring \
......@@ -388,4 +389,3 @@ gprof:
./$(BINARY)
gprof ./$(BINARY) > gprof.out
endif
AUTOMAKE_OPTIONS = no-dependencies
SUBDIRS=drivers monitoring
SUBDIRS=drivers monitoring simulator
C_FILES = $(srcdir)/po_hi_task.c \
$(srcdir)/po_hi_main.c \
$(srcdir)/po_hi_marshallers.c \
$(srcdir)/po_hi_messages.c \
$(srcdir)/po_hi_monitor.c \
$(srcdir)/po_hi_gqueue.c \
$(srcdir)/po_hi_giop.c \
$(srcdir)/po_hi_lua.c \
$(srcdir)/po_hi_protected.c \
$(srcdir)/po_hi_transport.c \
$(srcdir)/po_hi_storage.c \
$(srcdir)/po_hi_types.c \
$(srcdir)/po_hi_utils.c \
$(srcdir)/po_hi_simulink.c \
$(srcdir)/po_hi_gprof_rtems_leon.c \
$(srcdir)/po_hi_time.c
C_FILES = $(srcdir)/po_hi_task.c $(srcdir)/po_hi_main.c \
$(srcdir)/po_hi_marshallers.c $(srcdir)/po_hi_messages.c \
$(srcdir)/po_hi_monitor.c $(srcdir)/po_hi_gqueue.c \
$(srcdir)/po_hi_giop.c $(srcdir)/po_hi_lua.c \
$(srcdir)/po_hi_protected.c $(srcdir)/po_hi_transport.c \
$(srcdir)/po_hi_storage.c $(srcdir)/po_hi_types.c \
$(srcdir)/po_hi_utils.c $(srcdir)/po_hi_simulink.c \
$(srcdir)/po_hi_gprof_rtems_leon.c \
$(srcdir)/po_hi_time.c
csrc = ${shell $(CYGPATH_U) '$(OCARINA_RUNTIME)/polyorb-hi-c/src'}
......
......@@ -21,6 +21,16 @@
#endif
#endif
#if defined (SIMULATOR)
#include <um_threads.h>
#undef POSIX
#endif
#if defined (SIMULATOR) && defined (POSIX)
#error "fuck"
#endif
#if defined (RTEMS_POSIX) || defined (RTEMS_PURE)
#include <sys/cpuset.h>
#endif
......@@ -86,6 +96,8 @@ typedef struct
rtems_id rtems_id;
#elif defined(XENO_NATIVE)
RT_TASK xeno_id;
#elif defined(SIMULATOR)
um_thread_id um_id;
#endif
} __po_hi_task_t;
/*
......@@ -109,20 +121,27 @@ void __po_hi_wait_for_tasks ()
{
pthread_join( tasks[i].tid , NULL );
}
#elif defined (RTEMS_PURE)
rtems_task_suspend(RTEMS_SELF);
#elif defined (_WIN32)
WaitForMultipleObjects (__PO_HI_NB_TASKS, __po_hi_tasks_array, TRUE, INFINITE);
#elif defined (XENO_NATIVE)
int ret;
while (1)
{
ret = rt_task_join (&(tasks[0].xeno_id));
if (ret != 0)
{
__PO_HI_DEBUG_DEBUG ("Error while calling rt_task_suspend in __po_hi_wait_for_tasks (ret=%d)\n", ret);
}
ret = rt_task_join (&(tasks[0].xeno_id));
if (ret != 0)
{
__PO_HI_DEBUG_DEBUG ("Error while calling rt_task_suspend in __po_hi_wait_for_tasks (ret=%d)\n", ret);
}
}
#elif defined (SIMULATOR)
start_scheduler();
return (__PO_HI_SUCCESS);
#endif
#ifdef __PO_HI_DEBUG
......@@ -377,16 +396,17 @@ pthread_t __po_hi_posix_create_thread (__po_hi_priority_t priority,
int __po_hi_posix_initialize_task (__po_hi_task_t* task)
{
if (pthread_mutex_init (&(task->mutex), NULL) != 0)
{
return (__PO_HI_ERROR_PTHREAD_MUTEX);
}
if (pthread_mutex_init (&(task->mutex), NULL) != 0)
{
return (__PO_HI_ERROR_PTHREAD_MUTEX);
}
if (pthread_cond_init (&(task->cond), NULL) != 0)
{
return (__PO_HI_ERROR_PTHREAD_COND);
}
return (__PO_HI_SUCCESS);
if (pthread_cond_init (&(task->cond), NULL) != 0)
{
return (__PO_HI_ERROR_PTHREAD_COND);
}
return (__PO_HI_SUCCESS);
}
#endif /* POSIX || RTEMS_POSIX */
......@@ -513,14 +533,20 @@ int __po_hi_create_generic_task (const __po_hi_task_id id,
my_task->id = id;
#if defined (POSIX) || defined (RTEMS_POSIX) || defined (XENO_POSIX)
my_task->tid = __po_hi_posix_create_thread (priority, stack_size, core_id, start_routine, arg);
my_task->tid = __po_hi_posix_create_thread
(priority, stack_size, core_id, start_routine, arg);
__po_hi_posix_initialize_task (my_task);
#elif defined (RTEMS_PURE)
my_task->rtems_id = __po_hi_rtems_create_thread (priority, stack_size, core_id, start_routine, arg);
my_task->rtems_id = __po_hi_rtems_create_thread
(priority, stack_size, core_id, start_routine, arg);
#elif defined (_WIN32)
my_task->tid = __po_hi_win32_create_thread (id, priority, stack_size, start_routine, arg);
my_task->tid = __po_hi_win32_create_thread
(id, priority, stack_size, start_routine, arg);
#elif defined (XENO_NATIVE)
my_task->xeno_id = __po_hi_xenomai_create_thread (priority, stack_size, start_routine, arg);
my_task->xeno_id = __po_hi_xenomai_create_thread
(priority, stack_size, start_routine, arg);
#elif defined (SIMULATOR)
my_task->um_id = um_thread_create (start_routine, stack_size, priority);
#else
return (__PO_HI_UNAVAILABLE);
#endif
......@@ -561,8 +587,8 @@ int __po_hi_create_periodic_task (const __po_hi_task_id id,
{
return (__PO_HI_ERROR_CLOCK);
}
#elif defined (XENO_NATIVE)
#elif defined (XENO_NATIVE)
int ret;
ret = rt_task_set_periodic (&(tasks[id].xeno_id), TM_NOW, (tasks[id].period.sec * 1000000000) + tasks[id].period.nsec);
......
AUTOMAKE_OPTIONS = no-dependencies
SUBDIRS=
C_FILES = $(srcdir)/um_threads.c
csrc = ${shell $(CYGPATH_U) '$(OCARINA_RUNTIME)/polyorb-hi-c/src'}
install-data-local:
$(INSTALL) -d $(DESTDIR)$(csrc)
for f in $(C_FILES); do $(INSTALL) -m 444 $$f $(DESTDIR)$(csrc) ; done
uninstall-local:
rm -rf $(DESTDIR)$(csrc)
EXTRA_DIST = $(C_FILES)
CLEANFILES = *~
/*****************************************************/
/* This file contains all function of TASTE RUNTIME */
/* MONITORING API. */
/*****************************************************/
void init_all();
void kill_all();
void th_register();
void callback();
void get_port(port_values state);
void set_port(port_values state);
void trigger_task(int th_id);
void tick();
void dump_trace();
//void undo();
//void redo();
/*
* This is a part of PolyORB-HI-C distribution, a minimal
* middleware written for generated code from AADL models.
* You should use it with the Ocarina toolsuite.
*
* For more informations, please visit http://taste.tuxfamily.org/wiki
*
* Copyright (C) 2010-2014 ESA & ISAE.
*/
#include <deployment.h>
/* included files from the generated code */
#include <po_hi_config.h>
#include <po_hi_common.h>
#include <po_hi_returns.h>
#include <po_hi_monitor.h>
#include <po_hi_task.h>
#include <po_hi_debug.h>
#include <po_hi_protected.h>
#include <po_hi_utils.h>
/* included files from PolyORB-HI-C */
#if defined (MONITORING)
#include <trace_manager.hh>
#endif
/* Headers from run-time verification */
#if defined (POSIX) || defined (RTEMS_POSIX) || defined (XENO_POSIX)
#include <pthread.h>
/* POSIX files */
pthread_cond_t cond_init;
pthread_mutex_t mutex_init;
#endif
#if defined (RTEMS_POSIX) || defined (RTEMS_PURE)
#include <rtems.h>
#include <rtems/rtems/clock.h>
#endif
#ifdef RTEMS_PURE
rtems_id __po_hi_main_initialization_barrier;
#endif
#ifdef _WIN32
CRITICAL_SECTION __po_hi_main_initialization_critical_section;
HANDLE __po_hi_main_initialization_event;
#endif
#if defined (XENO_NATIVE)
#include <native/cond.h>
#include <native/mutex.h>
RT_COND cond_init;
RT_MUTEX mutex_init;
RT_TASK* main_task_id;
/*
* If we use the XENO_NATIVE skin, then, the main task
* is considered as non real-time and cannot lock
* mutexes that are used by real-time threads.
* Then, we need to differenciate operations
* between the main task and the other tasks.
*
* For that reason, the main task does not wait for
* the initialization of the other tasks. The
* __po_hi_wait_initialization just passes when it is
* called from the main task. To do that, we need
* to differentiate the main task from the other,
* we do that by getting the main task descriptor
* address in the main_task_id variable.
*
* Moreover, when using the XENO_NATIVE API, we
* remove one task to initialize (the main task).
* Only generated/created tasks wait for their mutual
* initialization.
*/
#endif
int __po_hi_initialized_tasks = 0;
/* The barrier is initialized with __PO_HI_NB_TASKS +1
* members, because the main function must pass the barrier.
*
* Be careful: for the XENO_NATIVE API, we decrement
* the __po_hi_nb_tasks_to_init variable since the main task
* does not wait for the other tasks to be initialized.
*/
int __po_hi_nb_tasks_to_init = __PO_HI_NB_TASKS + 1;
void __po_hi_initialize_add_task ()
{
__DEBUGMSG ("[MAIN] Add a task to initialize\n");
__po_hi_nb_tasks_to_init++;
}
int __po_hi_initialize_early ()
{
#if defined (XENO_POSIX) || defined (XENO_NATIVE)
/*
* Once initialization has been done, we avoid ALL
* potential paging operations that can introduce
* some indeterministic timing behavior.
*/
#include <sys/mman.h>
mlockall (MCL_CURRENT|MCL_FUTURE);
#endif
#if defined (XENO_NATIVE)
main_task_id = rt_task_self ();
__po_hi_nb_tasks_to_init--;
/*
* If we are using the XENO_NATIVE skin, we need
* to differentiate the main task (that is non real-time)
* from the others since the main task cannot use
* the services and operates on resources of real-time tasks.
* In addition, we decrement the amount of tasks to
* initialize since the main task does not wait
* for the initialization of the other tasks.
*/
#endif
#if defined (POSIX) || defined (RTEMS_POSIX) || defined (XENO_POSIX)
pthread_mutexattr_t mutex_attr;
if (pthread_mutexattr_init (&mutex_attr) != 0)
{
__DEBUGMSG ("[MAIN] Unable to init mutex attributes\n");
}
#ifdef RTEMS_POSIX
if (pthread_mutexattr_setprioceiling (&mutex_attr, 50) != 0)
{
__DEBUGMSG ("[MAIN] Unable to set priority ceiling on mutex\n");
}
#endif
if (pthread_mutex_init (&mutex_init, &mutex_attr) != 0 )
{
__DEBUGMSG ("[MAIN] Unable to init pthread_mutex\n");
return (__PO_HI_ERROR_PTHREAD_MUTEX);
}
__DEBUGMSG ("[MAIN] Have %d tasks to init\n", __po_hi_nb_tasks_to_init);
if (pthread_cond_init (&cond_init, NULL) != 0)
{
return (__PO_HI_ERROR_PTHREAD_COND);
}
#endif
#if defined (XENO_NATIVE)
if (rt_cond_create (&cond_init, NULL))
{
__DEBUGMSG ("[MAIN] Unable to init the initialization condition variable \n");
return (__PO_HI_ERROR_PTHREAD_MUTEX);
}
if (rt_mutex_create (&mutex_init, NULL) != 0)
{
__DEBUGMSG ("[MAIN] Unable to init the initialization mutex variable \n");
return (__PO_HI_ERROR_PTHREAD_COND);
}
#endif
#if defined (RTEMS_POSIX) || defined (RTEMS_PURE)
rtems_status_code ret;
rtems_time_of_day time;
time.year = 1988;
time.month = 12;
time.day = 31;
time.hour = 9;
time.minute = 1;
time.second = 10;
time.ticks = 0;
ret = rtems_clock_set( &time );
if (ret != RTEMS_SUCCESSFUL)
{
__DEBUGMSG ("[MAIN] Cannot set the clock\n");
return __PO_HI_ERROR_CLOCK;
}
#endif
#ifdef RTEMS_PURE
__DEBUGMSG ("[MAIN] Create a barrier that wait for %d tasks\n", __po_hi_nb_tasks_to_init);
ret = rtems_barrier_create (rtems_build_name ('B', 'A', 'R', 'M'), RTEMS_BARRIER_AUTOMATIC_RELEASE, __po_hi_nb_tasks_to_init, &__po_hi_main_initialization_barrier);
if (ret != RTEMS_SUCCESSFUL)
{
__DEBUGMSG ("[MAIN] Cannot create the main barrier, return code=%d\n", ret);
}
#endif
#ifdef _WIN32
__po_hi_main_initialization_event = CreateEvent (NULL, FALSE, FALSE, NULL);
InitializeCriticalSection (&__po_hi_main_initialization_critical_section);
#endif
__po_hi_initialize_tasking ();
/* Initialize protected objects */
#if __PO_HI_NB_PROTECTED > 0
__po_hi_protected_init();
#endif
#if __PO_HI_MONITOR_ENABLED == 1
__po_hi_monitor_init ();
#endif
return (__PO_HI_SUCCESS);
}
/*
* The __po_hi_initialize function is only called
* by the main thread (the one that executes the traditional
* main() function.
*/
int __po_hi_initialize ()
{
#if (defined (XM3_RTEMS_MODE) && (__PO_HI_NB_PORTS > 0))
#include <deployment.h>
#include <po_hi_types.h>
#include <po_hi_transport.h>
#include <xm.h>
__po_hi_port_kind_t pkind;
__po_hi_port_t tmp;
__po_hi_node_t tmpnode;
__po_hi_node_t mynode;
int portno;
mynode = __po_hi_transport_get_mynode ();
for (tmp = 0 ; tmp < __PO_HI_NB_PORTS ; tmp++)
{
pkind = __po_hi_transport_get_port_kind (tmp);
tmpnode = __po_hi_transport_get_node_from_entity (__po_hi_get_entity_from_global_port (tmp));
if ((tmpnode == mynode) &&
( (pkind == __PO_HI_IN_DATA_INTER_PROCESS) ||
(pkind == __PO_HI_OUT_DATA_INTER_PROCESS) ||
(pkind == __PO_HI_IN_EVENT_DATA_INTER_PROCESS) ||
(pkind == __PO_HI_OUT_EVENT_DATA_INTER_PROCESS)
))
{
__DEBUGMSG ("[MAIN] Should init port %d\n", tmp);
portno = -1;
switch (pkind)
{
case __PO_HI_IN_DATA_INTER_PROCESS:
portno = XM_create_sampling_port (__po_hi_transport_get_model_name (tmp), __po_hi_transport_get_queue_size (tmp), XM_DESTINATION_PORT);
break;
case __PO_HI_OUT_DATA_INTER_PROCESS:
portno = XM_create_sampling_port (__po_hi_transport_get_model_name (tmp), __po_hi_transport_get_queue_size (tmp), XM_SOURCE_PORT);
break;
case __PO_HI_IN_EVENT_DATA_INTER_PROCESS:
portno = XM_create_queuing_port (__po_hi_transport_get_model_name (tmp), __po_hi_transport_get_queue_size (tmp), __po_hi_transport_get_data_size (tmp), XM_DESTINATION_PORT);
break;
case __PO_HI_OUT_EVENT_DATA_INTER_PROCESS:
portno = XM_create_queuing_port (__po_hi_transport_get_model_name (tmp), __po_hi_transport_get_queue_size (tmp), __po_hi_transport_get_data_size (tmp), XM_SOURCE_PORT);
break;
default:
__DEBUGMSG ("[MAIN] Port kind not handled at this time for port %d\n", tmp);
break;
}
if (portno < 0)
{
__DEBUGMSG ("[MAIN] Cannot open port %d, name=%s, return=%d\n", tmp, __po_hi_transport_get_model_name (tmp), portno);
}
else
{
__po_hi_transport_xtratum_port_init (tmp, portno);
__DEBUGMSG ("[MAIN] Port %d (name=%s) created, identifier = %d\n", tmp, __po_hi_transport_get_model_name (tmp), portno);
}
}
}
#endif