Subversion Repositories shark

Rev

Rev 502 | 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
 *   Massimiliano Giorgi <massy@gandalf.sssup.it>
11
 *   Luca Abeni          <luca@gandalf.sssup.it>
12
 *   (see the web pages for full authors list)
13
 *
14
 * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
15
 *
16
 * http://www.sssup.it
17
 * http://retis.sssup.it
18
 * http://shark.sssup.it
19
 */
20
 
21
/**
22
 ------------
657 anton 23
 CVS :        $Id: posix.c,v 1.9 2004-05-17 15:03:52 anton Exp $
2 pj 24
 
25
 File:        $File$
657 anton 26
 Revision:    $Revision: 1.9 $
27
 Last update: $Date: 2004-05-17 15:03:52 $
2 pj 28
 ------------
29
 
30
 This file contains the scheduling module compatible with POSIX
31
 specifications
32
 
33
 Read posix.h for further details.
34
 
35
 RR tasks have the CONTROL_CAP bit set
36
 
37
**/
38
 
39
/*
40
 * Copyright (C) 2000 Paolo Gai
41
 *
42
 * This program is free software; you can redistribute it and/or modify
43
 * it under the terms of the GNU General Public License as published by
44
 * the Free Software Foundation; either version 2 of the License, or
45
 * (at your option) any later version.
46
 *
47
 * This program is distributed in the hope that it will be useful,
48
 * but WITHOUT ANY WARR2ANTY; without even the implied waRR2anty of
49
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
50
 * GNU General Public License for more details.
51
 *
52
 * You should have received a copy of the GNU General Public License
53
 * along with this program; if not, write to the Free Software
54
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
55
 *
56
 */
57
 
58
 
59
#include <modules/posix.h>
60
#include <ll/stdio.h>
61
#include <ll/string.h>
62
#include <kernel/model.h>
63
#include <kernel/descr.h>
64
#include <kernel/var.h>
65
#include <kernel/func.h>
66
 
353 giacomo 67
#include <tracer.h>
68
 
2 pj 69
/*+ Status used in the level +*/
70
#define POSIX_READY   MODULE_STATUS_BASE
71
 
72
/*+ the level redefinition for the Round Robin level +*/
73
typedef struct {
74
  level_des l;          /*+ the standard level descriptor          +*/
75
 
76
  int nact[MAX_PROC];   /*+ number of pending activations          +*/
29 pj 77
 
78
  int priority[MAX_PROC]; /*+ priority of each task                +*/
2 pj 79
 
29 pj 80
  IQUEUE *ready;        /*+ the ready queue array                  +*/
2 pj 81
 
82
  int slice;            /*+ the level's time slice                 +*/
83
 
84
  struct multiboot_info *multiboot; /*+ used if the level have to insert
85
                                        the main task +*/
86
  int maxpriority;      /*+ the priority are from 0 to maxpriority
87
                            (i.e 0 to 31)                          +*/
88
 
89
  int yielding;         /*+ equal to 1 when a sched_yield is called +*/
90
 
91
} POSIX_level_des;
92
 
93
/* This is not efficient but very fair :-)
94
   The need of all this stuff is because if a task execute a long time
95
   due to (shadow!) priority inheritance, then the task shall go to the
96
   tail of the queue many times... */
38 pj 97
static PID POSIX_public_scheduler(LEVEL l)
2 pj 98
{
99
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
100
 
101
  PID p;
102
 
103
  int prio;
104
 
105
  prio = lev->maxpriority;
106
 
107
  for (;;) {
29 pj 108
    p = iq_query_first(&lev->ready[prio]);
2 pj 109
    if (p == NIL) {
110
      if (prio) {
111
        prio--;
112
        continue;
113
      }
114
      else
115
        return NIL;
116
    }
117
 
118
    if ((proc_table[p].control & CONTROL_CAP) &&
119
        (proc_table[p].avail_time <= 0)) {
120
      proc_table[p].avail_time += proc_table[p].wcet;
29 pj 121
      iq_extract(p,&lev->ready[prio]);
122
      iq_insertlast(p,&lev->ready[prio]);
2 pj 123
    }
124
    else
125
      return p;
126
  }
127
}
128
 
38 pj 129
static int POSIX_public_create(LEVEL l, PID p, TASK_MODEL *m)
2 pj 130
{
38 pj 131
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
132
  NRT_TASK_MODEL *nrt;
2 pj 133
 
38 pj 134
  if (m->pclass != NRT_PCLASS) return -1;
135
  if (m->level != 0 && m->level != l) return -1;
2 pj 136
 
38 pj 137
  nrt = (NRT_TASK_MODEL *)m;
2 pj 138
 
139
  /* the task state is set at SLEEP by the general task_create */
140
 
141
  /* I used the wcet field because using wcet can account if a task
142
     consume more than the timeslice... */
143
 
144
  if (nrt->inherit == NRT_INHERIT_SCHED &&
145
      proc_table[exec_shadow].task_level == l) {
146
    /* We inherit the scheduling properties if the scheduling level
147
       *is* the same */
29 pj 148
    lev->priority[p] = lev->priority[exec_shadow];
2 pj 149
 
150
    proc_table[p].avail_time = proc_table[exec_shadow].avail_time;
151
    proc_table[p].wcet       = proc_table[exec_shadow].wcet;
152
 
153
    proc_table[p].control = (proc_table[p].control & ~CONTROL_CAP) |
154
                            (proc_table[exec_shadow].control & CONTROL_CAP);
155
 
156
    lev->nact[p] = (lev->nact[exec_shadow] == -1) ? -1 : 0;
157
  }
158
  else {
29 pj 159
    lev->priority[p] = nrt->weight;
2 pj 160
 
161
    if (nrt->slice) {
162
      proc_table[p].avail_time = nrt->slice;
163
      proc_table[p].wcet       = nrt->slice;
164
    }
165
    else {
166
      proc_table[p].avail_time = lev->slice;
167
      proc_table[p].wcet       = lev->slice;
168
    }
169
 
170
    if (nrt->policy == NRT_RR_POLICY)
171
      proc_table[p].control   |= CONTROL_CAP;
172
 
173
    if (nrt->arrivals == SAVE_ARRIVALS)
174
      lev->nact[p] = 0;
175
    else
176
      lev->nact[p] = -1;
177
  }
178
 
179
  return 0; /* OK */
180
}
181
 
38 pj 182
static void POSIX_public_dispatch(LEVEL l, PID p, int nostop)
2 pj 183
{
184
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
185
 
186
  /* the task state is set EXE by the scheduler()
187
     we extract the task from the ready queue
188
     NB: we can't assume that p is the first task in the queue!!! */
29 pj 189
  iq_extract(p, &lev->ready[lev->priority[p]]);
2 pj 190
}
191
 
38 pj 192
static void POSIX_public_epilogue(LEVEL l, PID p)
2 pj 193
{
194
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
195
 
196
  if (lev->yielding) {
197
    lev->yielding = 0;
29 pj 198
    iq_insertlast(p,&lev->ready[lev->priority[p]]);
2 pj 199
  }
200
  /* check if the slice is finished and insert the task in the coPOSIXect
201
     qqueue position */
202
  else if (proc_table[p].control & CONTROL_CAP &&
203
           proc_table[p].avail_time <= 0) {
204
    proc_table[p].avail_time += proc_table[p].wcet;
29 pj 205
    iq_insertlast(p,&lev->ready[lev->priority[p]]);
2 pj 206
  }
207
  else
29 pj 208
    iq_insertfirst(p,&lev->ready[lev->priority[p]]);
2 pj 209
 
210
  proc_table[p].status = POSIX_READY;
211
}
212
 
657 anton 213
static void POSIX_public_activate(LEVEL l, PID p, struct timespec *t)
2 pj 214
{
215
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
216
 
217
  /* Test if we are trying to activate a non sleeping task    */
218
  /* save activation (only if needed...) */
219
  if (proc_table[p].status != SLEEP) {
220
    if (lev->nact[p] != -1)
221
      lev->nact[p]++;
222
    return;
223
  }
224
 
225
  /* Insert task in the correct position */
226
  proc_table[p].status = POSIX_READY;
29 pj 227
  iq_insertlast(p,&lev->ready[lev->priority[p]]);
2 pj 228
}
229
 
38 pj 230
static void POSIX_public_unblock(LEVEL l, PID p)
2 pj 231
{
232
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
233
 
234
  /* Similar to POSIX_task_activate, but we don't check in what state
38 pj 235
     the task is */
2 pj 236
 
237
  /* Insert task in the coPOSIXect position */
238
  proc_table[p].status = POSIX_READY;
29 pj 239
  iq_insertlast(p,&lev->ready[lev->priority[p]]);
2 pj 240
}
241
 
38 pj 242
static void POSIX_public_block(LEVEL l, PID p)
2 pj 243
{
244
  /* Extract the running task from the level
245
     . we have already extract it from the ready queue at the dispatch time.
246
     . the capacity event have to be removed by the generic kernel
247
     . the wcet don't need modification...
248
     . the state of the task is set by the calling function
249
 
250
     So, we do nothing!!!
251
  */
252
}
253
 
38 pj 254
static int POSIX_public_message(LEVEL l, PID p, void *m)
2 pj 255
{
256
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
257
 
258
  if (lev->nact[p] > 0) {
259
    /* continue!!!! */
260
    lev->nact[p]--;
29 pj 261
    iq_insertfirst(p,&lev->ready[lev->priority[p]]);
2 pj 262
    proc_table[p].status = POSIX_READY;
263
  }
264
  else
265
    proc_table[p].status = SLEEP;
38 pj 266
 
267
  jet_update_endcycle(); /* Update the Jet data... */
502 giacomo 268
  TRACER_LOGEVENT(FTrace_EVT_task_end_cycle,(unsigned short int)proc_table[p].context,(unsigned int)l);
38 pj 269
 
270
  return 0;
2 pj 271
}
272
 
38 pj 273
static void POSIX_public_end(LEVEL l, PID p)
2 pj 274
{
275
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
276
 
277
  lev->nact[p] = -1;
278
 
279
  /* then, we insert the task in the free queue */
280
  proc_table[p].status = FREE;
29 pj 281
  iq_priority_insert(p,&freedesc);
2 pj 282
}
283
 
284
/* Registration functions */
285
 
286
/*+ This init function install the "main" task +*/
287
static void POSIX_call_main(void *l)
288
{
289
  LEVEL lev;
290
  PID p;
291
  NRT_TASK_MODEL m;
292
  void *mb;
293
 
294
  lev = (LEVEL)l;
295
 
296
  nrt_task_default_model(m);
297
  nrt_task_def_level(m,lev); /* with this we are sure that the task aPOSIXives
298
                                to the coPOSIXect level */
299
 
300
  mb = ((POSIX_level_des *)level_table[lev])->multiboot;
301
  nrt_task_def_arg(m,mb);
302
  nrt_task_def_usemath(m);
303
  nrt_task_def_nokill(m);
304
  nrt_task_def_ctrl_jet(m);
305
  nrt_task_def_weight(m,0);
306
  nrt_task_def_policy(m,NRT_RR_POLICY);
307
  nrt_task_def_inherit(m,NRT_EXPLICIT_SCHED);
308
 
309
  p = task_create("Main", __init__, (TASK_MODEL *)&m, NULL);
310
 
311
  if (p == NIL)
312
    printk("\nPanic!!! can't create main task...\n");
313
 
657 anton 314
  POSIX_public_activate(lev,p,NULL);
2 pj 315
}
316
 
317
 
318
/*+ Registration function:
319
    TIME slice                the slice for the Round Robin queue
320
    int createmain            1 if the level creates the main task 0 otherwise
321
    struct multiboot_info *mb used if createmain specified   +*/
38 pj 322
LEVEL POSIX_register_level(TIME slice,
2 pj 323
                       int createmain,
324
                       struct multiboot_info *mb,
325
                       int prioritylevels)
326
{
327
  LEVEL l;            /* the level that we register */
328
  POSIX_level_des *lev;  /* for readableness only */
329
  PID i;              /* a counter */
330
  int x;              /* a counter */
331
 
332
  printk("POSIX_register_level\n");
333
 
38 pj 334
  l = level_alloc_descriptor(sizeof(POSIX_level_des));
2 pj 335
 
38 pj 336
  lev = (POSIX_level_des *)level_table[l];
2 pj 337
 
338
  /* fill the standard descriptor */
38 pj 339
  lev->l.public_scheduler = POSIX_public_scheduler;
340
  lev->l.public_create    = POSIX_public_create;
341
  lev->l.public_end       = POSIX_public_end;
342
  lev->l.public_dispatch  = POSIX_public_dispatch;
343
  lev->l.public_epilogue  = POSIX_public_epilogue;
344
  lev->l.public_activate  = POSIX_public_activate;
345
  lev->l.public_unblock   = POSIX_public_unblock;
346
  lev->l.public_block     = POSIX_public_block;
347
  lev->l.public_message   = POSIX_public_message;
271 giacomo 348
  lev->l.public_guarantee = NULL;
2 pj 349
 
350
  /* fill the POSIX descriptor part */
351
  for (i = 0; i < MAX_PROC; i++)
352
    lev->nact[i] = -1;
353
 
354
  lev->maxpriority = prioritylevels -1;
355
 
29 pj 356
  lev->ready = (IQUEUE *)kern_alloc(sizeof(IQUEUE) * prioritylevels);
2 pj 357
 
358
  for (x = 0; x < prioritylevels; x++)
29 pj 359
    iq_init(&lev->ready[x], &freedesc, 0);
2 pj 360
 
361
  if (slice < POSIX_MINIMUM_SLICE) slice = POSIX_MINIMUM_SLICE;
362
  if (slice > POSIX_MAXIMUM_SLICE) slice = POSIX_MAXIMUM_SLICE;
363
  lev->slice      = slice;
364
 
365
  lev->multiboot  = mb;
366
 
367
  if (createmain)
368
    sys_atrunlevel(POSIX_call_main,(void *) l, RUNLEVEL_INIT);
38 pj 369
 
370
  return l;
2 pj 371
}
372
 
373
/*+ this function forces the running task to go to his queue tail;
374
    (it works only on the POSIX level) +*/
375
int POSIX_sched_yield(LEVEL l)
376
{
377
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
378
 
379
  if (proc_table[exec_shadow].task_level != l)
380
    return -1;
381
 
382
  proc_table[exec_shadow].context = kern_context_save();
383
  lev->yielding = 1;
384
  scheduler();
385
  kern_context_load(proc_table[exec_shadow].context);
386
  return 0;
387
}
388
 
389
/*+ this function returns the maximum level allowed for the POSIX level +*/
390
int POSIX_get_priority_max(LEVEL l)
391
{
392
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
393
  return lev->maxpriority;
394
}
395
 
396
/*+ this function returns the default timeslice for the POSIX level +*/
397
int POSIX_rr_get_interval(LEVEL l)
398
{
399
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
400
  return lev->slice;
401
}
402
 
403
/*+ this functions returns some paramaters of a task;
404
    policy must be NRT_RR_POLICY or NRT_FIFO_POLICY;
405
    priority must be in the range [0..prioritylevels]
406
    returns ENOSYS or ESRCH if there are problems +*/
407
int POSIX_getschedparam(LEVEL l, PID p, int *policy, int *priority)
408
{
409
  if (p<0 || p>= MAX_PROC || proc_table[p].status == FREE)
410
    return ESRCH;
411
 
412
  if (proc_table[p].task_level != l)
413
    return ENOSYS;
414
 
415
  if (proc_table[p].control & CONTROL_CAP)
416
    *policy = NRT_RR_POLICY;
417
  else
418
    *policy = NRT_FIFO_POLICY;
419
 
29 pj 420
  *priority = ((POSIX_level_des *)(level_table[l]))->priority[p];
2 pj 421
 
422
  return 0;
423
}
424
 
425
/*+ this functions sets paramaters of a task +*/
426
int POSIX_setschedparam(LEVEL l, PID p, int policy, int priority)
427
{
428
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
429
 
430
  if (p<0 || p>= MAX_PROC || proc_table[p].status == FREE)
431
    return ESRCH;
432
 
433
  if (proc_table[p].task_level != l)
434
    return ENOSYS;
435
 
436
  if (policy == SCHED_RR)
437
    proc_table[p].control |= CONTROL_CAP;
438
  else if (policy == SCHED_FIFO)
439
    proc_table[p].control &= ~CONTROL_CAP;
440
  else
441
    return EINVAL;
442
 
29 pj 443
  if (lev->priority[p] != priority) {
2 pj 444
    if (proc_table[p].status == POSIX_READY) {
29 pj 445
      iq_extract(p,&lev->ready[lev->priority[p]]);
446
      lev->priority[p] = priority;
447
      iq_insertlast(p,&lev->ready[priority]);
2 pj 448
    }
449
    else
29 pj 450
      lev->priority[p] = priority;
2 pj 451
  }
452
 
453
  return 0;
454
}
455
 
456
 
457