source: rtems/cpukit/posix/src/time.c @ 41be2e8

4.104.114.84.95
Last change on this file since 41be2e8 was 41be2e8, checked in by Joel Sherrill <joel.sherrill@…>, on 09/17/96 at 21:31:30

added routine _POSIX_Timespec_subtract

  • Property mode set to 100644
File size: 7.9 KB
Line 
1/*
2 *  $Id$
3 */
4
5#include <assert.h>
6#include <time.h>
7#include <errno.h>
8
9#include <rtems/system.h>
10#include <rtems/score/isr.h>
11#include <rtems/score/thread.h>
12#include <rtems/score/tod.h>
13
14#include <rtems/posix/seterr.h>
15#include <rtems/posix/time.h>
16
17/*PAGE
18 *
19 *  _POSIX_Timespec_subtract
20 */
21
22void _POSIX_Timespec_subtract(
23  const struct timespec *the_start,
24  const struct timespec *end,
25  struct timespec *result
26)
27{
28  struct timespec  start_struct = *the_start;
29  struct timespec *start = &start_struct;
30  unsigned int nsecs_per_sec = TOD_NANOSECONDS_PER_SECOND;
31 
32  if (end->tv_nsec < start->tv_nsec) {
33    int seconds = (start->tv_nsec - end->tv_nsec) / nsecs_per_sec + 1;
34    start->tv_nsec -= nsecs_per_sec * seconds;
35    start->tv_sec += seconds;
36  }
37 
38  if (end->tv_nsec - start->tv_nsec > nsecs_per_sec) {
39    int seconds = (start->tv_nsec - end->tv_nsec) / nsecs_per_sec;
40    start->tv_nsec += nsecs_per_sec * seconds;
41    start->tv_sec -= seconds;
42  }
43 
44  result->tv_sec  = end->tv_sec - start->tv_sec;
45  result->tv_nsec = end->tv_nsec - start->tv_nsec;
46}
47
48/*PAGE
49 *
50 *  _POSIX_Timespec_to_interval
51 */
52
53Watchdog_Interval _POSIX_Timespec_to_interval(
54  const struct timespec *time
55)
56{
57  Watchdog_Interval  ticks;
58
59  ticks  = (time->tv_sec * TOD_MICROSECONDS_PER_SECOND) /
60             _TOD_Microseconds_per_tick;
61
62  ticks += (time->tv_nsec / TOD_NANOSECONDS_PER_MICROSECOND) /
63             _TOD_Microseconds_per_tick;
64
65  return ticks;
66}
67
68/*PAGE
69 *
70 *  _POSIX_Interval_to_timespec
71 */
72 
73void _POSIX_Interval_to_timespec(
74  Watchdog_Interval  ticks,
75  struct timespec   *time
76)
77{
78  unsigned32  usecs;
79
80  usecs = ticks * _TOD_Microseconds_per_tick;
81
82  time->tv_sec  = usecs / TOD_MICROSECONDS_PER_SECOND;
83  time->tv_nsec = (usecs % TOD_MICROSECONDS_PER_SECOND) *
84                    TOD_NANOSECONDS_PER_MICROSECOND;
85}
86
87/*PAGE
88 *
89 *  4.5.1 Get System Time, P1003.1b-1993, p. 91
90 */
91
92time_t time(
93  time_t   *tloc
94)
95{
96  time_t  seconds_since_epoch;
97
98  /*
99   *  No error is the time of day is not set.   For RTEMS the system time
100   *  starts out at the rtems epoch.
101   */
102
103  /*
104   *  Internally the RTEMS epoch is 1988.  This must be taken into account.
105   */
106
107  seconds_since_epoch = _TOD_Seconds_since_epoch;
108     
109  seconds_since_epoch += POSIX_TIME_SECONDS_1970_THROUGH_1988;
110
111  if ( tloc )
112    *tloc = seconds_since_epoch;
113
114  return seconds_since_epoch;
115}
116
117/*PAGE
118 *
119 *  14.2.1 Clocks, P1003.1b-1993, p. 263
120 */
121
122int clock_settime(
123  clockid_t              clock_id,
124  const struct timespec *tp
125)
126{
127  struct tm         split_time;
128  TOD_Control       tod;
129  Watchdog_Interval seconds;
130
131  assert( tp );
132
133  switch ( clock_id ) {
134 
135    case CLOCK_REALTIME:
136      (void) gmtime_r( &tp->tv_sec, &split_time );
137 
138      /*
139       *  Convert the tm structure format to that used by the TOD Handler
140       *
141       *  NOTE: TOD Handler does not honor leap seconds.
142       */
143
144      tod.year   = split_time.tm_year + 1900;  /* RHS is years since 1900 */
145      tod.month  = split_time.tm_mon + 1;      /* RHS uses 0-11 */
146      tod.day    = split_time.tm_mday;
147      tod.hour   = split_time.tm_hour;
148      tod.minute = split_time.tm_min;
149      tod.second = split_time.tm_sec;  /* RHS allows 0-61 for leap seconds */
150
151      tod.ticks  = (tp->tv_nsec / TOD_NANOSECONDS_PER_MICROSECOND) /
152                      _TOD_Microseconds_per_tick;
153
154      if ( !_TOD_Validate( &tod ) )
155        set_errno_and_return_minus_one( EINVAL );
156 
157      /*
158       *  We can't use the tp->tv_sec field because it is based on
159       *  a different EPOCH.
160       */
161
162      seconds = _TOD_To_seconds( &tod );
163      _Thread_Disable_dispatch();
164        _TOD_Set( &tod, seconds );
165      _Thread_Enable_dispatch();
166      break;
167 
168#ifdef _POSIX_CPUTIME
169    case CLOCK_PROCESS_CPUTIME:
170      return POSIX_NOT_IMPLEMENTED();
171      break;
172#endif
173 
174#ifdef _POSIX_THREAD_CPUTIME
175    case CLOCK_THREAD_CPUTIME:
176      return POSIX_NOT_IMPLEMENTED();
177      break;
178#endif
179    default:
180      set_errno_and_return_minus_one( EINVAL );
181 
182  }
183  return 0;
184}
185
186/*PAGE
187 *
188 *  14.2.1 Clocks, P1003.1b-1993, p. 263
189 */
190
191int clock_gettime(
192  clockid_t        clock_id,
193  struct timespec *tp
194)
195{
196  ISR_Level      level;
197  time_t         seconds;
198  long           ticks;
199
200  if ( !tp )
201    set_errno_and_return_minus_one( EINVAL );
202
203  switch ( clock_id ) {
204
205    case CLOCK_REALTIME:
206 
207      _ISR_Disable( level );
208        seconds = _TOD_Seconds_since_epoch;
209        ticks   = _TOD_Current.ticks;
210      _ISR_Enable( level );
211 
212      tp->tv_sec  = seconds + POSIX_TIME_SECONDS_1970_THROUGH_1988;
213      tp->tv_nsec = ticks * _TOD_Microseconds_per_tick *
214                      TOD_NANOSECONDS_PER_MICROSECOND;
215      break;
216
217#ifdef _POSIX_CPUTIME
218    case CLOCK_PROCESS_CPUTIME:
219      /* don't base this on _Watchdog_Ticks_since_boot--duration is too short*/
220      return POSIX_NOT_IMPLEMENTED();
221      break;
222#endif
223
224#ifdef _POSIX_THREAD_CPUTIME
225    case CLOCK_THREAD_CPUTIME:
226      return POSIX_NOT_IMPLEMENTED();
227      break;
228#endif
229    default:
230      set_errno_and_return_minus_one( EINVAL );
231
232  }
233  return 0;
234}
235
236/*PAGE
237 *
238 *  14.2.1 Clocks, P1003.1b-1993, p. 263
239 */
240
241int clock_getres(
242  clockid_t        clock_id,
243  struct timespec *res
244)
245{
246  if ( !res )
247    set_errno_and_return_minus_one( EINVAL );
248 
249  switch ( clock_id ) {
250 
251    /*
252     *  All time in rtems is based on the same clock tick.
253     */
254
255    case CLOCK_REALTIME:
256    case CLOCK_PROCESS_CPUTIME:
257    case CLOCK_THREAD_CPUTIME:
258      if ( res )
259        _POSIX_Interval_to_timespec( _TOD_Microseconds_per_tick, res );
260      break;
261 
262    default:
263      set_errno_and_return_minus_one( EINVAL );
264 
265  }
266  return 0;
267}
268
269/*PAGE
270 *
271 *  14.2.5 High Resolution Sleep, P1003.1b-1993, p. 269
272 */
273
274int nanosleep(
275  const struct timespec  *rqtp,
276  struct timespec        *rmtp
277)
278{
279  Watchdog_Interval  ticks;
280  struct timespec   *the_rqtp;
281
282  if ( !rqtp )
283    set_errno_and_return_minus_one( EINVAL );
284
285  the_rqtp = (struct timespec *)rqtp;
286
287  /*
288   *  Return EAGAIN if the delay interval is negative. 
289   *
290   *  NOTE:  This behavior is beyond the POSIX specification. 
291   *         FSU pthreads shares this behavior.
292   */
293
294  if ( the_rqtp->tv_sec < 0 )
295    the_rqtp->tv_sec = 0;
296
297  if ( /* the_rqtp->tv_sec < 0 || */ the_rqtp->tv_nsec < 0 )
298    set_errno_and_return_minus_one( EAGAIN );
299
300  if ( the_rqtp->tv_nsec >= TOD_NANOSECONDS_PER_SECOND )
301    set_errno_and_return_minus_one( EINVAL );
302 
303  ticks = _POSIX_Timespec_to_interval( the_rqtp );
304
305  /*
306   *  This behavior is also beyond the POSIX specification but is
307   *  consistent with the RTEMS api and yields desirable behavior.
308   */
309
310  if ( !ticks ) {
311    _Thread_Yield_processor();
312    _Thread_Dispatch();
313    if ( rmtp ) {
314       rmtp->tv_sec = 0;
315       rmtp->tv_nsec = 0;
316    }
317    return 0;
318  }
319 
320  _Thread_Disable_dispatch();
321    _Thread_Set_state(
322      _Thread_Executing,
323      STATES_DELAYING | STATES_INTERRUPTIBLE_BY_SIGNAL
324    );
325    _Watchdog_Initialize(
326      &_Thread_Executing->Timer,
327      _Thread_Delay_ended,
328      _Thread_Executing->Object.id,
329      NULL
330    );
331    _Watchdog_Insert_ticks( &_Thread_Executing->Timer, ticks );
332  _Thread_Enable_dispatch();
333
334  /* calculate time remaining */
335
336  if ( rmtp ) {
337    ticks -=
338      _Thread_Executing->Timer.stop_time - _Thread_Executing->Timer.start_time;
339
340    _POSIX_Interval_to_timespec( ticks, rmtp );
341
342    /*
343     *  If there is time remaining, then we were interrupted by a signal.
344     */
345
346    if ( ticks )
347      set_errno_and_return_minus_one( EINTR );
348  }
349
350  return 0;
351}
352
353/*PAGE
354 *
355 *  20.1.3 Accessing a Process CPU-time CLock, P1003.4b/D8, p. 55
356 */
357
358int clock_getcpuclockid(
359  pid_t      pid,
360  clockid_t *clock_id
361)
362{
363  return POSIX_NOT_IMPLEMENTED();
364}
365
366/*PAGE
367 *
368 *  20.1.5 CPU-time Clock Attribute Access, P1003.4b/D8, p. 58
369 */
370
371int clock_setenable_attr(
372  clockid_t    clock_id,
373  int          attr
374)
375{
376  return POSIX_NOT_IMPLEMENTED();
377}
378
379/*PAGE
380 *
381 *  20.1.5 CPU-time Clock Attribute Access, P1003.4b/D8, p. 58
382 */
383
384int clock_getenable_attr(
385  clockid_t    clock_id,
386  int         *attr
387)
388{
389  return POSIX_NOT_IMPLEMENTED();
390}
Note: See TracBrowser for help on using the repository browser.