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([ ...@@ -194,10 +194,12 @@ AC_OUTPUT([
src/drivers/configuration/Makefile src/drivers/configuration/Makefile
src/monitoring/Makefile src/monitoring/Makefile
src/monitoring/cheddar_scheduling/Makefile src/monitoring/cheddar_scheduling/Makefile
src/simulator/Makefile
include/Makefile include/Makefile
include/drivers/Makefile include/drivers/Makefile
include/drivers/configuration/Makefile include/drivers/configuration/Makefile
include/monitoring/Makefile include/monitoring/Makefile
include/simulator/Makefile
examples/Makefile examples/Makefile
examples/aadlv1/Makefile examples/aadlv1/Makefile
examples/aadlv1/d3.1.3-1/Makefile examples/aadlv1/d3.1.3-1/Makefile
...@@ -245,5 +247,3 @@ AC_OUTPUT([ ...@@ -245,5 +247,3 @@ AC_OUTPUT([
share/config/gumstix-rtems/Makefile share/config/gumstix-rtems/Makefile
support/Makefile support/Makefile
]) ])
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* Define some values that are dependant of the * Define some values that are dependant of the
* underlying executive. * underlying executive.
*/ */
#if defined(POSIX) || defined (XENO_POSIX) #if defined(POSIX) || defined (XENO_POSIX) || defined (SIMULATOR)
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#define __PO_HI_MAIN_NAME main #define __PO_HI_MAIN_NAME main
...@@ -65,6 +65,13 @@ ...@@ -65,6 +65,13 @@
#define __PO_HI_MAX_PRIORITY sched_get_priority_max(SCHED_FIFO) #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_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) #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) #elif defined(_WIN32)
#include <inttypes.h> #include <inttypes.h>
#include <po_hi_time.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),) ...@@ -39,7 +39,7 @@ ifneq ($(USER_LD),)
LD=$(USER_LD) LD=$(USER_LD)
endif endif
CFLAGS=$(USER_CFLAGS) $(TARGET_CFLAGS) CFLAGS=$(TARGET_CFLAGS) $(USER_CFLAGS)
CPPFLAGS=$(CFLAGS) $(USER_CPPFLAGS) CPPFLAGS=$(CFLAGS) $(USER_CPPFLAGS)
LDFLAGS=$(TARGET_LDFLAGS) $(USER_LDFLAGS) LDFLAGS=$(TARGET_LDFLAGS) $(USER_LDFLAGS)
...@@ -206,6 +206,7 @@ ifeq ($(MONITORING), true) ...@@ -206,6 +206,7 @@ ifeq ($(MONITORING), true)
MONITORING_OBJS = trace_manager.o remote_configuration.o MONITORING_OBJS = trace_manager.o remote_configuration.o
PO_HI_CPPOBJS += $(MONITORING_OBJS) PO_HI_CPPOBJS += $(MONITORING_OBJS)
PO_HI_OBJS += um_threads.o
INCLUDE += -I$(RUNTIME_PATH)/src \ INCLUDE += -I$(RUNTIME_PATH)/src \
-I$(RUNTIME_PATH)/src/monitoring \ -I$(RUNTIME_PATH)/src/monitoring \
...@@ -388,4 +389,3 @@ gprof: ...@@ -388,4 +389,3 @@ gprof:
./$(BINARY) ./$(BINARY)
gprof ./$(BINARY) > gprof.out gprof ./$(BINARY) > gprof.out
endif endif
AUTOMAKE_OPTIONS = no-dependencies AUTOMAKE_OPTIONS = no-dependencies
SUBDIRS=drivers monitoring SUBDIRS=drivers monitoring simulator
C_FILES = $(srcdir)/po_hi_task.c \ C_FILES = $(srcdir)/po_hi_task.c $(srcdir)/po_hi_main.c \
$(srcdir)/po_hi_main.c \ $(srcdir)/po_hi_marshallers.c $(srcdir)/po_hi_messages.c \
$(srcdir)/po_hi_marshallers.c \ $(srcdir)/po_hi_monitor.c $(srcdir)/po_hi_gqueue.c \
$(srcdir)/po_hi_messages.c \ $(srcdir)/po_hi_giop.c $(srcdir)/po_hi_lua.c \
$(srcdir)/po_hi_monitor.c \ $(srcdir)/po_hi_protected.c $(srcdir)/po_hi_transport.c \
$(srcdir)/po_hi_gqueue.c \ $(srcdir)/po_hi_storage.c $(srcdir)/po_hi_types.c \
$(srcdir)/po_hi_giop.c \ $(srcdir)/po_hi_utils.c $(srcdir)/po_hi_simulink.c \
$(srcdir)/po_hi_lua.c \ $(srcdir)/po_hi_gprof_rtems_leon.c \
$(srcdir)/po_hi_protected.c \ $(srcdir)/po_hi_time.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'} csrc = ${shell $(CYGPATH_U) '$(OCARINA_RUNTIME)/polyorb-hi-c/src'}
......
...@@ -21,6 +21,16 @@ ...@@ -21,6 +21,16 @@
#endif #endif
#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) #if defined (RTEMS_POSIX) || defined (RTEMS_PURE)
#include <sys/cpuset.h> #include <sys/cpuset.h>
#endif #endif
...@@ -86,6 +96,8 @@ typedef struct ...@@ -86,6 +96,8 @@ typedef struct
rtems_id rtems_id; rtems_id rtems_id;
#elif defined(XENO_NATIVE) #elif defined(XENO_NATIVE)
RT_TASK xeno_id; RT_TASK xeno_id;
#elif defined(SIMULATOR)
um_thread_id um_id;
#endif #endif
} __po_hi_task_t; } __po_hi_task_t;
/* /*
...@@ -109,20 +121,27 @@ void __po_hi_wait_for_tasks () ...@@ -109,20 +121,27 @@ void __po_hi_wait_for_tasks ()
{ {
pthread_join( tasks[i].tid , NULL ); pthread_join( tasks[i].tid , NULL );
} }
#elif defined (RTEMS_PURE) #elif defined (RTEMS_PURE)
rtems_task_suspend(RTEMS_SELF); rtems_task_suspend(RTEMS_SELF);
#elif defined (_WIN32) #elif defined (_WIN32)
WaitForMultipleObjects (__PO_HI_NB_TASKS, __po_hi_tasks_array, TRUE, INFINITE); WaitForMultipleObjects (__PO_HI_NB_TASKS, __po_hi_tasks_array, TRUE, INFINITE);
#elif defined (XENO_NATIVE) #elif defined (XENO_NATIVE)
int ret; int ret;
while (1) while (1)
{ {
ret = rt_task_join (&(tasks[0].xeno_id)); ret = rt_task_join (&(tasks[0].xeno_id));
if (ret != 0) if (ret != 0)
{ {
__PO_HI_DEBUG_DEBUG ("Error while calling rt_task_suspend in __po_hi_wait_for_tasks (ret=%d)\n", ret); __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 #endif
#ifdef __PO_HI_DEBUG #ifdef __PO_HI_DEBUG
...@@ -377,16 +396,17 @@ pthread_t __po_hi_posix_create_thread (__po_hi_priority_t priority, ...@@ -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) int __po_hi_posix_initialize_task (__po_hi_task_t* task)
{ {
if (pthread_mutex_init (&(task->mutex), NULL) != 0) if (pthread_mutex_init (&(task->mutex), NULL) != 0)
{ {
return (__PO_HI_ERROR_PTHREAD_MUTEX); return (__PO_HI_ERROR_PTHREAD_MUTEX);
} }
if (pthread_cond_init (&(task->cond), NULL) != 0) if (pthread_cond_init (&(task->cond), NULL) != 0)
{ {
return (__PO_HI_ERROR_PTHREAD_COND); return (__PO_HI_ERROR_PTHREAD_COND);
} }
return (__PO_HI_SUCCESS);
return (__PO_HI_SUCCESS);
} }
#endif /* POSIX || RTEMS_POSIX */ #endif /* POSIX || RTEMS_POSIX */
...@@ -513,14 +533,20 @@ int __po_hi_create_generic_task (const __po_hi_task_id id, ...@@ -513,14 +533,20 @@ int __po_hi_create_generic_task (const __po_hi_task_id id,
my_task->id = id; my_task->id = id;
#if defined (POSIX) || defined (RTEMS_POSIX) || defined (XENO_POSIX) #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); __po_hi_posix_initialize_task (my_task);
#elif defined (RTEMS_PURE) #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) #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) #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 #else
return (__PO_HI_UNAVAILABLE); return (__PO_HI_UNAVAILABLE);
#endif #endif
...@@ -561,8 +587,8 @@ int __po_hi_create_periodic_task (const __po_hi_task_id id, ...@@ -561,8 +587,8 @@ int __po_hi_create_periodic_task (const __po_hi_task_id id,
{ {
return (__PO_HI_ERROR_CLOCK); return (__PO_HI_ERROR_CLOCK);
} }
#elif defined (XENO_NATIVE)
#elif defined (XENO_NATIVE)
int ret; int ret;
ret = rt_task_set_periodic (&(tasks[id].xeno_id), TM_NOW, (tasks[id].period.sec * 1000000000) + tasks[id].period.nsec); 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 ()