Subversion Repositories shark

Rev

Rev 318 | Rev 385 | Go to most recent revision | 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
 *   (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
 ------------
353 giacomo 21
 CVS :        $Id: grpcreat.c,v 1.5 2003-12-10 16:54:58 giacomo Exp $
2 pj 22
 
23
 File:        $File$
353 giacomo 24
 Revision:    $Revision: 1.5 $
25
 Last update: $Date: 2003-12-10 16:54:58 $
2 pj 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>
353 giacomo 67
//#include <kernel/trace.h>
68
#include <tracer.h>
2 pj 69
 
70
static DWORD unique_task_ID = 0;
71
 
72
/*+ Task create stub:
73
    when a task is created, the context is initialized to call this stub.
74
    Why??? for 2 reasons:
75
    - The signal delivery is done in the kern_context_load. When a task is
76
      created and activated but before the first dispatch, some signals
77
      could arrive... so the first thing a task have to do is to deliver
78
      pending signals...
79
    - When a task ends, it can return a value, so the value can be easily
80
      managed in the stub to implement task_join & co...
81
+*/
82
static void task_create_stub(void *arg)
83
{
84
  void *ret;
85
  kern_after_dispatch();
86
 
87
  ret = proc_table[exec_shadow].body(arg);
88
 
89
  kern_cli();
90
  //  kern_printf("EXIT task %d, value %d\n",exec_shadow,ret); 
91
  task_makefree(ret);
92
  // kern_printf("MAKEFREE return exec_shadow=%d task_counter=%d\n",exec_shadow,task_counter); 
93
 
94
  ll_context_to(proc_table[exec_shadow].context);
95
}
96
 
97
 
98
/*+
99
  Allocate & fill a task descriptor;
100
  After that call the task is ready to be guaranteed.
101
  look at group_create for some other comments :-)
102
  +*/
103
static
104
PID internal_create_init(char *name, /*+ the symbolic name of the task +*/
105
                         TASK (*body)(), /*+ a pointer to the task body    +*/
106
                         TASK_MODEL *m,  /*+ the task model                +*/
107
                         va_list rlist)  /*+ used to manage the resources
108
                                           models +*/
109
{
110
  PID i = NIL;     /* the task descriptor to fill... */
111
  LEVEL l;         /* used for searching the correct level of the task    */
112
  RLEVEL l_res;    /* used for searching the correct resource level ...   */
113
  RES_MODEL *r;    /* used for managing the resources models */
114
  int j;           /* a counter */
115
 
116
  printk("task_create\n");
117
 
118
  /* Get a free descriptor */
119
  for (;;) {
29 pj 120
    i = iq_getfirst(&freedesc);
2 pj 121
 
122
    /* If no one is available abort the system */
123
    if (i == NIL) {
124
      errno = ENO_AVAIL_TASK;
125
      return -1;
126
    }
127
 
128
    if (!(proc_table[i].control & WAIT_FOR_JOIN))
129
      break;
130
 
131
    proc_table[i].control |= DESCRIPTOR_DISCARDED;
132
  }
133
 
134
  /* Fill in the descriptor */
135
  proc_table[i].task_ID         = unique_task_ID++;
136
  proc_table[i].body            = body;
137
  strncpy(proc_table[i].name,name,19);
138
  proc_table[i].name[19]        = 0;
139
  proc_table[i].status          = SLEEP;    /* Task is not active when created */
140
  proc_table[i].pclass          = m->pclass & 0xFF00;
141
  proc_table[i].group           = m->group;
142
  proc_table[i].stacksize       = (m->stacksize == 0) ? STACK_SIZE : m->stacksize;
143
  proc_table[i].control         = m->control | KILL_DEFERRED | KILL_ENABLED;
144
  proc_table[i].frozen_activations = 0;
145
  proc_table[i].sigmask         = proc_table[exec_shadow].sigmask; /* mask inherit.*/
146
  proc_table[i].sigpending      = 0; /* No pending signal for new tasks*/
147
  proc_table[i].shadow          = i;
148
  proc_table[i].cleanup_stack   = NULL;
29 pj 149
  //  proc_table[i].next            = proc_table[i].prev = NIL;
2 pj 150
  proc_table[i].errnumber       = 0;        /* meaningless value */
151
 
152
  /* Fill jet info */
153
  proc_table[i].jet_tvalid      = 0;
154
  proc_table[i].jet_curr        = 0;
155
  proc_table[i].jet_max         = 0;
156
  proc_table[i].jet_sum         = 0;
157
  proc_table[i].jet_n           = 0;
158
  for (j=0; j<JET_TABLE_DIM; j++)
159
     proc_table[i].jet_table[j] = 0;
160
 
161
  proc_table[i].waiting_for_me  = NIL;
162
  proc_table[i].return_value    = NULL;
163
 
164
  proc_table[i].keys[0] = &proc_table[i].cleanup_stack;
165
  for (j=1; j<PTHREAD_KEYS_MAX; j++)
166
    proc_table[i].keys[j] = NULL;
167
 
168
  /* now, the task descriptor has some fields not initializated:
169
     - master_level   (initialized later, modified by l[]->task_create() )
170
     - task_level     (initialized later in this function)
171
     - context, stack (initialized at the end of this function)
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 */
38 pj 179
  for (l=level_first; l != -1; l=level_next[l])
180
    if (level_table[l]->public_create(l,i,m) >= 0)
2 pj 181
      break;
38 pj 182
 
183
  if (l == -1) {
2 pj 184
    /* no level can accept the task_model, exit!!! */
185
    proc_table[i].status = FREE;
29 pj 186
    iq_insertfirst(i,&freedesc);
2 pj 187
    errno = ENO_AVAIL_SCHEDLEVEL;
188
    return -1;
189
  }
190
 
191
  /* initialize task level */
192
  proc_table[i].task_level = l;
193
 
194
  /* register all the resource models passed */
195
  for (;;) {
196
    r = va_arg(rlist,RES_MODEL *);
197
 
198
    if (!r) break;   /* all the resource models are managed */
199
 
200
    /* search for a level that can manage the resource model */
201
    for (l_res=0; l_res<res_levels; l_res++)
38 pj 202
      if (resource_table[l_res]->res_register(l_res, i, r) >= 0)
2 pj 203
        break;
204
    if (l_res == res_levels) {
205
      /* no level can accept the resource_model, exit!!! */
206
      /* detach the resources and the task */
207
      group_create_reject(i);
208
      errno = ENO_AVAIL_RESLEVEL;
209
      return -1;
210
    }
211
  }
212
  return i;
213
}
214
 
215
/* This function allow to create a set of tasks without guarantee.
216
   It must be called with interrupts disabled and it must be used with
217
   group_create_accept and group_create_reject.
218
 
219
   This function allocates a task descriptor and fills it.
220
   After that, the guarantee() function should be called to check for task(s)
221
   admission.
222
   Next, each task created with group_create must be accepted with a call to
223
   group_create_accept() or rejected with a call to group_create_reject.
224
 
225
   The function returns the PID of the allocated descriptor, or NIL(-1)
226
   if the descriptor cannot be allocated or some problems arises the creation.
227
   If -1 is returned, errno is set to a value that represent the error:
228
      ENO_AVAIL_TASK       -> no free descriptors available
229
      ENO_AVAIL_SCHEDLEVEL -> there were no scheduling modules that can handle
230
                              the TASK_MODEL *m passed as parameter
231
      ETASK_CREATE         -> there was an error during the creation of the
232
                              task into the scheduling module
233
      ENO_AVAIL_RESLEVEL   -> there were no resource modules that can handle
234
                              one of the RES_MODEL * passed as parameter
235
*/
236
PID group_create(char *name,
237
                 TASK (*body)(),
238
                 TASK_MODEL *m,
239
                 ...)
240
{
241
  PID p;
242
  va_list rlist;
243
 
244
  va_start(rlist, m);
245
  p = internal_create_init(name, body, m, rlist);
246
  va_end(rlist);
247
 
248
  return p;
249
}
250
 
251
/*
252
  This function should be called when a task created with group_create
253
  is successfully guaranteed and accepted in the system.
254
  This function finish the creation process allocating the last resources
255
  for the task (i.e., the stack and the context).
256
  it returns:
257
 
258
  -1 if something goes wrong. In this case, THE TASK IS AUTOMATICALLY REJECTED
259
     AND THE GROUP_CREATE_REJECT MUST NOT BE CALLED.
260
     errno is set to a value that explains the problem occurred:
261
 
262
     ENO_AVAIL_STACK_MEM -> No stack memory available for the task
263
     ENO_AVAIL_TSS       -> No context available for the task (This is a
264
                            CRITICAL error, and usually never happens...)
265
*/
266
int group_create_accept(PID i, TASK_MODEL *m)
267
{
268
  CONTEXT c;       /* the context of the new task */
269
  BYTE *tos;       /* top of stack of the new task */
270
 
271
  /* Allocate a stack for the task, only if stackaddr != NULL */
272
  if (m->stackaddr) {
273
    tos = proc_table[i].stack = m->stackaddr;
274
    proc_table[i].control |= STACKADDR_SPECIFIED;
275
  }
276
  else {
277
    tos = proc_table[i].stack = (BYTE *) kern_alloc(proc_table[i].stacksize);
278
    if (proc_table[i].stack == NULL) {
279
      group_create_reject(i);
280
      errno = ENO_AVAIL_STACK_MEM;
281
      return -1;
282
    }
283
  }
284
 
285
 
286
  /* Set up the initial context */
287
  tos += proc_table[i].stacksize;
288
  c = kern_context_create(task_create_stub,tos,m->arg,NULL,m->control);
289
  // { extern CONTEXT global_context; 
290
  if (!c) { // || c == global_context) {
291
    /*    grx_close();
292
    { int i;
318 giacomo 293
    for (i = 0; i<10000; i++)
294
    kern_printf("!!!\n"); ll_abort(666);*/
2 pj 295
    kern_free(tos, proc_table[i].stacksize);
296
    group_create_reject(i);
297
    errno = ENO_AVAIL_TSS;
298
    return -1;
299
  }
300
/*
301
  printf_xy(0,0,WHITE,"context = %d global=%d stack=%p",c,global_context,proc_table[i].stack);
302
  }*/
303
  proc_table[i].context = c;
304
 
305
  /* Tracer stuff */
353 giacomo 306
  TRACER_LOGEVENT(FTrace_EVT_task_create,3,i,(int)c);
307
 
2 pj 308
  //kern_printf("[c%i %i]",i,proc_table[i].context);
309
 
310
  /* Count the task if it is an Application or System Task... */
311
  if (!(m->control & SYSTEM_TASK))
312
    task_counter++;
313
  else if (!(m->control & NO_KILL))
314
    system_counter++;
315
 
316
  return 0;
317
}
318
 
319
/*
320
  This function should be called when a task created with group_create
321
  can not be successfully guaranteed.
322
  This function reject the task from the system.
323
  You cannot use the PID of a rejected task after this call.
324
*/
325
void group_create_reject(PID i)
326
{
327
  LEVEL  l;     /* stores the level of a task */
328
  RLEVEL lr;    /* used for searching the correct resource level ...   */
329
 
330
  for (lr=0; lr<res_levels; lr++)
331
    resource_table[lr]->res_detach(lr,i);
332
 
333
  l = proc_table[i].task_level;  
38 pj 334
  level_table[l]->public_detach(l,i);
2 pj 335
 
336
  proc_table[i].status = FREE;
337
 
29 pj 338
  iq_insertfirst(i,&freedesc);
2 pj 339
}
340
 
341
 
342
 
343
/*+
344
  Allocate & fill a task descriptor; the task is not explicitely
345
  activated; you have to use the task_activate to do this
346
  Just set up the minimum necessary to make thing works well          
347
 
348
  This function creates and guarantees a task using the group_create
349
  functions.
350
  If in your code you never need to create group of tasks, consider replacing
351
  this file with the file kernel/create.c, that handle all the task
352
  creation process in a single function call.
353
+*/
354
PID task_createn(char *name,      /*+ the symbolic name of the task +*/
355
                 TASK (*body)(),  /*+ a pointer to the task body    +*/
356
                 TASK_MODEL *m,   /*+ the task model                +*/
357
                 ...)             /*+ the resources models, a list
358
                                     of RES_MODEL * terminated by NULL +*/
359
{
360
  PID p;           /* the task descriptor to fill... */
361
  va_list rlist;   /* used for managing the resources models */
362
  SYS_FLAGS f;     /* the flags to be restored at the end
363
                      (we must save them because the task_create can be
364
                       called at system initialization) */
365
 
366
  f = kern_fsave();
367
 
368
  va_start(rlist, m);
369
  p = internal_create_init(name, body, m, rlist);
370
  va_end(rlist);
371
 
372
  if (p != NIL) {
38 pj 373
    if (level_table[proc_table[p].task_level]->public_guarantee)
2 pj 374
      if (guarantee() < 0) {
375
        group_create_reject(p);
376
        errno = ENO_GUARANTEE;
377
        kern_frestore(f);
378
        return -1;
379
      }
380
 
381
    if (group_create_accept(p,m)) p = -1;
382
  }
383
  kern_frestore(f);
384
 
385
  return p;
386
}
387
 
388
 
389
 
390
 
391
 
392
 
393