source: rtems/cpukit/posix/src/nanosleep.c @ e0f17fc

5
Last change on this file since e0f17fc was e0f17fc, checked in by Gedare Bloom <gedare@…>, on 07/15/16 at 16:52:05

posix: fix clock_nanosleep and nanosleep clock use

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

  • Property mode set to 100644
File size: 5.1 KB
RevLine 
[d527562e]1/**
2 * @file
3 *
[d937d36]4 * @brief Suspends Execution of calling thread until Time elapses
[5cb175bb]5 * @ingroup POSIXAPI
[d527562e]6 */
7
[9f95a19]8/*
[d937d36]9 *  COPYRIGHT (c) 1989-2015.
[412dbff6]10 *  On-Line Applications Research Corporation (OAR).
[6e98ea91]11 *
12 *  Copyright (c) 2016. Gedare Bloom.
[412dbff6]13 *
14 *  The license and distribution terms for this file may be
15 *  found in the file LICENSE in this distribution or at
[c499856]16 *  http://www.rtems.org/license/LICENSE.
[9f95a19]17 */
18
[f42b726]19#if HAVE_CONFIG_H
20#include "config.h"
21#endif
22
[9f95a19]23#include <time.h>
24#include <errno.h>
25
[c6e21ee1]26#include <rtems/seterr.h>
[5618c37a]27#include <rtems/score/threadimpl.h>
[aa05cfbb]28#include <rtems/score/threadqimpl.h>
[c6e21ee1]29#include <rtems/score/timespec.h>
[4b48ece0]30#include <rtems/score/watchdogimpl.h>
[9f95a19]31
[aa05cfbb]32static Thread_queue_Control _Nanosleep_Pseudo_queue =
[1e1a91ed]33  THREAD_QUEUE_INITIALIZER( "Nanosleep" );
[aa05cfbb]34
[6e98ea91]35static inline int nanosleep_helper(
[e0f17fc]36  uint64_t              ticks,
37  struct timespec      *rmtp,
38  Watchdog_Discipline   discipline
[9f95a19]39)
40{
[6eba7c85]41  /*
42   * It is critical to obtain the executing thread after thread dispatching is
43   * disabled on SMP configurations.
44   */
[aa05cfbb]45  Thread_Control  *executing;
46  Per_CPU_Control *cpu_self;
[6eba7c85]47
[03b900d]48  Watchdog_Interval  start;
[d937d36]49  Watchdog_Interval  elapsed;
[9f95a19]50
[aa05cfbb]51  executing = _Thread_Get_executing();
52
[812da54]53  /*
54   *  A nanosleep for zero time is implemented as a yield.
[9f95a19]55   *  This behavior is also beyond the POSIX specification but is
[412dbff6]56   *  consistent with the RTEMS API and yields desirable behavior.
[9f95a19]57   */
58  if ( !ticks ) {
[aa05cfbb]59    cpu_self = _Thread_Dispatch_disable();
[701dd96f]60      _Thread_Yield( executing );
[aa05cfbb]61    _Thread_Dispatch_enable( cpu_self );
[9f95a19]62    if ( rmtp ) {
[874297f3]63       rmtp->tv_sec = 0;
64       rmtp->tv_nsec = 0;
[9f95a19]65    }
66    return 0;
67  }
[874297f3]68
[03b900d]69  start = _Watchdog_Ticks_since_boot;
70
[812da54]71  /*
72   *  Block for the desired amount of time
73   */
[aa05cfbb]74  _Thread_queue_Enqueue(
75    &_Nanosleep_Pseudo_queue,
[1e1a91ed]76    &_Thread_queue_Operations_FIFO,
[aa05cfbb]77    executing,
78    STATES_DELAYING | STATES_INTERRUPTIBLE_BY_SIGNAL,
[93306058]79    ticks,
[6e98ea91]80    discipline,
[93306058]81    1
[aa05cfbb]82  );
[9f95a19]83
[d937d36]84  /*
85   * Calculate the time that passed while we were sleeping and how
86   * much remains from what we requested.
87   */
[03b900d]88  elapsed = _Watchdog_Ticks_since_boot - start;
[d937d36]89  if ( elapsed >= ticks )
90    ticks = 0;
91  else
92    ticks -= elapsed;
[9f95a19]93
[d937d36]94  /*
95   * If the user wants the time remaining, do the conversion.
96   */
[e0f17fc]97  if ( rmtp ) {
[412dbff6]98    _Timespec_From_ticks( ticks, rmtp );
[d937d36]99  }
[9f95a19]100
[d937d36]101  /*
102   *  Only when POSIX is enabled, can a sleep be interrupted.
103   */
104  #if defined(RTEMS_POSIX_API)
[9f95a19]105    /*
[d937d36]106     *  If there is time remaining, then we were interrupted by a signal.
[9f95a19]107     */
[d937d36]108    if ( ticks )
[6e98ea91]109      return EINTR;
[d937d36]110  #endif
[9f95a19]111
112  return 0;
113}
[6e98ea91]114/*
115 *  14.2.5 High Resolution Sleep, P1003.1b-1993, p. 269
116 */
117int nanosleep(
118  const struct timespec  *rqtp,
119  struct timespec        *rmtp
120)
121{
[e0f17fc]122  int err;
123  struct timespec timeout;
124  uint64_t ticks;
125
126  /*
127   *  Return EINVAL if the delay interval is negative.
128   *
129   *  NOTE:  This behavior is beyond the POSIX specification.
130   *         FSU and GNU/Linux pthreads shares this behavior.
131   */
132  if ( !_Timespec_Is_valid( rqtp ) )
133    return EINVAL;
134
135 /* CLOCK_REALTIME can be adjusted during the timeout,
136  * so convert to an absolute timeout value and put the
137  * thread on the WATCHDOG_ABSOLUTE threadq. */
138  err = clock_gettime( CLOCK_REALTIME, &timeout );
139  if ( err != 0 )
140    return -1;
141
142  _Timespec_Add_to( &timeout, rqtp );
143  ticks = _Watchdog_Ticks_from_timespec( &timeout );
144  err = nanosleep_helper(ticks, rmtp, WATCHDOG_ABSOLUTE );
145  if ( err != 0 ) {
[6e98ea91]146    rtems_set_errno_and_return_minus_one( err );
147  }
148  return 0;
149}
150
151/*
152 * High Resolution Sleep with Specifiable Clock, IEEE Std 1003.1, 2001
153 */
154int clock_nanosleep(
155  clockid_t               clock_id,
156  int                     flags,
157  const struct timespec  *rqtp,
158  struct timespec        *rmtp
159)
160{
161  int err = 0;
[e0f17fc]162  struct timespec absolute_timeout;
163  uint64_t ticks;
164  Watchdog_Interval relative_ticks;
165  TOD_Absolute_timeout_conversion_results status;
166
167  /*
168   *  Return EINVAL if the delay interval is negative.
169   *
170   *  NOTE:  This behavior is beyond the POSIX specification.
171   *         FSU and GNU/Linux pthreads shares this behavior.
172   */
173  if ( !_Timespec_Is_valid( rqtp ) )
174    return EINVAL;
175
176  if ( flags & TIMER_ABSTIME ) {
177    /* See if absolute time already passed */
178    status = _TOD_Absolute_timeout_to_ticks(rqtp, clock_id, &relative_ticks);
179    if ( status == TOD_ABSOLUTE_TIMEOUT_INVALID )
180      return EINVAL;
181    if ( status == TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST ||
182        status == TOD_ABSOLUTE_TIMEOUT_IS_NOW ) {
183      return 0;
184    }
185    rmtp = NULL; /* Do not touch rmtp when using absolute time */
186  } else {
187    relative_ticks = _Timespec_To_ticks(rqtp);
188  }
189
190  if ( clock_id == CLOCK_REALTIME ) {
[6e98ea91]191    if ( flags & TIMER_ABSTIME ) {
[e0f17fc]192      ticks = _Watchdog_Ticks_from_timespec(rqtp);
[6e98ea91]193    } else {
[e0f17fc]194      err = clock_gettime( CLOCK_REALTIME, &absolute_timeout );
195      if ( err != 0 ) {
196        return EINVAL;
197      }
198      _Timespec_Add_to( &absolute_timeout, rqtp );
199      ticks = _Watchdog_Ticks_from_timespec( &absolute_timeout );
[6e98ea91]200    }
[e0f17fc]201    err = nanosleep_helper( ticks, rmtp, WATCHDOG_ABSOLUTE );
202  } else if ( clock_id == CLOCK_MONOTONIC ) {
203    /* use the WATCHDOG_RELATIVE to ignore changes in wall time */
204    err = nanosleep_helper( relative_ticks, rmtp, WATCHDOG_RELATIVE );
[6e98ea91]205  } else {
206    err = ENOTSUP;
207  }
208  return err;
209}
Note: See TracBrowser for help on using the repository browser.