Subversion Repositories shark

Rev

Rev 965 | Go to most recent revision | Details | Last modification | View Log | RSS feed

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