source: rtems/cpukit/posix/src/nanosleep.c @ 6e98ea91

5
Last change on this file since 6e98ea91 was 6e98ea91, checked in by Gedare Bloom <gedare@…>, on 06/09/16 at 15:40:35

posix: add clock_nanosleep and tests

updates #2732

  • Property mode set to 100644
File size: 3.7 KB
Line 
1/**
2 * @file
3 *
4 * @brief Suspends Execution of calling thread until Time elapses
5 * @ingroup POSIXAPI
6 */
7
8/*
9 *  COPYRIGHT (c) 1989-2015.
10 *  On-Line Applications Research Corporation (OAR).
11 *
12 *  Copyright (c) 2016. Gedare Bloom.
13 *
14 *  The license and distribution terms for this file may be
15 *  found in the file LICENSE in this distribution or at
16 *  http://www.rtems.org/license/LICENSE.
17 */
18
19#if HAVE_CONFIG_H
20#include "config.h"
21#endif
22
23#include <time.h>
24#include <errno.h>
25
26#include <rtems/seterr.h>
27#include <rtems/score/threadimpl.h>
28#include <rtems/score/threadqimpl.h>
29#include <rtems/score/timespec.h>
30#include <rtems/score/watchdogimpl.h>
31
32static Thread_queue_Control _Nanosleep_Pseudo_queue =
33  THREAD_QUEUE_INITIALIZER( "Nanosleep" );
34
35static inline int nanosleep_helper(
36  const struct timespec  *rqtp,
37  struct timespec        *rmtp,
38  Watchdog_Discipline     discipline
39)
40{
41  /*
42   * It is critical to obtain the executing thread after thread dispatching is
43   * disabled on SMP configurations.
44   */
45  Thread_Control  *executing;
46  Per_CPU_Control *cpu_self;
47
48  Watchdog_Interval  ticks;
49  Watchdog_Interval  start;
50  Watchdog_Interval  elapsed;
51
52
53  /*
54   *  Return EINVAL if the delay interval is negative.
55   *
56   *  NOTE:  This behavior is beyond the POSIX specification.
57   *         FSU and GNU/Linux pthreads shares this behavior.
58   */
59  if ( !_Timespec_Is_valid( rqtp ) )
60    return EINVAL;
61
62  /*
63   * Convert the timespec delay into the appropriate number of clock ticks.
64   */
65  ticks = _Timespec_To_ticks( rqtp );
66
67  executing = _Thread_Get_executing();
68
69  /*
70   *  A nanosleep for zero time is implemented as a yield.
71   *  This behavior is also beyond the POSIX specification but is
72   *  consistent with the RTEMS API and yields desirable behavior.
73   */
74  if ( !ticks ) {
75    cpu_self = _Thread_Dispatch_disable();
76      _Thread_Yield( executing );
77    _Thread_Dispatch_enable( cpu_self );
78    if ( rmtp ) {
79       rmtp->tv_sec = 0;
80       rmtp->tv_nsec = 0;
81    }
82    return 0;
83  }
84
85  start = _Watchdog_Ticks_since_boot;
86
87  /*
88   *  Block for the desired amount of time
89   */
90  _Thread_queue_Enqueue(
91    &_Nanosleep_Pseudo_queue,
92    &_Thread_queue_Operations_FIFO,
93    executing,
94    STATES_DELAYING | STATES_INTERRUPTIBLE_BY_SIGNAL,
95    ticks,
96    discipline,
97    1
98  );
99
100  /*
101   * Calculate the time that passed while we were sleeping and how
102   * much remains from what we requested.
103   */
104  elapsed = _Watchdog_Ticks_since_boot - start;
105  if ( elapsed >= ticks )
106    ticks = 0;
107  else
108    ticks -= elapsed;
109
110  /*
111   * If the user wants the time remaining, do the conversion.
112   */
113  if ( rmtp && discipline == WATCHDOG_RELATIVE ) {
114    _Timespec_From_ticks( ticks, rmtp );
115  }
116
117  /*
118   *  Only when POSIX is enabled, can a sleep be interrupted.
119   */
120  #if defined(RTEMS_POSIX_API)
121    /*
122     *  If there is time remaining, then we were interrupted by a signal.
123     */
124    if ( ticks )
125      return EINTR;
126  #endif
127
128  return 0;
129}
130/*
131 *  14.2.5 High Resolution Sleep, P1003.1b-1993, p. 269
132 */
133int nanosleep(
134  const struct timespec  *rqtp,
135  struct timespec        *rmtp
136)
137{
138  int err = nanosleep_helper(rqtp, rmtp, WATCHDOG_RELATIVE);
139  if (err) {
140    rtems_set_errno_and_return_minus_one( err );
141  }
142  return 0;
143}
144
145/*
146 * High Resolution Sleep with Specifiable Clock, IEEE Std 1003.1, 2001
147 */
148int clock_nanosleep(
149  clockid_t               clock_id,
150  int                     flags,
151  const struct timespec  *rqtp,
152  struct timespec        *rmtp
153)
154{
155  int err = 0;
156  if ( clock_id == CLOCK_REALTIME || clock_id == CLOCK_MONOTONIC ) {
157    if ( flags & TIMER_ABSTIME ) {
158      err = nanosleep_helper(rqtp, rmtp, WATCHDOG_ABSOLUTE);
159    } else {
160      err = nanosleep_helper(rqtp, rmtp, WATCHDOG_RELATIVE);
161    }
162  } else {
163    err = ENOTSUP;
164  }
165  return err;
166}
Note: See TracBrowser for help on using the repository browser.