Subversion Repositories shark

Rev

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