Subversion Repositories shark

Rev

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

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