Skip to content

Commit

Permalink
Fix #429, update OSAL code to use time accessors
Browse files Browse the repository at this point in the history
Do not access members of OS_time_t directly, instead
use conversion/accessor inline functions to get the
desired value.

Update the "stat" structure output by OS_stat to use
the OS_time_t struct instead of int32, and update
the OS_stat implemention to transfer the full resolution
if it supports it (POSIX.1-2008 or newer).
  • Loading branch information
jphickey committed Dec 31, 2020
1 parent d698a4d commit ccbaca0
Show file tree
Hide file tree
Showing 13 changed files with 365 additions and 67 deletions.
291 changes: 288 additions & 3 deletions src/os/inc/osapi-clock.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,26 @@
#include "osconfig.h"
#include "common_types.h"

/** @brief OSAL time */
/**
* @brief OSAL time interval structure
*
* This is used to represent a basic time interval.
*
* When used with OS_GetLocalTime/OS_SetLocalTime, this represents the
* interval from the OS's epoch point, typically 01 Jan 1970 00:00:00 UTC
* on systems that have a persistent real time clock (RTC), or the system
* boot time if there is no RTC available.
*
* Applications should not directly access fields within this structure,
* as the definition may change in future versions of OSAL. Instead,
* applications should use the accessor/conversion methods defined below.
*/
typedef struct
{
uint32 seconds;
uint32 microsecs;
} OS_time_t;


/** @defgroup OSAPIClock OSAL Real Time Clock APIs
* @{
*/
Expand Down Expand Up @@ -66,7 +78,280 @@ int32 OS_GetLocalTime(OS_time_t *time_struct);
*
* @return Set local time status, see @ref OSReturnCodes
*/
int32 OS_SetLocalTime(OS_time_t *time_struct);
int32 OS_SetLocalTime(const OS_time_t *time_struct);


/*-------------------------------------------------------------------------------------*/
/*
* Accessor / Unit Conversion routines for OS_time_t
*
* These routines allow the user to simply interpret OS_time_t intervals into
* in normalized units of whole seconds, milliseconds, microseconds, or nanoseconds.
*/
/*-------------------------------------------------------------------------------------*/

/*-------------------------------------------------------------------------------------*/
/**
* @brief Get interval from an OS_time_t object normalized to whole number of seconds
*
* Extracts the number of whole seconds from a given OS_time_t object, discarding
* any fractional component.
*
* This may also replace a direct read of the "seconds" field from
* the OS_time_t object from previous versions of OSAL, where the
* structure was defined with separate seconds/microseconds fields.
*
* @sa OS_TimeGetMicrosecondsPart()
*
* @param[in] tm Time interval value
* @returns Whole number of seconds in time interval
*/
static inline int64 OS_TimeGetTotalSeconds(OS_time_t tm)
{
return (tm.seconds);
}

/*-------------------------------------------------------------------------------------*/
/**
* @brief Get interval from an OS_time_t object normalized to millisecond units
*
* Note this refers to the complete interval, not just the fractional part.
*
* @param[in] tm Time interval value
* @returns Whole number of milliseconds in time interval
*/
static inline int64 OS_TimeGetTotalMilliseconds(OS_time_t tm)
{
return (((int64)tm.seconds * 1000) + (tm.microsecs / 1000));
}

/*-------------------------------------------------------------------------------------*/
/**
* @brief Get interval from an OS_time_t object normalized to microsecond units
*
* Note this refers to the complete interval, not just the fractional part.
*
* @param[in] tm Time interval value
* @returns Whole number of microseconds in time interval
*/
static inline int64 OS_TimeGetTotalMicroseconds(OS_time_t tm)
{
return (((int64)tm.seconds * 1000000) + tm.microsecs);
}

/*-------------------------------------------------------------------------------------*/
/**
* @brief Get interval from an OS_time_t object normalized to nanosecond units
*
* Note this refers to the complete interval, not just the fractional part.
*
* @note There is no protection against overflow of the 64-bit return value.
* Applications must use caution to ensure that the interval does not exceed the
* representable range of a signed 64 bit integer - approximately 140 years.
*
* @param[in] tm Time interval value
* @returns Whole number of microseconds in time interval
*/
static inline int64 OS_TimeGetTotalNanoseconds(OS_time_t tm)
{
return (((int64)tm.seconds * 1000000000) + (tm.microsecs * 1000));
}

/*-------------------------------------------------------------------------------------*/
/**
* @brief Get subseconds portion (fractional part only) from an OS_time_t object
*
* Extracts the fractional part from a given OS_time_t object.
* Units returned are in ticks, not normalized to any standard time unit.
*
* @param[in] tm Time interval value
* @returns Fractional/subsecond portion of time interval in ticks
*/
static inline int64 OS_TimeGetFractionalPart(OS_time_t tm)
{
return (tm.microsecs);
}

/*-------------------------------------------------------------------------------------*/
/**
* @brief Get 32-bit normalized subseconds (fractional part only) from an OS_time_t object
*
* Extracts the fractional part from a given OS_time_t object in maximum precision,
* with units of 2^(-32) sec. This is a base-2 fixed-point fractional value
* with the point left-justified in the 32-bit value (i.e. left of MSB).
*
* This is (mostly) compatible with the CFE "subseconds" value, where 0x80000000 represents
* exactly one half second, and 0 represents a full second.
*
* @param[in] tm Time interval value
* @returns Fractional/subsecond portion of time interval as 32-bit fixed point value
*/
static inline uint32 OS_TimeGetSubsecondsPart(OS_time_t tm)
{
/*
* This computation avoids a 32-bit left shift which may not be implemented.
*
* It also must round up, otherwise this may result in a value one
* less than the original when converted back to usec again.
*/
return (((OS_TimeGetFractionalPart(tm) << 26) + 15624) / 15625);
}


/*-------------------------------------------------------------------------------------*/
/**
* @brief Get milliseconds portion (fractional part only) from an OS_time_t object
*
* Extracts the fractional part from a given OS_time_t object normalized
* to units of milliseconds.
*
* @sa OS_TimeGetTotalSeconds()
*
* @param[in] tm Time interval value
* @returns Number of milliseconds in time interval
*/
static inline uint32 OS_TimeGetMillisecondsPart(OS_time_t tm)
{
return OS_TimeGetFractionalPart(tm) / 1000;
}

/*-------------------------------------------------------------------------------------*/
/**
* @brief Get microseconds portion (fractional part only) from an OS_time_t object
*
* Extracts the fractional part from a given OS_time_t object normalized
* to units of microseconds.
*
* This function may be used to adapt applications initially implemented
* using an older OSAL version where OS_time_t was a structure containing
* a "seconds" and "microsecs" field.
*
* This function will obtain a value that is compatible with the "microsecs" field of
* OS_time_t as it was defined in previous versions of OSAL, as well as the "tv_usec"
* field of POSIX-style "struct timeval" values.
*
* @sa OS_TimeGetTotalSeconds()
*
* @param[in] tm Time interval value
* @returns Number of microseconds in time interval
*/
static inline uint32 OS_TimeGetMicrosecondsPart(OS_time_t tm)
{
return OS_TimeGetFractionalPart(tm);
}

/*-------------------------------------------------------------------------------------*/
/**
* @brief Get nanoseconds portion (fractional part only) from an OS_time_t object
*
* Extracts the only number of nanoseconds from a given OS_time_t object.
*
* This function will obtain a value that is compatible with the "tv_nsec" field
* of POSIX-style "struct timespec" values.
*
* @sa OS_TimeGetTotalSeconds()
*
* @param[in] tm Time interval value
* @returns Number of nanoseconds in time interval
*/
static inline uint32 OS_TimeGetNanosecondsPart(OS_time_t tm)
{
return OS_TimeGetFractionalPart(tm) * 1000;
}

/*-------------------------------------------------------------------------------------*/
/**
* @brief Assemble/Convert a number of seconds + nanoseconds into an OS_time_t interval
*
* This creates an OS_time_t value using a whole number of seconds and a fractional
* part in units of nanoseconds. This is the inverse of OS_TimeGetTotalSeconds()
* and OS_TimeGetNanosecondsPart(), and should recreate the original OS_time_t
* value from these separate values (aside from any potential conversion losses
* due to limited resolution of the data types/units).
*
* @sa OS_TimeGetTotalSeconds(), OS_TimeGetNanosecondsPart()
*
* @param[in] seconds Whole number of seconds
* @param[in] nanoseconds Number of nanoseconds (fractional part only)
* @returns The input arguments represented as an OS_time_t interval
*/
static inline OS_time_t OS_TimeAssembleFromNanoseconds(int64 seconds, uint32 nanoseconds)
{
OS_time_t result;
result.seconds = seconds;
result.microsecs = nanoseconds / 1000;
return result;
}

/*-------------------------------------------------------------------------------------*/
/**
* @brief Assemble/Convert a number of seconds + subseconds into an OS_time_t interval
*
* This creates an OS_time_t value using a whole number of seconds and a fractional
* part in units of sub-seconds (1/2^32). This is the inverse of OS_TimeGetTotalSeconds()
* and OS_TimeGetSubsecondsPart(), and should recreate the original OS_time_t
* value from these separate values (aside from any potential conversion losses
* due to limited resolution of the data types/units).
*
* @sa OS_TimeGetTotalSeconds(), OS_TimeGetNanosecondsPart()
* @param[in] seconds Whole number of seconds
* @param[in] subseconds Number of subseconds (32 bit fixed point fractional part)
* @returns The input arguments represented as an OS_time_t interval
*/
static inline OS_time_t OS_TimeAssembleFromSubseconds(int64 seconds, uint32 subseconds)
{
OS_time_t result;
result.seconds = seconds;
/* this should not round in any way, as the 32-bit input value has higher precision */
result.microsecs = ((int64)subseconds * 15625) >> 26;
return result;
}

/*-------------------------------------------------------------------------------------*/
/**
* @brief Computes the sum of two time intervals
*
* @param[in] time1 The first interval
* @param[in] time2 The second interval
*
* @return The sum of the two intervals (time1 + time2)
*/
static inline OS_time_t OS_TimeAdd(OS_time_t time1, OS_time_t time2)
{
OS_time_t result = time1;
result.seconds += time2.seconds;
result.microsecs += time2.microsecs;
if (result.microsecs >= 1000000)
{
++result.seconds;
result.microsecs -= 1000000;
}
return result;
}

/*-------------------------------------------------------------------------------------*/
/**
* @brief Computes the difference between two time intervals
*
* @param[in] time1 The first interval
* @param[in] time2 The second interval
*
* @return The difference of the two intervals (time1 - time2)
*/
static inline OS_time_t OS_TimeSubtract(OS_time_t time1, OS_time_t time2)
{
OS_time_t result = time1;
result.seconds -= time2.seconds;
result.microsecs -= time2.microsecs;
if (result.microsecs >= 1000000)
{
--result.seconds;
result.microsecs += 1000000;
}
return result;
}


/**@}*/

#endif
11 changes: 6 additions & 5 deletions src/os/inc/osapi-file.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#include "osconfig.h"
#include "common_types.h"
#include "osapi-clock.h"


/** @defgroup OSFileAccess OSAL File Access Option Defines
Expand Down Expand Up @@ -63,9 +64,9 @@ typedef struct
*/
typedef struct
{
uint32 FileModeBits;
int32 FileTime;
size_t FileSize;
uint32 FileModeBits;
OS_time_t FileTime;
size_t FileSize;
} os_fstat_t;

/**
Expand Down Expand Up @@ -96,8 +97,8 @@ enum
#define OS_FILESTAT_READ(x) ((x).FileModeBits & OS_FILESTAT_MODE_READ)
/** @brief Access file stat size field */
#define OS_FILESTAT_SIZE(x) ((x).FileSize)
/** @brief Access file stat time field */
#define OS_FILESTAT_TIME(x) ((x).FileTime)
/** @brief Access file stat time field as a whole number of seconds */
#define OS_FILESTAT_TIME(x) (OS_TimeGetTotalSeconds((x).FileTime))

/**
* @brief Flags that can be used with opening of a file (bitmask)
Expand Down
Loading

0 comments on commit ccbaca0

Please sign in to comment.