-//----------------------------------------------------------------------
-// Copyright (C) 2006 - 2007 by the FRESCOR consortium:
+// -----------------------------------------------------------------------
+// Copyright (C) 2006 - 2008 FRESCOR consortium partners:
//
// Universidad de Cantabria, SPAIN
// University of York, UK
// Scuola Superiore Sant'Anna, ITALY
// Kaiserslautern University, GERMANY
-// Univ. Politecnica Valencia, SPAIN
+// Univ. Politécnica Valencia, SPAIN
// Czech Technical University in Prague, CZECH REPUBLIC
// ENEA SWEDEN
// Thales Communication S.A. FRANCE
// Rapita Systems Ltd UK
// Evidence ITALY
//
-// See http://www.frescor.org
+// See http://www.frescor.org for a link to partners' websites
//
-// The FRESCOR project (FP6/2005/IST/5-034026) is funded
+// 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.
// Universidad de Cantabria, SPAIN
// University of York, UK
//
-// This file is part of FOSA (Frsh Operating System Abstraction)
+// 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.
+// 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.
+// 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.
// -----------------------------------------------------------------------
//fosa_time_timespec.h
//==============================================
// **//// /** ** ////////** /**//////**
// ** /** ** /** /** /**
// ** /** ** ******** /** /**
-// // /******/ //////// // //
+// // /******/ //////// // //
//
// FOSA(Frescor Operating System Adaptation layer)
//================================================
#ifndef FOSA_TIME_TIMESPEC_H_
#define FOSA_TIME_TIMESPEC_H_
+#include <stdlib.h>
+#include <assert.h>
/**********************************/
/* T I M E S P E C M A C R O S */
/**********************************/
+#define normalize_timespec(t1) \
+do \
+{ \
+ if ((t1).tv_nsec >= 1000000000) \
+ { \
+ (t1).tv_sec++; \
+ (t1).tv_nsec -= 1000000000; \
+ } \
+} while(0)
+
#define add_timespec(sum, t1, t2) \
do { \
(sum).tv_sec = (t1).tv_sec + (t2).tv_sec; \
(sum).tv_nsec = (t1).tv_nsec + (t2).tv_nsec; \
- if ((sum).tv_nsec >= 1000000000) \
- { \
- (sum).tv_sec++; \
- (sum).tv_nsec -= 1000000000; \
- } \
+ normalize_timespec(sum); \
} while(0)
+#define incr_timespec(t1, t2) \
+do { \
+ (t1).tv_sec += (t2).tv_sec; \
+ (t1).tv_nsec += (t2).tv_nsec; \
+ normalize_timespec(t1); \
+} while(0)
// -------------------------------------------------------------------
do { \
if ((base).tv_nsec < (interval).tv_nsec) \
{ \
- (diff).tv_sec = (base).tv_sec - (interval).tv_sec + 1; \
+ (diff).tv_sec = (base).tv_sec - (interval).tv_sec - 1; \
(diff).tv_nsec = (base).tv_nsec + 1000000000 - (interval).tv_nsec; \
} \
else \
(diff).tv_sec = (base).tv_sec - (interval).tv_sec; \
(diff).tv_nsec = (base).tv_nsec - (interval).tv_nsec; \
} \
-} while(0)
+} while(0)
// ---------------------------------------------------------
// ---------------------------------------------------------
#define timespec_to_msec(t1) \
- ( ((t1).tv_sec % 2147482) * 1000 + (t1).tv_nsec/1000000 )
+ ( ((t1).tv_sec % 2147482) * 1000 + (t1).tv_nsec/1000000 )
// ---------------------------------------------------------
( ((t1).tv_sec % 2148) * 1000000 + (t1).tv_nsec/1000 )
+// ---------------------------------------------------------
+
+#define nsec_to_timespec(tspec, nsec) \
+do { \
+ if ((nsec) >= 1000000000) { \
+ (tspec).tv_sec = (nsec)/1000000000; \
+ (tspec).tv_nsec = (nsec) % 1000000000; \
+ } else { \
+ (tspec).tv_sec = 0; \
+ (tspec).tv_nsec = (nsec); \
+ } \
+} while(0)
+
+// ---------------------------------------------------------
+
+#define timespec_to_nsec(t1) \
+ ( ((t1).tv_sec % 2) * 1000000000 + (t1).tv_nsec )
+
+
+
+// ---------------------------------------------------------
+
+#define timespec_equal(t1, t2) ( (t1).tv_sec == (t2).tv_sec ) && ( (t1).tv_nsec == (t2).tv_nsec )
+
+#define timespec_is_null(t1) ( (t1).tv_sec == 0 ) && ( (t1).tv_nsec == 0 )
+
+
/***************************************/
/* T I M E S P E C F U N C T I O N S */
static inline fosa_abs_time_t fosa_abs_time_incr(fosa_abs_time_t base, fosa_rel_time_t interval)
{
fosa_abs_time_t result;
-
+
add_timespec(result, base, interval);
return result;
{
fosa_abs_time_t result;
-
-
substract_timespec(result, base, interval);
return result;
return result;
}
-
// ---------------------------------------------------------
return result;
}
+// ---------------------------------------------------------
+
+/**
+ * exact_long_multiply_smaller_10e5()
+ *
+ * Same as below but with operands smaller than 10000 which allows
+ * to perform all component multiplications without an overflow risk.
+ **/
+static inline struct timespec exact_long_multiply_smaller_10e5(long t, long k)
+{
+ /* Since operands are smaller than 10e5 we can use 1000 */
+ /* the base without risking to cause overflows in the */
+ /* operations. */
+ /********************************************************/
+ assert(t < 10000);
+ assert(k < 10000);
+
+ struct timespec result;
+
+ long base = 1000;
+
+ long t_high = t / base;
+ long t_low = t % base;
+ long k_high = k / base;
+ long k_low = k % base;
+
+ long thkh = t_high * k_high;
+ long thkl = t_high * k_low;
+ long tlkh = t_low * k_high;
+ long tlkl = t_low * k_low;
+
+ long thkl_high = thkl / base;
+ long tlkh_high = tlkh / base;
+ long thkl_low = thkl % base;
+ long tlkh_low = tlkh % base;
+
+ long c2 = thkh + thkl_high + tlkh_high; // Normalized at 10^6
+ long c1 = thkl_low + tlkh_low; // Normalized at 10^3
+ long c0 = tlkl;
+
+ result.tv_sec = c2/1000 + c1/1000000;
+ result.tv_nsec = (c2 % 1000) * 1000000 + (c1 % 1000000) * 1000 + c0;
+
+ result.tv_sec += (result.tv_nsec / 1000000000);
+ result.tv_nsec %= 1000000000;
+
+ return result;
+}
+
+
+// -------------------------------------------------------------
+
+
+
+/**
+ * exact_long_multiply()
+ *
+ * This function performs an exact long * long operations on operands
+ * lower than 1e9 without using more than 32bit (1e9) arithmetic.
+ *
+ * To achieve this we decompose the operands in high and low:
+ *
+ * num = (num/base) * base + (num % base)
+ * ^^^^^^^^ ^^^^^^^^^^^^
+ * high component low component
+ *
+ * t * k = (th*kh + th*kl/base + tl*kh/base )*base^2
+ * + (th*kl % base)*base + (tl*kh % base) * base + tl*kl
+ *
+ * The problem is that we cannot use an exact base because sqrt(1e9)
+ * is not a multiple of 1e9 (in fact it is not even integer).
+ *
+ * So we use as a base 100000 which means that the last term tl*kl may
+ * need another exact calculation with a lower base (100)
+ **/
+static inline struct timespec exact_long_multiply(long t, long k)
+{
+ struct timespec result;
+
+ long t_high;
+ long t_low;
+ long k_high;
+ long k_low;
+
+ long base = 100000; /* Power of 10 closest to sqrt(1e9) from
+ * above */
+
+ t_high = t / base;
+ t_low = t % base; // Between 0 99999
+ k_high = k / base;
+ k_low = k % base; // Between 0 99999
+
+ /* These numbers are always lower than 1e9 */
+ long thkh = t_high * k_high;
+ long thkl = t_high * k_low;
+ long tlkh = t_low * k_high;
+
+ long thkl_high = thkl / base;
+ long thkl_low = thkl % base;
+ long tlkh_high = tlkh / base;
+ long tlkh_low = tlkh % base;
+
+ /* We can calculate the base^2 term (note however that this is 10
+ * times the tv_sec component because it is multiplied by 10^10 */
+ long c2 = thkh + thkl_high + tlkh_high; // scaled to 10^10
+ long c1 = thkl_low + tlkh_low; // scaled to 10^5
+
+ struct timespec c0;
+
+ /* Now we can write the initial values of result */
+ result.tv_sec = c2*10 + c1/10000;
+ result.tv_nsec = (c1 % 10000) * 100000;
+
+ normalize_timespec(result);
+
+ /* To calculate c0 we must check if there is a risk of overflow */
+ /* Remember operands cannot be larger than 99999 and result */
+ /* larger than 1e9. */
+ /****************************************************************/
+ bool overflow_risk;
+ overflow_risk = false;
+
+ if (
+ ( (t_low > 31622) && (k_low >= 10000) ) ||
+ ( (k_low > 31622) && (t_low >= 10000) )
+ )
+ {
+ overflow_risk = true;
+ }
+
+ if (! overflow_risk)
+ {
+ c0.tv_sec = 0;
+ c0.tv_nsec = t_low * k_low;
+ normalize_timespec(c0);
+ }
+ else
+ {
+ c0 = exact_long_multiply_smaller_10e5(t_low, k_low);
+ }
+ add_timespec(result, result, c0);
+
+ return result;
+}
+
+// -------------------------------------------------------------
+
+
+static inline fosa_rel_time_t fosa_rel_time_times_integer(fosa_rel_time_t time, long multiplier)
+{
+ struct timespec result;
+ struct timespec intermediate;
+
+ result.tv_sec = time.tv_sec * multiplier; // No overflow check here
+ result.tv_nsec = 0;
+
+ intermediate = exact_long_multiply(time.tv_nsec, multiplier);
+
+ add_timespec(result, result, intermediate);
+
+ return result;
+}
+
+// ---------------------------------------------------------
+
+static inline fosa_rel_time_t fosa_rel_time_divided_by_integer(fosa_rel_time_t time, long divider)
+{
+ struct timespec result;
+ long reminder;
+
+
+ result.tv_sec = time.tv_sec / divider;
+ result.tv_nsec = 0;
+
+ /* We iterate until the reminder is lower than 2 (to later fit in
+ * a 32 bit signed integer multiplied by 1e9 */
+
+ reminder = time.tv_sec % divider;
+
+
+ if (reminder == 0)
+ {
+ /* We are lucky no reminder so no need to transfer it to the
+ nsec scale.
+ */
+ result.tv_nsec = time.tv_nsec/divider;
+ return result;
+ }
+
+ long enhacer;
+ long back_enhacer;
+ long next_dividend;
+ int next_numeral; /* Between 0 and 9 */
+ enhacer = 1;
+ do
+ {
+ enhacer *= 10;
+ back_enhacer = 1000000000 / enhacer;
+ next_numeral = (time.tv_nsec / back_enhacer) % 10;
+
+ // Note: a possible overflow may happen here with large denominators
+ if (reminder > 200000000)
+ {
+ /* An overflow is going to be produced */
+ abort();
+ }
+ next_dividend = reminder * 10 + next_numeral;
+
+ result.tv_nsec += (next_dividend / divider) * back_enhacer;
+ reminder = next_dividend % divider;
+ } while (back_enhacer > 1);
+
+
+ return result;
+}
+
+// ---------------------------------------------------------
+
/* Comparison */
/**************/
}
+// -----------------------------------------------------------
+
+static inline bool fosa_rel_time_equal(fosa_rel_time_t relt1, fosa_rel_time_t relt2)
+{
+ bool result;
+
+ result = timespec_equal(relt1, relt2);
+
+ return result;
+}
+
+
+// -----------------------------------------------------------
+
+static inline bool fosa_abs_time_equal(fosa_abs_time_t abst1, fosa_abs_time_t abst2)
+{
+ bool result;
+
+ result = timespec_equal(abst1, abst2);
+
+ return result;
+}
+
+// -----------------------------------------------------------
+
+static inline bool fosa_rel_time_is_null(fosa_rel_time_t relt)
+{
+ bool result;
+
+ result = timespec_is_null(relt);
+
+ return result;
+}
+
+
+// -----------------------------------------------------------
+
+static inline bool fosa_abs_time_is_null(fosa_abs_time_t abst)
+{
+ bool result;
+
+ result = timespec_is_null(abst);
+
+ return result;
+}
+
+
+
+
/* Conversion */
/**************/
static inline fosa_rel_time_t fosa_msec_to_rel_time(long msec)
return result;
}
+// --------------------------------------------------
+
+static inline fosa_rel_time_t fosa_nsec_to_rel_time(long nsec)
+{
+ fosa_rel_time_t result;
+
+ nsec_to_timespec(result, nsec);
+
+ return result;
+}
+
+// --------------------------------------------------
+
+static inline long fosa_rel_time_to_nsec(fosa_rel_time_t relt)
+{
+ long result;
+
+ result = timespec_to_nsec(relt);
+
+ return result;
+}
+
+
+// --------------------------------------------------
+
+static inline fosa_abs_time_t fosa_nsec_to_abs_time(long nsec)
+{
+ fosa_abs_time_t result;
+
+ nsec_to_timespec(result, nsec);
+
+ return result;
+}
+
+// --------------------------------------------------
+
+static inline long fosa_abs_time_to_nsec(fosa_abs_time_t abst)
+{
+ long result;
+
+ result = timespec_to_nsec(abst);
+
+ return result;
+}
+
// --------------------------------------------------
return (struct timespec) abst;
}
+// --------------------------------------------------
+
+static inline double fosa_rel_time_to_double(fosa_rel_time_t relt)
+{
+ double result;
+
+ result = relt.tv_nsec*0.000000001 + (double)relt.tv_sec;
+
+ return result;
+}
+
+// --------------------------------------------------
+
+static inline fosa_rel_time_t fosa_double_to_rel_time(double time)
+{
+ fosa_rel_time_t result;
+
+ result.tv_sec = (long) time;
+ result.tv_nsec = (long) ( (time - (double)result.tv_sec) * 1e9 );
+
+ return result;
+}
#endif /* !FOSA_TIME_TIMESPEC_H_ */