source: rtems/cpukit/posix/src/ptimer1.c @ 860c34e

4.104.114.95
Last change on this file since 860c34e was 860c34e, checked in by Glenn Humphrey <glenn.humphrey@…>, on 11/30/07 at 20:34:13

2007-11-30 Glenn Humphrey <glenn.humphrey@…>

  • posix/include/rtems/posix/mutex.h, posix/include/rtems/posix/semaphore.h, posix/src/cancel.c, posix/src/conddestroy.c, posix/src/condsignalsupp.c, posix/src/condwaitsupp.c, posix/src/keydelete.c, posix/src/keygetspecific.c, posix/src/keysetspecific.c, posix/src/mqueueclose.c, posix/src/mqueuegetattr.c, posix/src/mqueuenotify.c, posix/src/mqueuerecvsupp.c, posix/src/mqueuesendsupp.c, posix/src/mqueuesetattr.c, posix/src/mqueuetranslatereturncode.c, posix/src/mutexdestroy.c, posix/src/mutexgetprioceiling.c, posix/src/mutexinit.c, posix/src/mutexlocksupp.c, posix/src/mutexsetprioceiling.c, posix/src/mutexunlock.c, posix/src/pbarrierdestroy.c, posix/src/pbarriertranslatereturncode.c, posix/src/pbarrierwait.c, posix/src/prwlockdestroy.c, posix/src/prwlockrdlock.c, posix/src/prwlocktimedrdlock.c, posix/src/prwlocktimedwrlock.c, posix/src/prwlocktranslatereturncode.c, posix/src/prwlocktryrdlock.c, posix/src/prwlocktrywrlock.c, posix/src/prwlockunlock.c, posix/src/prwlockwrlock.c, posix/src/pspindestroy.c, posix/src/pspinlock.c, posix/src/pspinlocktranslatereturncode.c, posix/src/pspintrylock.c, posix/src/pspinunlock.c, posix/src/pthreaddetach.c, posix/src/pthreadequal.c, posix/src/pthreadgetschedparam.c, posix/src/pthreadjoin.c, posix/src/pthreadkill.c, posix/src/pthreadsetschedparam.c, posix/src/ptimer1.c, posix/src/semaphorewaitsupp.c, posix/src/semclose.c, posix/src/semdestroy.c, posix/src/semgetvalue.c, posix/src/sempost.c, posix/src/types.c, rtems/src/msgqtranslatereturncode.c, rtems/src/semobtain.c, rtems/src/timerfireafter.c, score/include/rtems/system.h, score/include/rtems/score/corebarrier.h, score/include/rtems/score/coremsg.h, score/include/rtems/score/coremutex.h, score/include/rtems/score/coresem.h: Restructed to move the OBJECTS_LOCAL case to the top of the switch statement and eliminate the fall-through return of POSIX_BOTTOM_REACHED. These changes produced simplier assembly code and allowed for complete test coverage. Also applied some consistency to the functions that translate the core status codes to POSIX status codes.
  • posix/src/mutextranslatereturncode.c, posix/src/semaphoretranslatereturncode.c: New files.
  • posix/src/mutexfromcorestatus.c: Removed.
  • Property mode set to 100644
File size: 12.4 KB
Line 
1/*
2 *  COPYRIGHT (c) 1989-2007.
3 *  On-Line Applications Research Corporation (OAR).
4 *
5 *  The license and distribution terms for this file may be
6 *  found in the file LICENSE in this distribution or at
7 *  http://www.rtems.com/license/LICENSE.
8 *
9 *  $Id$
10 */
11
12#if HAVE_CONFIG_H
13#include "config.h"
14#endif
15
16#include <time.h>
17#include <errno.h>
18
19#include <rtems/system.h>
20#include <rtems/score/isr.h>
21#include <rtems/score/thread.h>
22#include <rtems/score/tod.h>
23
24#include <rtems/posix/time.h>
25
26/************************************/
27/* These includes are now necessary */
28/************************************/
29
30#include <unistd.h>
31#include <rtems/rtems/status.h>
32#include <rtems/rtems/types.h>
33#include <rtems/rtems/timer.h>
34#include <rtems/rtems/clock.h>
35#include <rtems/posix/psignal.h>
36#include <pthread.h>
37#include <stdio.h>
38#include <signal.h>
39
40#include <rtems/seterr.h>
41#include <rtems/posix/timer.h>
42
43boolean _Watchdog_Insert_ticks_helper(
44  Watchdog_Control               *timer,
45  Watchdog_Interval               ticks,
46  Objects_Id                      id,
47  Watchdog_Service_routine_entry  TSR,
48  void                           *arg
49)
50{
51  ISR_Level            level;
52
53  (void) _Watchdog_Remove( timer );
54  _ISR_Disable( level );
55
56    /*
57     *  Check to see if the watchdog has just been inserted by a
58     *  higher priority interrupt.  If so, abandon this insert.
59     */
60    if ( timer->state != WATCHDOG_INACTIVE ) {
61      _ISR_Enable( level );
62      return FALSE;
63    }
64
65    /*
66     *  OK.  Now we now the timer was not rescheduled by an interrupt
67     *  so we can atomically initialize it as in use.
68     */
69    _Watchdog_Initialize( timer, TSR, id, arg );
70    _Watchdog_Insert_ticks( timer, ticks );
71  _ISR_Enable( level );
72  return TRUE;
73}
74
75/* #define DEBUG_MESSAGES */
76
77/* ***************************************************************************
78 * _POSIX_Timer_TSR
79 *
80 *  Description: This is the operation that is ran when a timer expires
81 * ***************************************************************************/
82
83
84void _POSIX_Timer_TSR(Objects_Id timer, void *data)
85{
86  POSIX_Timer_Control *ptimer;
87  boolean              activated;
88
89  ptimer = (POSIX_Timer_Control *)data;
90
91  /* Increment the number of expirations. */
92  ptimer->overrun = ptimer->overrun + 1;
93  /* The timer must be reprogrammed */
94  if ( ( ptimer->timer_data.it_interval.tv_sec  != 0 ) ||
95       ( ptimer->timer_data.it_interval.tv_nsec != 0 ) ) {
96#if 0
97    status = rtems_timer_fire_after(
98         ptimer->timer_id, ptimer->ticks, _POSIX_Timer_TSR, ptimer );
99#endif
100    activated = _Watchdog_Insert_ticks_helper(
101      &ptimer->Timer,
102      ptimer->ticks,
103      ptimer->Object.id,
104      _POSIX_Timer_TSR,
105      ptimer
106    );
107    if ( !activated )
108      return;
109
110    /* Store the time when the timer was started again */
111    _TOD_Get( &ptimer->time );
112
113    /* The state really did not change but just to be safe */
114    ptimer->state = POSIX_TIMER_STATE_CREATE_RUN;
115  } else {
116   /* Indicates that the timer is stopped */
117   ptimer->state = POSIX_TIMER_STATE_CREATE_STOP;
118  }
119
120  /*
121   * The sending of the signal to the process running the handling function
122   * specified for that signal is simulated
123   */
124
125  if ( pthread_kill ( ptimer->thread_id, ptimer->inf.sigev_signo ) ) {
126    /* XXX error handling */
127  }
128
129  /* After the signal handler returns, the count of expirations of the
130   * timer must be set to 0.
131   */
132  ptimer->overrun = 0;
133}
134
135/* *********************************************************************
136 *  14.2.2 Create a Per-Process Timer, P1003.1b-1993, p. 264
137 * ********************************************************************/
138
139/* **************
140 * timer_create
141 * **************/
142
143int timer_create(
144  clockid_t        clock_id,
145  struct sigevent *evp,
146  timer_t         *timerid
147)
148{
149  POSIX_Timer_Control *ptimer;
150
151  if ( clock_id != CLOCK_REALTIME )
152    rtems_set_errno_and_return_minus_one( EINVAL );
153
154 /*
155  *  The data of the structure evp are checked in order to verify if they
156  *  are coherent.
157  */
158
159  if (evp != NULL) {
160    /* The structure has data */
161    if ( ( evp->sigev_notify != SIGEV_NONE ) &&
162         ( evp->sigev_notify != SIGEV_SIGNAL ) ) {
163       /* The value of the field sigev_notify is not valid */
164       rtems_set_errno_and_return_minus_one( EINVAL );
165     }
166
167     if ( !evp->sigev_signo )
168       rtems_set_errno_and_return_minus_one( EINVAL );
169
170     if ( !is_valid_signo(evp->sigev_signo) )
171       rtems_set_errno_and_return_minus_one( EINVAL );
172  }
173
174  _Thread_Disable_dispatch();         /* to prevent deletion */
175
176  /*
177   *  Allocate a timer
178   */
179  ptimer = _POSIX_Timer_Allocate();
180  if ( !ptimer ) {
181    _Thread_Enable_dispatch();
182    rtems_set_errno_and_return_minus_one( EAGAIN );
183  }
184
185  /* The data of the created timer are stored to use them later */
186
187  ptimer->state     = POSIX_TIMER_STATE_CREATE_NEW;
188  ptimer->thread_id = _Thread_Executing->Object.id;
189
190  if ( evp != NULL ) {
191    ptimer->inf.sigev_notify = evp->sigev_notify;
192    ptimer->inf.sigev_signo  = evp->sigev_signo;
193    ptimer->inf.sigev_value  = evp->sigev_value;
194  }
195
196  ptimer->overrun  = 0;
197  ptimer->timer_data.it_value.tv_sec     = 0;
198  ptimer->timer_data.it_value.tv_nsec    = 0;
199  ptimer->timer_data.it_interval.tv_sec  = 0;
200  ptimer->timer_data.it_interval.tv_nsec = 0;
201
202  _Watchdog_Initialize( &ptimer->Timer, NULL, 0, NULL );
203  _Objects_Open(&_POSIX_Timer_Information, &ptimer->Object, (Objects_Name) 0);
204
205  *timerid  = ptimer->Object.id;
206  _Thread_Enable_dispatch();
207  return 0;
208}
209
210/*
211 *  14.2.3 Delete a Per_process Timer, P1003.1b-1993, p. 266
212 */
213
214int timer_delete(
215  timer_t timerid
216)
217{
218 /*
219  * IDEA: This function must probably stop the timer first and then delete it
220  *
221  *       It will have to do a call to rtems_timer_cancel and then another
222  *       call to rtems_timer_delete.
223  *       The call to rtems_timer_delete will be probably unnecessary,
224  *       because rtems_timer_delete stops the timer before deleting it.
225  */
226  POSIX_Timer_Control *ptimer;
227  Objects_Locations    location;
228
229  ptimer = _POSIX_Timer_Get( timerid, &location );
230  switch ( location ) {
231
232    case OBJECTS_LOCAL:
233      _Objects_Close( &_POSIX_Timer_Information, &ptimer->Object );
234      ptimer->state = POSIX_TIMER_STATE_FREE;
235      (void) _Watchdog_Remove( &ptimer->Timer );
236      _POSIX_Timer_Free( ptimer );
237      _Thread_Enable_dispatch();
238      return 0;
239
240#if defined(RTEMS_MULTIPROCESSING)
241    case OBJECTS_REMOTE:
242#endif
243    case OBJECTS_ERROR:
244      break;
245  }
246
247  rtems_set_errno_and_return_minus_one( EINVAL );
248}
249
250/*
251 *  14.2.4 Per-Process Timers, P1003.1b-1993, p. 267
252 */
253
254/* **************
255 * timer_settime
256 * **************/
257
258
259int timer_settime(
260  timer_t                  timerid,
261  int                      flags,
262  const struct itimerspec *value,
263  struct itimerspec       *ovalue
264)
265{
266  POSIX_Timer_Control *ptimer;
267  Objects_Locations    location;
268  boolean              activated;
269
270  if ( value == NULL ) {
271    rtems_set_errno_and_return_minus_one( EINVAL );
272  }
273
274  /* First, it verifies if the structure "value" is correct */
275  if ( ( value->it_value.tv_nsec > TOD_NANOSECONDS_PER_SECOND ) ||
276       ( value->it_value.tv_nsec < 0 ) ) {
277    /* The number of nanoseconds is not correct */
278    rtems_set_errno_and_return_minus_one( EINVAL );
279  }
280 
281  /* XXX check for seconds in the past */
282
283  if ( flags != TIMER_ABSTIME && flags != POSIX_TIMER_RELATIVE ) {
284    rtems_set_errno_and_return_minus_one( EINVAL );
285  }
286
287  /* If the function reaches this point, then it will be necessary to do
288   * something with the structure of times of the timer: to stop, start
289   * or start it again
290   */
291
292  ptimer = _POSIX_Timer_Get( timerid, &location );
293  switch ( location ) {
294
295    case OBJECTS_LOCAL:
296      /* First, it verifies if the timer must be stopped */
297      if ( value->it_value.tv_sec == 0 && value->it_value.tv_nsec == 0 ) {
298         /* Stop the timer */
299         (void) _Watchdog_Remove( &ptimer->Timer );
300         /* The old data of the timer are returned */
301         if ( ovalue )
302           *ovalue = ptimer->timer_data;
303         /* The new data are set */
304         ptimer->timer_data = *value;
305         /* Indicates that the timer is created and stopped */
306         ptimer->state = POSIX_TIMER_STATE_CREATE_STOP;
307         /* Returns with success */
308        _Thread_Enable_dispatch();
309        return 0;
310       }
311
312       /* absolute or relative? */
313       switch (flags) {
314         case TIMER_ABSTIME:
315
316           /* The fire time is absolute: use "rtems_time_fire_when" */
317           /* First, it converts from struct itimerspec to rtems_time_of_day */
318
319           _Watchdog_Initialize(
320             &ptimer->Timer, _POSIX_Timer_TSR, ptimer->Object.id, ptimer );
321
322           _Watchdog_Insert_seconds(
323              &ptimer->Timer,
324              value->it_value.tv_sec - _TOD_Seconds_since_epoch
325           );
326
327           /* Returns the old ones in "ovalue" */
328           if ( ovalue )
329             *ovalue = ptimer->timer_data;
330           ptimer->timer_data = *value;
331
332           /* Indicate that the time is running */
333           ptimer->state = POSIX_TIMER_STATE_CREATE_RUN;
334
335           /* Stores the time in which the timer was started again */
336           _TOD_Get( &ptimer->time );
337           _Thread_Enable_dispatch();
338           return 0;
339           break;
340
341         /* The fire time is relative: use "rtems_time_fire_after" */
342         case POSIX_TIMER_RELATIVE:
343           /* First, convert from seconds and nanoseconds to ticks */
344           ptimer->ticks = _Timespec_To_ticks( &value->it_value );
345
346           activated = _Watchdog_Insert_ticks_helper(
347             &ptimer->Timer,
348             ptimer->ticks,
349             ptimer->Object.id,
350             _POSIX_Timer_TSR,
351             ptimer
352           );
353           if ( !activated )
354             return 0;
355
356           /* The timer has been started and is running */
357           /* return the old ones in "ovalue" */
358           if ( ovalue )
359             *ovalue = ptimer->timer_data;
360           ptimer->timer_data = *value;
361
362           /* Indicate that the time is running */
363           ptimer->state = POSIX_TIMER_STATE_CREATE_RUN;
364           _TOD_Get( &ptimer->time );
365            _Thread_Enable_dispatch();
366           return 0;
367      }
368      _Thread_Enable_dispatch();
369      break;
370
371#if defined(RTEMS_MULTIPROCESSING)
372    case OBJECTS_REMOTE:
373#endif
374    case OBJECTS_ERROR:
375      break;
376  }
377
378  rtems_set_errno_and_return_minus_one( EINVAL );
379}
380
381/*
382 *  14.2.4 Per-Process Timers, P1003.1b-1993, p. 267
383 */
384
385/* **************
386 * timer_gettime
387 * **************/
388
389int timer_gettime(
390  timer_t            timerid,
391  struct itimerspec *value
392)
393{
394
395 /*
396  * IDEA:  This function does not use functions of RTEMS to the handle
397  *        of timers. It uses some functions for managing the time.
398  *
399  *        A possible form to do this is the following:
400  *
401  *          - When a timer is initialized, the value of the time in
402  *            that moment is stored.
403  *          - When this function is called, it returns the difference
404  *            between the current time and the initialization time.
405  */
406
407  POSIX_Timer_Control *ptimer;
408  Objects_Locations    location;
409  struct timespec      current_time;
410
411  /* Reads the current time */
412  _TOD_Get( &current_time );
413
414  ptimer = _POSIX_Timer_Get( timerid, &location );
415  switch ( location ) {
416
417    case OBJECTS_LOCAL:
418
419      /* Calculates the time left before the timer finishes */
420
421      _Timespec_Subtract(
422        &ptimer->timer_data.it_value,
423        &current_time,
424        &value->it_value
425      );
426
427      value->it_interval  = ptimer->timer_data.it_interval;
428
429      _Thread_Enable_dispatch();
430      return 0;
431
432#if defined(RTEMS_MULTIPROCESSING)
433    case OBJECTS_REMOTE:
434#endif
435    case OBJECTS_ERROR:
436      break;
437  }
438
439  rtems_set_errno_and_return_minus_one( EINVAL );
440}
441
442/*
443 *  14.2.4 Per-Process Timers, P1003.1b-1993, p. 267
444 */
445
446/*
447 * timer_getoverrun
448 *
449 * The expiration of a timer must increase by one a counter.
450 * After the signal handler associated to the timer finishes
451 * its execution, _POSIX_Timer_TSR will have to set this counter to 0.
452 */
453
454int timer_getoverrun(
455  timer_t   timerid
456)
457{
458  int                  overrun;
459  POSIX_Timer_Control *ptimer;
460  Objects_Locations    location;
461
462  ptimer = _POSIX_Timer_Get( timerid, &location );
463  switch ( location ) {
464
465    case OBJECTS_LOCAL:
466      overrun = ptimer->overrun;
467      ptimer->overrun = 0;
468      _Thread_Enable_dispatch();
469      return overrun;
470
471#if defined(RTEMS_MULTIPROCESSING)
472    case OBJECTS_REMOTE:
473#endif
474    case OBJECTS_ERROR:
475      break;
476  }
477
478  rtems_set_errno_and_return_minus_one( EINVAL );
479}
Note: See TracBrowser for help on using the repository browser.