source: rtems/c/src/exec/posix/src/time.c @ 98dca75

4.104.114.84.95
Last change on this file since 98dca75 was 5a909149, checked in by Joel Sherrill <joel.sherrill@…>, on 05/07/99 at 17:09:20

Made all calls to _Thread_Yield_processor consistent in how they are
wrapped by calls to _Thread_Enable_dispatch and _Thread_Disable_dispatch.

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