source: rtems/cpukit/posix/src/ptimer1.c @ 35ee867

4.104.114.84.95
Last change on this file since 35ee867 was 35ee867, checked in by Joel Sherrill <joel.sherrill@…>, on Dec 2, 2002 at 7:15:24 PM

2002-12-02 Joel Sherrill <joel@…>

  • include/rtems/posix/timer.h, src/keygetspecific.c, src/posixtimespecsubtract.c, src/ptimer1.c, src/semunlink.c: Added casts to eliminate warnings on 16-bit targets like the h8300.
  • Property mode set to 100644
File size: 21.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 <sys/features.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 * SEC_TO_TICKS_C ) /
179                        NSEC_PER_SEC_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 /*
275  *  The data of the structure evp are checked in order to verify if they
276  *  are coherent.
277  */
278
279  if (evp != NULL) {
280    /* The structure has data */
281    if ( ( evp->sigev_notify != SIGEV_NONE ) && 
282         ( evp->sigev_notify != SIGEV_SIGNAL ) ) {
283       /* The value of the field sigev_notify is not valid */
284       rtems_set_errno_and_return_minus_one( EINVAL );
285     }
286  }
287 
288 /*
289  *  A timer is created using the primitive rtems_timer_create
290  */
291
292  return_v = rtems_timer_create ( clock_id, &timer_id );
293
294  switch (return_v) {
295     case RTEMS_SUCCESSFUL : 
296
297       /*
298        * The timer has been created properly
299        */
300 
301        /* Obtains the first free position in the table of timers */
302
303        timer_pos = FIRST_FREE_POSITION_F();
304
305        if ( timer_pos == NO_MORE_TIMERS_C ) {
306           /* There is not position for another timers in spite of RTEMS
307            * supports it. It will necessaty to increase the structure used */
308
309           rtems_set_errno_and_return_minus_one( EAGAIN );
310        }
311
312        /* Exit parameter */
313
314        *timerid  = timer_id;
315
316        /* The data of the created timer are stored to use them later */
317
318        timer_struct[timer_pos].state     = STATE_CREATE_NEW_C;
319
320        /* NEW VERSION*/
321        timer_struct[timer_pos].thread_id = pthread_self ();
322       
323        if ( evp != NULL ) {
324           timer_struct[timer_pos].inf.sigev_notify = evp->sigev_notify;
325           timer_struct[timer_pos].inf.sigev_signo  = evp->sigev_signo;
326           timer_struct[timer_pos].inf.sigev_value  = evp->sigev_value;
327        }
328
329        timer_struct[timer_pos].timer_id = timer_id;
330        timer_struct[timer_pos].overrun  = 0;
331
332        timer_struct[timer_pos].timer_data.it_value.tv_sec     = 0;
333        timer_struct[timer_pos].timer_data.it_value.tv_nsec    = 0;
334        timer_struct[timer_pos].timer_data.it_interval.tv_sec  = 0;
335        timer_struct[timer_pos].timer_data.it_interval.tv_nsec = 0;
336
337        return 0;
338
339     case RTEMS_INVALID_NAME : /* The assigned name is not valid */
340
341       rtems_set_errno_and_return_minus_one( EINVAL );
342
343     case RTEMS_TOO_MANY :
344
345       /* There has been created too much timers for the same process */
346       rtems_set_errno_and_return_minus_one( EAGAIN );
347     
348     default :
349
350       /*
351        * Does nothing. It only returns the error without assigning a value
352        * to errno. In theory, it can not happen because the call to
353        * rtems_timer_create can not return other different value.
354        */
355
356       rtems_set_errno_and_return_minus_one( EINVAL );
357  }
358
359  /*
360   * The next sentence is used to avoid singular situations
361   */
362
363  rtems_set_errno_and_return_minus_one( EINVAL );
364}
365
366/*
367 *  14.2.3 Delete a Per_process Timer, P1003.1b-1993, p. 266
368 */
369
370int timer_delete(
371  timer_t timerid
372)
373{
374 
375 /*
376  * IDEA: This function must probably stop the timer first and then delete it
377  *
378  *       It will have to do a call to rtems_timer_cancel and then another
379  *       call to rtems_timer_delete.
380  *       The call to rtems_timer_delete will be probably unnecessary,
381  *       because rtems_timer_delete stops the timer before deleting it.
382  */
383
384  int               timer_pos;
385  rtems_status_code status;
386
387
388   /* First the position in the table of timers is obtained */
389
390   timer_pos = TIMER_POSITION_F ( timerid );
391
392   if ( timer_pos == BAD_TIMER_C ) {
393      /* The timer identifier is erroneus */
394      rtems_set_errno_and_return_minus_one( EINVAL );
395   }
396
397   /* The timer is deleted */
398
399   status = rtems_timer_delete ( timerid );
400
401   if ( status == RTEMS_INVALID_ID ) {
402     /* The timer identifier is erroneus */
403     rtems_set_errno_and_return_minus_one( EINVAL );
404   }
405
406   /* Initializes the data of the timer */
407
408   TIMER_INITIALIZE_S ( timer_pos );
409   return 0;
410}
411
412/*
413 *  14.2.4 Per-Process Timers, P1003.1b-1993, p. 267
414 */
415
416/* **************
417 * timer_settime
418 * **************/
419
420
421int timer_settime(
422  timer_t                  timerid,
423  int                      flags,
424  const struct itimerspec *value,
425  struct itimerspec       *ovalue
426)
427{
428
429   rtems_status_code return_v;   /* Return of the calls to RTEMS        */
430   int               timer_pos;  /* Position of the timer in the table  */
431   rtems_time_of_day rtems_time; /* Time in RTEMS                       */
432   
433
434   /* First the position in the table of timers is obtained */
435
436   timer_pos = TIMER_POSITION_F ( timerid );
437
438   if ( timer_pos == BAD_TIMER_C ) {
439     /* The timer identifier is erroneus */
440     rtems_set_errno_and_return_minus_one( EINVAL );
441   }
442
443   if ( value == NULL ) {
444     /* The stucture of times of the timer is free, and then returns an
445        error but the variable errno is not actualized */
446
447     rtems_set_errno_and_return_minus_one( EINVAL );
448   }
449
450   /* If the function reaches this point, then it will be necessary to do
451    * something with the structure of times of the timer: to stop, start
452    * or start it again */
453
454   /* First, it verifies if the timer must be stopped */
455
456   if ( value->it_value.tv_sec == 0 && value->it_value.tv_nsec == 0 ) {
457      /* The timer is stopped */
458
459      return_v = rtems_timer_cancel ( timerid );
460
461      /* The old data of the timer are returned */
462
463      if ( ovalue )
464        *ovalue = timer_struct[timer_pos].timer_data;
465
466      /* The new data are set */
467
468      timer_struct[timer_pos].timer_data = *value;
469
470      /* Indicates that the timer is created and stopped */
471 
472      timer_struct[timer_pos].state = STATE_CREATE_STOP_C;
473
474      /* Returns with success */
475
476      return 0;
477   }
478
479   /*
480    * If the function reaches this point, then the timer will have to be
481    * initialized with new values: to start it or start it again
482    */
483 
484   /* First, it verifies if the structure "value" is correct */
485
486    if ( ( value->it_value.tv_nsec > MAX_NSEC_C ) ||
487         ( value->it_value.tv_nsec < MIN_NSEC_C ) ) {
488       /* The number of nanoseconds is not correct */
489
490       rtems_set_errno_and_return_minus_one( EINVAL );
491    }
492
493   /* Then, "value" must be converted from seconds and nanoseconds to clock
494    * ticks, to use it in the calls to RTEMS */
495
496   /* It is also necessary to take in account if the time is absolute
497    * or relative */
498
499   switch (flags) {
500      case TIMER_ABSTIME:
501
502        /* The fire time is absolute:
503         * It has to use "rtems_time_fire_when" */
504
505        /* First, it converts from struct itimerspec to rtems_time_of_day */
506
507        ITIMERSPEC_TO_RTEMS_TIME_OF_DAY_S ( value, &rtems_time );
508
509        return_v = rtems_timer_fire_when ( timerid, &rtems_time, FIRE_TIMER_S, NULL);
510
511        switch ( return_v ) {
512           case RTEMS_SUCCESSFUL:
513
514              /* The timer has been started and is running */
515
516              /* Actualizes the data of the structure and
517               * returns the old ones in "ovalue" */
518
519              if ( ovalue )
520                *ovalue = timer_struct[timer_pos].timer_data;
521
522              timer_struct[timer_pos].timer_data = *value;
523 
524              /* It indicates that the time is running */
525
526              timer_struct[timer_pos].state = STATE_CREATE_RUN_C;
527
528              /* Stores the time in which the timer was started again */
529
530              timer_struct[timer_pos].time = _TOD_Current;
531              return 0;
532
533              break;
534
535           case RTEMS_INVALID_ID:
536
537              /* XXX error handling */
538              break;
539
540           case RTEMS_NOT_DEFINED:
541
542              /* XXX error handling */
543              break;
544
545           case RTEMS_INVALID_CLOCK:
546
547              /* XXX error handling */
548              break;
549
550           default: break;
551
552       
553        }
554     
555        break;
556
557      case TIMER_RELATIVE_C:
558
559        /* The fire time is relative:
560         * It has to use "rtems_time_fire_after" */
561
562        /* First, it converts from seconds and nanoseconds to ticks */
563
564        /* The form in which this operation is done can produce a lost
565         * of precision of 1 second */
566 
567/*      This is the process to convert from nanoseconds to ticks
568 *
569 *      There is a tick every 10 miliseconds, then the nanoseconds are
570 *      divided between 10**7. The result of this operation will be the
571 *      number of ticks
572 */
573
574        timer_struct[timer_pos].ticks = 
575             ( SEC_TO_TICKS_C * value->it_value.tv_sec ) +
576             ( value->it_value.tv_nsec / 
577                 (1000L * (unsigned32)(1000 * 10) ));
578
579        return_v = rtems_timer_fire_after ( timerid, 
580                                           timer_struct[timer_pos].ticks, 
581                                           FIRE_TIMER_S, 
582                                           NULL );
583
584        switch (return_v) {
585           case RTEMS_SUCCESSFUL:
586
587              /* The timer has been started and is running */
588
589              /* Actualizes the data of the structure and
590               * returns the old ones in "ovalue" */
591
592              if ( ovalue )
593                *ovalue = timer_struct[timer_pos].timer_data;
594
595              timer_struct[timer_pos].timer_data = *value;
596 
597              /* It indicates that the time is running */
598
599              timer_struct[timer_pos].state = STATE_CREATE_RUN_C;
600
601              /* Stores the time in which the timer was started again */
602
603              timer_struct[timer_pos].time = _TOD_Current;
604 
605              return 0;
606
607              break;
608
609           case RTEMS_INVALID_ID:
610
611              /* The timer identifier is not correct. In theory, this
612               * situation can not occur, but the solution is easy */ 
613
614              rtems_set_errno_and_return_minus_one( EINVAL );
615
616              break;
617
618           case RTEMS_INVALID_NUMBER:
619
620              /* In this case, RTEMS fails because the values of timing
621               * are incorrect */
622
623              /*
624               * I do not know if errno must be actualized
625               *
626               * errno = EINVAL;
627               */
628
629              rtems_set_errno_and_return_minus_one( EINVAL );
630              break;
631           
632           default: break;
633        }
634
635        break;
636
637      default: break;
638
639        /* It does nothing, although it will be probably necessary to
640         * return an error */
641   }
642
643   /* To avoid problems */
644   return 0;
645}
646
647
648/*
649 *  14.2.4 Per-Process Timers, P1003.1b-1993, p. 267
650 */
651
652/* **************
653 * timer_gettime
654 * **************/
655
656int timer_gettime(
657  timer_t            timerid,
658  struct itimerspec *value
659)
660{
661
662 /*
663  * IDEA:  This function does not use functions of RTEMS to the handle
664  *        of timers. It uses some functions for managing the time.
665  *
666  *        A possible form to do this is the following:
667  *
668  *          - When a timer is initialized, the value of the time in
669  *            that moment is stored.
670  *          - When this function is called, it returns the difference
671  *            between the current time and the initialization time.
672  */
673 
674  rtems_time_of_day current_time;
675  int               timer_pos;
676  unsigned32        hours;
677  unsigned32        minutes;
678  unsigned32        seconds;
679  unsigned32        ticks;
680  unsigned32        nanosec;
681 
682
683  /* Reads the current time */
684
685  current_time = _TOD_Current;
686
687  timer_pos = TIMER_POSITION_F ( timerid );
688
689  if ( timer_pos == BAD_TIMER_C ) {
690    /* The timer identifier is erroneus */ 
691    rtems_set_errno_and_return_minus_one( EINVAL );
692  }
693
694  /* Calculates the difference between the start time of the timer and
695   * the current one */
696
697  hours    = current_time.hour - timer_struct[timer_pos].time.hour;
698
699  if ( current_time.minute < timer_struct[timer_pos].time.minute ) {
700     minutes = 60 - timer_struct[timer_pos].time.minute + current_time.minute;
701     hours--;
702  } else {
703     minutes = current_time.minute - timer_struct[timer_pos].time.minute;
704  }
705   
706  if ( current_time.second < timer_struct[timer_pos].time.second ) {
707     seconds = 60 - timer_struct[timer_pos].time.second + current_time.second;
708     minutes--;
709  } else {
710     seconds = current_time.second - timer_struct[timer_pos].time.second; 
711  }
712
713  if ( current_time.ticks < timer_struct[timer_pos].time.ticks ) {
714     ticks = 100 - timer_struct[timer_pos].time.ticks + current_time.ticks;
715     seconds--;
716  } else {
717     ticks = current_time.ticks - timer_struct[timer_pos].time.ticks; 
718  }
719
720  /* The time that the timer is running is calculated */
721  seconds = hours   * 60 * 60 +
722            minutes * 60      +
723            seconds; 
724
725  nanosec  = ticks * 10 *  /* msec     */
726             1000  *       /* microsec */
727             1000;         /* nanosec  */
728
729 
730  /* Calculates the time left before the timer finishes */
731 
732  value->it_value.tv_sec = 
733    timer_struct[timer_pos].timer_data.it_value.tv_sec - seconds;
734 
735  value->it_value.tv_nsec = 
736    timer_struct[timer_pos].timer_data.it_value.tv_nsec - nanosec;
737
738
739  value->it_interval.tv_sec  = 
740    timer_struct[timer_pos].timer_data.it_interval.tv_sec;
741  value->it_interval.tv_nsec = 
742    timer_struct[timer_pos].timer_data.it_interval.tv_nsec;
743 
744
745  return 0;
746
747}
748
749/*
750 *  14.2.4 Per-Process Timers, P1003.1b-1993, p. 267
751 */
752
753/* *****************
754 * timer_getoverrun
755 * *****************/
756
757int timer_getoverrun(
758  timer_t   timerid
759)
760{
761
762 /*
763  * IDEA: This function must count the times the timer expires.
764  *   
765  *       The expiration of a timer must increase by one a counter.
766  *       After the signal handler associated to the timer finishs
767  *       its execution, FIRE_TIMER_S will have to set this counter to 0.
768  */
769
770  int timer_pos; /* Position of the timer in the structure     */
771  int overrun;   /* Overflow count                             */
772
773
774  timer_pos = TIMER_POSITION_F ( timerid );
775
776  if ( timer_pos == BAD_TIMER_C ) {
777    /* The timer identifier is erroneus */
778    rtems_set_errno_and_return_minus_one( EINVAL );
779  }
780
781  /* The overflow count of the timer is stored in "overrun" */
782
783  overrun = timer_struct[timer_pos].overrun;
784
785  /* It is set to 0 */
786
787  timer_struct[timer_pos].overrun = 0;
788
789  return overrun;
790
791}
Note: See TracBrowser for help on using the repository browser.