Subversion Repositories shark

Rev

Details | 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
 *   (see the web pages for full authors list)
11
 *
12
 * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
13
 *
14
 * http://www.sssup.it
15
 * http://retis.sssup.it
16
 * http://shark.sssup.it
17
 */
18
 
19
/**
20
 ------------
21
 CVS :        $Id: grpcreat.c,v 1.1.1.1 2002-03-29 14:12:51 pj Exp $
22
 
23
 File:        $File$
24
 Revision:    $Revision: 1.1.1.1 $
25
 Last update: $Date: 2002-03-29 14:12:51 $
26
 ------------
27
 
28
 This file contains:
29
 
30
 - the function that creates a task
31
 
32
**/
33
 
34
/*
35
 * Copyright (C) 2000 Paolo Gai
36
 *
37
 * This program is free software; you can redistribute it and/or modify
38
 * it under the terms of the GNU General Public License as published by
39
 * the Free Software Foundation; either version 2 of the License, or
40
 * (at your option) any later version.
41
 *
42
 * This program is distributed in the hope that it will be useful,
43
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
44
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
45
 * GNU General Public License for more details.
46
 *
47
 * You should have received a copy of the GNU General Public License
48
 * along with this program; if not, write to the Free Software
49
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
50
 *
51
 */
52
 
53
#include <stdarg.h>
54
#include <ll/ll.h>
55
#include <ll/stdlib.h>
56
#include <ll/stdio.h>
57
#include <ll/string.h>
58
#include <kernel/config.h>
59
#include <kernel/model.h>
60
#include <kernel/const.h>
61
#include <sys/types.h>
62
#include <kernel/types.h>
63
#include <kernel/descr.h>
64
#include <errno.h>
65
#include <kernel/var.h>
66
#include <kernel/func.h>
67
#include <kernel/trace.h>
68
 
69
static DWORD unique_task_ID = 0;
70
 
71
/*+ Task create stub:
72
    when a task is created, the context is initialized to call this stub.
73
    Why??? for 2 reasons:
74
    - The signal delivery is done in the kern_context_load. When a task is
75
      created and activated but before the first dispatch, some signals
76
      could arrive... so the first thing a task have to do is to deliver
77
      pending signals...
78
    - When a task ends, it can return a value, so the value can be easily
79
      managed in the stub to implement task_join & co...
80
+*/
81
static void task_create_stub(void *arg)
82
{
83
  void *ret;
84
  kern_after_dispatch();
85
 
86
  ret = proc_table[exec_shadow].body(arg);
87
 
88
  kern_cli();
89
  //  kern_printf("EXIT task %d, value %d\n",exec_shadow,ret); 
90
  task_makefree(ret);
91
  // kern_printf("MAKEFREE return exec_shadow=%d task_counter=%d\n",exec_shadow,task_counter); 
92
 
93
  ll_context_to(proc_table[exec_shadow].context);
94
}
95
 
96
 
97
/*+
98
  Allocate & fill a task descriptor;
99
  After that call the task is ready to be guaranteed.
100
  look at group_create for some other comments :-)
101
  +*/
102
static
103
PID internal_create_init(char *name, /*+ the symbolic name of the task +*/
104
                         TASK (*body)(), /*+ a pointer to the task body    +*/
105
                         TASK_MODEL *m,  /*+ the task model                +*/
106
                         va_list rlist)  /*+ used to manage the resources
107
                                           models +*/
108
{
109
  PID i = NIL;     /* the task descriptor to fill... */
110
  LEVEL l;         /* used for searching the correct level of the task    */
111
  RLEVEL l_res;    /* used for searching the correct resource level ...   */
112
  RES_MODEL *r;    /* used for managing the resources models */
113
  int j;           /* a counter */
114
 
115
  printk("task_create\n");
116
 
117
  /* Get a free descriptor */
118
  for (;;) {
119
    i = q_getfirst(&freedesc);
120
 
121
    /* If no one is available abort the system */
122
    if (i == NIL) {
123
      errno = ENO_AVAIL_TASK;
124
      return -1;
125
    }
126
 
127
    if (!(proc_table[i].control & WAIT_FOR_JOIN))
128
      break;
129
 
130
    proc_table[i].control |= DESCRIPTOR_DISCARDED;
131
  }
132
 
133
  /* Fill in the descriptor */
134
  proc_table[i].task_ID         = unique_task_ID++;
135
  proc_table[i].body            = body;
136
  strncpy(proc_table[i].name,name,19);
137
  proc_table[i].name[19]        = 0;
138
  proc_table[i].status          = SLEEP;    /* Task is not active when created */
139
  proc_table[i].pclass          = m->pclass & 0xFF00;
140
  proc_table[i].group           = m->group;
141
  proc_table[i].stacksize       = (m->stacksize == 0) ? STACK_SIZE : m->stacksize;
142
  proc_table[i].control         = m->control | KILL_DEFERRED | KILL_ENABLED;
143
  proc_table[i].frozen_activations = 0;
144
  proc_table[i].sigmask         = proc_table[exec_shadow].sigmask; /* mask inherit.*/
145
  proc_table[i].sigpending      = 0; /* No pending signal for new tasks*/
146
  proc_table[i].shadow          = i;
147
  proc_table[i].cleanup_stack   = NULL;
148
  proc_table[i].next            = proc_table[i].prev = NIL;
149
  proc_table[i].errnumber       = 0;        /* meaningless value */
150
 
151
  /* Fill jet info */
152
  proc_table[i].jet_tvalid      = 0;
153
  proc_table[i].jet_curr        = 0;
154
  proc_table[i].jet_max         = 0;
155
  proc_table[i].jet_sum         = 0;
156
  proc_table[i].jet_n           = 0;
157
  for (j=0; j<JET_TABLE_DIM; j++)
158
     proc_table[i].jet_table[j] = 0;
159
 
160
  proc_table[i].waiting_for_me  = NIL;
161
  proc_table[i].return_value    = NULL;
162
 
163
  proc_table[i].keys[0] = &proc_table[i].cleanup_stack;
164
  for (j=1; j<PTHREAD_KEYS_MAX; j++)
165
    proc_table[i].keys[j] = NULL;
166
 
167
  /* now, the task descriptor has some fields not initializated:
168
     - master_level   (initialized later, modified by l[]->task_create() )
169
     - task_level     (initialized later in this function)
170
     - context, stack (initialized at the end of this function)
171
     - request_time   (initialized when a request (activation) is issued)
172
     - additional stuff like priority & co. have to be init. only if used...)
173
     - delay_timer    (initialized in __kernel_init__ and mantained coherent
174
                       by the scheduling modules...)
175
     - guest_pclass   (set only in guest_create and used with guest task)
176
  */
177
 
178
  /* search for a level that can manage the task model */
179
  for (l=0; l<sched_levels; l++)
180
    if (level_table[l]->level_accept_task_model(l,m) >= 0)
181
      break;
182
  if (l == sched_levels) {
183
    /* no level can accept the task_model, exit!!! */
184
    proc_table[i].status = FREE;
185
    q_insertfirst(i,&freedesc);
186
    errno = ENO_AVAIL_SCHEDLEVEL;
187
    return -1;
188
  }
189
 
190
  /* initialize task level */
191
  proc_table[i].task_level = l;
192
 
193
  /* calls the task-oriented function task_create */
194
  if (level_table[l]->task_create(l,i,m) < 0) {
195
    /* an error occurred in the task_create */
196
    proc_table[i].status = FREE;
197
    q_insertfirst(i,&freedesc);
198
    errno = ETASK_CREATE;
199
    return -1;
200
  }
201
 
202
  /* register all the resource models passed */
203
  for (;;) {
204
    r = va_arg(rlist,RES_MODEL *);
205
 
206
    if (!r) break;   /* all the resource models are managed */
207
 
208
    /* search for a level that can manage the resource model */
209
    for (l_res=0; l_res<res_levels; l_res++)
210
      if (resource_table[l_res]->level_accept_resource_model(l_res,r) >= 0) {
211
        resource_table[l_res]->res_register(l_res, i, r);
212
        break;
213
      }
214
    if (l_res == res_levels) {
215
      /* no level can accept the resource_model, exit!!! */
216
      /* detach the resources and the task */
217
      group_create_reject(i);
218
      errno = ENO_AVAIL_RESLEVEL;
219
      return -1;
220
    }
221
  }
222
  return i;
223
}
224
 
225
/* This function allow to create a set of tasks without guarantee.
226
   It must be called with interrupts disabled and it must be used with
227
   group_create_accept and group_create_reject.
228
 
229
   This function allocates a task descriptor and fills it.
230
   After that, the guarantee() function should be called to check for task(s)
231
   admission.
232
   Next, each task created with group_create must be accepted with a call to
233
   group_create_accept() or rejected with a call to group_create_reject.
234
 
235
   The function returns the PID of the allocated descriptor, or NIL(-1)
236
   if the descriptor cannot be allocated or some problems arises the creation.
237
   If -1 is returned, errno is set to a value that represent the error:
238
      ENO_AVAIL_TASK       -> no free descriptors available
239
      ENO_AVAIL_SCHEDLEVEL -> there were no scheduling modules that can handle
240
                              the TASK_MODEL *m passed as parameter
241
      ETASK_CREATE         -> there was an error during the creation of the
242
                              task into the scheduling module
243
      ENO_AVAIL_RESLEVEL   -> there were no resource modules that can handle
244
                              one of the RES_MODEL * passed as parameter
245
*/
246
PID group_create(char *name,
247
                 TASK (*body)(),
248
                 TASK_MODEL *m,
249
                 ...)
250
{
251
  PID p;
252
  va_list rlist;
253
 
254
  va_start(rlist, m);
255
  p = internal_create_init(name, body, m, rlist);
256
  va_end(rlist);
257
 
258
  return p;
259
}
260
 
261
/*
262
  This function should be called when a task created with group_create
263
  is successfully guaranteed and accepted in the system.
264
  This function finish the creation process allocating the last resources
265
  for the task (i.e., the stack and the context).
266
  it returns:
267
 
268
  -1 if something goes wrong. In this case, THE TASK IS AUTOMATICALLY REJECTED
269
     AND THE GROUP_CREATE_REJECT MUST NOT BE CALLED.
270
     errno is set to a value that explains the problem occurred:
271
 
272
     ENO_AVAIL_STACK_MEM -> No stack memory available for the task
273
     ENO_AVAIL_TSS       -> No context available for the task (This is a
274
                            CRITICAL error, and usually never happens...)
275
*/
276
int group_create_accept(PID i, TASK_MODEL *m)
277
{
278
  CONTEXT c;       /* the context of the new task */
279
  BYTE *tos;       /* top of stack of the new task */
280
 
281
  /* Allocate a stack for the task, only if stackaddr != NULL */
282
  if (m->stackaddr) {
283
    tos = proc_table[i].stack = m->stackaddr;
284
    proc_table[i].control |= STACKADDR_SPECIFIED;
285
  }
286
  else {
287
    tos = proc_table[i].stack = (BYTE *) kern_alloc(proc_table[i].stacksize);
288
    if (proc_table[i].stack == NULL) {
289
      group_create_reject(i);
290
      errno = ENO_AVAIL_STACK_MEM;
291
      return -1;
292
    }
293
  }
294
 
295
 
296
  /* Set up the initial context */
297
  tos += proc_table[i].stacksize;
298
  c = kern_context_create(task_create_stub,tos,m->arg,NULL,m->control);
299
  // { extern CONTEXT global_context; 
300
  if (!c) { // || c == global_context) {
301
    /*    grx_close();
302
    { int i;
303
    for (i = 0; i<10000; i++)
304
    kern_printf("!!!\n"); } ll_abort(666);*/
305
    kern_free(tos, proc_table[i].stacksize);
306
    group_create_reject(i);
307
    errno = ENO_AVAIL_TSS;
308
    return -1;
309
  }
310
/*
311
  printf_xy(0,0,WHITE,"context = %d global=%d stack=%p",c,global_context,proc_table[i].stack);
312
  }*/
313
  proc_table[i].context = c;
314
 
315
  /* Tracer stuff */
316
  trc_logevent(TRC_CREATE,&i);
317
  //kern_printf("[c%i %i]",i,proc_table[i].context);
318
 
319
  /* Count the task if it is an Application or System Task... */
320
  if (!(m->control & SYSTEM_TASK))
321
    task_counter++;
322
  else if (!(m->control & NO_KILL))
323
    system_counter++;
324
 
325
  return 0;
326
}
327
 
328
/*
329
  This function should be called when a task created with group_create
330
  can not be successfully guaranteed.
331
  This function reject the task from the system.
332
  You cannot use the PID of a rejected task after this call.
333
*/
334
void group_create_reject(PID i)
335
{
336
  LEVEL  l;     /* stores the level of a task */
337
  RLEVEL lr;    /* used for searching the correct resource level ...   */
338
 
339
  for (lr=0; lr<res_levels; lr++)
340
    resource_table[lr]->res_detach(lr,i);
341
 
342
  l = proc_table[i].task_level;  
343
  level_table[l]->task_detach(l,i);
344
 
345
  proc_table[i].status = FREE;
346
 
347
  q_insertfirst(i,&freedesc);
348
}
349
 
350
 
351
 
352
/*+
353
  Allocate & fill a task descriptor; the task is not explicitely
354
  activated; you have to use the task_activate to do this
355
  Just set up the minimum necessary to make thing works well          
356
 
357
  This function creates and guarantees a task using the group_create
358
  functions.
359
  If in your code you never need to create group of tasks, consider replacing
360
  this file with the file kernel/create.c, that handle all the task
361
  creation process in a single function call.
362
+*/
363
PID task_createn(char *name,      /*+ the symbolic name of the task +*/
364
                 TASK (*body)(),  /*+ a pointer to the task body    +*/
365
                 TASK_MODEL *m,   /*+ the task model                +*/
366
                 ...)             /*+ the resources models, a list
367
                                     of RES_MODEL * terminated by NULL +*/
368
{
369
  PID p;           /* the task descriptor to fill... */
370
  va_list rlist;   /* used for managing the resources models */
371
  SYS_FLAGS f;     /* the flags to be restored at the end
372
                      (we must save them because the task_create can be
373
                       called at system initialization) */
374
 
375
  f = kern_fsave();
376
 
377
  va_start(rlist, m);
378
  p = internal_create_init(name, body, m, rlist);
379
  va_end(rlist);
380
 
381
  if (p != NIL) {
382
    if (level_table[proc_table[p].task_level]->level_guarantee)
383
      if (guarantee() < 0) {
384
        group_create_reject(p);
385
        errno = ENO_GUARANTEE;
386
        kern_frestore(f);
387
        return -1;
388
      }
389
 
390
    if (group_create_accept(p,m)) p = -1;
391
  }
392
  kern_frestore(f);
393
 
394
  return p;
395
}
396
 
397
 
398
 
399
 
400
 
401
 
402