/* * $Id$ */ #include #include #include #include #include #include #include #include #include /*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(); }