--- /dev/null
+// -----------------------------------------------------------------------
+// Copyright (C) 2006 - 2008 FRESCOR consortium partners:
+//
+// Universidad de Cantabria, SPAIN
+// University of York, UK
+// Scuola Superiore Sant'Anna, ITALY
+// Kaiserslautern University, GERMANY
+// Univ. Politécnica Valencia, SPAIN
+// Czech Technical University in Prague, CZECH REPUBLIC
+// ENEA SWEDEN
+// Thales Communication S.A. FRANCE
+// Visual Tools S.A. SPAIN
+// Rapita Systems Ltd UK
+// Evidence ITALY
+//
+// See http://www.frescor.org for a link to partners' websites
+//
+// FRESCOR project (FP6/2005/IST/5-034026) is funded
+// in part by the European Union Sixth Framework Programme
+// The European Union is not liable of any use that may be
+// made of this code.
+//
+//
+// based on previous work (FSF) done in the FIRST project
+//
+// Copyright (C) 2005 Mälardalen University, SWEDEN
+// Scuola Superiore S.Anna, ITALY
+// Universidad de Cantabria, SPAIN
+// University of York, UK
+//
+// FSF API web pages: http://marte.unican.es/fsf/docs
+// http://shark.sssup.it/contrib/first/docs/
+//
+// This file is part of FOSA (Frsh Operating System Adaption)
+//
+// FOSA is free software; you can redistribute it and/or modify it
+// under terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2, or (at your option) any
+// later version. FOSA is distributed in the hope that it will be
+// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details. You should have received a
+// copy of the GNU General Public License along with FOSA; see file
+// COPYING. If not, write to the Free Software Foundation, 675 Mass Ave,
+// Cambridge, MA 02139, USA.
+//
+// As a special exception, including FOSA header files in a file,
+// instantiating FOSA generics or templates, or linking other files
+// with FOSA objects to produce an executable application, does not
+// by itself cause the resulting executable application to be covered
+// by the GNU General Public License. This exception does not
+// however invalidate any other reasons why the executable file might be
+// covered by the GNU Public License.
+// -----------------------------------------------------------------------
+
+#include <stdio.h> // for printf
+#include <string.h> // for strlen, strncpy
+#include <unistd.h> // for sleep
+#include <time.h> // for nanosleep
+
+
+// TODO: use #include <assert.h> when it works for all architectures
+#include <stdlib.h> // for exit in assert
+
+#include "fosa.h"
+
+static void inline assert(expression)
+{
+ if (!expression) {
+ printe(__FILE__":%u: failed assertion.\n", __LINE__);
+ exit (-1);
+ }
+}
+
+///////////////////////////////////////////////////////
+// 0) Function prototypes
+///////////////////////////////////////////////////////
+
+static void *thread_code(void *arg);
+
+static void fosa_callback_init
+ (void *sched_data, void *arg);
+
+static void fosa_callback_new_thread
+ (void *sched_data,
+ fosa_thread_id_t thread,
+ fosa_ads_actions_t *actions,
+ fosa_abs_time_t *current_time);
+
+static void fosa_callback_thread_terminate
+ (void *sched_data,
+ fosa_thread_id_t thread,
+ fosa_ads_actions_t *actions,
+ fosa_abs_time_t *current_time);
+
+static void fosa_callback_thread_ready
+ (void *sched_data,
+ fosa_thread_id_t thread,
+ fosa_ads_actions_t *actions,
+ fosa_abs_time_t *current_time);
+
+static void fosa_callback_thread_block
+ (void *sched_data,
+ fosa_thread_id_t thread,
+ fosa_ads_actions_t *actions,
+ fosa_abs_time_t *current_time);
+
+static void fosa_callback_change_sched_param_thread
+ (void *sched_data,
+ fosa_thread_id_t thread,
+ fosa_ads_actions_t *actions,
+ fosa_abs_time_t *current_time);
+
+static void fosa_callback_explicit_call_with_data
+ (void *sched_data,
+ fosa_thread_id_t thread,
+ const void * msg,
+ size_t msg_size,
+ void *reply,
+ size_t *reply_size,
+ fosa_ads_actions_t *actions,
+ fosa_abs_time_t *current_time);
+
+static void fosa_callback_notification_for_thread
+ (void *sched_data,
+ fosa_thread_id_t thread,
+ fosa_clock_id_t clock,
+ fosa_ads_actions_t *actions,
+ fosa_abs_time_t *current_time);
+
+static void fosa_callback_timeout
+ (void *sched_data,
+ fosa_ads_actions_t *actions,
+ fosa_abs_time_t *current_time);
+
+static void fosa_callback_signal
+ (void *sched_data,
+ fosa_signal_t signal,
+ fosa_signal_info_t siginfo,
+ fosa_ads_actions_t *actions,
+ fosa_abs_time_t *current_time);
+
+static void fosa_callback_appsched_error
+ (void *sched_data,
+ fosa_thread_id_t thread,
+ fosa_ads_error_cause_t cause,
+ fosa_ads_actions_t *actions);
+
+///////////////////////////////////////////////////////
+// 1) Types, Module variables and Constants
+///////////////////////////////////////////////////////
+
+static fosa_ads_scheduler_ops_t scheduler_ops = {
+ .init = fosa_callback_init,
+ .new_thread = fosa_callback_new_thread,
+ .thread_terminate = fosa_callback_thread_terminate,
+ .thread_ready = fosa_callback_thread_ready,
+ .thread_block = fosa_callback_thread_block,
+ .change_sched_param_thread = fosa_callback_change_sched_param_thread,
+ .explicit_call_with_data = fosa_callback_explicit_call_with_data,
+ .notification_for_thread = fosa_callback_notification_for_thread,
+ .timeout = fosa_callback_timeout,
+ .signal = fosa_callback_signal,
+ .appsched_error = fosa_callback_appsched_error,
+};
+
+static fosa_mutex_t lock;
+
+const unsigned int MX_INIT_ARGS_STRING = 30;
+const unsigned int MX_PRIO = 20;
+#define MX_THREADS 2
+
+// general control structure for the scheduler
+typedef struct {
+ fosa_ads_urgency_t array_prio[MX_THREADS];
+ int array_status[MX_THREADS];
+} fosa_sched_data_t;
+
+typedef struct {
+ fosa_ads_urgency_t prio;
+} appsched_params_t;
+
+typedef enum {
+ ACTIVATE,
+ SUSPEND,
+ CAUSE_ERROR
+} command_t;
+
+typedef struct {
+ fosa_thread_id_t thread_id;
+ command_t command;
+} signal_action_t;
+
+///////////////////////////////////////////////////////
+// 2) Main program
+///////////////////////////////////////////////////////
+
+int main () {
+
+ int err;
+ char init_args_string[MX_INIT_ARGS_STRING + 1];
+ fosa_thread_id_t tid1, tid2, tid3;
+ fosa_thread_attr_t th_attr;
+ bool is_appsched;
+ appsched_params_t params;
+ fosa_signal_info_t timer_info;
+ fosa_timer_id_t timerid;
+ fosa_rel_time_t timerval;
+ signal_action_t signal_action;
+
+
+ err = fosa_thread_set_prio (fosa_thread_self(), MX_PRIO + 1);
+ printf("set main to highest priority, err=%d\n", err);
+ assert(err == 0);
+
+ err = fosa_mutex_init(&lock, MX_PRIO);
+ printf("mutex initialized with ceiling %d. err=%d\n", MX_PRIO, err);
+ assert(err == 0);
+
+ //////////////////////////////////
+ // 2a) Create the scheduler
+ //////////////////////////////////
+
+ printf("--------------------------------------------------\n");
+ printf("2a) Create the scheduler\n");
+
+ strncpy(init_args_string, "Hello Scheduler!!", MX_INIT_ARGS_STRING);
+ init_args_string[MX_INIT_ARGS_STRING] = '\0';
+
+ err = fosa_ads_scheduler_create
+ (&scheduler_ops,
+ sizeof(fosa_sched_data_t),
+ init_args_string, // INIT IS CALLED INMEDIATELY??!!!
+ strlen(init_args_string) + 1);
+ printf("scheduler created, err=%d\n", err);
+ assert(err == 0);
+
+ //////////////////////////////////////////////////////////////
+ // 2b) Create two application scheduled threads
+ //////////////////////////////////////////////////////////////
+
+ printf("--------------------------------------------------\n");
+ printf("2b) Create two application scheduled threads\n");
+
+ err = fosa_thread_attr_init(&th_attr);
+ printf("thread attributes object initialized, err=%d\n", err);
+ assert(err == 0);
+
+ err = fosa_thread_attr_set_stacksize(&th_attr,40000);
+ printf("thread attr set stack size to 40000, err=%d\n", err);
+ assert(err == 0);
+
+ err = fosa_thread_attr_set_prio(&th_attr, MX_PRIO - 1);
+ printf("thread attr set prio to 10, err=%d\n",err);
+ assert(err == 0);
+
+ err = fosa_thread_attr_set_appscheduled(&th_attr, true);
+ printf("thread attr set appscheduled, err=%d\n", err);
+ assert(err == 0);
+
+ err = fosa_thread_attr_get_appscheduled(&th_attr, &is_appsched);
+ printf("thread attr get appscheduled=%d, err=%d\n",is_appsched, err);
+ assert(err == 0);
+
+ params.prio = 10;
+ err = fosa_thread_attr_set_appsched_params
+ (&th_attr, (void *)¶ms, sizeof(params));
+ printf("thread attr set params prio=%d, err=%d\n", params.prio, err);
+ assert(err == 0);
+
+ // create thread 1
+ err = fosa_thread_create (&tid1, &th_attr, thread_code, (void *)1);
+ printf("created thread 1 with prio=%d, err=%d\n", params.prio, err);
+ assert(err == 0);
+
+ params.prio = 15;
+ err = fosa_thread_attr_set_appsched_params
+ (&th_attr, (void *)¶ms, sizeof(params));
+ printf("thread attr set params prio=%d, err=%d\n", params.prio, err);
+ assert(err == 0);
+
+ // create thread 2
+ err = fosa_thread_create (&tid2, &th_attr, thread_code, (void *)2);
+ printf("created thread 2 with prio=%d, err=%d\n",params.prio, err);
+ assert(err == 0);
+
+ // create thread 3 - should be rejected
+ err = fosa_thread_create (&tid3, &th_attr, thread_code, (void *)3);
+ printf("created thread 3 (rejected=%d), err=%d\n",
+ (err == FOSA_EREJECT), err);
+
+ err = fosa_thread_attr_destroy(&th_attr);
+ printf("thread attributes object destroyed, err=%d\n",err);
+ assert(err == 0);
+
+ sleep (5);
+
+ //////////////////////////////////////////////////////////////
+ // 2c) Change appsched params
+ //////////////////////////////////////////////////////////////
+ printf("--------------------------------------------------\n");
+ printf("2c) Change appsched params\n");
+
+ err = fosa_thread_set_prio(tid1,14);
+ printf("priority of thread 1 set to 14, err=%d\n", err);
+ assert(err == 0);
+
+ sleep (1);
+
+ params.prio = MX_PRIO - 5;
+ err = fosa_ads_set_appsched_params(tid2, (void *)¶ms, sizeof(params));
+ printf("urgency of thread 2 set to %d, err=%d\n", params.prio, err);
+ assert(err == 0);
+
+ sleep (3);
+
+ //////////////////////////////////////////////////////////////
+ // 2d) Signals
+ //////////////////////////////////////////////////////////////
+ printf("--------------------------------------------------\n");
+ printf("2d) Signals\n");
+
+ signal_action.command = SUSPEND;
+ signal_action.thread_id = tid1;
+ timer_info.sival_ptr = (void *)&signal_action;
+
+ err = fosa_timer_create
+ (FOSA_CLOCK_REALTIME, FOSA_SIGNAL_MAX, timer_info, &timerid);
+ printf("timer created, err=%d\n", err);
+ assert(err == 0);
+
+ timerval = fosa_msec_to_rel_time(500);
+
+ err=fosa_rel_timer_arm(timerid, &timerval);
+ printf("suspend thread 1 in 0.5 secs, err=%d\n", err);
+ assert(err == 0);
+
+ sleep (5);
+
+ signal_action.command = ACTIVATE;
+ err=fosa_rel_timer_arm(timerid, &timerval);
+ printf("activate thread 1 in 0.5 secs, err=%d\n", err);
+ assert(err == 0);
+
+ sleep (3);
+
+ //////////////////////////////////////////////////////////////
+ // 2e) Cause error
+ //////////////////////////////////////////////////////////////
+ printf("--------------------------------------------------\n");
+ printf("2e) Cause error\n");
+
+ signal_action.command = CAUSE_ERROR;
+ err=fosa_rel_timer_arm(timerid, &timerval);
+ printf("causing an ERROR callback in 0.5 secs, err=%d\n", err);
+ assert(err == 0);
+
+ sleep (3);
+
+ //////////////////////////////////////////////////////////////
+ // 2f) Dettach from application scheduler
+ //////////////////////////////////////////////////////////////
+ printf("--------------------------------------------------\n");
+ printf("2f) Dettach from application scheduler\n");
+
+ err = fosa_ads_set_appscheduled (tid1, false);
+ printf("dettach thread 1, err=%d\n", err);
+ assert(err == 0);
+
+ err = fosa_ads_get_appscheduled (tid1, &is_appsched);
+ printf("thread 1 is dettached? %d, err=%d\n", !is_appsched, err);
+ assert(err == 0);
+
+ err = fosa_ads_get_appscheduled (tid2, &is_appsched);
+ printf("thread 2 is dettached? %d, err=%d\n", !is_appsched, err);
+ assert(err == 0);
+
+ fosa_timer_delete(timerid);
+
+ sleep(1000);
+ return 0;
+}
+
+///////////////////////////////////////////////////////
+// 3) Threads Code
+///////////////////////////////////////////////////////
+
+static void *thread_code (void * arg)
+{
+ struct timespec ts = {2, 0};
+ int err, i;
+ char whoami[] = "who am i?";
+ int reply;
+ size_t reply_size;
+ fosa_rel_time_t one_second = fosa_msec_to_rel_time(1000);
+
+ printf("THREAD %d - starts\n", (int)arg);
+ for (i=1;i<50;i++) {
+ nanosleep (&ts, NULL);
+
+ printf("THREAD %d - locking mutex\n", (int)arg);
+ err=fosa_mutex_lock(&lock);
+ assert(err == 0);
+
+ fosa_eat (&one_second);
+
+ printf("THREAD %d - unlocking mutex\n", (int)arg);
+ err=fosa_mutex_unlock(&lock);
+ assert(err == 0);
+
+ printf("THREAD %d - asking with invoke_withdata\n", (int)arg);
+ err = fosa_ads_invoke_withdata
+ (whoami, sizeof(whoami), (void *)&reply, &reply_size);
+ printf("THREAD %d - received reply, correct?: %d, err=%d\n", (int)arg,
+ reply == (int)fosa_thread_self(), err);
+ if (err != 0) {
+ printf("THREAD %d - bye bye!!\n", (int)arg);
+ pthread_exit (NULL);
+ }
+
+ }
+ return NULL;
+}
+
+///////////////////////////////////////////////////////
+// 4) Implementation of Application Defined Callbacks
+///////////////////////////////////////////////////////
+static void fosa_callback_init
+ (void *sched_data, void *arg)
+{
+ fosa_sched_data_t *frsh = (fosa_sched_data_t *)sched_data;
+ int i, err;
+ fosa_signal_t sched_signal = FOSA_SIGNAL_MAX; // HOW TO PUT SIGNALS IF IS OPAQUE??
+
+ printf ("BEGIN CALLBACK: %s \n", __func__);
+ printf ("init args string received: %s \n", (char *)arg);
+
+ err = fosa_ads_set_handled_signal_set(&sched_signal, 1);
+ printf("set signal set, err=%d\n", err);
+ assert(err == 0);
+
+ for (i=0; i<MX_THREADS; i++) {
+ frsh->array_prio[i] = 0;
+ frsh->array_status[i] = 0;
+ }
+ printf ("END CALLBACK: %s \n", __func__);
+}
+
+static void fosa_callback_new_thread
+ (void *sched_data,
+ fosa_thread_id_t thread,
+ fosa_ads_actions_t *actions,
+ fosa_abs_time_t *current_time)
+{
+ int err;
+ unsigned int i, index;
+ fosa_sched_data_t *frsh = (fosa_sched_data_t *)sched_data;
+ appsched_params_t params;
+ size_t size;
+
+ printf ("BEGIN CALLBACK: %s \n", __func__);
+
+ index = MX_THREADS;
+ for (i=0; i<MX_THREADS; i++) {
+ if (frsh->array_status[i] == 0) {
+ index = i;
+ break;
+ }
+ }
+
+ if (index == MX_THREADS) {
+ err = fosa_adsactions_add_reject(actions, thread);
+ assert(err == 0);
+ } else {
+ // Get the priority for the new thread
+ size = sizeof(params);
+ err = fosa_ads_get_appsched_params(thread, (void *)¶ms, &size);
+ assert(err == 0);
+
+ frsh->array_prio[index] = params.prio;
+ frsh->array_status[index] = 1;
+ }
+ printf ("END CALLBACK: %s \n", __func__);
+}
+
+static void fosa_callback_thread_terminate
+ (void *sched_data,
+ fosa_thread_id_t thread,
+ fosa_ads_actions_t *actions,
+ fosa_abs_time_t *current_time)
+{
+ fosa_abs_time_t at_time;
+ int err;
+
+ printf ("BEGIN CALLBACK: %s \n", __func__);
+
+ fosa_clock_get_time(FOSA_CLOCK_REALTIME, &at_time);
+ printf("current time %ld msec\n", fosa_abs_time_to_msec(at_time) );
+ at_time = fosa_abs_time_incr(at_time, fosa_msec_to_rel_time(1000) );
+
+
+ err = fosa_adsactions_add_timeout(actions, FOSA_CLOCK_REALTIME, &at_time);
+ printf("put a timeout of one second, err=%d\n", err);
+ assert(err == 0);
+ printf ("END CALLBACK: %s \n", __func__);
+}
+
+static void fosa_callback_thread_ready
+ (void *sched_data,
+ fosa_thread_id_t thread,
+ fosa_ads_actions_t *actions,
+ fosa_abs_time_t *current_time)
+{
+ printf ("BEGIN CALLBACK: %s \n", __func__);
+ printf ("END CALLBACK: %s \n", __func__);
+}
+
+static void fosa_callback_thread_block
+ (void *sched_data,
+ fosa_thread_id_t thread,
+ fosa_ads_actions_t *actions,
+ fosa_abs_time_t *current_time)
+{
+ int err;
+ fosa_abs_time_t at_time;
+
+ printf ("BEGIN CALLBACK: %s \n", __func__);
+
+ fosa_clock_get_time(FOSA_CLOCK_REALTIME, &at_time);
+ printf("current time %ld msec\n", fosa_abs_time_to_msec(at_time) );
+ at_time = fosa_abs_time_incr(at_time, fosa_msec_to_rel_time(1000) );
+
+ err = fosa_adsactions_add_timeout(actions, FOSA_CLOCK_REALTIME, &at_time);
+ printf("put a timeout of one second, err=%d\n", err);
+ assert(err == 0);
+ printf ("END CALLBACK: %s \n", __func__);
+}
+
+static void fosa_callback_change_sched_param_thread
+ (void *sched_data,
+ fosa_thread_id_t thread,
+ fosa_ads_actions_t *actions,
+ fosa_abs_time_t *current_time)
+{
+ printf ("BEGIN CALLBACK: %s \n", __func__);
+ // HOW DO I KNOW THE REASON IS SETPRIO OR SETSCHEDPARAMS????
+ printf ("END CALLBACK: %s \n", __func__);
+}
+
+static void fosa_callback_explicit_call_with_data
+ (void *sched_data,
+ fosa_thread_id_t thread,
+ const void * msg,
+ size_t msg_size,
+ void *reply,
+ size_t *reply_size,
+ fosa_ads_actions_t *actions,
+ fosa_abs_time_t *current_time)
+{
+ printf ("BEGIN CALLBACK: %s \n", __func__);
+ *((int *)reply) = (int)thread;
+ printf ("received command: %s , answer %d \n", (char *)msg,
+ *((int *)reply));
+ printf ("END CALLBACK: %s \n", __func__);
+}
+
+static void fosa_callback_notification_for_thread
+ (void *sched_data,
+ fosa_thread_id_t thread,
+ fosa_clock_id_t clock,
+ fosa_ads_actions_t *actions,
+ fosa_abs_time_t *current_time)
+{
+ printf ("BEGIN CALLBACK: %s \n", __func__);
+ printf ("END CALLBACK: %s \n", __func__);
+}
+
+static void fosa_callback_timeout // WHY NOT WATCHDOG????
+ (void *sched_data,
+ fosa_ads_actions_t *actions,
+ fosa_abs_time_t *current_time) // WHY IS IN OUT and not IN???
+{
+ printf ("BEGIN CALLBACK: %s \n", __func__);
+ printf("current time %ld msec", fosa_abs_time_to_msec(*current_time) );
+ printf ("END CALLBACK: %s \n", __func__);
+}
+
+static void fosa_callback_signal
+ (void *sched_data,
+ fosa_signal_t signal,
+ fosa_signal_info_t siginfo, // HOW DO I KNOW THE ORIGIN (see signal_info type)
+ fosa_ads_actions_t *actions,
+ fosa_abs_time_t *current_time)
+{
+ int err;
+ signal_action_t *signal_action = (signal_action_t *)siginfo.sival_ptr;
+ fosa_sched_data_t *frsh = (fosa_sched_data_t *)sched_data;
+
+ printf ("BEGIN CALLBACK: %s \n", __func__);
+
+ switch (signal_action->command) {
+ case SUSPEND:
+ err=fosa_adsactions_add_suspend(actions, signal_action->thread_id);
+ printf("suspending thread 1 , err=%d\n", err);
+ assert(err == 0);
+ break;
+ case ACTIVATE:
+ err = fosa_adsactions_add_activate
+ (actions, signal_action->thread_id, frsh->array_prio[0]);
+ printf("activating thread 1, err=%d\n", err);
+ assert(err == 0);
+ break;
+ case CAUSE_ERROR:
+ // cause an error by overwriting actions with 666 ;D
+ *(int *)actions = 666;
+ err = 666;
+ printf("causing an error, err=%d\n", err);
+ break;
+ }
+ printf ("END CALLBACK: %s \n", __func__);
+}
+
+static void fosa_callback_appsched_error
+ (void *sched_data,
+ fosa_thread_id_t thread,
+ fosa_ads_error_cause_t cause,
+ fosa_ads_actions_t *actions)
+{
+ printf ("BEGIN CALLBACK: %s \n", __func__);
+ printf ("END CALLBACK: %s \n", __func__);
+}