Subversion Repositories shark

Rev

Rev 29 | 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
 ------------
38 pj 23
 CVS :        $Id: posix.c,v 1.4 2003-01-07 17:07:50 pj Exp $
2 pj 24
 
25
 File:        $File$
38 pj 26
 Revision:    $Revision: 1.4 $
27
 Last update: $Date: 2003-01-07 17:07:50 $
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>
38 pj 66
#include <kernel/trace.h>
2 pj 67
 
68
/*+ Status used in the level +*/
69
#define POSIX_READY   MODULE_STATUS_BASE
70
 
71
/*+ the level redefinition for the Round Robin level +*/
72
typedef struct {
73
  level_des l;          /*+ the standard level descriptor          +*/
74
 
75
  int nact[MAX_PROC];   /*+ number of pending activations          +*/
29 pj 76
 
77
  int priority[MAX_PROC]; /*+ priority of each task                +*/
2 pj 78
 
29 pj 79
  IQUEUE *ready;        /*+ the ready queue array                  +*/
2 pj 80
 
81
  int slice;            /*+ the level's time slice                 +*/
82
 
83
  struct multiboot_info *multiboot; /*+ used if the level have to insert
84
                                        the main task +*/
85
  int maxpriority;      /*+ the priority are from 0 to maxpriority
86
                            (i.e 0 to 31)                          +*/
87
 
88
  int yielding;         /*+ equal to 1 when a sched_yield is called +*/
89
 
90
} POSIX_level_des;
91
 
92
/* This is not efficient but very fair :-)
93
   The need of all this stuff is because if a task execute a long time
94
   due to (shadow!) priority inheritance, then the task shall go to the
95
   tail of the queue many times... */
38 pj 96
static PID POSIX_public_scheduler(LEVEL l)
2 pj 97
{
98
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
99
 
100
  PID p;
101
 
102
  int prio;
103
 
104
  prio = lev->maxpriority;
105
 
106
  for (;;) {
29 pj 107
    p = iq_query_first(&lev->ready[prio]);
2 pj 108
    if (p == NIL) {
109
      if (prio) {
110
        prio--;
111
        continue;
112
      }
113
      else
114
        return NIL;
115
    }
116
 
117
    if ((proc_table[p].control & CONTROL_CAP) &&
118
        (proc_table[p].avail_time <= 0)) {
119
      proc_table[p].avail_time += proc_table[p].wcet;
29 pj 120
      iq_extract(p,&lev->ready[prio]);
121
      iq_insertlast(p,&lev->ready[prio]);
2 pj 122
    }
123
    else
124
      return p;
125
  }
126
}
127
 
38 pj 128
static int POSIX_public_create(LEVEL l, PID p, TASK_MODEL *m)
2 pj 129
{
38 pj 130
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
131
  NRT_TASK_MODEL *nrt;
2 pj 132
 
38 pj 133
  if (m->pclass != NRT_PCLASS) return -1;
134
  if (m->level != 0 && m->level != l) return -1;
2 pj 135
 
38 pj 136
  nrt = (NRT_TASK_MODEL *)m;
2 pj 137
 
138
  /* the task state is set at SLEEP by the general task_create */
139
 
140
  /* I used the wcet field because using wcet can account if a task
141
     consume more than the timeslice... */
142
 
143
  if (nrt->inherit == NRT_INHERIT_SCHED &&
144
      proc_table[exec_shadow].task_level == l) {
145
    /* We inherit the scheduling properties if the scheduling level
146
       *is* the same */
29 pj 147
    lev->priority[p] = lev->priority[exec_shadow];
2 pj 148
 
149
    proc_table[p].avail_time = proc_table[exec_shadow].avail_time;
150
    proc_table[p].wcet       = proc_table[exec_shadow].wcet;
151
 
152
    proc_table[p].control = (proc_table[p].control & ~CONTROL_CAP) |
153
                            (proc_table[exec_shadow].control & CONTROL_CAP);
154
 
155
    lev->nact[p] = (lev->nact[exec_shadow] == -1) ? -1 : 0;
156
  }
157
  else {
29 pj 158
    lev->priority[p] = nrt->weight;
2 pj 159
 
160
    if (nrt->slice) {
161
      proc_table[p].avail_time = nrt->slice;
162
      proc_table[p].wcet       = nrt->slice;
163
    }
164
    else {
165
      proc_table[p].avail_time = lev->slice;
166
      proc_table[p].wcet       = lev->slice;
167
    }
168
 
169
    if (nrt->policy == NRT_RR_POLICY)
170
      proc_table[p].control   |= CONTROL_CAP;
171
 
172
    if (nrt->arrivals == SAVE_ARRIVALS)
173
      lev->nact[p] = 0;
174
    else
175
      lev->nact[p] = -1;
176
  }
177
 
178
  return 0; /* OK */
179
}
180
 
38 pj 181
static void POSIX_public_dispatch(LEVEL l, PID p, int nostop)
2 pj 182
{
183
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
184
 
185
  /* the task state is set EXE by the scheduler()
186
     we extract the task from the ready queue
187
     NB: we can't assume that p is the first task in the queue!!! */
29 pj 188
  iq_extract(p, &lev->ready[lev->priority[p]]);
2 pj 189
}
190
 
38 pj 191
static void POSIX_public_epilogue(LEVEL l, PID p)
2 pj 192
{
193
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
194
 
195
  if (lev->yielding) {
196
    lev->yielding = 0;
29 pj 197
    iq_insertlast(p,&lev->ready[lev->priority[p]]);
2 pj 198
  }
199
  /* check if the slice is finished and insert the task in the coPOSIXect
200
     qqueue position */
201
  else if (proc_table[p].control & CONTROL_CAP &&
202
           proc_table[p].avail_time <= 0) {
203
    proc_table[p].avail_time += proc_table[p].wcet;
29 pj 204
    iq_insertlast(p,&lev->ready[lev->priority[p]]);
2 pj 205
  }
206
  else
29 pj 207
    iq_insertfirst(p,&lev->ready[lev->priority[p]]);
2 pj 208
 
209
  proc_table[p].status = POSIX_READY;
210
}
211
 
38 pj 212
static void POSIX_public_activate(LEVEL l, PID p)
2 pj 213
{
214
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
215
 
216
  /* Test if we are trying to activate a non sleeping task    */
217
  /* save activation (only if needed...) */
218
  if (proc_table[p].status != SLEEP) {
219
    if (lev->nact[p] != -1)
220
      lev->nact[p]++;
221
    return;
222
  }
223
 
224
  /* Insert task in the correct position */
225
  proc_table[p].status = POSIX_READY;
29 pj 226
  iq_insertlast(p,&lev->ready[lev->priority[p]]);
2 pj 227
}
228
 
38 pj 229
static void POSIX_public_unblock(LEVEL l, PID p)
2 pj 230
{
231
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
232
 
233
  /* Similar to POSIX_task_activate, but we don't check in what state
38 pj 234
     the task is */
2 pj 235
 
236
  /* Insert task in the coPOSIXect position */
237
  proc_table[p].status = POSIX_READY;
29 pj 238
  iq_insertlast(p,&lev->ready[lev->priority[p]]);
2 pj 239
}
240
 
38 pj 241
static void POSIX_public_block(LEVEL l, PID p)
2 pj 242
{
243
  /* Extract the running task from the level
244
     . we have already extract it from the ready queue at the dispatch time.
245
     . the capacity event have to be removed by the generic kernel
246
     . the wcet don't need modification...
247
     . the state of the task is set by the calling function
248
 
249
     So, we do nothing!!!
250
  */
251
}
252
 
38 pj 253
static int POSIX_public_message(LEVEL l, PID p, void *m)
2 pj 254
{
255
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
256
 
257
  if (lev->nact[p] > 0) {
258
    /* continue!!!! */
259
    lev->nact[p]--;
29 pj 260
    iq_insertfirst(p,&lev->ready[lev->priority[p]]);
2 pj 261
    proc_table[p].status = POSIX_READY;
262
  }
263
  else
264
    proc_table[p].status = SLEEP;
38 pj 265
 
266
  jet_update_endcycle(); /* Update the Jet data... */
267
  trc_logevent(TRC_ENDCYCLE,&exec_shadow); /* tracer stuff */
268
 
269
  return 0;
2 pj 270
}
271
 
38 pj 272
static void POSIX_public_end(LEVEL l, PID p)
2 pj 273
{
274
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
275
 
276
  lev->nact[p] = -1;
277
 
278
  /* then, we insert the task in the free queue */
279
  proc_table[p].status = FREE;
29 pj 280
  iq_priority_insert(p,&freedesc);
2 pj 281
}
282
 
283
/* Registration functions */
284
 
285
/*+ This init function install the "main" task +*/
286
static void POSIX_call_main(void *l)
287
{
288
  LEVEL lev;
289
  PID p;
290
  NRT_TASK_MODEL m;
291
  void *mb;
292
 
293
  lev = (LEVEL)l;
294
 
295
  nrt_task_default_model(m);
296
  nrt_task_def_level(m,lev); /* with this we are sure that the task aPOSIXives
297
                                to the coPOSIXect level */
298
 
299
  mb = ((POSIX_level_des *)level_table[lev])->multiboot;
300
  nrt_task_def_arg(m,mb);
301
  nrt_task_def_usemath(m);
302
  nrt_task_def_nokill(m);
303
  nrt_task_def_ctrl_jet(m);
304
  nrt_task_def_weight(m,0);
305
  nrt_task_def_policy(m,NRT_RR_POLICY);
306
  nrt_task_def_inherit(m,NRT_EXPLICIT_SCHED);
307
 
308
  p = task_create("Main", __init__, (TASK_MODEL *)&m, NULL);
309
 
310
  if (p == NIL)
311
    printk("\nPanic!!! can't create main task...\n");
312
 
38 pj 313
  POSIX_public_activate(lev,p);
2 pj 314
}
315
 
316
 
317
/*+ Registration function:
318
    TIME slice                the slice for the Round Robin queue
319
    int createmain            1 if the level creates the main task 0 otherwise
320
    struct multiboot_info *mb used if createmain specified   +*/
38 pj 321
LEVEL POSIX_register_level(TIME slice,
2 pj 322
                       int createmain,
323
                       struct multiboot_info *mb,
324
                       int prioritylevels)
325
{
326
  LEVEL l;            /* the level that we register */
327
  POSIX_level_des *lev;  /* for readableness only */
328
  PID i;              /* a counter */
329
  int x;              /* a counter */
330
 
331
  printk("POSIX_register_level\n");
332
 
38 pj 333
  l = level_alloc_descriptor(sizeof(POSIX_level_des));
2 pj 334
 
38 pj 335
  lev = (POSIX_level_des *)level_table[l];
2 pj 336
 
337
  printk("    lev=%d\n",(int)lev);
338
 
339
  /* fill the standard descriptor */
38 pj 340
  lev->l.public_scheduler = POSIX_public_scheduler;
341
  lev->l.public_create    = POSIX_public_create;
342
  lev->l.public_end       = POSIX_public_end;
343
  lev->l.public_dispatch  = POSIX_public_dispatch;
344
  lev->l.public_epilogue  = POSIX_public_epilogue;
345
  lev->l.public_activate  = POSIX_public_activate;
346
  lev->l.public_unblock   = POSIX_public_unblock;
347
  lev->l.public_block     = POSIX_public_block;
348
  lev->l.public_message   = POSIX_public_message;
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