source: rtems/cpukit/posix/src/ptimer1.c @ 0ff3df03

4.104.114.84.9
Last change on this file since 0ff3df03 was 0ff3df03, checked in by Ralf Corsepius <ralf.corsepius@…>, on Dec 10, 2004 at 4:17:50 AM

2004-12-10 Ralf Corsepius <ralf.corsepius@…>

  • posix/include/aio.h, posix/include/devctl.h, posix/include/intr.h, posix/include/mqueue.h, posix/include/sched.h, posix/include/semaphore.h, posix/src/ptimer.c, posix/src/ptimer1.c: Include <unistd.h> instead of <sys/features.h> to pick up _POSIX_* defines (Mandated by POSIX).
  • Property mode set to 100644
File size: 21.6 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 <rtems/score/wkspace.h>
31#include <pthread.h>
32#include <stdio.h>
33#include <signal.h>
34
35#include <rtems/seterr.h>
36#include <rtems/posix/timer.h>
37
38/*****************************/
39/* End of necessary includes */
40/*****************************/
41
42/* ************
43 * Constants
44 * ************/
45
46/*
47#define DEBUG_MESSAGES
48 */
49
50/*
51 * Data for the signals
52 */
53
54/***********************************
55 * Definition of Internal Functions
56 ***********************************/
57
58/* ***************************************************************************
59 * TIMER_INITIALIZE_S
60 *
61 *  Description: Initialize the data of a timer
62 * ***************************************************************************/
63
64extern void TIMER_INITIALIZE_S ( int timer_pos );
65
66/* ***************************************************************************
67 * _POSIX_Timer_Manager_initialization
68 *
69 *  Description: Initialize the internal structure in which the data of all
70 *               the timers are stored
71 * ***************************************************************************/
72
73/* split to reduce minimum size */
74
75/* ***************************************************************************
76 * FIRST_FREE_POSITION_F
77 *
78 *  Description: Returns the first free position in the table of timers.
79 *               If there is not a free position, it returns NO_MORE_TIMERS_C
80 * ***************************************************************************/
81
82int FIRST_FREE_POSITION_F ()
83{
84   int index;
85
86   for (index=0; index<timer_max; index++) {
87      if ( timer_struct[index].state == STATE_FREE_C ) {
88         return index;
89      }
90   }
91
92   /* The function reaches this point only if all the position are occupied */
93
94   return NO_MORE_TIMERS_C;
95}
96
97/* ***************************************************************************
98 * TIMER_POSITION_F
99 *
100 *  Description: Returns the position in the table of timers in which the
101 *               data of the timer are stored.
102 *               If the timer identifier does not exist, it returns
103 *               BAD_TIMER_C
104 * ***************************************************************************/
105
106int TIMER_POSITION_F ( timer_t timer_id )
107{
108  int index;
109
110  for (index=0; index<timer_max; index++ ) {
111
112     /* Looks for the position of the timer. The timer must exist and the
113      * position can not be free */
114     if ( ( timer_struct[index].timer_id == timer_id ) &&
115          ( timer_struct[index].state != STATE_FREE_C ) ) {
116        return index;
117     }
118  }
119
120  /* If the function reaches this point is because the timer identifier
121   * is not correct */
122
123   return BAD_TIMER_C;
124
125}
126
127/* ***************************************************************************
128 * COPY_ITIMERSPEC_S
129 *
130 *  Description: Does a copy of a variable of type struct itimerspec
131 * ***************************************************************************/
132
133void COPY_ITIMERSPEC_S ( const struct itimerspec *source,
134                         struct itimerspec *target )
135{
136
137   target->it_value.tv_sec     = source->it_value.tv_sec;
138   target->it_value.tv_nsec    = source->it_value.tv_nsec;
139   target->it_interval.tv_sec  = source->it_interval.tv_sec;
140   target->it_interval.tv_nsec = source->it_interval.tv_nsec;
141
142}
143
144/* ***************************************************************************
145 * ITIMERSPEC_TO_RTEMS_TIME_OF_DAY_S
146 *
147 *  Description: This function converts the data of a structure itimerspec
148 *               into structure rtems_time_of_day
149 * ***************************************************************************/
150
151void ITIMERSPEC_TO_RTEMS_TIME_OF_DAY_S
152   ( const struct itimerspec *itimer, rtems_time_of_day *rtems_time )
153{
154   unsigned long int seconds;
155
156   /* The leap years and the months with 28, 29 or 31 days have not been
157    * considerated. It will be made in the future */
158
159   seconds            = itimer->it_value.tv_sec;
160
161   rtems_time->year   = seconds / SECONDS_PER_YEAR_C;
162   seconds            = seconds % SECONDS_PER_YEAR_C;
163
164   rtems_time->month  = seconds / SECONDS_PER_MONTH_C;
165   seconds            = seconds % SECONDS_PER_MONTH_C;
166
167   rtems_time->day    = seconds / SECONDS_PER_DAY_C;
168   seconds            = seconds % SECONDS_PER_DAY_C;
169
170   rtems_time->hour   = seconds / SECONDS_PER_HOUR_C;
171   seconds            = seconds % SECONDS_PER_HOUR_C;
172
173   rtems_time->minute = seconds / SECONDS_PER_MINUTE_C;
174   seconds            = seconds % SECONDS_PER_MINUTE_C;
175
176   rtems_time->second = seconds;
177
178   rtems_time->ticks  = itimer->it_value.tv_nsec/
179                        (NSEC_PER_SEC_C / SEC_TO_TICKS_C);
180
181}
182
183
184/* ***************************************************************************
185 * FIRE_TIMER_S
186 *
187 *  Description: This is the operation that is ran when a timer expires
188 * ***************************************************************************/
189
190
191rtems_timer_service_routine FIRE_TIMER_S (rtems_id timer, void *data)
192{
193  int               timer_pos;  /* Position in the table of the timer that
194                                 *  has expirated                            */
195  rtems_status_code return_v;   /* Return value of rtems_timer_fire_after    */
196  int               sig_number; /* Number of the signal to send              */
197
198
199  /* The position of the table of timers that contains the data of the
200   * expired timer will be stored in "timer_pos". In theory a timer can not
201   * expire if it has not been created or has been deleted */
202
203  timer_pos = TIMER_POSITION_F(timer);
204
205  /* Increases the number of expiration of the timer in one unit. */
206  timer_struct[timer_pos].overrun = timer_struct[timer_pos].overrun + 1;
207
208
209  if ( ( timer_struct[timer_pos].timer_data.it_interval.tv_sec  != 0 ) ||
210       ( timer_struct[timer_pos].timer_data.it_interval.tv_nsec != 0 ) ) {
211
212     /* The timer must be reprogrammed */
213
214     return_v = rtems_timer_fire_after ( timer,
215                                        timer_struct[timer_pos].ticks,
216                                        FIRE_TIMER_S,
217                                        NULL );
218
219     /* Stores the time when the timer was started again */
220
221     timer_struct[timer_pos].time = _TOD_Current;
222
223     /* The state has not to be actualized, because nothing modifies it */
224
225     timer_struct[timer_pos].state = STATE_CREATE_RUN_C;
226
227  } else {
228     /* Indicates that the timer is stopped */
229
230     timer_struct[timer_pos].state = STATE_CREATE_STOP_C;
231
232  }
233
234  /*
235   * The sending of the signal to the process running the handling function
236   * specified for that signal is simulated
237   */
238
239  sig_number = timer_struct[timer_pos].inf.sigev_signo;
240
241  if( pthread_kill ( timer_struct[timer_pos].thread_id ,
242                     timer_struct[timer_pos].inf.sigev_signo ) ) {
243     /* XXX error handling */
244  }
245
246  /*
247   * After the signal handler returns, the count of expirations of the
248   * timer must be set to 0.
249   */
250
251  timer_struct[timer_pos].overrun = 0;
252
253}
254
255/* *********************************************************************
256 *  14.2.2 Create a Per-Process Timer, P1003.1b-1993, p. 264
257 * ********************************************************************/
258
259/* **************
260 * timer_create
261 * **************/
262
263int timer_create(
264  clockid_t        clock_id,
265  struct sigevent *evp,
266  timer_t         *timerid
267)
268{
269
270  rtems_status_code return_v;  /* return value of the operation    */
271  rtems_id          timer_id;  /* created timer identifier         */
272  int               timer_pos; /* Position in the table of timers  */
273
274  if ( clock_id != CLOCK_REALTIME )
275    rtems_set_errno_and_return_minus_one( EINVAL );
276
277 /*
278  *  The data of the structure evp are checked in order to verify if they
279  *  are coherent.
280  */
281
282  if (evp != NULL) {
283    /* The structure has data */
284    if ( ( evp->sigev_notify != SIGEV_NONE ) &&
285         ( evp->sigev_notify != SIGEV_SIGNAL ) ) {
286       /* The value of the field sigev_notify is not valid */
287       rtems_set_errno_and_return_minus_one( EINVAL );
288     }
289
290     if ( !evp->sigev_signo )
291       rtems_set_errno_and_return_minus_one( EINVAL );
292
293     if ( !is_valid_signo(evp->sigev_signo) )
294       rtems_set_errno_and_return_minus_one( EINVAL );
295  }
296
297 /*
298  *  A timer is created using the primitive rtems_timer_create
299  */
300
301  return_v = rtems_timer_create ( clock_id, &timer_id );
302
303  switch (return_v) {
304     case RTEMS_SUCCESSFUL :
305
306       /*
307        * The timer has been created properly
308        */
309
310        /* Obtains the first free position in the table of timers */
311
312        timer_pos = FIRST_FREE_POSITION_F();
313
314        if ( timer_pos == NO_MORE_TIMERS_C ) {
315           /* There is not position for another timers in spite of RTEMS
316            * supports it. It will necessaty to increase the structure used */
317
318           rtems_set_errno_and_return_minus_one( EAGAIN );
319        }
320
321        /* Exit parameter */
322
323        *timerid  = timer_id;
324
325        /* The data of the created timer are stored to use them later */
326
327        timer_struct[timer_pos].state     = STATE_CREATE_NEW_C;
328
329        /* NEW VERSION*/
330        timer_struct[timer_pos].thread_id = pthread_self ();
331
332        if ( evp != NULL ) {
333           timer_struct[timer_pos].inf.sigev_notify = evp->sigev_notify;
334           timer_struct[timer_pos].inf.sigev_signo  = evp->sigev_signo;
335           timer_struct[timer_pos].inf.sigev_value  = evp->sigev_value;
336        }
337
338        timer_struct[timer_pos].timer_id = timer_id;
339        timer_struct[timer_pos].overrun  = 0;
340
341        timer_struct[timer_pos].timer_data.it_value.tv_sec     = 0;
342        timer_struct[timer_pos].timer_data.it_value.tv_nsec    = 0;
343        timer_struct[timer_pos].timer_data.it_interval.tv_sec  = 0;
344        timer_struct[timer_pos].timer_data.it_interval.tv_nsec = 0;
345
346        return 0;
347
348     case RTEMS_INVALID_NAME : /* The assigned name is not valid */
349
350       rtems_set_errno_and_return_minus_one( EINVAL );
351
352     case RTEMS_TOO_MANY :
353
354       /* There has been created too much timers for the same process */
355       rtems_set_errno_and_return_minus_one( EAGAIN );
356
357     default :
358
359       /*
360        * Does nothing. It only returns the error without assigning a value
361        * to errno. In theory, it can not happen because the call to
362        * rtems_timer_create can not return other different value.
363        */
364
365       rtems_set_errno_and_return_minus_one( EINVAL );
366  }
367
368  /*
369   * The next sentence is used to avoid singular situations
370   */
371
372  rtems_set_errno_and_return_minus_one( EINVAL );
373}
374
375/*
376 *  14.2.3 Delete a Per_process Timer, P1003.1b-1993, p. 266
377 */
378
379int timer_delete(
380  timer_t timerid
381)
382{
383
384 /*
385  * IDEA: This function must probably stop the timer first and then delete it
386  *
387  *       It will have to do a call to rtems_timer_cancel and then another
388  *       call to rtems_timer_delete.
389  *       The call to rtems_timer_delete will be probably unnecessary,
390  *       because rtems_timer_delete stops the timer before deleting it.
391  */
392
393  int               timer_pos;
394  rtems_status_code status;
395
396
397   /* First the position in the table of timers is obtained */
398
399   timer_pos = TIMER_POSITION_F ( timerid );
400
401   if ( timer_pos == BAD_TIMER_C ) {
402      /* The timer identifier is erroneus */
403      rtems_set_errno_and_return_minus_one( EINVAL );
404   }
405
406   /* The timer is deleted */
407
408   status = rtems_timer_delete ( timerid );
409
410   if ( status == RTEMS_INVALID_ID ) {
411     /* The timer identifier is erroneus */
412     rtems_set_errno_and_return_minus_one( EINVAL );
413   }
414
415   /* Initializes the data of the timer */
416
417   TIMER_INITIALIZE_S ( timer_pos );
418   return 0;
419}
420
421/*
422 *  14.2.4 Per-Process Timers, P1003.1b-1993, p. 267
423 */
424
425/* **************
426 * timer_settime
427 * **************/
428
429
430int timer_settime(
431  timer_t                  timerid,
432  int                      flags,
433  const struct itimerspec *value,
434  struct itimerspec       *ovalue
435)
436{
437
438   rtems_status_code return_v;   /* Return of the calls to RTEMS        */
439   int               timer_pos;  /* Position of the timer in the table  */
440   rtems_time_of_day rtems_time; /* Time in RTEMS                       */
441
442
443   /* First the position in the table of timers is obtained */
444
445   timer_pos = TIMER_POSITION_F ( timerid );
446
447   if ( timer_pos == BAD_TIMER_C ) {
448     /* The timer identifier is erroneus */
449     rtems_set_errno_and_return_minus_one( EINVAL );
450   }
451
452   if ( value == NULL ) {
453     /* The stucture of times of the timer is free, and then returns an
454        error but the variable errno is not actualized */
455
456     rtems_set_errno_and_return_minus_one( EINVAL );
457   }
458
459   /* If the function reaches this point, then it will be necessary to do
460    * something with the structure of times of the timer: to stop, start
461    * or start it again */
462
463   /* First, it verifies if the timer must be stopped */
464
465   if ( value->it_value.tv_sec == 0 && value->it_value.tv_nsec == 0 ) {
466      /* The timer is stopped */
467
468      return_v = rtems_timer_cancel ( timerid );
469
470      /* The old data of the timer are returned */
471
472      if ( ovalue )
473        *ovalue = timer_struct[timer_pos].timer_data;
474
475      /* The new data are set */
476
477      timer_struct[timer_pos].timer_data = *value;
478
479      /* Indicates that the timer is created and stopped */
480
481      timer_struct[timer_pos].state = STATE_CREATE_STOP_C;
482
483      /* Returns with success */
484
485      return 0;
486   }
487
488   /*
489    * If the function reaches this point, then the timer will have to be
490    * initialized with new values: to start it or start it again
491    */
492
493   /* First, it verifies if the structure "value" is correct */
494
495    if ( ( value->it_value.tv_nsec > MAX_NSEC_C ) ||
496         ( value->it_value.tv_nsec < MIN_NSEC_C ) ) {
497       /* The number of nanoseconds is not correct */
498
499       rtems_set_errno_and_return_minus_one( EINVAL );
500    }
501
502   /* Then, "value" must be converted from seconds and nanoseconds to clock
503    * ticks, to use it in the calls to RTEMS */
504
505   /* It is also necessary to take in account if the time is absolute
506    * or relative */
507
508   switch (flags) {
509      case TIMER_ABSTIME:
510
511        /* The fire time is absolute:
512         * It has to use "rtems_time_fire_when" */
513
514        /* First, it converts from struct itimerspec to rtems_time_of_day */
515
516        ITIMERSPEC_TO_RTEMS_TIME_OF_DAY_S ( value, &rtems_time );
517
518        return_v = rtems_timer_fire_when ( timerid, &rtems_time, FIRE_TIMER_S, NULL);
519
520        switch ( return_v ) {
521           case RTEMS_SUCCESSFUL:
522
523              /* The timer has been started and is running */
524
525              /* Actualizes the data of the structure and
526               * returns the old ones in "ovalue" */
527
528              if ( ovalue )
529                *ovalue = timer_struct[timer_pos].timer_data;
530
531              timer_struct[timer_pos].timer_data = *value;
532
533              /* It indicates that the time is running */
534
535              timer_struct[timer_pos].state = STATE_CREATE_RUN_C;
536
537              /* Stores the time in which the timer was started again */
538
539              timer_struct[timer_pos].time = _TOD_Current;
540              return 0;
541
542              break;
543
544           case RTEMS_INVALID_ID:
545
546              /* XXX error handling */
547              break;
548
549           case RTEMS_NOT_DEFINED:
550
551              /* XXX error handling */
552              break;
553
554           case RTEMS_INVALID_CLOCK:
555
556              /* XXX error handling */
557              break;
558
559           default: break;
560
561
562        }
563
564        break;
565
566      case TIMER_RELATIVE_C:
567
568        /* The fire time is relative:
569         * It has to use "rtems_time_fire_after" */
570
571        /* First, it converts from seconds and nanoseconds to ticks */
572
573        /* The form in which this operation is done can produce a lost
574         * of precision of 1 second */
575
576/*      This is the process to convert from nanoseconds to ticks
577 *
578 *      There is a tick every 10 miliseconds, then the nanoseconds are
579 *      divided between 10**7. The result of this operation will be the
580 *      number of ticks
581 */
582
583        timer_struct[timer_pos].ticks =
584             ( SEC_TO_TICKS_C * value->it_value.tv_sec ) +
585             ( value->it_value.tv_nsec / (NSEC_PER_SEC_C / SEC_TO_TICKS_C));
586
587        return_v = rtems_timer_fire_after ( timerid,
588                                           timer_struct[timer_pos].ticks,
589                                           FIRE_TIMER_S,
590                                           NULL );
591
592        switch (return_v) {
593           case RTEMS_SUCCESSFUL:
594
595              /* The timer has been started and is running */
596
597              /* Actualizes the data of the structure and
598               * returns the old ones in "ovalue" */
599
600              if ( ovalue )
601                *ovalue = timer_struct[timer_pos].timer_data;
602
603              timer_struct[timer_pos].timer_data = *value;
604
605              /* It indicates that the time is running */
606
607              timer_struct[timer_pos].state = STATE_CREATE_RUN_C;
608
609              /* Stores the time in which the timer was started again */
610
611              timer_struct[timer_pos].time = _TOD_Current;
612
613              return 0;
614
615              break;
616
617           case RTEMS_INVALID_ID:
618
619              /* The timer identifier is not correct. In theory, this
620               * situation can not occur, but the solution is easy */
621
622              rtems_set_errno_and_return_minus_one( EINVAL );
623
624              break;
625
626           case RTEMS_INVALID_NUMBER:
627
628              /* In this case, RTEMS fails because the values of timing
629               * are incorrect */
630
631              /*
632               * I do not know if errno must be actualized
633               *
634               * errno = EINVAL;
635               */
636
637              rtems_set_errno_and_return_minus_one( EINVAL );
638              break;
639
640           default: break;
641        }
642
643        break;
644
645      default: break;
646
647        /* It does nothing, although it will be probably necessary to
648         * return an error */
649   }
650
651   /* To avoid problems */
652   return 0;
653}
654
655
656/*
657 *  14.2.4 Per-Process Timers, P1003.1b-1993, p. 267
658 */
659
660/* **************
661 * timer_gettime
662 * **************/
663
664int timer_gettime(
665  timer_t            timerid,
666  struct itimerspec *value
667)
668{
669
670 /*
671  * IDEA:  This function does not use functions of RTEMS to the handle
672  *        of timers. It uses some functions for managing the time.
673  *
674  *        A possible form to do this is the following:
675  *
676  *          - When a timer is initialized, the value of the time in
677  *            that moment is stored.
678  *          - When this function is called, it returns the difference
679  *            between the current time and the initialization time.
680  */
681
682  rtems_time_of_day current_time;
683  int               timer_pos;
684  uint32_t          hours;
685  uint32_t          minutes;
686  uint32_t          seconds;
687  uint32_t          ticks;
688  uint32_t          nanosec;
689
690
691  /* Reads the current time */
692
693  current_time = _TOD_Current;
694
695  timer_pos = TIMER_POSITION_F ( timerid );
696
697  if ( timer_pos == BAD_TIMER_C ) {
698    /* The timer identifier is erroneus */
699    rtems_set_errno_and_return_minus_one( EINVAL );
700  }
701
702  /* Calculates the difference between the start time of the timer and
703   * the current one */
704
705  hours    = current_time.hour - timer_struct[timer_pos].time.hour;
706
707  if ( current_time.minute < timer_struct[timer_pos].time.minute ) {
708     minutes = 60 - timer_struct[timer_pos].time.minute + current_time.minute;
709     hours--;
710  } else {
711     minutes = current_time.minute - timer_struct[timer_pos].time.minute;
712  }
713
714  if ( current_time.second < timer_struct[timer_pos].time.second ) {
715     seconds = 60 - timer_struct[timer_pos].time.second + current_time.second;
716     minutes--;
717  } else {
718     seconds = current_time.second - timer_struct[timer_pos].time.second;
719  }
720
721  if ( current_time.ticks < timer_struct[timer_pos].time.ticks ) {
722     ticks = 100 - timer_struct[timer_pos].time.ticks + current_time.ticks;
723     seconds--;
724  } else {
725     ticks = current_time.ticks - timer_struct[timer_pos].time.ticks;
726  }
727
728  /* The time that the timer is running is calculated */
729  seconds = hours   * 60 * 60 +
730            minutes * 60      +
731            seconds;
732
733  nanosec  = ticks * 10 *  /* msec     */
734             1000  *       /* microsec */
735             1000;         /* nanosec  */
736
737
738  /* Calculates the time left before the timer finishes */
739
740  value->it_value.tv_sec =
741    timer_struct[timer_pos].timer_data.it_value.tv_sec - seconds;
742
743  value->it_value.tv_nsec =
744    timer_struct[timer_pos].timer_data.it_value.tv_nsec - nanosec;
745
746
747  value->it_interval.tv_sec  =
748    timer_struct[timer_pos].timer_data.it_interval.tv_sec;
749  value->it_interval.tv_nsec =
750    timer_struct[timer_pos].timer_data.it_interval.tv_nsec;
751
752
753  return 0;
754
755}
756
757/*
758 *  14.2.4 Per-Process Timers, P1003.1b-1993, p. 267
759 */
760
761/* *****************
762 * timer_getoverrun
763 * *****************/
764
765int timer_getoverrun(
766  timer_t   timerid
767)
768{
769
770 /*
771  * IDEA: This function must count the times the timer expires.
772  *
773  *       The expiration of a timer must increase by one a counter.
774  *       After the signal handler associated to the timer finishs
775  *       its execution, FIRE_TIMER_S will have to set this counter to 0.
776  */
777
778  int timer_pos; /* Position of the timer in the structure     */
779  int overrun;   /* Overflow count                             */
780
781
782  timer_pos = TIMER_POSITION_F ( timerid );
783
784  if ( timer_pos == BAD_TIMER_C ) {
785    /* The timer identifier is erroneus */
786    rtems_set_errno_and_return_minus_one( EINVAL );
787  }
788
789  /* The overflow count of the timer is stored in "overrun" */
790
791  overrun = timer_struct[timer_pos].overrun;
792
793  /* It is set to 0 */
794
795  timer_struct[timer_pos].overrun = 0;
796
797  return overrun;
798
799}
Note: See TracBrowser for help on using the repository browser.