Subversion Repositories shark

Rev

Rev 29 | Rev 318 | 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
 ------------
38 pj 21
 CVS :        $Id: grpcreat.c,v 1.3 2003-01-07 17:07:49 pj Exp $
2 pj 22
 
23
 File:        $File$
38 pj 24
 Revision:    $Revision: 1.3 $
25
 Last update: $Date: 2003-01-07 17:07:49 $
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>
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 (;;) {
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;
292
    for (i = 0; i<10000; i++)
293
    kern_printf("!!!\n"); } ll_abort(666);*/
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 */
305
  trc_logevent(TRC_CREATE,&i);
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