[PATCH] posix: Use far future for very long timeouts

Sebastian Huber sebastian.huber at embedded-brains.de
Thu Nov 2 11:54:15 UTC 2017


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 <time.h>
 #include <errno.h>
+#include <stdint.h>
 
 #include "pmacros.h"
 #include "pritime.h"
 
+#include <rtems.h>
 #include <rtems/score/todimpl.h>
 
 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 <rtems/confdefs.h>
-- 
2.12.3



More information about the devel mailing list