diff options
Diffstat (limited to 'c/src/exec/posix/src/time.c')
-rw-r--r-- | c/src/exec/posix/src/time.c | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/c/src/exec/posix/src/time.c b/c/src/exec/posix/src/time.c new file mode 100644 index 0000000000..acb4b507b1 --- /dev/null +++ b/c/src/exec/posix/src/time.c @@ -0,0 +1,393 @@ +/* + * $Id$ + */ + +#include <assert.h> +#include <time.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/tod.h> + +#include <rtems/posix/seterr.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * _POSIX_Timespec_subtract + */ + +void _POSIX_Timespec_subtract( + const struct timespec *the_start, + const struct timespec *end, + struct timespec *result +) +{ + struct timespec start_struct = *the_start; + struct timespec *start = &start_struct; + unsigned int nsecs_per_sec = TOD_NANOSECONDS_PER_SECOND; + + if (end->tv_nsec < start->tv_nsec) { + int seconds = (start->tv_nsec - end->tv_nsec) / nsecs_per_sec + 1; + start->tv_nsec -= nsecs_per_sec * seconds; + start->tv_sec += seconds; + } + + if (end->tv_nsec - start->tv_nsec > nsecs_per_sec) { + int seconds = (start->tv_nsec - end->tv_nsec) / nsecs_per_sec; + start->tv_nsec += nsecs_per_sec * seconds; + start->tv_sec -= seconds; + } + + result->tv_sec = end->tv_sec - start->tv_sec; + result->tv_nsec = end->tv_nsec - start->tv_nsec; +} + +/*PAGE + * + * _POSIX_Timespec_to_interval + */ + +Watchdog_Interval _POSIX_Timespec_to_interval( + const struct timespec *time +) +{ + Watchdog_Interval ticks; + + ticks = (time->tv_sec * TOD_MICROSECONDS_PER_SECOND) / + _TOD_Microseconds_per_tick; + + ticks += (time->tv_nsec / TOD_NANOSECONDS_PER_MICROSECOND) / + _TOD_Microseconds_per_tick; + + return ticks; +} + +/*PAGE + * + * _POSIX_Interval_to_timespec + */ + +void _POSIX_Interval_to_timespec( + Watchdog_Interval ticks, + struct timespec *time +) +{ + unsigned32 usecs; + + usecs = ticks * _TOD_Microseconds_per_tick; + + time->tv_sec = usecs / TOD_MICROSECONDS_PER_SECOND; + time->tv_nsec = (usecs % TOD_MICROSECONDS_PER_SECOND) * + TOD_NANOSECONDS_PER_MICROSECOND; +} + +/*PAGE + * + * 4.5.1 Get System Time, P1003.1b-1993, p. 91 + */ + +/* Using the implementation in newlib */ +#if 0 +time_t time( + time_t *tloc +) +{ + time_t seconds_since_epoch; + + /* + * No error is the time of day is not set. For RTEMS the system time + * starts out at the rtems epoch. + */ + + /* + * Internally the RTEMS epoch is 1988. This must be taken into account. + */ + + seconds_since_epoch = _TOD_Seconds_since_epoch; + + seconds_since_epoch += POSIX_TIME_SECONDS_1970_THROUGH_1988; + + if ( tloc ) + *tloc = seconds_since_epoch; + + return seconds_since_epoch; +} +#endif + +/*PAGE + * + * 14.2.1 Clocks, P1003.1b-1993, p. 263 + */ + +int clock_settime( + clockid_t clock_id, + const struct timespec *tp +) +{ + struct tm split_time; + TOD_Control tod; + Watchdog_Interval seconds; + + assert( tp ); + + switch ( clock_id ) { + + case CLOCK_REALTIME: + (void) gmtime_r( &tp->tv_sec, &split_time ); + + /* + * Convert the tm structure format to that used by the TOD Handler + * + * NOTE: TOD Handler does not honor leap seconds. + */ + + tod.year = split_time.tm_year + 1900; /* RHS is years since 1900 */ + tod.month = split_time.tm_mon + 1; /* RHS uses 0-11 */ + tod.day = split_time.tm_mday; + tod.hour = split_time.tm_hour; + tod.minute = split_time.tm_min; + tod.second = split_time.tm_sec; /* RHS allows 0-61 for leap seconds */ + + tod.ticks = (tp->tv_nsec / TOD_NANOSECONDS_PER_MICROSECOND) / + _TOD_Microseconds_per_tick; + + if ( !_TOD_Validate( &tod ) ) + set_errno_and_return_minus_one( EINVAL ); + + /* + * We can't use the tp->tv_sec field because it is based on + * a different EPOCH. + */ + + seconds = _TOD_To_seconds( &tod ); + _Thread_Disable_dispatch(); + _TOD_Set( &tod, seconds ); + _Thread_Enable_dispatch(); + break; + +#ifdef _POSIX_CPUTIME + case CLOCK_PROCESS_CPUTIME: + return POSIX_NOT_IMPLEMENTED(); + break; +#endif + +#ifdef _POSIX_THREAD_CPUTIME + case CLOCK_THREAD_CPUTIME: + return POSIX_NOT_IMPLEMENTED(); + break; +#endif + default: + set_errno_and_return_minus_one( EINVAL ); + + } + return 0; +} + +/*PAGE + * + * 14.2.1 Clocks, P1003.1b-1993, p. 263 + */ + +int clock_gettime( + clockid_t clock_id, + struct timespec *tp +) +{ + ISR_Level level; + time_t seconds; + long ticks; + + if ( !tp ) + set_errno_and_return_minus_one( EINVAL ); + + switch ( clock_id ) { + + case CLOCK_REALTIME: + + _ISR_Disable( level ); + seconds = _TOD_Seconds_since_epoch; + ticks = _TOD_Current.ticks; + _ISR_Enable( level ); + + tp->tv_sec = seconds + POSIX_TIME_SECONDS_1970_THROUGH_1988; + tp->tv_nsec = ticks * _TOD_Microseconds_per_tick * + TOD_NANOSECONDS_PER_MICROSECOND; + break; + +#ifdef _POSIX_CPUTIME + case CLOCK_PROCESS_CPUTIME: + /* don't base this on _Watchdog_Ticks_since_boot--duration is too short*/ + return POSIX_NOT_IMPLEMENTED(); + break; +#endif + +#ifdef _POSIX_THREAD_CPUTIME + case CLOCK_THREAD_CPUTIME: + return POSIX_NOT_IMPLEMENTED(); + break; +#endif + default: + set_errno_and_return_minus_one( EINVAL ); + + } + return 0; +} + +/*PAGE + * + * 14.2.1 Clocks, P1003.1b-1993, p. 263 + */ + +int clock_getres( + clockid_t clock_id, + struct timespec *res +) +{ + if ( !res ) + set_errno_and_return_minus_one( EINVAL ); + + switch ( clock_id ) { + + /* + * All time in rtems is based on the same clock tick. + */ + + case CLOCK_REALTIME: + case CLOCK_PROCESS_CPUTIME: + case CLOCK_THREAD_CPUTIME: + if ( res ) + _POSIX_Interval_to_timespec( _TOD_Microseconds_per_tick, res ); + break; + + default: + set_errno_and_return_minus_one( EINVAL ); + + } + return 0; +} + +/*PAGE + * + * 14.2.5 High Resolution Sleep, P1003.1b-1993, p. 269 + */ + +int nanosleep( + const struct timespec *rqtp, + struct timespec *rmtp +) +{ + Watchdog_Interval ticks; + struct timespec *the_rqtp; + + if ( !rqtp ) + set_errno_and_return_minus_one( EINVAL ); + + the_rqtp = (struct timespec *)rqtp; + + /* + * Return EAGAIN if the delay interval is negative. + * + * NOTE: This behavior is beyond the POSIX specification. + * FSU pthreads shares this behavior. + */ + + if ( the_rqtp->tv_sec < 0 ) + the_rqtp->tv_sec = 0; + + if ( /* the_rqtp->tv_sec < 0 || */ the_rqtp->tv_nsec < 0 ) + set_errno_and_return_minus_one( EAGAIN ); + + if ( the_rqtp->tv_nsec >= TOD_NANOSECONDS_PER_SECOND ) + set_errno_and_return_minus_one( EINVAL ); + + ticks = _POSIX_Timespec_to_interval( the_rqtp ); + + /* + * This behavior is also beyond the POSIX specification but is + * consistent with the RTEMS api and yields desirable behavior. + */ + + if ( !ticks ) { + _Thread_Yield_processor(); + _Thread_Dispatch(); + if ( rmtp ) { + rmtp->tv_sec = 0; + rmtp->tv_nsec = 0; + } + return 0; + } + + _Thread_Disable_dispatch(); + _Thread_Set_state( + _Thread_Executing, + STATES_DELAYING | STATES_INTERRUPTIBLE_BY_SIGNAL + ); + _Watchdog_Initialize( + &_Thread_Executing->Timer, + _Thread_Delay_ended, + _Thread_Executing->Object.id, + NULL + ); + _Watchdog_Insert_ticks( &_Thread_Executing->Timer, ticks ); + _Thread_Enable_dispatch(); + + /* calculate time remaining */ + + if ( rmtp ) { + ticks -= + _Thread_Executing->Timer.stop_time - _Thread_Executing->Timer.start_time; + + _POSIX_Interval_to_timespec( ticks, rmtp ); + + /* + * If there is time remaining, then we were interrupted by a signal. + */ + + if ( ticks ) + set_errno_and_return_minus_one( EINTR ); + } + + return 0; +} + +/*PAGE + * + * 20.1.3 Accessing a Process CPU-time CLock, P1003.4b/D8, p. 55 + */ + +int clock_getcpuclockid( + pid_t pid, + clockid_t *clock_id +) +{ + return POSIX_NOT_IMPLEMENTED(); +} + +/*PAGE + * + * 20.1.5 CPU-time Clock Attribute Access, P1003.4b/D8, p. 58 + */ + +int clock_setenable_attr( + clockid_t clock_id, + int attr +) +{ + return POSIX_NOT_IMPLEMENTED(); +} + +/*PAGE + * + * 20.1.5 CPU-time Clock Attribute Access, P1003.4b/D8, p. 58 + */ + +int clock_getenable_attr( + clockid_t clock_id, + int *attr +) +{ + return POSIX_NOT_IMPLEMENTED(); +} |