diff --git a/configure.ac b/configure.ac index 50b96a3d3d2b41e09a7e775745c590f4964d260e..2ffca71886eb01a25793138473a0fcd54803076d 100644 --- a/configure.ac +++ b/configure.ac @@ -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 ]) - - diff --git a/include/po_hi_task.h b/include/po_hi_task.h index c936cc08600d2a074476651ea7b4fc9d62edef9f..a52bb89f44d2e0c91d968d46ee780dd778571647 100644 --- a/include/po_hi_task.h +++ b/include/po_hi_task.h @@ -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 #include #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 + #define __PO_HI_MAX_PRIORITY 255 + #define __PO_HI_MIN_PRIORITY 1 + #define __PO_HI_DEFAULT_PRIORITY 128 + #elif defined(_WIN32) #include #include diff --git a/include/simulator/Makefile.am b/include/simulator/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..0cf3de2cdeb61e048c0c6f045a964852a849ba2e --- /dev/null +++ b/include/simulator/Makefile.am @@ -0,0 +1,17 @@ +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) diff --git a/include/simulator/um_threads.h b/include/simulator/um_threads.h new file mode 100644 index 0000000000000000000000000000000000000000..6299dcebf54a824a082d98c953b9fb21bb4c1c01 --- /dev/null +++ b/include/simulator/um_threads.h @@ -0,0 +1,85 @@ +/****************************************************************************** + * User-mode thread library + * + * This library relies on to define a limited runtime to + * support threads and various scheduling policies. + ******************************************************************************/ + +#ifndef __UM_THREADS_H__ +#define __UM_THREADS_H__ + +#include +#include +#include +#include +#include + +#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__ */ diff --git a/share/make/Makefile.common.in b/share/make/Makefile.common.in index 4e1f5c80aa03c739b126e3f2fd265ec3461ff4c1..c1ee8943984c64239b6bf7fede9732c910bf3f3f 100644 --- a/share/make/Makefile.common.in +++ b/share/make/Makefile.common.in @@ -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 - diff --git a/src/Makefile.am b/src/Makefile.am index c42d03294b34f759c109cad486aa4a20530ea8e2..2ecab42dbfcd5948312ee7c046d5fa560831ae0a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,22 +1,15 @@ 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'} diff --git a/src/po_hi_task.c b/src/po_hi_task.c index e7dc1045c75caa171ded9abb271c9bcab264797d..fa98d866bdc006b5bebf5c13a41ebe51af3c1f24 100644 --- a/src/po_hi_task.c +++ b/src/po_hi_task.c @@ -21,6 +21,16 @@ #endif #endif +#if defined (SIMULATOR) +#include +#undef POSIX +#endif + + +#if defined (SIMULATOR) && defined (POSIX) +#error "fuck" +#endif + #if defined (RTEMS_POSIX) || defined (RTEMS_PURE) #include #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); diff --git a/src/simulator/Makefile.am b/src/simulator/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..95cccdb9d06210f566e92ae679565ce70add086b --- /dev/null +++ b/src/simulator/Makefile.am @@ -0,0 +1,17 @@ +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 = *~ diff --git a/src/simulator/simulator_api.h b/src/simulator/simulator_api.h new file mode 100644 index 0000000000000000000000000000000000000000..d20fc5b46d073d442df3ab08d3d7eca6809d01f0 --- /dev/null +++ b/src/simulator/simulator_api.h @@ -0,0 +1,30 @@ +/*****************************************************/ + +/* 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(); diff --git a/src/simulator/simulator_main.c b/src/simulator/simulator_main.c new file mode 100644 index 0000000000000000000000000000000000000000..734930391033c046cea4d9706415527cb7dd44a7 --- /dev/null +++ b/src/simulator/simulator_main.c @@ -0,0 +1,430 @@ +/* + * 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 +/* included files from the generated code */ + +#include +#include +#include +#include +#include +#include +#include +#include +/* included files from PolyORB-HI-C */ + +#if defined (MONITORING) +#include +#endif +/* Headers from run-time verification */ + +#if defined (POSIX) || defined (RTEMS_POSIX) || defined (XENO_POSIX) +#include +/* POSIX files */ + +pthread_cond_t cond_init; +pthread_mutex_t mutex_init; +#endif + +#if defined (RTEMS_POSIX) || defined (RTEMS_PURE) +#include +#include +#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 +#include +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 + 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 + #include + #include + #include + + __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 + + +/*! + * Initialize the monitoring trace if needed + */ +#if defined (MONITORING) + trace_initialize (); +#endif + + return (__PO_HI_SUCCESS); +} + +int __po_hi_wait_initialization () +{ +#if defined (POSIX) || defined (RTEMS_POSIX) || defined (XENO_POSIX) + int cstate; + if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, &cstate) != 0) + { + __DEBUGMSG ("[MAIN] Cannot modify the cancel state\n"); + } + + if (pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &cstate) != 0) + { + __DEBUGMSG ("[MAIN] Cannot modify the cancel type\n"); + } + + if (pthread_mutex_lock (&mutex_init) != 0) + { + __DEBUGMSG ("[MAIN] Unable to lock the mutex\n"); + return (__PO_HI_ERROR_PTHREAD_MUTEX); + } + + __po_hi_initialized_tasks++; + + __DEBUGMSG ("[MAIN] %d task(s) initialized (total to init =%d)\n", __po_hi_initialized_tasks, __po_hi_nb_tasks_to_init); + + while (__po_hi_initialized_tasks < __po_hi_nb_tasks_to_init) + { + pthread_cond_wait (&cond_init, &mutex_init); + } + pthread_cond_broadcast (&cond_init); + pthread_mutex_unlock (&mutex_init); + + __PO_HI_INSTRUMENTATION_VCD_INIT + + return (__PO_HI_SUCCESS); +#elif defined (_WIN32) + EnterCriticalSection (&__po_hi_main_initialization_critical_section); + + __po_hi_initialized_tasks++; + + __DEBUGMSG ("[MAIN] %d task(s) initialized (total to init =%d)\n", __po_hi_initialized_tasks, __po_hi_nb_tasks_to_init); + + while (__po_hi_initialized_tasks < __po_hi_nb_tasks_to_init) + { + LeaveCriticalSection (&__po_hi_main_initialization_critical_section); + WaitForSingleObject (__po_hi_main_initialization_event, INFINITE); + EnterCriticalSection (&__po_hi_main_initialization_critical_section); + } + + SetEvent (__po_hi_main_initialization_event); + LeaveCriticalSection (&__po_hi_main_initialization_critical_section); + return (__PO_HI_SUCCESS); + +#elif defined (RTEMS_PURE) + rtems_status_code ret; + + __DEBUGMSG ("[MAIN] Task wait for the barrier\n"); + ret = rtems_barrier_wait (__po_hi_main_initialization_barrier, RTEMS_WAIT); + if (ret != RTEMS_SUCCESSFUL) + { + __DEBUGMSG ("[MAIN] Error while waiting for the barrier, return code=%d\n", ret); + return (__PO_HI_ERROR_UNKNOWN); + } + __DEBUGMSG ("[MAIN] Task release the barrier\n"); + return (__PO_HI_SUCCESS); +#elif defined (XENO_NATIVE) + int ret; + + if (main_task_id == rt_task_self ()) + { + /* + * Here, this function is called by the main thread (the one that executes + * the main() function) so that we don't wait for the initialization of the + * other tasks, we automatically pass through the function and immeditaly + * return. + */ + return (__PO_HI_SUCCESS); + } + + ret = rt_mutex_acquire (&mutex_init, TM_INFINITE); + if (ret != 0) + { + __DEBUGMSG ("[MAIN] Cannot acquire mutex (return code = %d)\n", ret); + return (__PO_HI_ERROR_PTHREAD_MUTEX); + } + + __po_hi_initialized_tasks++; + + __DEBUGMSG ("[MAIN] %d task(s) initialized (total to init =%d)\n", __po_hi_initialized_tasks, __po_hi_nb_tasks_to_init); + + while (__po_hi_initialized_tasks < __po_hi_nb_tasks_to_init) + { + rt_cond_wait (&cond_init, &mutex_init, TM_INFINITE); + } + rt_cond_broadcast (&cond_init); + rt_mutex_release (&mutex_init); + return (__PO_HI_SUCCESS); + +#else + return (__PO_HI_UNAVAILABLE); +#endif +} + +#ifdef __PO_HI_USE_GPROF +void __po_hi_wait_end_of_instrumentation () +{ +#ifdef RTEMS_PURE + rtems_task_wake_after (10000000 / _TOD_Microseconds_per_tick); +#else + #include + #include + + __po_hi_time_t now; + __po_hi_time_t ten_secs; + __po_hi_time_t time_to_wait; + __po_hi_get_time (&now); + __po_hi_seconds (&ten_secs, 10); + __po_hi_add_times (&time_to_wait, &ten_secs, &now); + __po_hi_delay_until (&time_to_wait); +#endif + __DEBUGMSG ("Call exit()\n"); + __po_hi_tasks_killall (); + exit (1); + + __DEBUGMSG ("exit() called\n"); +#ifdef RTEMS_PURE + rtems_task_delete (rtems_self ()); +#endif +} +#endif diff --git a/src/simulator/simulator_main.h b/src/simulator/simulator_main.h new file mode 100644 index 0000000000000000000000000000000000000000..b8cb45d80d84267de317b43cfc56569e2d4bb372 --- /dev/null +++ b/src/simulator/simulator_main.h @@ -0,0 +1,53 @@ +/* + * 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__ */ diff --git a/src/simulator/um_threads.c b/src/simulator/um_threads.c new file mode 100644 index 0000000000000000000000000000000000000000..887369d52628dcf9d09f3a9613737ec94186073d --- /dev/null +++ b/src/simulator/um_threads.c @@ -0,0 +1,214 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#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"); +}