Subversion Repositories shark

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Project: S.Ha.R.K.
 *
 * Coordinators:
 *   Giorgio Buttazzo    <giorgio@sssup.it>
 *   Paolo Gai           <pj@gandalf.sssup.it>
 *
 * Authors     :
 *   Paolo Gai           <pj@gandalf.sssup.it>
 *   (see the web pages for full authors list)
 *
 * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
 *
 * http://www.sssup.it
 * http://retis.sssup.it
 * http://shark.sssup.it
 */


/**
 ------------
 CVS :        $Id: create.c,v 1.1.1.1 2002-03-29 14:12:51 pj Exp $

 File:        $File$
 Revision:    $Revision: 1.1.1.1 $
 Last update: $Date: 2002-03-29 14:12:51 $
 ------------

 This file contains:

 - the function that creates a task

---------------------------------------------------------------------
---------------------------------------------------------------------
---------------------------------------------------------------------
---------------------------------------------------------------------
IMPORTANT:
THIS FILE CURRENTLY IS NOT COMPILED BECAUSE IT IS SUBSTITUTED BY
THE GRPCREAT.C
IF YOU DON'T USE THE group_create FUNCTION, YOU CAN COMPILE THIS
FILE INSTEAD OF GRPCREAT.C
---------------------------------------------------------------------
---------------------------------------------------------------------
---------------------------------------------------------------------
---------------------------------------------------------------------

**/


/*
 * Copyright (C) 2000 Paolo Gai
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */


#include <stdarg.h>
#include <ll/ll.h>
#include <ll/stdlib.h>
#include <ll/stdio.h>
#include <ll/string.h>
#include <kernel/config.h>
#include <kernel/model.h>
#include <kernel/const.h>
#include <sys/types.h>
#include <kernel/types.h>
#include <kernel/descr.h>
#include <errno.h>
#include <kernel/var.h>
#include <kernel/func.h>
#include <kernel/trace.h>

static DWORD unique_task_ID = 0;

/*+ Task create stub:
    when a task is created, the context is initialized to call this stub.
    Why??? for 2 reasons:
    - The signal delivery is done in the kern_context_load. When a task is
      created and activated but before the first dispatch, some signals
      could arrive... so the first thing a task have to do is to deliver
      pending signals...
    - When a task ends, it can return a value, so the value can be easily
      managed in the stub to implement task_join & co...
+*/

static void task_create_stub(void *arg)
{
  void *ret;
  kern_after_dispatch();

  ret = proc_table[exec_shadow].body(arg);

  kern_cli();
//  kern_printf("EXIT task %d, value %d\n",exec_shadow,ret);
  task_makefree(ret);
//  kern_printf("MAKEFREE return exec_shadow=%d task_counter=%d\n",exec_shadow,task_counter);

  ll_context_to(proc_table[exec_shadow].context);
}

/*+
  Allocate & fill a task descriptor; the task is not explicitely
  activated; you have to use the task_activate to do this
  Just set up the minimum necessary to make thing works well           +*/


PID task_createn(char *name,      /*+ the symbolic name of the task +*/
                 TASK (*body)(),  /*+ a pointer to the task body    +*/
                 TASK_MODEL *m,   /*+ the task model                +*/
                 ...)             /*+ the resources models, a list
                                     of RES_MODEL * terminated by NULL +*/

{
  PID i = NIL;     /* the task descriptor to fill... */
  CONTEXT c;       /* the context of the new task */
  BYTE *tos;       /* top of stack of the new task */
  LEVEL l;         /* used for searching the correct level of the task    */
  RLEVEL l_res;    /* used for searching the correct resource level ...   */
  RLEVEL l_rexit;  /* used for detaching a task from the resources levels */
  va_list rlist;   /* used for managing the resources models */
  RES_MODEL *r;    /*  "    "     "      "      "       "    */
  int j;           /* a counter */
  SYS_FLAGS f;     /* the flags to be restored at the end
                      (we must save them because the task_create can be
                       called at system initialization) */


  f = kern_fsave();

  printk("task_create\n");

  /* Get a free descriptor */
  for (;;) {
    i = q_getfirst(&freedesc);

    /* If no one is available abort the system */
    if (i == NIL) {
      errno = ENO_AVAIL_TASK;
      kern_frestore(f);
      return -1;
    }

    if (!(proc_table[i].control & WAIT_FOR_JOIN))
      break;

    proc_table[i].control |= DESCRIPTOR_DISCARDED;
  }

  /* Fill in the descriptor */
  proc_table[i].task_ID         = unique_task_ID++;
  proc_table[i].body            = body;
  strncpy(proc_table[i].name,name,19);
  proc_table[i].name[19]        = 0;
  proc_table[i].status          = SLEEP;    /* Task is not active when created */
  proc_table[i].pclass          = m->pclass & 0xFF00;
  proc_table[i].group           = m->group;
  proc_table[i].stacksize       = (m->stacksize == 0) ? STACK_SIZE : m->stacksize;
  proc_table[i].control         = m->control | KILL_DEFERRED | KILL_ENABLED;
  proc_table[i].frozen_activations = 0;
  proc_table[i].sigmask         = proc_table[exec_shadow].sigmask; /* mask inherit.*/
  proc_table[i].sigpending      = 0; /* No pending signal for new tasks*/
  proc_table[i].shadow          = i;
  proc_table[i].cleanup_stack   = NULL;
  proc_table[i].next            = proc_table[i].prev = NIL;
  proc_table[i].errnumber       = 0;        /* meaningless value */

  /* Fill jet info */
  proc_table[i].jet_tvalid      = 0;
  proc_table[i].jet_curr        = 0;
  proc_table[i].jet_max         = 0;
  proc_table[i].jet_sum         = 0;
  proc_table[i].jet_n           = 0;
  for (j=0; j<JET_TABLE_DIM; j++)
     proc_table[i].jet_table[j] = 0;

  proc_table[i].waiting_for_me  = NIL;
  proc_table[i].return_value    = NULL;

  proc_table[i].keys[0] = &proc_table[i].cleanup_stack;
  for (j=1; j<PTHREAD_KEYS_MAX; j++)
    proc_table[i].keys[j] = NULL;

  /* now, the task descriptor has some fields not initializated:
     - master_level   (initialized later, modified by l[]->task_create() )
     - task_level     (initialized later in this function)
     - context, stack (initialized at the end of this function)
     - request_time   (initialized when a request (activation) is issued)
     - additional stuff like priority & co. have to be init. only if used...)
     - delay_timer    (initialized in __kernel_init__ and mantained coherent
                       by the scheduling modules...)
     - guest_pclass   (set only in guest_create and used with guest task)
  */


  /* search for a level that can manage the task model */
  for (l=0; l<sched_levels; l++)
    if (level_table[l]->level_accept_task_model(l,m) >= 0)
      break;
  if (l == sched_levels) {
    /* no level can accept the task_model, exit!!! */
    proc_table[i].status = FREE;
    q_insertfirst(i,&freedesc);
    errno = ENO_AVAIL_SCHEDLEVEL;
    kern_frestore(f);
    return -1;
  }

  /* initialize task level and master level */
  proc_table[i].task_level = l;

  /* calls the task-oriented function task_create */
  if (level_table[l]->task_create(l,i,m) < 0) {
    /* an error occurred in the task_create */
    proc_table[i].status = FREE;
    q_insertfirst(i,&freedesc);
    errno = ETASK_CREATE;
    kern_frestore(f);
    return -1;
  }

  /* register all the resource models passed */
  va_start(rlist, m);
  for (;;) {
    r = va_arg(rlist,RES_MODEL *);

    if (!r) break;   /* all the resource models are managed */

    /* search for a level that can manage the resource model */
    for (l_res=0; l_res<res_levels; l_res++)
      if (resource_table[l_res]->level_accept_resource_model(l_res,r) >= 0) {
        resource_table[l_res]->res_register(l_res, i, r);
        break;
      }
    if (l_res == res_levels) {
      /* no level can accept the resource_model, exit!!! */
      /* detach the resources and the task */
      for (l_rexit=0; l_rexit<res_levels; l_rexit++)
        resource_table[l_rexit]->res_detach(l_rexit,i);
      level_table[l]->task_detach(l,i);
      proc_table[i].status = FREE;
      q_insertfirst(i,&freedesc);
      errno = ENO_AVAIL_RESLEVEL;
      kern_frestore(f);
      return -1;
    }
  }
  va_end(rlist);

  /* now we have to do the on-line guarantee of the system...
     The guarantee is made only if the task is inserted in a level that
     uses the guarantee (level_table[l]->level_guarantee != NULL)      */

  if (level_table[l]->level_guarantee)
    if (guarantee() < 0) {
      for (l_rexit=0; l_rexit<res_levels; l_rexit++)
        resource_table[l_rexit]->res_detach(l_rexit,i);
      level_table[l]->task_detach(l,i);
      proc_table[i].status = FREE;
      q_insertfirst(i,&freedesc);
      errno = ENO_GUARANTEE;
      kern_frestore(f);
      return -1;
    }

  /* Allocate a stack for the task, only if stackaddr != NULL */
  if (m->stackaddr) {
    tos = proc_table[i].stack = m->stackaddr;
    proc_table[i].control |= STACKADDR_SPECIFIED;
  }
  else {
    tos = proc_table[i].stack = (BYTE *) kern_alloc(proc_table[i].stacksize);
    if (proc_table[i].stack == NULL) {
      for (l_rexit=0; l_rexit<res_levels; l_rexit++)
        resource_table[l_rexit]->res_detach(l_rexit, i);
      level_table[l]->task_detach(l,i);
      proc_table[i].status = FREE;
      q_insertfirst(i,&freedesc);
      errno = ENO_AVAIL_STACK_MEM;
      kern_frestore(f);
      return -1;
    }
  }

  /* Set up the initial context */
  tos += proc_table[i].stacksize;
  c = kern_context_create(task_create_stub,tos,m->arg,NULL,m->control);
//  { extern CONTEXT global_context;
  if (!c) {// || c == global_context) {
/*    grx_close();
    { int i;
    for (i = 0; i<10000; i++)
    kern_printf("!!!\n"); } ll_abort(666); */

    kern_free(tos, proc_table[i].stacksize);
    for (l_rexit=0; l_rexit<res_levels; l_rexit++)
      resource_table[l_rexit]->res_detach(l_rexit, i);
    level_table[l]->task_detach(l,i);
    proc_table[i].status = FREE;
    q_insertfirst(i,&freedesc);
    errno = ENO_AVAIL_TSS;
    kern_frestore(f);
    return -1;
  }
//  }
  proc_table[i].context = c;

  /* Tracer stuff */
  trc_logevent(TRC_CREATE,&i);
  //kern_printf("[c%i %i]",i,proc_table[i].context);
             
  /* Count the task if it is an Application or System Task... */
  if (!(m->control & SYSTEM_TASK))
    task_counter++;
  else if (!(m->control & NO_KILL))
    system_counter++;

  kern_frestore(f);

  return(i);
}