source: rtems/cpukit/posix/src/ptimer1.c @ 0061ef98

4.104.114.84.9
Last change on this file since 0061ef98 was 0061ef98, checked in by Joel Sherrill <joel.sherrill@…>, on Mar 26, 2007 at 10:56:12 PM

2007-03-26 Joel Sherrill <joel@…>

PR 1231/cpukit

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