Blame |
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
);
}