Subversion Repositories shark

Rev

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