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 diff is collapsed.
/*
* 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) 2007-2009 Telecom ParisTech, 2010-2014 ESA & ISAE.
*/
#ifndef __PO_HI_MAIN__
#define __PO_HI_MAIN__
int __po_hi_initialize (void);
/*
* Invoke all functions to initialize tasks
* and network. Return __PO_HI_SUCCESS if there
* is no error. Else, it can return the value
* __PO_HI_ERROR_PTHREAD_BARRIER.
*/
void __po_hi_initialize_add_task (void);
/*
* Declare that another task has to be initialized
*/
int __po_hi_wait_initialization (void);
/*
* Invoked by each node to wait initialization
* of other node. It is used by synchronize all
* processes.
* Return __PO_HI_SUCCESS value is there is no
* error. Return __PO_HI_ERROR_PTHREAD_BARRIER
* if there is an error.
*/
#ifdef __PO_HI_USE_GPROF
void __po_hi_wait_end_of_instrumentation (void);
/*
* Wait a certain amount of time to finish the
* execution of the system.
*/
#endif
int __po_hi_initialize_early (void);
/*
* __po_hi_initialize_earlier() is used to perform
* some early initialization, before device
* init functions are invoked.
*/
#endif /* __PO_HI_MAIN__ */
#include<signal.h>
#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/time.h>
#include<ucontext.h>
#include<stdio.h>
#include <po_hi_debug.h>
#include <activity.h>
#include <deployment.h>
#include "subprograms.h"
#include "um_threads.h"
/******************************************************************************/
void configure_fifo_scheduler (void);
um_thread_t threads[__PO_HI_NB_TASKS]; /* XXXX */
uint32_t um_thread_index = 0;
int sched_current_context_id = 0; /* Current thread executing */
ucontext_t *sched_context; /* a pointer to the running thread */
scheduler_function the_scheduler;
/******************************************************************************/
um_thread_id um_thread_create
(void (*function)(void),
stack_size_t stack_size,
priority_t priority)
{
void *stack;
int err;
printf ("o< \n");
__DEBUGMSG ("[CREATE] 1\n");
err = getcontext(&(threads[um_thread_index].um_context));
if (err < 0)
perror("getcontext");
if (stack_size == 0)
threads[um_thread_index].stack_size = STACKSIZE;
else
threads[um_thread_index].stack_size = stack_size;
/* Allocate memory for the thread stack */
stack = malloc(threads[um_thread_index].stack_size);
if (stack == NULL) {
perror("malloc");
exit(1);
}
/* Initialze the ucontext structure:
* - stack and stack size
* - reset sigmask
*/
threads[um_thread_index].um_context.uc_stack.ss_sp = stack;
threads[um_thread_index].um_context.uc_stack.ss_size
= threads[um_thread_index].stack_size;
threads[um_thread_index].um_context.uc_stack.ss_flags = 0;
sigemptyset(&threads[um_thread_index].um_context.uc_sigmask);
/* Attach user function */
makecontext(&threads[um_thread_index].um_context, function, 0);
/* Update internal arrays of threads */
threads[um_thread_index].tid = um_thread_index;
threads[um_thread_index].priority = priority;
threads[um_thread_index].state = READY;
/* debug_printf("Created thread context: %p, tid %d, function %p\n",
&(threads[um_thread_index].um_context), threads[um_thread_index].tid,
function);
*/
return um_thread_index++;
}
/******************************************************************************/
ucontext_t *get_context (um_thread_id tid) {
return &(threads[tid].um_context);
}
/******************************************************************************/
ucontext_t *get_current_context (void) {
return sched_context;
}
/******************************************************************************/
um_thread_id get_current_context_id (void) {
return sched_current_context_id;
}
/******************************************************************************/
void start_scheduler (void) {
configure_fifo_scheduler();
sched_current_context_id = 0;
sched_context = get_context(sched_current_context_id);
__DEBUGMSG ("[MAIN] Starting scheduler\n");
scheduler();
}
/******************************************************************************/
/* The scheduling algorithm; selects the next context to run, then starts it. */
void scheduler(void)
{
um_thread_id previous = sched_current_context_id;
threads[sched_current_context_id].state = READY;
sched_current_context_id = the_scheduler ();
sched_context = get_context (sched_current_context_id);
threads[sched_current_context_id].state = RUNNING;
setcontext(sched_context); /* go */
}
/******************************************************************************/
void um_thread_yield (void) {
scheduler ();
}
/******************************************************************************/
void configure_scheduler (scheduler_function s) {
the_scheduler = s;
}
/******************************************************************************/
um_thread_id scheduler_fifo (void) {
int i;
um_thread_id elected_thread = 0;
for (i = 0; i < __PO_HI_NB_TASKS; i++)
if (threads[i].state == READY
&& threads[i].priority > threads[elected_thread].priority)
elected_thread = i;
return elected_thread;
}
/******************************************************************************/
void configure_fifo_scheduler (void) {
configure_scheduler(scheduler_fifo); /* initialize the scheduler */
}
/******************************************************************************/
ucontext_t signal_context; /* the interrupt context */
void *signal_stack; /* global interrupt stack */
/******************************************************************************/
/* Timer interrupt handler:
* Creates a new context to run the scheduler in, masks signals, then
* swaps contexts saving the previously executing thread and jumping
* to the scheduler.
*/
void timer_interrupt(int j, siginfo_t *si, void *old_context)
{
/* Create new scheduler context */
getcontext(&signal_context);
signal_context.uc_stack.ss_sp = signal_stack;
signal_context.uc_stack.ss_size = STACKSIZE;
signal_context.uc_stack.ss_flags = 0;
sigemptyset(&signal_context.uc_sigmask);
makecontext(&signal_context, scheduler, 0);
/* Save running thread, jump to scheduler */
swapcontext(get_current_context(), &signal_context);
}
/******************************************************************************/
/* Set up SIGALRM signal handler:
* We use the SIGALRM signal to emulate a timer-based interrupt for
* quantum-based scheduling policies.
*/
void setup_timer(uint32_t period, bool periodic)
{
struct sigaction act;
struct itimerval it;
signal_stack = malloc(STACKSIZE); /* allocate the signal/interrupt stack */
if (signal_stack == NULL) {
perror("malloc");
exit(1);
}
act.sa_sigaction = timer_interrupt; /* bind function to the timer */
sigemptyset(&act.sa_mask); /* reset set of signals */
act.sa_flags = SA_RESTART /* interruptible functions do not raise [EINTR] */
| SA_SIGINFO; /* to select particular signature signal handler */
if(sigaction(SIGALRM, &act, NULL) != 0)
perror("Signal handler");
/* setup our timer */
it.it_value.tv_sec = 0;
it.it_value.tv_usec = period * 1000;
if (periodic == true)
it.it_interval = it.it_value;
else {
it.it_interval.tv_sec = 0;
it.it_interval.tv_usec = 0;
}
if (setitimer(ITIMER_REAL, &it, NULL))
perror("setitiimer");
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment