Subversion Repositories shark

Rev

Rev 657 | 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
 ------------
870 trimarchi 23
 CVS :        $Id: posix.c,v 1.10 2004-10-25 14:44:28 trimarchi Exp $
2 pj 24
 
25
 File:        $File$
870 trimarchi 26
 Revision:    $Revision: 1.10 $
27
 Last update: $Date: 2004-10-25 14:44:28 $
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>
870 trimarchi 68
#include <modules/comm_message.h>
353 giacomo 69
 
2 pj 70
/*+ Status used in the level +*/
71
#define POSIX_READY   MODULE_STATUS_BASE
72
 
870 trimarchi 73
/*+ Use for change level in POSIX +*/
74
#define POSIX_CHANGE_LEVEL 1
75
 
76
 
2 pj 77
/*+ the level redefinition for the Round Robin level +*/
78
typedef struct {
79
  level_des l;          /*+ the standard level descriptor          +*/
80
 
81
  int nact[MAX_PROC];   /*+ number of pending activations          +*/
29 pj 82
 
83
  int priority[MAX_PROC]; /*+ priority of each task                +*/
2 pj 84
 
29 pj 85
  IQUEUE *ready;        /*+ the ready queue array                  +*/
2 pj 86
 
87
  int slice;            /*+ the level's time slice                 +*/
88
 
89
  struct multiboot_info *multiboot; /*+ used if the level have to insert
90
                                        the main task +*/
91
  int maxpriority;      /*+ the priority are from 0 to maxpriority
92
                            (i.e 0 to 31)                          +*/
93
 
94
  int yielding;         /*+ equal to 1 when a sched_yield is called +*/
95
 
870 trimarchi 96
  /* introduce for changing level in POSIX */
97
  int flag[MAX_PROC];
98
 
99
  int new_level[MAX_PROC];
100
  int new_slice[MAX_PROC];
101
  int new_control[MAX_PROC];
102
 
2 pj 103
} POSIX_level_des;
104
 
105
/* This is not efficient but very fair :-)
106
   The need of all this stuff is because if a task execute a long time
107
   due to (shadow!) priority inheritance, then the task shall go to the
108
   tail of the queue many times... */
38 pj 109
static PID POSIX_public_scheduler(LEVEL l)
2 pj 110
{
111
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
112
 
113
  PID p;
114
 
115
  int prio;
116
 
117
  prio = lev->maxpriority;
118
 
119
  for (;;) {
29 pj 120
    p = iq_query_first(&lev->ready[prio]);
2 pj 121
    if (p == NIL) {
122
      if (prio) {
123
        prio--;
124
        continue;
125
      }
126
      else
127
        return NIL;
128
    }
129
 
130
    if ((proc_table[p].control & CONTROL_CAP) &&
131
        (proc_table[p].avail_time <= 0)) {
132
      proc_table[p].avail_time += proc_table[p].wcet;
29 pj 133
      iq_extract(p,&lev->ready[prio]);
134
      iq_insertlast(p,&lev->ready[prio]);
2 pj 135
    }
136
    else
137
      return p;
138
  }
139
}
140
 
38 pj 141
static int POSIX_public_create(LEVEL l, PID p, TASK_MODEL *m)
2 pj 142
{
38 pj 143
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
144
  NRT_TASK_MODEL *nrt;
2 pj 145
 
38 pj 146
  if (m->pclass != NRT_PCLASS) return -1;
147
  if (m->level != 0 && m->level != l) return -1;
2 pj 148
 
38 pj 149
  nrt = (NRT_TASK_MODEL *)m;
2 pj 150
 
151
  /* the task state is set at SLEEP by the general task_create */
152
 
153
  /* I used the wcet field because using wcet can account if a task
154
     consume more than the timeslice... */
155
 
156
  if (nrt->inherit == NRT_INHERIT_SCHED &&
157
      proc_table[exec_shadow].task_level == l) {
158
    /* We inherit the scheduling properties if the scheduling level
159
       *is* the same */
29 pj 160
    lev->priority[p] = lev->priority[exec_shadow];
2 pj 161
 
162
    proc_table[p].avail_time = proc_table[exec_shadow].avail_time;
163
    proc_table[p].wcet       = proc_table[exec_shadow].wcet;
164
 
165
    proc_table[p].control = (proc_table[p].control & ~CONTROL_CAP) |
166
                            (proc_table[exec_shadow].control & CONTROL_CAP);
167
 
168
    lev->nact[p] = (lev->nact[exec_shadow] == -1) ? -1 : 0;
169
  }
170
  else {
29 pj 171
    lev->priority[p] = nrt->weight;
2 pj 172
 
173
    if (nrt->slice) {
174
      proc_table[p].avail_time = nrt->slice;
175
      proc_table[p].wcet       = nrt->slice;
176
    }
177
    else {
178
      proc_table[p].avail_time = lev->slice;
179
      proc_table[p].wcet       = lev->slice;
180
    }
181
 
182
    if (nrt->policy == NRT_RR_POLICY)
183
      proc_table[p].control   |= CONTROL_CAP;
184
 
185
    if (nrt->arrivals == SAVE_ARRIVALS)
186
      lev->nact[p] = 0;
187
    else
188
      lev->nact[p] = -1;
189
  }
190
 
870 trimarchi 191
  lev->flag[p] = 0;
192
 
2 pj 193
  return 0; /* OK */
194
}
195
 
38 pj 196
static void POSIX_public_dispatch(LEVEL l, PID p, int nostop)
2 pj 197
{
198
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
199
 
200
  /* the task state is set EXE by the scheduler()
201
     we extract the task from the ready queue
202
     NB: we can't assume that p is the first task in the queue!!! */
29 pj 203
  iq_extract(p, &lev->ready[lev->priority[p]]);
2 pj 204
}
205
 
38 pj 206
static void POSIX_public_epilogue(LEVEL l, PID p)
2 pj 207
{
208
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
209
 
870 trimarchi 210
  /* Change task level */
211
  if (lev->flag[p] & POSIX_CHANGE_LEVEL) {
212
 
213
    STD_command_message msg;
214
 
215
    proc_table[p].status = SLEEP;
216
    proc_table[p].task_level = lev->new_level[p];
217
    msg.command = STD_ACTIVATE_TASK;
218
    level_table[lev->new_level[p]] -> public_message(lev->new_level[p],p,&msg);
219
 
220
    return;
221
 
222
  }
223
 
2 pj 224
  if (lev->yielding) {
225
    lev->yielding = 0;
29 pj 226
    iq_insertlast(p,&lev->ready[lev->priority[p]]);
2 pj 227
  }
228
  /* check if the slice is finished and insert the task in the coPOSIXect
229
     qqueue position */
230
  else if (proc_table[p].control & CONTROL_CAP &&
231
           proc_table[p].avail_time <= 0) {
232
    proc_table[p].avail_time += proc_table[p].wcet;
29 pj 233
    iq_insertlast(p,&lev->ready[lev->priority[p]]);
2 pj 234
  }
235
  else
29 pj 236
    iq_insertfirst(p,&lev->ready[lev->priority[p]]);
2 pj 237
 
238
  proc_table[p].status = POSIX_READY;
239
}
240
 
657 anton 241
static void POSIX_public_activate(LEVEL l, PID p, struct timespec *t)
2 pj 242
{
243
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
244
 
245
  /* Test if we are trying to activate a non sleeping task    */
246
  /* save activation (only if needed...) */
247
  if (proc_table[p].status != SLEEP) {
248
    if (lev->nact[p] != -1)
249
      lev->nact[p]++;
250
    return;
251
  }
252
 
253
  /* Insert task in the correct position */
254
  proc_table[p].status = POSIX_READY;
29 pj 255
  iq_insertlast(p,&lev->ready[lev->priority[p]]);
2 pj 256
}
257
 
38 pj 258
static void POSIX_public_unblock(LEVEL l, PID p)
2 pj 259
{
260
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
261
 
262
  /* Similar to POSIX_task_activate, but we don't check in what state
38 pj 263
     the task is */
2 pj 264
 
265
  /* Insert task in the coPOSIXect position */
266
  proc_table[p].status = POSIX_READY;
29 pj 267
  iq_insertlast(p,&lev->ready[lev->priority[p]]);
2 pj 268
}
269
 
38 pj 270
static void POSIX_public_block(LEVEL l, PID p)
2 pj 271
{
272
  /* Extract the running task from the level
273
     . we have already extract it from the ready queue at the dispatch time.
274
     . the capacity event have to be removed by the generic kernel
275
     . the wcet don't need modification...
276
     . the state of the task is set by the calling function
277
 
278
     So, we do nothing!!!
279
  */
280
}
281
 
870 trimarchi 282
#ifdef OLDVERSION
38 pj 283
static int POSIX_public_message(LEVEL l, PID p, void *m)
2 pj 284
{
285
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
286
 
287
  if (lev->nact[p] > 0) {
288
    /* continue!!!! */
289
    lev->nact[p]--;
29 pj 290
    iq_insertfirst(p,&lev->ready[lev->priority[p]]);
2 pj 291
    proc_table[p].status = POSIX_READY;
292
  }
293
  else
294
    proc_table[p].status = SLEEP;
38 pj 295
 
296
  jet_update_endcycle(); /* Update the Jet data... */
502 giacomo 297
  TRACER_LOGEVENT(FTrace_EVT_task_end_cycle,(unsigned short int)proc_table[p].context,(unsigned int)l);
38 pj 298
 
299
  return 0;
2 pj 300
}
870 trimarchi 301
#else
302
static int POSIX_public_message(LEVEL l, PID p, void *m)
303
{
304
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
305
  STD_command_message *msg;
306
 
307
  NRT_TASK_MODEL *nrt;
2 pj 308
 
870 trimarchi 309
  /* Task Endcycle */
310
  switch ((long)(m)) {
311
 
312
    case (long)(NULL):
313
      if (lev->nact[p] > 0) {
314
        /* continue!!!! */
315
        lev->nact[p]--;
316
        iq_insertfirst(p,&lev->ready[lev->priority[p]]);
317
        proc_table[p].status = POSIX_READY;
318
      } else
319
        proc_table[p].status = SLEEP;
320
 
321
      jet_update_endcycle(); /* Update the Jet data... */
322
      TRACER_LOGEVENT(FTrace_EVT_task_end_cycle,(unsigned short int)proc_table[p].context,(unsigned int)l);
323
 
324
      break;
325
 
326
   /* Task Disable */
327
   case (long)(1):
328
 
329
     break;
330
 
331
   default:
332
 
333
     msg = (STD_command_message *)m;
334
 
335
     switch(msg->command) {
336
       case STD_SET_NEW_LEVEL:
337
 
338
         lev->flag[p] |= POSIX_CHANGE_LEVEL;
339
         lev->new_level[p] = (int)(msg->param);
340
 
341
         break;
342
       case STD_SET_NEW_MODEL:
343
 
344
         nrt = (NRT_TASK_MODEL *)(msg->param);
345
 
346
         lev->priority[p] = nrt->weight;
347
 
348
         if (nrt->slice) {
349
           lev->new_slice[p] = nrt->slice;
350
         } else {
351
           lev->new_slice[p] = 0;
352
         }
353
 
354
         if (nrt->policy == NRT_RR_POLICY)
355
           lev->new_control[p] |= CONTROL_CAP;
356
 
357
         if (nrt->arrivals == SAVE_ARRIVALS)
358
           lev->nact[p] = 0;
359
         else
360
           lev->nact[p] = -1;
361
 
362
         lev->flag[p] = 0;
363
 
364
         break;
365
 
366
       case STD_ACTIVATE_TASK:
367
 
368
         if (lev->new_slice[p]) {
369
           proc_table[p].avail_time = lev->new_slice[p];
370
           proc_table[p].wcet = lev->new_slice[p];
371
         } else {
372
           proc_table[p].avail_time = lev->slice;
373
           proc_table[p].wcet = lev->slice;
374
         }
375
 
376
         proc_table[p].control = lev->new_control[p];
377
 
378
         POSIX_public_activate(l,p, NULL);
379
 
380
         break;
381
 
382
     }
383
 
384
     break;
385
 
386
  }
387
 
388
  return 0;
389
}
390
 
391
#endif
392
 
38 pj 393
static void POSIX_public_end(LEVEL l, PID p)
2 pj 394
{
395
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
396
 
397
  lev->nact[p] = -1;
398
 
399
  /* then, we insert the task in the free queue */
400
  proc_table[p].status = FREE;
29 pj 401
  iq_priority_insert(p,&freedesc);
2 pj 402
}
403
 
404
/* Registration functions */
405
 
406
/*+ This init function install the "main" task +*/
407
static void POSIX_call_main(void *l)
408
{
409
  LEVEL lev;
410
  PID p;
411
  NRT_TASK_MODEL m;
412
  void *mb;
413
 
414
  lev = (LEVEL)l;
415
 
416
  nrt_task_default_model(m);
417
  nrt_task_def_level(m,lev); /* with this we are sure that the task aPOSIXives
418
                                to the coPOSIXect level */
419
 
420
  mb = ((POSIX_level_des *)level_table[lev])->multiboot;
421
  nrt_task_def_arg(m,mb);
422
  nrt_task_def_usemath(m);
423
  nrt_task_def_nokill(m);
424
  nrt_task_def_ctrl_jet(m);
425
  nrt_task_def_weight(m,0);
426
  nrt_task_def_policy(m,NRT_RR_POLICY);
427
  nrt_task_def_inherit(m,NRT_EXPLICIT_SCHED);
428
 
429
  p = task_create("Main", __init__, (TASK_MODEL *)&m, NULL);
430
 
431
  if (p == NIL)
432
    printk("\nPanic!!! can't create main task...\n");
433
 
657 anton 434
  POSIX_public_activate(lev,p,NULL);
2 pj 435
}
436
 
437
 
438
/*+ Registration function:
439
    TIME slice                the slice for the Round Robin queue
440
    int createmain            1 if the level creates the main task 0 otherwise
441
    struct multiboot_info *mb used if createmain specified   +*/
38 pj 442
LEVEL POSIX_register_level(TIME slice,
2 pj 443
                       int createmain,
444
                       struct multiboot_info *mb,
445
                       int prioritylevels)
446
{
447
  LEVEL l;            /* the level that we register */
448
  POSIX_level_des *lev;  /* for readableness only */
449
  PID i;              /* a counter */
450
  int x;              /* a counter */
451
 
452
  printk("POSIX_register_level\n");
453
 
38 pj 454
  l = level_alloc_descriptor(sizeof(POSIX_level_des));
2 pj 455
 
38 pj 456
  lev = (POSIX_level_des *)level_table[l];
2 pj 457
 
458
  /* fill the standard descriptor */
38 pj 459
  lev->l.public_scheduler = POSIX_public_scheduler;
460
  lev->l.public_create    = POSIX_public_create;
461
  lev->l.public_end       = POSIX_public_end;
462
  lev->l.public_dispatch  = POSIX_public_dispatch;
463
  lev->l.public_epilogue  = POSIX_public_epilogue;
464
  lev->l.public_activate  = POSIX_public_activate;
465
  lev->l.public_unblock   = POSIX_public_unblock;
466
  lev->l.public_block     = POSIX_public_block;
467
  lev->l.public_message   = POSIX_public_message;
271 giacomo 468
  lev->l.public_guarantee = NULL;
2 pj 469
 
470
  /* fill the POSIX descriptor part */
471
  for (i = 0; i < MAX_PROC; i++)
472
    lev->nact[i] = -1;
473
 
474
  lev->maxpriority = prioritylevels -1;
475
 
29 pj 476
  lev->ready = (IQUEUE *)kern_alloc(sizeof(IQUEUE) * prioritylevels);
2 pj 477
 
478
  for (x = 0; x < prioritylevels; x++)
29 pj 479
    iq_init(&lev->ready[x], &freedesc, 0);
2 pj 480
 
481
  if (slice < POSIX_MINIMUM_SLICE) slice = POSIX_MINIMUM_SLICE;
482
  if (slice > POSIX_MAXIMUM_SLICE) slice = POSIX_MAXIMUM_SLICE;
483
  lev->slice      = slice;
484
 
485
  lev->multiboot  = mb;
486
 
487
  if (createmain)
488
    sys_atrunlevel(POSIX_call_main,(void *) l, RUNLEVEL_INIT);
38 pj 489
 
490
  return l;
2 pj 491
}
492
 
493
/*+ this function forces the running task to go to his queue tail;
494
    (it works only on the POSIX level) +*/
495
int POSIX_sched_yield(LEVEL l)
496
{
497
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
498
 
499
  if (proc_table[exec_shadow].task_level != l)
500
    return -1;
501
 
502
  proc_table[exec_shadow].context = kern_context_save();
503
  lev->yielding = 1;
504
  scheduler();
505
  kern_context_load(proc_table[exec_shadow].context);
506
  return 0;
507
}
508
 
509
/*+ this function returns the maximum level allowed for the POSIX level +*/
510
int POSIX_get_priority_max(LEVEL l)
511
{
512
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
513
  return lev->maxpriority;
514
}
515
 
516
/*+ this function returns the default timeslice for the POSIX level +*/
517
int POSIX_rr_get_interval(LEVEL l)
518
{
519
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
520
  return lev->slice;
521
}
522
 
523
/*+ this functions returns some paramaters of a task;
524
    policy must be NRT_RR_POLICY or NRT_FIFO_POLICY;
525
    priority must be in the range [0..prioritylevels]
526
    returns ENOSYS or ESRCH if there are problems +*/
527
int POSIX_getschedparam(LEVEL l, PID p, int *policy, int *priority)
528
{
529
  if (p<0 || p>= MAX_PROC || proc_table[p].status == FREE)
530
    return ESRCH;
531
 
532
  if (proc_table[p].task_level != l)
533
    return ENOSYS;
534
 
535
  if (proc_table[p].control & CONTROL_CAP)
536
    *policy = NRT_RR_POLICY;
537
  else
538
    *policy = NRT_FIFO_POLICY;
539
 
29 pj 540
  *priority = ((POSIX_level_des *)(level_table[l]))->priority[p];
2 pj 541
 
542
  return 0;
543
}
544
 
545
/*+ this functions sets paramaters of a task +*/
546
int POSIX_setschedparam(LEVEL l, PID p, int policy, int priority)
547
{
548
  POSIX_level_des *lev = (POSIX_level_des *)(level_table[l]);
549
 
550
  if (p<0 || p>= MAX_PROC || proc_table[p].status == FREE)
551
    return ESRCH;
552
 
553
  if (proc_table[p].task_level != l)
554
    return ENOSYS;
555
 
556
  if (policy == SCHED_RR)
557
    proc_table[p].control |= CONTROL_CAP;
558
  else if (policy == SCHED_FIFO)
559
    proc_table[p].control &= ~CONTROL_CAP;
560
  else
561
    return EINVAL;
562
 
29 pj 563
  if (lev->priority[p] != priority) {
2 pj 564
    if (proc_table[p].status == POSIX_READY) {
29 pj 565
      iq_extract(p,&lev->ready[lev->priority[p]]);
566
      lev->priority[p] = priority;
567
      iq_insertlast(p,&lev->ready[priority]);
2 pj 568
    }
569
    else
29 pj 570
      lev->priority[p] = priority;
2 pj 571
  }
572
 
573
  return 0;
574
}
575
 
576
 
577