--- /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.
+// -----------------------------------------------------------------------
+
+/*
+ Idea of the test:
+
+ This test verifies that the remaining budget of an execution-time
+ clock decreases in a monotonic way with execution time.
+
+ Some traces in a FRSH demo with Thales made us believe that
+ sometimes this does not happen.
+
+ The test consists in creating a monitored thread that execute very
+ small time slots and remain blocked for most of the time. In each
+ block-unblock period the cpu clock is read, the timer is disarmed
+ and armed again.
+
+ We verify that the remaining time obtained when disarming the
+ timer is equal or less than the time used to arm the timer
+ initially.
+
+*/
+
+#include <unistd.h>
+#include <stdio.h>
+#include <time.h> // for nanosleep
+
+#include <assert.h>
+#include <stdlib.h> // for exit in assert
+#include <string.h> // for memset
+
+#include "fosa.h"
+#include <misc/error_checks.h>
+#include <drivers/console_switcher.h>
+
+/*****************************/
+/* D E F I N I T I O N S */
+/*****************************/
+#define NUMBER_OF_TRIES 25
+#define SLEEP_TIME_MSECS 5
+#define ARMED_BUDGET_MSECS 2000
+
+#define MAIN_PRIO 5
+#define MUTEX_CEILING 5
+#define MONITORED_THREAD_PRIO 5
+
+#define TIMER_SIGNAL (FOSA_SIGNAL_MAX - 1)
+
+
+typedef struct _thread_arg_t
+{
+ fosa_cond_t *conditional_variable;
+ fosa_mutex_t *sync_mutex;
+ int *slave_can_run;
+} thread_arg_t;
+
+
+/***************************/
+/* P R O T O T Y P E S */
+/***************************/
+static void *monitored_thread_body(void *arg);
+
+
+int main ()
+{
+ SERIAL_CONSOLE_INIT();
+
+
+ fosa_thread_attr_t monitored_attr;
+ fosa_thread_id_t monitored_tid;
+
+ fosa_cond_t conditional_variable;
+ fosa_mutex_t sync_mutex;
+ int slave_can_run;
+
+ fosa_clock_id_t monitored_clock;
+ fosa_timer_id_t monitored_timer;
+
+ fosa_signal_t signal_set[1];
+ fosa_signal_info_t signal_info_to_send;
+
+ fosa_rel_time_t remaining_time = fosa_msec_to_rel_time(ARMED_BUDGET_MSECS);
+ fosa_rel_time_t interval_to_sleep = fosa_msec_to_rel_time(SLEEP_TIME_MSECS);
+ int i;
+
+
+ thread_arg_t thread_arg;
+
+ /* Set the process-wide signal mask */
+ /************************************/
+ signal_set[0] = TIMER_SIGNAL;
+ CHK( fosa_set_accepted_signals(signal_set, 1) );
+ CHK( fosa_thread_set_prio(fosa_thread_self(), fosa_get_priority_min() + MAIN_PRIO) );
+
+
+ /* We initializa the condvar the mutex and */
+ /* set the predicate to false */
+ /*******************************************/
+ CHK( fosa_cond_init(&conditional_variable) );
+ CHK( fosa_mutex_init(&sync_mutex, fosa_get_priority_min() + MUTEX_CEILING) );
+ slave_can_run = 0;
+
+
+ thread_arg.conditional_variable = &conditional_variable;
+ thread_arg.sync_mutex = &sync_mutex;
+ thread_arg.slave_can_run = &slave_can_run;
+
+ /* We create the monitored thread that will stop in the */
+ /* conditional variable wait. */
+ /********************************************************/
+ thread_arg.conditional_variable = &conditional_variable;
+ thread_arg.sync_mutex = &sync_mutex;
+
+ CHK( fosa_thread_attr_init(&monitored_attr) );
+ CHK( fosa_thread_attr_set_prio(&monitored_attr, fosa_get_priority_min() + MONITORED_THREAD_PRIO) );
+
+ CHK( fosa_thread_create(&monitored_tid, &monitored_attr, monitored_thread_body, &thread_arg) );
+
+ /* We create the CPU timer for the monitored thread */
+ /* and program it for a long expiration period. */
+ /****************************************************/
+ signal_info_to_send.sival_int = 42;
+ CHK( fosa_thread_get_cputime_clock(monitored_tid, &monitored_clock) );
+ CHK( fosa_timer_create(monitored_clock, TIMER_SIGNAL, signal_info_to_send, &monitored_timer) );
+
+
+ for (i = 0; i < NUMBER_OF_TRIES; i++)
+ {
+ long int msecs_armed_after_activation;
+ long int msecs_disarmed_after_blocking;
+ fosa_abs_time_t current_time;
+ fosa_abs_time_t awakening_time;
+ struct timespec awakening_time_tspec;
+
+ /* We first unblock the thread by signalling the condition var */
+ CHK( fosa_mutex_lock(&sync_mutex) );
+ assert(slave_can_run == 0);
+ slave_can_run = 1;
+ CHK( fosa_cond_signal(&conditional_variable) );
+ CHK( fosa_mutex_unlock(&sync_mutex) );
+
+ printf("MAIN: Slave activation # %d\n", i);
+ /* Since we have the lock, we have a higher priority */
+ /* due to the priority ceiling of the mutex. */
+ /****************************************************/
+
+ // We arm the timer
+ msecs_armed_after_activation = fosa_rel_time_to_msec(remaining_time);
+ printf("MAIN: Timer armed with: %ld msec\n", msecs_armed_after_activation);
+ CHK( fosa_rel_timer_arm(monitored_timer, &remaining_time) );
+
+
+ // We let the thread execute something (short) and then block
+ // itself again
+ CHK( fosa_clock_get_time(FOSA_CLOCK_REALTIME, ¤t_time) );
+ printf("MAIN: SLEEPING\n");
+ awakening_time = fosa_abs_time_incr(current_time, interval_to_sleep);
+ awakening_time_tspec = fosa_abs_time_to_timespec(awakening_time);
+
+
+ CHK( clock_nanosleep(FOSA_CLOCK_REALTIME, TIMER_ABSTIME, &awakening_time_tspec, NULL) );
+
+
+ // We disarm the timer and release the mutex
+ CHK( fosa_timer_disarm(monitored_timer, &remaining_time) );
+ msecs_disarmed_after_blocking = fosa_rel_time_to_msec(remaining_time);
+
+ printf("MAIN: Timer disarmed with %ld msec\n", msecs_disarmed_after_blocking);
+
+ if (msecs_disarmed_after_blocking > msecs_armed_after_activation)
+ {
+ printf("MAIN: BINGOO Bug reproduced!!!\n");
+ exit(1);
+ }
+
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------
+
+static void *monitored_thread_body(void *arg)
+{
+ thread_arg_t *thread_args = (thread_arg_t *) arg;
+
+ int nr_activation = 0;
+
+ while(1)
+ {
+ printf("SLAVE about to block\n");
+ CHK( fosa_mutex_lock(thread_args->sync_mutex) );
+
+ while (!*(thread_args->slave_can_run))
+ {
+ CHK( fosa_cond_wait(thread_args->conditional_variable,
+ thread_args->sync_mutex) );
+ }
+
+ printf("This comes second\n");
+
+ printf("SLAVE: Activation nr: %d\n", nr_activation);
+ nr_activation++;
+
+ *(thread_args->slave_can_run) = 0;
+ CHK( fosa_mutex_unlock(thread_args->sync_mutex) );
+
+ }
+}
+
+