source: rtems/cpukit/posix/src/ptimer1.c @ 0243b0d

4.104.114.84.95
Last change on this file since 0243b0d was 0243b0d, checked in by Joel Sherrill <joel.sherrill@…>, on 06/08/06 at 20:47:48

2006-06-08 Joel Sherrill <joel@…>

  • posix/Makefile.am, posix/preinstall.am, posix/include/rtems/posix/timer.h, posix/src/ptimer.c, posix/src/ptimer1.c, sapi/src/posixapi.c, score/include/rtems/score/object.h:
  • Property mode set to 100644
File size: 15.5 KB
Line 
1/*
2 *  ptimer.c,v 1.1 1996/06/03 16:29:58 joel Exp
3 */
4
5#if HAVE_CONFIG_H
6#include "config.h"
7#endif
8
9#include <assert.h>
10#include <time.h>
11#include <errno.h>
12
13#include <rtems/system.h>
14#include <rtems/score/isr.h>
15#include <rtems/score/thread.h>
16#include <rtems/score/tod.h>
17
18#include <rtems/posix/time.h>
19
20/************************************/
21/* These includes are now necessary */
22/************************************/
23
24#include <unistd.h>
25#include <rtems/rtems/status.h>
26#include <rtems/rtems/types.h>
27#include <rtems/rtems/timer.h>
28#include <rtems/rtems/clock.h>
29#include <rtems/posix/psignal.h>
30#include <pthread.h>
31#include <stdio.h>
32#include <signal.h>
33
34#include <rtems/seterr.h>
35#include <rtems/posix/timer.h>
36
37boolean _Watchdog_Insert_ticks_helper(
38  Watchdog_Control               *timer,
39  Watchdog_Interval               ticks,
40  Objects_Id                      id,
41  Watchdog_Service_routine_entry  TSR,
42  void                           *arg
43)
44{
45  ISR_Level            level;
46
47  (void) _Watchdog_Remove( timer );
48  _ISR_Disable( level );
49
50    /*
51     *  Check to see if the watchdog has just been inserted by a
52     *  higher priority interrupt.  If so, abandon this insert.
53     */
54    if ( timer->state != WATCHDOG_INACTIVE ) {
55      _ISR_Enable( level );
56      return FALSE;
57    }
58
59    /*
60     *  OK.  Now we now the timer was not rescheduled by an interrupt
61     *  so we can atomically initialize it as in use.
62     */
63    _Watchdog_Initialize( timer, TSR, id, arg );
64    _Watchdog_Insert_ticks( timer, ticks );
65  _ISR_Enable( level );
66  return TRUE;
67}
68
69/* #define DEBUG_MESSAGES */
70
71/*
72 * ITIMERSPEC_TO_RTEMS_TIME_OF_DAY_S
73 *
74 *  Description: This function converts the data of a structure itimerspec
75 *               into structure rtems_time_of_day
76  */
77
78void ITIMERSPEC_TO_RTEMS_TIME_OF_DAY_S(
79  const struct itimerspec *itimer,
80  rtems_time_of_day *rtems_time
81)
82{
83   unsigned long int seconds;
84
85   /* The leap years and the months with 28, 29 or 31 days have not been
86    * considered. It will be made in the future */
87
88   seconds            = itimer->it_value.tv_sec;
89
90   rtems_time->year   = seconds / SECONDS_PER_YEAR_C;
91   seconds            = seconds % SECONDS_PER_YEAR_C;
92
93   rtems_time->month  = seconds / SECONDS_PER_MONTH_C;
94   seconds            = seconds % SECONDS_PER_MONTH_C;
95
96   rtems_time->day    = seconds / SECONDS_PER_DAY_C;
97   seconds            = seconds % SECONDS_PER_DAY_C;
98
99   rtems_time->hour   = seconds / SECONDS_PER_HOUR_C;
100   seconds            = seconds % SECONDS_PER_HOUR_C;
101
102   rtems_time->minute = seconds / SECONDS_PER_MINUTE_C;
103   seconds            = seconds % SECONDS_PER_MINUTE_C;
104
105   rtems_time->second = seconds;
106
107   rtems_time->ticks  = itimer->it_value.tv_nsec/
108                        (NSEC_PER_SEC_C / SEC_TO_TICKS_C);
109
110}
111
112
113/* ***************************************************************************
114 * _POSIX_Timer_TSR
115 *
116 *  Description: This is the operation that is ran when a timer expires
117 * ***************************************************************************/
118
119
120void _POSIX_Timer_TSR(Objects_Id timer, void *data)
121{
122  POSIX_Timer_Control *ptimer;
123  boolean              activated;
124
125  ptimer = (POSIX_Timer_Control *)data;
126
127  /* Increment the number of expirations. */
128  ptimer->overrun = ptimer->overrun + 1;
129  /* The timer must be reprogrammed */
130  if ( ( ptimer->timer_data.it_interval.tv_sec  != 0 ) ||
131       ( ptimer->timer_data.it_interval.tv_nsec != 0 ) ) {
132#if 0
133    status = rtems_timer_fire_after(
134         ptimer->timer_id, ptimer->ticks, _POSIX_Timer_TSR, ptimer );
135#endif
136    activated = _Watchdog_Insert_ticks_helper(
137      &ptimer->Timer,
138      ptimer->ticks,
139      ptimer->Object.id,
140      _POSIX_Timer_TSR,
141      ptimer
142    );
143    if ( !activated )
144      return;
145
146    /* Store the time when the timer was started again */
147    ptimer->time = _TOD_Current;
148
149    /* The state really did not change but just to be safe */
150    ptimer->state = STATE_CREATE_RUN_C;
151  } else {
152   /* Indicates that the timer is stopped */
153   ptimer->state = STATE_CREATE_STOP_C;
154  }
155
156  /*
157   * The sending of the signal to the process running the handling function
158   * specified for that signal is simulated
159   */
160
161  if ( pthread_kill ( ptimer->thread_id, ptimer->inf.sigev_signo ) ) {
162    /* XXX error handling */
163  }
164
165  /* After the signal handler returns, the count of expirations of the
166   * timer must be set to 0.
167   */
168  ptimer->overrun = 0;
169}
170
171/* *********************************************************************
172 *  14.2.2 Create a Per-Process Timer, P1003.1b-1993, p. 264
173 * ********************************************************************/
174
175/* **************
176 * timer_create
177 * **************/
178
179int timer_create(
180  clockid_t        clock_id,
181  struct sigevent *evp,
182  timer_t         *timerid
183)
184{
185  POSIX_Timer_Control *ptimer;
186
187  if ( clock_id != CLOCK_REALTIME )
188    rtems_set_errno_and_return_minus_one( EINVAL );
189
190 /*
191  *  The data of the structure evp are checked in order to verify if they
192  *  are coherent.
193  */
194
195  if (evp != NULL) {
196    /* The structure has data */
197    if ( ( evp->sigev_notify != SIGEV_NONE ) &&
198         ( evp->sigev_notify != SIGEV_SIGNAL ) ) {
199       /* The value of the field sigev_notify is not valid */
200       rtems_set_errno_and_return_minus_one( EINVAL );
201     }
202
203     if ( !evp->sigev_signo )
204       rtems_set_errno_and_return_minus_one( EINVAL );
205
206     if ( !is_valid_signo(evp->sigev_signo) )
207       rtems_set_errno_and_return_minus_one( EINVAL );
208  }
209
210  _Thread_Disable_dispatch();         /* to prevent deletion */
211
212  /*
213   *  Allocate a timer
214   */
215  ptimer = _POSIX_Timer_Allocate();
216  if ( !ptimer ) {
217    _Thread_Enable_dispatch();
218    rtems_set_errno_and_return_minus_one( EAGAIN );
219  }
220
221  /* The data of the created timer are stored to use them later */
222
223  ptimer->state     = STATE_CREATE_NEW_C;
224  ptimer->thread_id = _Thread_Executing->Object.id;
225
226  if ( evp != NULL ) {
227    ptimer->inf.sigev_notify = evp->sigev_notify;
228    ptimer->inf.sigev_signo  = evp->sigev_signo;
229    ptimer->inf.sigev_value  = evp->sigev_value;
230  }
231
232  ptimer->overrun  = 0;
233  ptimer->timer_data.it_value.tv_sec     = 0;
234  ptimer->timer_data.it_value.tv_nsec    = 0;
235  ptimer->timer_data.it_interval.tv_sec  = 0;
236  ptimer->timer_data.it_interval.tv_nsec = 0;
237
238  _Watchdog_Initialize( &ptimer->Timer, NULL, 0, NULL );
239  _Objects_Open(&_POSIX_Timer_Information, &ptimer->Object, (Objects_Name) 0);
240
241  *timerid  = ptimer->Object.id;
242  _Thread_Enable_dispatch();
243  return 0;
244}
245
246/*
247 *  14.2.3 Delete a Per_process Timer, P1003.1b-1993, p. 266
248 */
249
250int timer_delete(
251  timer_t timerid
252)
253{
254 /*
255  * IDEA: This function must probably stop the timer first and then delete it
256  *
257  *       It will have to do a call to rtems_timer_cancel and then another
258  *       call to rtems_timer_delete.
259  *       The call to rtems_timer_delete will be probably unnecessary,
260  *       because rtems_timer_delete stops the timer before deleting it.
261  */
262  POSIX_Timer_Control *ptimer;
263  Objects_Locations    location;
264
265  ptimer = _POSIX_Timer_Get( timerid, &location );
266  switch ( location ) {
267    case OBJECTS_REMOTE:
268#if defined(RTEMS_MULTIPROCESSING)
269      _Thread_Dispatch();
270      rtems_set_errno_and_return_minus_one( EINVAL );
271#endif
272
273    case OBJECTS_ERROR:
274      rtems_set_errno_and_return_minus_one( EINVAL );
275
276    case OBJECTS_LOCAL:
277      _Objects_Close( &_POSIX_Timer_Information, &ptimer->Object );
278      ptimer->state = STATE_FREE_C;
279      (void) _Watchdog_Remove( &ptimer->Timer );
280      _POSIX_Timer_Free( ptimer );
281      _Thread_Enable_dispatch();
282      return 0;
283  }
284  return -1;   /* unreached - only to remove warnings */
285}
286
287/*
288 *  14.2.4 Per-Process Timers, P1003.1b-1993, p. 267
289 */
290
291/* **************
292 * timer_settime
293 * **************/
294
295
296int timer_settime(
297  timer_t                  timerid,
298  int                      flags,
299  const struct itimerspec *value,
300  struct itimerspec       *ovalue
301)
302{
303  POSIX_Timer_Control *ptimer;
304  Objects_Locations    location;
305  boolean              activated;
306
307  if ( value == NULL ) {
308    rtems_set_errno_and_return_minus_one( EINVAL );
309  }
310
311  /* First, it verifies if the structure "value" is correct */
312  if ( ( value->it_value.tv_nsec > MAX_NSEC_C ) ||
313       ( value->it_value.tv_nsec < MIN_NSEC_C ) ) {
314    /* The number of nanoseconds is not correct */
315    rtems_set_errno_and_return_minus_one( EINVAL );
316  }
317 
318  /* XXX check for seconds in the past */
319
320  if ( flags != TIMER_ABSTIME && flags != TIMER_RELATIVE_C ) {
321    rtems_set_errno_and_return_minus_one( EINVAL );
322  }
323
324  /* If the function reaches this point, then it will be necessary to do
325   * something with the structure of times of the timer: to stop, start
326   * or start it again
327   */
328
329  ptimer = _POSIX_Timer_Get( timerid, &location );
330  switch ( location ) {
331    case OBJECTS_REMOTE:
332#if defined(RTEMS_MULTIPROCESSING)
333      _Thread_Dispatch();
334      return -1;
335     rtems_set_errno_and_return_minus_one( EINVAL );
336#endif
337
338    case OBJECTS_ERROR:
339      return -1;
340
341    case OBJECTS_LOCAL:
342      /* First, it verifies if the timer must be stopped */
343      if ( value->it_value.tv_sec == 0 && value->it_value.tv_nsec == 0 ) {
344         /* Stop the timer */
345         (void) _Watchdog_Remove( &ptimer->Timer );
346         /* The old data of the timer are returned */
347         if ( ovalue )
348           *ovalue = ptimer->timer_data;
349         /* The new data are set */
350         ptimer->timer_data = *value;
351         /* Indicates that the timer is created and stopped */
352         ptimer->state = STATE_CREATE_STOP_C;
353         /* Returns with success */
354        _Thread_Enable_dispatch();
355        return 0;
356       }
357
358       /* absolute or relative? */
359       switch (flags) {
360         case TIMER_ABSTIME:
361
362           /* The fire time is absolute: use "rtems_time_fire_when" */
363           /* First, it converts from struct itimerspec to rtems_time_of_day */
364
365#if 0
366           ITIMERSPEC_TO_RTEMS_TIME_OF_DAY_S( value, &tod );
367           status = rtems_timer_fire_when(
368             ptimer->timer_id, &tod, _POSIX_Timer_TSR, ptimer);
369#endif
370           _Watchdog_Initialize(
371             &ptimer->Timer, _POSIX_Timer_TSR, ptimer->Object.id, ptimer );
372
373           _Watchdog_Insert_seconds(
374              &ptimer->Timer,
375              value->it_value.tv_sec - _TOD_Seconds_since_epoch
376           );
377
378           /* Returns the old ones in "ovalue" */
379           if ( ovalue )
380             *ovalue = ptimer->timer_data;
381           ptimer->timer_data = *value;
382
383           /* Indicate that the time is running */
384           ptimer->state = STATE_CREATE_RUN_C;
385
386           /* Stores the time in which the timer was started again */
387           ptimer->time = _TOD_Current;
388           _Thread_Enable_dispatch();
389           return 0;
390           break;
391
392         /* The fire time is relative: use "rtems_time_fire_after" */
393         case TIMER_RELATIVE_C:
394           /* First, convert from seconds and nanoseconds to ticks */
395           ptimer->ticks = ( SEC_TO_TICKS_C * value->it_value.tv_sec ) +
396                ( value->it_value.tv_nsec / (NSEC_PER_SEC_C / SEC_TO_TICKS_C));
397
398#if 0
399           status = rtems_timer_fire_after(
400             ptimer->timer_id, ptimer->ticks, _POSIX_Timer_TSR, ptimer );
401#endif
402           activated = _Watchdog_Insert_ticks_helper(
403             &ptimer->Timer,
404             ptimer->ticks,
405             ptimer->Object.id,
406             _POSIX_Timer_TSR,
407             ptimer
408           );
409           if ( !activated )
410             return 0;
411
412           /* The timer has been started and is running */
413           /* return the old ones in "ovalue" */
414           if ( ovalue )
415             *ovalue = ptimer->timer_data;
416           ptimer->timer_data = *value;
417
418           /* Indicate that the time is running */
419           ptimer->state = STATE_CREATE_RUN_C;
420           ptimer->time = _TOD_Current;
421            _Thread_Enable_dispatch();
422           return 0;
423      }
424      _Thread_Enable_dispatch();
425      rtems_set_errno_and_return_minus_one( EINVAL );
426  }
427  return -1;   /* unreached - only to remove warnings */
428}
429
430/*
431 *  14.2.4 Per-Process Timers, P1003.1b-1993, p. 267
432 */
433
434/* **************
435 * timer_gettime
436 * **************/
437
438int timer_gettime(
439  timer_t            timerid,
440  struct itimerspec *value
441)
442{
443
444 /*
445  * IDEA:  This function does not use functions of RTEMS to the handle
446  *        of timers. It uses some functions for managing the time.
447  *
448  *        A possible form to do this is the following:
449  *
450  *          - When a timer is initialized, the value of the time in
451  *            that moment is stored.
452  *          - When this function is called, it returns the difference
453  *            between the current time and the initialization time.
454  */
455
456  POSIX_Timer_Control *ptimer;
457  Objects_Locations    location;
458  rtems_time_of_day    current_time;
459  uint32_t             hours;
460  uint32_t             minutes;
461  uint32_t             seconds;
462  uint32_t             ticks;
463  uint32_t             nanosec;
464
465  /* Reads the current time */
466  current_time = _TOD_Current;
467
468  ptimer = _POSIX_Timer_Get( timerid, &location );
469  switch ( location ) {
470    case OBJECTS_REMOTE:
471#if defined(RTEMS_MULTIPROCESSING)
472      _Thread_Dispatch();
473      rtems_set_errno_and_return_minus_one( EINVAL );
474#endif
475
476    case OBJECTS_ERROR:
477      rtems_set_errno_and_return_minus_one( EINVAL );
478
479    case OBJECTS_LOCAL:
480      /* Calculates the difference between the start time of the timer and
481       * the current one */
482
483      hours    = current_time.hour - ptimer->time.hour;
484
485      if ( current_time.minute < ptimer->time.minute ) {
486        minutes = 60 - ptimer->time.minute + current_time.minute;
487        hours--;
488      } else {
489        minutes = current_time.minute - ptimer->time.minute;
490      }
491
492      if ( current_time.second < ptimer->time.second ) {
493        seconds = 60 - ptimer->time.second + current_time.second;
494        minutes--;
495      } else {
496        seconds = current_time.second - ptimer->time.second;
497      }
498
499      if ( current_time.ticks < ptimer->time.ticks ) {
500        ticks = 100 - ptimer->time.ticks + current_time.ticks;
501        seconds--;
502      } else {
503        ticks = current_time.ticks - ptimer->time.ticks;
504      }
505
506      /* The time that the timer is running is calculated */
507      seconds = hours   * 60 * 60 +
508                minutes * 60      +
509                seconds;
510
511      nanosec  = ticks * 10 *  /* msec     */
512                 1000  *       /* microsec */
513                 1000;         /* nanosec  */
514
515
516      /* Calculates the time left before the timer finishes */
517
518      value->it_value.tv_sec  = ptimer->timer_data.it_value.tv_sec - seconds;
519      value->it_value.tv_nsec = ptimer->timer_data.it_value.tv_nsec - nanosec;
520
521      value->it_interval.tv_sec  = ptimer->timer_data.it_interval.tv_sec;
522      value->it_interval.tv_nsec = ptimer->timer_data.it_interval.tv_nsec;
523
524      _Thread_Enable_dispatch();
525      return 0;
526  }
527  return -1;   /* unreached - only to remove warnings */
528}
529
530/*
531 *  14.2.4 Per-Process Timers, P1003.1b-1993, p. 267
532 */
533
534/*
535 * timer_getoverrun
536 *
537 * The expiration of a timer must increase by one a counter.
538 * After the signal handler associated to the timer finishes
539 * its execution, _POSIX_Timer_TSR will have to set this counter to 0.
540 */
541
542int timer_getoverrun(
543  timer_t   timerid
544)
545{
546  int                  overrun;
547  POSIX_Timer_Control *ptimer;
548  Objects_Locations    location;
549
550  ptimer = _POSIX_Timer_Get( timerid, &location );
551  switch ( location ) {
552    case OBJECTS_REMOTE:
553#if defined(RTEMS_MULTIPROCESSING)
554      _Thread_Dispatch();
555      rtems_set_errno_and_return_minus_one( EINVAL );
556#endif
557
558    case OBJECTS_ERROR:
559      rtems_set_errno_and_return_minus_one( EINVAL );
560
561    case OBJECTS_LOCAL:
562      overrun = ptimer->overrun;
563      ptimer->overrun = 0;
564      _Thread_Enable_dispatch();
565      return overrun;
566  }
567  return -1;   /* unreached - only to remove warnings */
568}
Note: See TracBrowser for help on using the repository browser.