[PATCH] posix: fix clock_nanosleep and nanosleep clock use

Gedare Bloom gedare at rtems.org
Fri Jul 15 16:58:40 UTC 2016


Sleeping with CLOCK_REALTIME should use the WATCHDOG_ABSOLUTE
clock discipline for the threadq so that the timeout interval
may change in case the clock source changes. Similarly,
CLOCK_MONOTONIC uses the WATCHDOG_RELATIVE threadq that will
only wakeup the thread after the requested count of ticks elapse.

updates #2732
---
 cpukit/posix/src/nanosleep.c | 67 +++++++++++++++++++++++++++++++++-----------
 1 file changed, 51 insertions(+), 16 deletions(-)

diff --git a/cpukit/posix/src/nanosleep.c b/cpukit/posix/src/nanosleep.c
index e60dd53..ce0100f 100644
--- a/cpukit/posix/src/nanosleep.c
+++ b/cpukit/posix/src/nanosleep.c
@@ -33,9 +33,9 @@ static Thread_queue_Control _Nanosleep_Pseudo_queue =
   THREAD_QUEUE_INITIALIZER( "Nanosleep" );
 
 static inline int nanosleep_helper(
-  const struct timespec  *rqtp,
-  struct timespec        *rmtp,
-  Watchdog_Discipline     discipline
+  uint64_t              ticks,
+  struct timespec      *rmtp,
+  Watchdog_Discipline   discipline
 )
 {
   /*
@@ -45,11 +45,9 @@ static inline int nanosleep_helper(
   Thread_Control  *executing;
   Per_CPU_Control *cpu_self;
 
-  Watchdog_Interval  ticks;
   Watchdog_Interval  start;
   Watchdog_Interval  elapsed;
 
-
   /*
    *  Return EINVAL if the delay interval is negative.
    *
@@ -59,11 +57,6 @@ static inline int nanosleep_helper(
   if ( !_Timespec_Is_valid( rqtp ) )
     return EINVAL;
 
-  /*
-   * Convert the timespec delay into the appropriate number of clock ticks.
-   */
-  ticks = _Timespec_To_ticks( rqtp );
-
   executing = _Thread_Get_executing();
 
   /*
@@ -110,7 +103,7 @@ static inline int nanosleep_helper(
   /*
    * If the user wants the time remaining, do the conversion.
    */
-  if ( rmtp && discipline == WATCHDOG_RELATIVE ) {
+  if ( rmtp ) {
     _Timespec_From_ticks( ticks, rmtp );
   }
 
@@ -135,8 +128,22 @@ int nanosleep(
   struct timespec        *rmtp
 )
 {
-  int err = nanosleep_helper(rqtp, rmtp, WATCHDOG_RELATIVE);
-  if (err) {
+  int err;
+  struct timespec timeout;
+  uint64_t ticks;
+
+ /* CLOCK_REALTIME can be adjusted during the timeout,
+  * so convert to an absolute timeout value and put the
+  * thread on the WATCHDOG_ABSOLUTE threadq. */
+  err = clock_gettime( CLOCK_REALTIME, &timeout );
+  if ( err != 0 )
+    return -1;
+  }
+
+  _Timespec_Add_to( &timeout, rqtp );
+  ticks = _Watchdog_Ticks_from_timespec( &timeout );
+  err = nanosleep_helper(ticks, rmtp, WATCHDOG_ABSOLUTE );
+  if ( err != 0 ) {
     rtems_set_errno_and_return_minus_one( err );
   }
   return 0;
@@ -153,12 +160,40 @@ int clock_nanosleep(
 )
 {
   int err = 0;
-  if ( clock_id == CLOCK_REALTIME || clock_id == CLOCK_MONOTONIC ) {
+  struct timespec absolute_timeout;
+  uint64_t ticks;
+  Watchdog_Interval relative_ticks;
+  TOD_Absolute_timeout_conversion_results status;
+
+  if ( flags & TIMER_ABSTIME ) {
+    /* See if absolute time already passed */
+    status = _TOD_Absolute_timeout_to_ticks(rqtp, clock_id, &relative_ticks);
+    if ( status == TOD_ABSOLUTE_TIMEOUT_INVALID )
+      return EINVAL;
+    if ( status == TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST ||
+        status == TOD_ABSOLUTE_TIMEOUT_IS_NOW ) {
+      return 0;
+    }
+    rmtp = NULL; /* Do not touch rmtp when using absolute time */
+  } else {
+    relative_ticks = _Timespec_To_ticks(rqtp);
+  }
+
+  if ( clock_id == CLOCK_REALTIME ) {
     if ( flags & TIMER_ABSTIME ) {
-      err = nanosleep_helper(rqtp, rmtp, WATCHDOG_ABSOLUTE);
+      ticks = _Watchdog_Ticks_from_timespec(rqtp);
     } else {
-      err = nanosleep_helper(rqtp, rmtp, WATCHDOG_RELATIVE);
+      err = clock_gettime( CLOCK_REALTIME, &absolute_timeout );
+      if ( err != 0 ) {
+        return EINVAL;
+      }
+      _Timespec_Add_to( &absolute_timeout, rqtp );
+      ticks = _Watchdog_Ticks_from_timespec( &absolute_timeout );
     }
+    err = nanosleep_helper( ticks, rmtp, WATCHDOG_ABSOLUTE );
+  } else if ( clock_id == CLOCK_MONOTONIC ) {
+    /* use the WATCHDOG_RELATIVE to ignore changes in wall time */
+    err = nanosleep_helper( relative_ticks, rmtp, WATCHDOG_RELATIVE );
   } else {
     err = ENOTSUP;
   }
-- 
1.9.1



More information about the devel mailing list