From 3e81d52e27ea030fc93580c610c40616ab2b0559 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Sun, 29 Oct 2017 20:29:05 +0100 Subject: posix: Use far future for very long timeouts Close #3205. --- cpukit/posix/src/nanosleep.c | 14 ++---- cpukit/posix/src/sigtimedwait.c | 16 +++---- cpukit/score/include/rtems/score/watchdogimpl.h | 30 +++++++++++++ testsuites/psxtests/psxclock/init.c | 59 ++++++++++++++++++++++--- 4 files changed, 90 insertions(+), 29 deletions(-) diff --git a/cpukit/posix/src/nanosleep.c b/cpukit/posix/src/nanosleep.c index f65c91bc17..5bd1b00aa9 100644 --- a/cpukit/posix/src/nanosleep.c +++ b/cpukit/posix/src/nanosleep.c @@ -63,7 +63,7 @@ int clock_nanosleep( ) { Thread_queue_Context queue_context; - struct timespec spare_end; + struct timespec uptime; const struct timespec *end; Thread_Control *executing; int eno; @@ -93,16 +93,8 @@ int clock_nanosleep( ); } } else { - if ( !_Watchdog_Is_valid_interval_timespec( rqtp ) ) { - return EINVAL; - } - - _TOD_Get_zero_based_uptime_as_timespec( &spare_end ); - - /* In case this overflows, then the enqueue callout will reject it */ - _Timespec_Add_to( &spare_end, rqtp ); - - end = &spare_end; + _TOD_Get_zero_based_uptime_as_timespec( &uptime ); + end = _Watchdog_Future_timespec( &uptime, rqtp ); _Thread_queue_Context_set_enqueue_timeout_monotonic_timespec( &queue_context, end diff --git a/cpukit/posix/src/sigtimedwait.c b/cpukit/posix/src/sigtimedwait.c index a0e18adef0..72f4919be9 100644 --- a/cpukit/posix/src/sigtimedwait.c +++ b/cpukit/posix/src/sigtimedwait.c @@ -76,6 +76,7 @@ int sigtimedwait( siginfo_t signal_information; siginfo_t *the_info; int signo; + struct timespec uptime; Thread_queue_Context queue_context; int error; @@ -92,20 +93,13 @@ int sigtimedwait( */ if ( timeout != NULL ) { - struct timespec end; - - if ( !_Watchdog_Is_valid_interval_timespec( timeout ) ) { - return EINVAL; - } - - _TOD_Get_zero_based_uptime_as_timespec( &end ); - - /* In case this overflows, then the enqueue callout will reject it */ - _Timespec_Add_to( &end, timeout ); + const struct timespec *end; + _TOD_Get_zero_based_uptime_as_timespec( &uptime ); + end = _Watchdog_Future_timespec( &uptime, timeout ); _Thread_queue_Context_set_enqueue_timeout_monotonic_timespec( &queue_context, - &end + end ); } else { _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context ); diff --git a/cpukit/score/include/rtems/score/watchdogimpl.h b/cpukit/score/include/rtems/score/watchdogimpl.h index 7866c0ce44..f219a70768 100644 --- a/cpukit/score/include/rtems/score/watchdogimpl.h +++ b/cpukit/score/include/rtems/score/watchdogimpl.h @@ -324,6 +324,36 @@ RTEMS_INLINE_ROUTINE bool _Watchdog_Is_valid_interval_timespec( return _Watchdog_Is_valid_timespec( ts ) && ts->tv_sec >= 0; } +RTEMS_INLINE_ROUTINE const struct timespec * _Watchdog_Future_timespec( + struct timespec *now, + const struct timespec *delta +) +{ + uint64_t sec; + + if ( !_Watchdog_Is_valid_interval_timespec( delta ) ) { + return NULL; + } + + sec = (uint64_t) now->tv_sec; + sec += (uint64_t) delta->tv_sec; + now->tv_nsec += delta->tv_nsec; + + /* We have 2 * (2**63 - 1) + 1 == UINT64_MAX */ + if ( now->tv_nsec >= WATCHDOG_NANOSECONDS_PER_SECOND ) { + now->tv_nsec -= WATCHDOG_NANOSECONDS_PER_SECOND; + ++sec; + } + + if ( sec <= INT64_MAX ) { + now->tv_sec = sec; + } else { + now->tv_sec = INT64_MAX; + } + + return now; +} + RTEMS_INLINE_ROUTINE bool _Watchdog_Is_far_future_monotonic_timespec( const struct timespec *ts ) diff --git a/testsuites/psxtests/psxclock/init.c b/testsuites/psxtests/psxclock/init.c index 669f4bb0c4..1e7dae7bde 100644 --- a/testsuites/psxtests/psxclock/init.c +++ b/testsuites/psxtests/psxclock/init.c @@ -13,19 +13,17 @@ #include #include +#include #include "pmacros.h" #include "pritime.h" +#include #include const char rtems_test_name[] = "PSXCLOCK"; -/* forward declarations to avoid warnings */ -rtems_task Init(rtems_task_argument argument); -void check_enosys(int status); - -void check_enosys(int status) +static void check_enosys(int status) { if ( (status == -1) && (errno == ENOSYS) ) return; @@ -33,7 +31,52 @@ void check_enosys(int status) rtems_test_exit(0); } -rtems_task Init( +typedef struct { + int counter; + struct timespec delta; +} nanosleep_contex; + +static void task_nanosleep( rtems_task_argument arg ) +{ + nanosleep_contex *ctx; + + ctx = (nanosleep_contex *) arg; + ++ctx->counter; + nanosleep( &ctx->delta, NULL ); +} + +static void test_far_future_nanosleep( void ) +{ + rtems_status_code sc; + rtems_id id; + nanosleep_contex ctx; + + sc = rtems_task_create( + rtems_build_name( 'N', 'A', 'N', 'O' ), + 1, + RTEMS_MINIMUM_STACK_SIZE, + RTEMS_DEFAULT_MODES, + RTEMS_DEFAULT_ATTRIBUTES, + &id + ); + rtems_test_assert( sc == RTEMS_SUCCESSFUL ); + + ctx.counter = 0; + ctx.delta.tv_sec = INT64_MAX; + ctx.delta.tv_nsec = 999999999; + sc = rtems_task_start( id, task_nanosleep, (rtems_task_argument) &ctx ); + rtems_test_assert( sc == RTEMS_SUCCESSFUL ); + + sc = rtems_task_wake_after( RTEMS_YIELD_PROCESSOR ); + rtems_test_assert( sc == RTEMS_SUCCESSFUL ); + + rtems_test_assert( ctx.counter == 1 ); + + sc = rtems_task_delete( id ); + rtems_test_assert( sc == RTEMS_SUCCESSFUL ); +} + +static rtems_task Init( rtems_task_argument argument ) { @@ -140,6 +183,8 @@ rtems_task Init( printf( "Init: seconds remaining (%d)\n", (int)remaining ); rtems_test_assert( !remaining ); + test_far_future_nanosleep(); + /* error cases in nanosleep */ empty_line(); @@ -267,7 +312,7 @@ rtems_task Init( #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION #define CONFIGURE_RTEMS_INIT_TASKS_TABLE -#define CONFIGURE_MAXIMUM_TASKS 1 +#define CONFIGURE_MAXIMUM_TASKS 2 #define CONFIGURE_INIT #include -- cgit v1.2.3