Subversion Repositories shark

Rev

Rev 2 | 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
 ------------
21
 CVS :        $Id: time.c,v 1.1.1.1 2002-03-29 14:12:52 pj Exp $
22
 
23
 File:        $File$
24
 Revision:    $Revision: 1.1.1.1 $
25
 Last update: $Date: 2002-03-29 14:12:52 $
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
{
145
  if (clock_id != CLOCK_REALTIME) {
146
    errno = EINVAL;
147
    return -1;
148
  }
149
 
150
  kern_cli();
151
 
152
  if (timerqueue_free == -1 || sigqueue_free == -1) {
153
    kern_sti();
154
    errno = EAGAIN;
155
    return -1;
156
  }
157
 
158
  /* alloc a timer descriptor */
159
  *timerid = timerqueue_free;
160
  timerqueue_free = timer_table[timerqueue_free].next;
161
  timer_table[*timerid].used = 1;
162
 
163
  /* alloc a signal descriptor and fill the timer struct */
164
  if (!evp) {
165
    // set default data for the evp field
166
    timer_table[*timerid].evp.sigev_notify = SIGEV_SIGNAL;
167
    timer_table[*timerid].evp.sigev_signo  = DEFAULT_TIMER_SIGNAL;
168
    timer_table[*timerid].evp.sigev_value.sival_int = *timerid;
169
  }
170
  else
171
    timer_table[*timerid].evp = *evp;
172
 
173
  if (timer_table[*timerid].evp.sigev_notify == SIGEV_SIGNAL) {
174
    // alloc a signal descriptor
175
    timer_table[*timerid].signal = sigqueue_free;
176
    sig_queue[sigqueue_free].flags |= USED_FOR_TIMER;
177
    sigqueue_free = sig_queue[sigqueue_free].next;
178
  }
179
 
180
  timer_table[*timerid].event = -1;
181
 
182
  NULL_TIMESPEC(&timer_table[*timerid].period);
183
  NULL_TIMESPEC(&timer_table[*timerid].current);
184
 
185
  timer_table[*timerid].overrun = 0;
186
 
187
  kern_sti();
188
  return 0;
189
}
190
 
191
 
192
/*---------------------------------------------------------------------*/
193
/* 14.2.3 - Delete a Per-Process Timer                                 */
194
/*---------------------------------------------------------------------*/
195
 
196
int timer_delete(timer_t timerid)
197
{
198
  if (timerid < 0 || timerid >= TIMER_MAX) {
199
    errno = EINVAL;
200
    return -1;
201
  }
202
 
203
  kern_cli();
204
 
205
  if (!timer_table[timerid].used) {
206
    kern_sti();
207
    errno = EINVAL;
208
    return -1;
209
  }
210
 
211
  timer_table[timerid].used = 0;
212
 
213
  /* delete the event if the timer is armed */
214
  if (timer_table[timerid].event != -1)
215
    event_delete(timer_table[timerid].event);
216
 
217
  if (timer_table[timerid].evp.sigev_notify == SIGEV_SIGNAL) {
218
    if (!(sig_queue[ timer_table[timerid].signal ].flags & SIGNAL_POSTED)) {
219
      /* if the signal is not pending, we insert it into the sigqueue_free.
220
         instead, if it is pending, it will be inserted into the queue when
221
         delivered */
222
      sig_queue[ timer_table[timerid].signal ].next = sigqueue_free;
223
      sigqueue_free = timer_table[timerid].signal;
224
    }
225
 
226
    /* reset the timer flags... */
227
    sig_queue[ timer_table[timerid].signal ].flags &=
228
      ~(USED_FOR_TIMER | SIGNAL_POSTED);
229
  }
230
 
231
  kern_sti();
232
  return 0;
233
}
234
 
235
/*---------------------------------------------------------------------*/
236
/* 14.2.4 - Per-Process Timers                                         */
237
/*---------------------------------------------------------------------*/
238
 
239
void timer_timerfire(void *arg)
240
{
241
  /* Now, we queue the signal:
242
     - if the signal is already pending, only increment the pending
243
       activations
244
     - if the signal isn't pending,
245
       - we insert the reserved signal into
246
         the sigqueue_free (so it will be popped by the sigqueue)
247
       - we set the posted flag (it will be resetted when the signal
248
         will be dispatched)
249
  */
250
 
251
  int t = (int)arg;
252
 
253
//  kern_printf("*%d",t);
254
  // do the action required...
255
  if (timer_table[t].evp.sigev_notify == SIGEV_SIGNAL) {
256
    if (sig_queue[ timer_table[t].signal ].flags & SIGNAL_POSTED) {
257
      // the signal is already pending, increment the pending activations...
258
      if (timer_table[t].overrun != DELAYTIMER_MAX)
259
        timer_table[t].overrun++;
260
    }
261
    else {
262
      timer_table[t].overrun = 0;
263
      // there is no signal pending... post the signal!!!
264
      // This a dirty trick: The timer has allocated a signal descriptor,
265
      // then the timer put at the top of the free queue,
266
      // so sigqueue_internal pick the right number!!!
267
      sig_queue[ timer_table[t].signal ].next = sigqueue_free;
268
      sigqueue_free = timer_table[t].signal;
269
      sigqueue_internal(0,
270
                        timer_table[t].evp.sigev_signo,
271
                        timer_table[t].evp.sigev_value,
272
                        SI_TIMER);
273
      // setting this flag is used for counting overruns...
274
      sig_queue[ timer_table[t].signal ].flags |= SIGNAL_POSTED;
275
    }
276
 
277
  } else if (timer_table[t].evp.sigev_notify == SIGEV_THREAD) {
278
    /* a new thread must be created; note that the pthread_create
279
       calls task_createn and task_activate; task_activate works into
280
       signal handlers and calls event_need_reschedule */
281
    pthread_t new_thread;
282
 
283
    if (timer_table[t].evp.sigev_notify_attributes)
284
      pthread_create(&new_thread,
285
                     timer_table[t].evp.sigev_notify_attributes,
286
                     (void *(*)(void *))timer_table[t].evp.sigev_notify_function,
287
                     timer_table[t].evp.sigev_value.sival_ptr);
288
    else {
289
      pthread_attr_t new_attr;
290
      // the task must be created detached
291
      pthread_attr_init(&new_attr);
292
      pthread_attr_setdetachstate(&new_attr, PTHREAD_CREATE_DETACHED);
293
 
294
      pthread_create(&new_thread,
295
                     &new_attr,
296
                     (void *(*)(void *))timer_table[t].evp.sigev_notify_function,
297
                     &timer_table[t].evp.sigev_value);
298
    }
299
  }
300
 
301
  if (timer_table[t].period.tv_sec != 0 ||
302
      timer_table[t].period.tv_nsec != 0) {
303
    struct timespec temp;
304
 
305
    TIMESPEC_ASSIGN(&temp,&timer_table[t].current);
306
    ADDTIMESPEC(&temp, &timer_table[t].period, &timer_table[t].current);
307
 
308
    timer_table[t].event =
309
      kern_event_post(&timer_table[t].current,
310
                      timer_timerfire,
311
                      (void *)t);
312
/*    kern_printf("(post e%d %d.%d)", t,
313
                timer_table[t].current.tv_sec,
314
                timer_table[t].current.tv_nsec/1000); */
315
  }
316
  else
317
    timer_table[t].event = -1;
318
}
319
 
320
int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
321
                  struct itimerspec *ovalue)
322
{
323
  struct timespec ct;  /* current time */
324
  int ct_read = 0;     /* we take the current time only once */
325
 
326
  if (timerid < 0 || timerid >= TIMER_MAX || !value) {
327
    errno = EINVAL;
328
    return -1;
329
  }
330
 
331
  if (value->it_interval.tv_nsec < 0 ||
332
      value->it_interval.tv_nsec >= 1000000000) {
333
    errno = EINVAL;
334
    return -1;
335
  }
336
 
337
  if (value->it_value.tv_nsec < 0 ||
338
      value->it_value.tv_nsec >= 1000000000) {
339
    errno = EINVAL;
340
    return -1;
341
  }
342
 
343
  kern_cli();
344
 
345
  if (!timer_table[timerid].used) {
346
    kern_sti();
347
    errno = EINVAL;
348
    return -1;
349
  }
350
 
351
  if (ovalue) {
352
    if (timer_table[timerid].event == -1)
353
      /* the timer is disarmed, set it_value to 0 */
354
      NULL_TIMESPEC(&ovalue->it_value);
355
    else {
356
      /* the timer is armed, return the remaining expiration time */
357
      ll_gettime(TIME_EXACT, &ct);
358
      ct_read = 1;
359
      SUBTIMESPEC(&timer_table[timerid].current, &ct, &ovalue->it_value);
360
    }
361
    /* and return the reactivation period */
362
    TIMESPEC_ASSIGN(&ovalue->it_interval, &timer_table[timerid].period);
363
  }
364
 
365
  /* if it_value is 0, the timer shall be disarmed; if != 0, the timer is
366
     armed: in all the cases, the event must be deleted... */
367
  if (timer_table[timerid].event != -1)
368
    event_delete(timer_table[timerid].event);
369
 
370
  if (value->it_value.tv_sec != 0 || value->it_value.tv_nsec != 0) {
371
    /* it_value != 0 -> arm the timer! */
372
    TIMESPEC_ASSIGN(&timer_table[timerid].period, &value->it_interval);
373
 
374
    if (flags & TIMER_ABSTIME)
375
      /* the time is absolute */
376
      TIMESPEC_ASSIGN(&timer_table[timerid].current, &value->it_value);
377
    else {
378
      /* the time is relative to current time */
379
      if (!ct_read)
380
        ll_gettime(TIME_EXACT, &ct);
381
      ADDTIMESPEC(&ct, &value->it_value, &timer_table[timerid].current);
382
    }
383
    timer_table[timerid].event =
384
      kern_event_post(&timer_table[timerid].current,
385
                      timer_timerfire,
386
                      (void *)timerid);
387
/*    kern_printf("(post e%d %d.%d)", timerid,
388
                timer_table[timerid].current.tv_sec,
389
                timer_table[timerid].current.tv_nsec/1000); */
390
  }
391
 
392
  kern_sti();
393
  return 0;
394
}
395
 
396
int timer_gettime(timer_t timerid, struct itimerspec *value)
397
{
398
  struct timespec ct;  /* current time */
399
 
400
  if (timerid < 0 || timerid >= TIMER_MAX) {
401
    errno = EINVAL;
402
    return -1;
403
  }
404
 
405
  kern_cli();
406
 
407
  if (!timer_table[timerid].used) {
408
    kern_sti();
409
    errno = EINVAL;
410
    return -1;
411
  }
412
 
413
  if (timer_table[timerid].event == -1)
414
    /* the timer is disarmed, set it_value to 0 */
415
    NULL_TIMESPEC(&value->it_value);
416
  else {
417
    /* the timer is armed, return the remaining expiration time */
418
    ll_gettime(TIME_EXACT, &ct);
419
    SUBTIMESPEC(&timer_table[timerid].current, &ct, &value->it_value);
420
  }
421
  /* and return the reactivation period */
422
  TIMESPEC_ASSIGN(&value->it_interval, &timer_table[timerid].period);
423
 
424
  kern_sti();
425
  return 0;
426
}
427
 
428
int timer_getoverrun(timer_t timerid)
429
{
430
  int returnvalue;
431
 
432
  if (timerid < 0 || timerid >= TIMER_MAX) {
433
    errno = EINVAL;
434
    return -1;
435
  }
436
 
437
  kern_cli();
438
 
439
  if (!timer_table[timerid].used) {
440
    kern_sti();
441
    errno = EINVAL;
442
    return -1;
443
  }
444
 
445
  returnvalue = timer_table[timerid].overrun;
446
  kern_sti();
447
  return returnvalue;
448
}
449