Subversion Repositories shark

Rev

Rev 38 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 pj 1
/*
2
 * Project: S.Ha.R.K.
3
 *
4
 * Coordinators:
5
 *   Giorgio Buttazzo    <giorgio@sssup.it>
6
 *   Paolo Gai           <pj@gandalf.sssup.it>
7
 *
8
 * Authors     :
9
 *   Paolo Gai           <pj@gandalf.sssup.it>
10
 *   (see the web pages for full authors list)
11
 *
12
 * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
13
 *
14
 * http://www.sssup.it
15
 * http://retis.sssup.it
16
 * http://shark.sssup.it
17
 */
18
 
19
/**
20
 ------------
318 giacomo 21
 CVS :        $Id: time.c,v 1.3 2003-11-05 15:05:12 giacomo Exp $
2 pj 22
 
23
 File:        $File$
318 giacomo 24
 Revision:    $Revision: 1.3 $
25
 Last update: $Date: 2003-11-05 15:05:12 $
2 pj 26
 ------------
27
 
28
 This file contains the functions defined in time.h
29
 
30
**/
31
 
32
/*
33
 * Copyright (C) 2000 Paolo Gai
34
 *
35
 * This program is free software; you can redistribute it and/or modify
36
 * it under the terms of the GNU General Public License as published by
37
 * the Free Software Foundation; either version 2 of the License, or
38
 * (at your option) any later version.
39
 *
40
 * This program is distributed in the hope that it will be useful,
41
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
43
 * GNU General Public License for more details.
44
 *
45
 * You should have received a copy of the GNU General Public License
46
 * along with this program; if not, write to the Free Software
47
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
48
 *
49
 */
50
 
51
 
52
#include <ll/ll.h>
53
#include <errno.h>
54
#include <kernel/func.h>
55
#include <pthread.h>
56
#include <signal.h>
57
#include <time.h>
58
#include <limits.h>
59
 
60
struct internal_timer_struct {
61
  struct sigevent evp;     /* the sigevent MUST be allocated by the applic. */
62
  int event;               /* the timer event... the timer is disarmed when
63
                              event == -1 */
64
  struct timespec period;  /* period for periodic timers */
65
  struct timespec current; /* time at whitch the event is posted */
66
 
67
  /* these fields are used only if SIGEV_SIGNAL is specified */
68
  int signal;              /* the reserved signal entry for the timer */
69
  int overrun;             /* the signal overrun counter */
70
 
71
  int used;                /* 1 if the timer is used */
72
  int next;
73
};
74
 
75
 
76
/* the timer table */
77
static struct internal_timer_struct timer_table[TIMER_MAX];
78
 
79
/* the free timer pointer */
80
static int timerqueue_free;
81
 
82
void TIMER_register_module()
83
{
84
  int x;
85
 
86
  for (x = 0; x < TIMER_MAX; x++) {
87
    timer_table[x].event = -1; /* invalid value */
88
    NULL_TIMESPEC(&timer_table[x].period);
89
    timer_table[x].used = 0;
90
    timer_table[x].overrun = 0;
91
    // evp is not initialized
92
    timer_table[x].next = x+1;
93
  }
94
  timer_table[TIMER_MAX-1].next = -1;
95
  timerqueue_free = 0;
96
 
97
}
98
 
99
/*---------------------------------------------------------------------*/
100
/* 14.2.1 - Clocks                                                     */
101
/*---------------------------------------------------------------------*/
102
 
103
int clock_settime(clockid_t clock_id, const struct timespec *tp)
104
{
105
  if (clock_id != CLOCK_REALTIME)
106
    errno = EINVAL;
107
  else
108
    errno = EPERM;
109
  return -1;
110
}
111
 
112
int clock_gettime(clockid_t clock_id, struct timespec *tp)
113
{
114
  if (clock_id != CLOCK_REALTIME) {
115
    errno = EINVAL;
116
    return -1;
117
  }
118
 
119
  sys_gettime(tp);
120
  return 0;
121
}
122
 
123
int clock_getres(clockid_t clock_id, struct timespec *res)
124
{
125
  if (clock_id != CLOCK_REALTIME) {
126
    errno = EINVAL;
127
    return -1;
128
  }
129
 
130
  if (res) {
131
    /* 1 usec */
132
    res->tv_sec  = 0;
133
    res->tv_nsec = 1000;
134
  }
135
 
136
  return 0;
137
}
138
 
139
/*---------------------------------------------------------------------*/
140
/* 14.2.2 - Create a Per-Process Timer                                 */
141
/*---------------------------------------------------------------------*/
142
 
143
int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid)
144
{
318 giacomo 145
  SYS_FLAGS f;
146
 
2 pj 147
  if (clock_id != CLOCK_REALTIME) {
148
    errno = EINVAL;
149
    return -1;
150
  }
151
 
318 giacomo 152
  f = kern_fsave();
2 pj 153
 
154
  if (timerqueue_free == -1 || sigqueue_free == -1) {
318 giacomo 155
    kern_frestore(f);
2 pj 156
    errno = EAGAIN;
157
    return -1;
158
  }
159
 
160
  /* alloc a timer descriptor */
161
  *timerid = timerqueue_free;
162
  timerqueue_free = timer_table[timerqueue_free].next;
163
  timer_table[*timerid].used = 1;
164
 
165
  /* alloc a signal descriptor and fill the timer struct */
166
  if (!evp) {
167
    // set default data for the evp field
168
    timer_table[*timerid].evp.sigev_notify = SIGEV_SIGNAL;
169
    timer_table[*timerid].evp.sigev_signo  = DEFAULT_TIMER_SIGNAL;
170
    timer_table[*timerid].evp.sigev_value.sival_int = *timerid;
171
  }
172
  else
173
    timer_table[*timerid].evp = *evp;
174
 
175
  if (timer_table[*timerid].evp.sigev_notify == SIGEV_SIGNAL) {
176
    // alloc a signal descriptor
177
    timer_table[*timerid].signal = sigqueue_free;
178
    sig_queue[sigqueue_free].flags |= USED_FOR_TIMER;
179
    sigqueue_free = sig_queue[sigqueue_free].next;
180
  }
181
 
182
  timer_table[*timerid].event = -1;
183
 
184
  NULL_TIMESPEC(&timer_table[*timerid].period);
185
  NULL_TIMESPEC(&timer_table[*timerid].current);
186
 
187
  timer_table[*timerid].overrun = 0;
188
 
318 giacomo 189
  kern_frestore(f);
2 pj 190
  return 0;
191
}
192
 
193
 
194
/*---------------------------------------------------------------------*/
195
/* 14.2.3 - Delete a Per-Process Timer                                 */
196
/*---------------------------------------------------------------------*/
197
 
198
int timer_delete(timer_t timerid)
199
{
318 giacomo 200
  SYS_FLAGS f;
201
 
2 pj 202
  if (timerid < 0 || timerid >= TIMER_MAX) {
203
    errno = EINVAL;
204
    return -1;
205
  }
206
 
318 giacomo 207
  f = kern_fsave();
2 pj 208
 
209
  if (!timer_table[timerid].used) {
318 giacomo 210
    kern_frestore(f);
2 pj 211
    errno = EINVAL;
212
    return -1;
213
  }
214
 
215
  timer_table[timerid].used = 0;
216
 
217
  /* delete the event if the timer is armed */
218
  if (timer_table[timerid].event != -1)
38 pj 219
    kern_event_delete(timer_table[timerid].event);
2 pj 220
 
221
  if (timer_table[timerid].evp.sigev_notify == SIGEV_SIGNAL) {
222
    if (!(sig_queue[ timer_table[timerid].signal ].flags & SIGNAL_POSTED)) {
223
      /* if the signal is not pending, we insert it into the sigqueue_free.
224
         instead, if it is pending, it will be inserted into the queue when
225
         delivered */
226
      sig_queue[ timer_table[timerid].signal ].next = sigqueue_free;
227
      sigqueue_free = timer_table[timerid].signal;
228
    }
229
 
230
    /* reset the timer flags... */
231
    sig_queue[ timer_table[timerid].signal ].flags &=
232
      ~(USED_FOR_TIMER | SIGNAL_POSTED);
233
  }
234
 
318 giacomo 235
  kern_frestore(f);
2 pj 236
  return 0;
237
}
238
 
239
/*---------------------------------------------------------------------*/
240
/* 14.2.4 - Per-Process Timers                                         */
241
/*---------------------------------------------------------------------*/
242
 
243
void timer_timerfire(void *arg)
244
{
245
  /* Now, we queue the signal:
246
     - if the signal is already pending, only increment the pending
247
       activations
248
     - if the signal isn't pending,
249
       - we insert the reserved signal into
250
         the sigqueue_free (so it will be popped by the sigqueue)
251
       - we set the posted flag (it will be resetted when the signal
252
         will be dispatched)
253
  */
254
 
255
  int t = (int)arg;
256
 
257
//  kern_printf("*%d",t);
258
  // do the action required...
259
  if (timer_table[t].evp.sigev_notify == SIGEV_SIGNAL) {
260
    if (sig_queue[ timer_table[t].signal ].flags & SIGNAL_POSTED) {
261
      // the signal is already pending, increment the pending activations...
262
      if (timer_table[t].overrun != DELAYTIMER_MAX)
263
        timer_table[t].overrun++;
264
    }
265
    else {
266
      timer_table[t].overrun = 0;
267
      // there is no signal pending... post the signal!!!
268
      // This a dirty trick: The timer has allocated a signal descriptor,
269
      // then the timer put at the top of the free queue,
270
      // so sigqueue_internal pick the right number!!!
271
      sig_queue[ timer_table[t].signal ].next = sigqueue_free;
272
      sigqueue_free = timer_table[t].signal;
273
      sigqueue_internal(0,
274
                        timer_table[t].evp.sigev_signo,
275
                        timer_table[t].evp.sigev_value,
276
                        SI_TIMER);
277
      // setting this flag is used for counting overruns...
278
      sig_queue[ timer_table[t].signal ].flags |= SIGNAL_POSTED;
279
    }
280
 
281
  } else if (timer_table[t].evp.sigev_notify == SIGEV_THREAD) {
282
    /* a new thread must be created; note that the pthread_create
283
       calls task_createn and task_activate; task_activate works into
284
       signal handlers and calls event_need_reschedule */
285
    pthread_t new_thread;
286
 
287
    if (timer_table[t].evp.sigev_notify_attributes)
288
      pthread_create(&new_thread,
289
                     timer_table[t].evp.sigev_notify_attributes,
290
                     (void *(*)(void *))timer_table[t].evp.sigev_notify_function,
291
                     timer_table[t].evp.sigev_value.sival_ptr);
292
    else {
293
      pthread_attr_t new_attr;
294
      // the task must be created detached
295
      pthread_attr_init(&new_attr);
296
      pthread_attr_setdetachstate(&new_attr, PTHREAD_CREATE_DETACHED);
297
 
298
      pthread_create(&new_thread,
299
                     &new_attr,
300
                     (void *(*)(void *))timer_table[t].evp.sigev_notify_function,
301
                     &timer_table[t].evp.sigev_value);
302
    }
303
  }
304
 
305
  if (timer_table[t].period.tv_sec != 0 ||
306
      timer_table[t].period.tv_nsec != 0) {
307
    struct timespec temp;
308
 
309
    TIMESPEC_ASSIGN(&temp,&timer_table[t].current);
310
    ADDTIMESPEC(&temp, &timer_table[t].period, &timer_table[t].current);
311
 
312
    timer_table[t].event =
313
      kern_event_post(&timer_table[t].current,
314
                      timer_timerfire,
315
                      (void *)t);
316
/*    kern_printf("(post e%d %d.%d)", t,
317
                timer_table[t].current.tv_sec,
318
                timer_table[t].current.tv_nsec/1000); */
319
  }
320
  else
321
    timer_table[t].event = -1;
322
}
323
 
324
int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
325
                  struct itimerspec *ovalue)
326
{
327
  struct timespec ct;  /* current time */
328
  int ct_read = 0;     /* we take the current time only once */
318 giacomo 329
  SYS_FLAGS f;
2 pj 330
 
331
  if (timerid < 0 || timerid >= TIMER_MAX || !value) {
332
    errno = EINVAL;
333
    return -1;
334
  }
335
 
336
  if (value->it_interval.tv_nsec < 0 ||
337
      value->it_interval.tv_nsec >= 1000000000) {
338
    errno = EINVAL;
339
    return -1;
340
  }
341
 
342
  if (value->it_value.tv_nsec < 0 ||
343
      value->it_value.tv_nsec >= 1000000000) {
344
    errno = EINVAL;
345
    return -1;
346
  }
347
 
318 giacomo 348
  f = kern_fsave();
2 pj 349
 
350
  if (!timer_table[timerid].used) {
318 giacomo 351
    kern_frestore(f);
2 pj 352
    errno = EINVAL;
353
    return -1;
354
  }
355
 
356
  if (ovalue) {
357
    if (timer_table[timerid].event == -1)
358
      /* the timer is disarmed, set it_value to 0 */
359
      NULL_TIMESPEC(&ovalue->it_value);
360
    else {
361
      /* the timer is armed, return the remaining expiration time */
38 pj 362
      kern_gettime(&ct);
2 pj 363
      ct_read = 1;
364
      SUBTIMESPEC(&timer_table[timerid].current, &ct, &ovalue->it_value);
365
    }
366
    /* and return the reactivation period */
367
    TIMESPEC_ASSIGN(&ovalue->it_interval, &timer_table[timerid].period);
368
  }
369
 
370
  /* if it_value is 0, the timer shall be disarmed; if != 0, the timer is
371
     armed: in all the cases, the event must be deleted... */
372
  if (timer_table[timerid].event != -1)
38 pj 373
    kern_event_delete(timer_table[timerid].event);
2 pj 374
 
375
  if (value->it_value.tv_sec != 0 || value->it_value.tv_nsec != 0) {
376
    /* it_value != 0 -> arm the timer! */
377
    TIMESPEC_ASSIGN(&timer_table[timerid].period, &value->it_interval);
378
 
379
    if (flags & TIMER_ABSTIME)
380
      /* the time is absolute */
381
      TIMESPEC_ASSIGN(&timer_table[timerid].current, &value->it_value);
382
    else {
383
      /* the time is relative to current time */
384
      if (!ct_read)
38 pj 385
        kern_gettime(&ct);
2 pj 386
      ADDTIMESPEC(&ct, &value->it_value, &timer_table[timerid].current);
387
    }
388
    timer_table[timerid].event =
389
      kern_event_post(&timer_table[timerid].current,
390
                      timer_timerfire,
391
                      (void *)timerid);
392
/*    kern_printf("(post e%d %d.%d)", timerid,
393
                timer_table[timerid].current.tv_sec,
394
                timer_table[timerid].current.tv_nsec/1000); */
395
  }
396
 
318 giacomo 397
  kern_frestore(f);
2 pj 398
  return 0;
399
}
400
 
401
int timer_gettime(timer_t timerid, struct itimerspec *value)
402
{
403
  struct timespec ct;  /* current time */
318 giacomo 404
  SYS_FLAGS f;
2 pj 405
 
406
  if (timerid < 0 || timerid >= TIMER_MAX) {
407
    errno = EINVAL;
408
    return -1;
409
  }
410
 
318 giacomo 411
  f = kern_fsave();
2 pj 412
 
413
  if (!timer_table[timerid].used) {
318 giacomo 414
    kern_frestore(f);
2 pj 415
    errno = EINVAL;
416
    return -1;
417
  }
418
 
419
  if (timer_table[timerid].event == -1)
420
    /* the timer is disarmed, set it_value to 0 */
421
    NULL_TIMESPEC(&value->it_value);
422
  else {
423
    /* the timer is armed, return the remaining expiration time */
38 pj 424
    kern_gettime(&ct);
2 pj 425
    SUBTIMESPEC(&timer_table[timerid].current, &ct, &value->it_value);
426
  }
427
  /* and return the reactivation period */
428
  TIMESPEC_ASSIGN(&value->it_interval, &timer_table[timerid].period);
429
 
318 giacomo 430
  kern_frestore(f);
2 pj 431
  return 0;
432
}
433
 
434
int timer_getoverrun(timer_t timerid)
435
{
436
  int returnvalue;
318 giacomo 437
  SYS_FLAGS f;
2 pj 438
 
439
  if (timerid < 0 || timerid >= TIMER_MAX) {
440
    errno = EINVAL;
441
    return -1;
442
  }
443
 
318 giacomo 444
  f = kern_fsave();
2 pj 445
 
446
  if (!timer_table[timerid].used) {
318 giacomo 447
    kern_frestore(f);
2 pj 448
    errno = EINVAL;
449
    return -1;
450
  }
451
 
452
  returnvalue = timer_table[timerid].overrun;
318 giacomo 453
  kern_frestore(f);
2 pj 454
  return returnvalue;
455
}
456