Subversion Repositories shark

Rev

Rev 353 | Rev 777 | 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: kill.c,v 1.8 2004-03-10 14:51:42 giacomo Exp $
2 pj 22
 
23
 File:        $File$
502 giacomo 24
 Revision:    $Revision: 1.8 $
25
 Last update: $Date: 2004-03-10 14:51:42 $
2 pj 26
 ------------
27
 
28
 This file contains:
29
 
30
 - the function that kill a task (task_kill, group_kill)
31
 - the function that frees a task descriptor (makefree)
32
 - the task_abort
33
 
34
**/
35
 
36
/*
37
 * Copyright (C) 2000 Paolo Gai
38
 *
39
 * This program is free software; you can redistribute it and/or modify
40
 * it under the terms of the GNU General Public License as published by
41
 * the Free Software Foundation; either version 2 of the License, or
42
 * (at your option) any later version.
43
 *
44
 * This program is distributed in the hope that it will be useful,
45
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
46
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
47
 * GNU General Public License for more details.
48
 *
49
 * You should have received a copy of the GNU General Public License
50
 * along with this program; if not, write to the Free Software
51
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
52
 *
53
 */
54
 
55
#include <stdarg.h>
56
#include <ll/ll.h>
57
#include <ll/stdlib.h>
58
#include <ll/stdio.h>
59
#include <ll/string.h>
60
#include <kernel/config.h>
61
#include <kernel/model.h>
62
#include <kernel/const.h>
63
#include <sys/types.h>
64
#include <kernel/types.h>
65
#include <kernel/descr.h>
66
#include <errno.h>
67
#include <kernel/var.h>
68
#include <kernel/func.h>
69
 
353 giacomo 70
#include <tracer.h>
71
 
2 pj 72
/*+ this structure contains the functions to be called to test if a
73
    task is blocked on a cancellation point +*/
74
static struct {
75
  int (*test)(PID p, void *arg);
76
  void *arg;
77
} cancellation_table[MAX_CANCPOINTS];
78
 
79
static int cancellation_points = 0;
80
 
81
void check_killed_async(void)
82
{
83
    if (proc_table[exec_shadow].control & KILL_ENABLED     &&
84
        !(proc_table[exec_shadow].control & KILL_DEFERRED) &&
327 giacomo 85
        proc_table[exec_shadow].control & KILL_REQUEST &&      
86
        !(proc_table[exec_shadow].control & TASK_MAKEFREE)) {
2 pj 87
      task_makefree(TASK_CANCELED);
88
 
89
      ll_context_to(proc_table[exec_shadow].context);
90
      // never returns!!!
91
    }
92
}
93
 
94
/*+ This function register a cancellation point into the system.
95
    Be careful!!! no check are performed... +*/
96
void register_cancellation_point(int (*func)(PID p, void *arg), void *arg)
97
{
98
  cancellation_table[cancellation_points].test = func;
99
  cancellation_table[cancellation_points].arg = arg;
100
  cancellation_points++;
101
}
102
 
103
 
104
/*+
105
   This function frees the current task descriptor.
106
   It deletes the context and call the task_end and
107
   res_detach functions.
108
+*/
109
void task_makefree(void *ret)
110
{
111
    RLEVEL l;        /* used for managing the res_detach... */
112
    LEVEL lev;       /* for readableness */
113
    PID p;           /* used for controlling shadows */
114
    PID i;           /* used for readableness instead of exec_shadow */
115
 
116
    i = exec_shadow;
327 giacomo 117
 
118
    /* Avoid a double call of task_makefree */
119
    proc_table[i].control |= TASK_MAKEFREE;
2 pj 120
 
121
    /* first, contol if the task is joinable and someone is waiting for him
122
       This checks has to be done before  the shadow check (see below)
123
       because the task join uses the shadow field!!! */
124
    if (proc_table[i].control & TASK_JOINABLE) {
125
      proc_table[i].return_value = ret;
126
      proc_table[i].control |= WAIT_FOR_JOIN;
127
      if (proc_table[i].waiting_for_me != NIL) {
128
        /* someone is waiting for me... wake up him!!!
129
           Note that if the task woken up is killed by someone, the current
130
           task remain undetached; it is correct, as specified in 16.2.3 */
131
        register PID x;
132
        LEVEL l;
133
 
134
        x = proc_table[i].waiting_for_me;
135
        l = proc_table[x].task_level;
38 pj 136
        level_table[l]->public_unblock(l,x);
2 pj 137
 
138
        proc_table[x].shadow = x;
139
      }
140
    }
141
 
142
/*  {
143
   int xxx;
144
   kern_printf("(makefree ");
145
   for (xxx = 0; xxx<7; xxx++) kern_printf("p%d s%d|",xxx, proc_table[xxx].shadow);
146
   kern_printf(")\n");
147
  }*/
148
 
149
    /* we control if the task has someone with the shadow equal to
150
       the task being canceled... */
151
    for (p = 0; p<MAX_PROC; p++)
152
      if (p != i && proc_table[p].shadow == i) {
14 pj 153
        kern_raise(XINVALID_KILL_SHADOW,i);
2 pj 154
        return;
155
      }
156
 
157
    /* we call the cleanups functions */
158
    while (proc_table[i].cleanup_stack) {
159
      kern_sti();
160
      proc_table[i].cleanup_stack->f(proc_table[i].cleanup_stack->a);
161
      kern_cli();
162
      proc_table[i].cleanup_stack = proc_table[i].cleanup_stack->next;
163
    }
164
 
165
    /* call the thread-specific destructors */
166
    call_task_specific_data_destructors();
167
 
168
    /* Free the used context space */
169
    kern_context_delete(proc_table[i].context);
170
 
171
    /* tracer stuff */
502 giacomo 172
    TRACER_LOGEVENT(FTrace_EVT_task_end,(unsigned short int)i,0);
2 pj 173
    //kern_printf("[k%i]",i);
174
 
175
    /* Free the used stack area */
176
    /* Warning! we could be executing on the stack we are */
177
    /* going to destroy; this should cause no problem as  */
178
    /* the task_kill() cannot be interrupted & the memory */
179
    /* released can only be reassigned when we exit the   */
180
    /* primitive!                                         */
181
    if (!(proc_table[i].control & STACKADDR_SPECIFIED))
182
      kern_free(proc_table[i].stack,proc_table[i].stacksize);
183
 
184
 
185
    for (l=0; l<res_levels; l++)
186
      resource_table[l]->res_detach(l,i);
187
 
188
    lev = proc_table[i].task_level;
38 pj 189
    level_table[lev]->public_end(lev,i);
2 pj 190
 
191
    /* THIS ASSIGNMENT MUST STAY HERE!!!
192
       if we move it near the scheduler (after the counter checks)
193
       the kernel doesn't work, because:
194
       - if the task is the last one, a sys_end is called, but exec_shadow
195
         is != -1, so the sys_end calls the task_epilogue that reinsert
196
         the KILLED task into the ready queue!!!
197
    */
198
    exec = exec_shadow = -1;
199
 
200
    /* Decrement the Application task counter and end the system
201
       if necessary*/
202
    if (!(proc_table[i].control & SYSTEM_TASK)) {
203
      //kern_printf("Ûtask%dÛ",task_counter);
204
      task_counter--;
205
      if (!task_counter)
206
        sys_end();
207
    }
208
    else if (!(proc_table[i].control & NO_KILL)) {
209
      //kern_printf("Ûsyst%dÛ",system_counter);
210
      system_counter--;
211
      if (!system_counter)
212
        sys_end();
213
    }
214
 
326 giacomo 215
    //DON'T REMOVE !!! BUG IF EXEC_SHADOW = -1
216
    //kern_epilogue_macro();
2 pj 217
    /* there is no epilogue... */
327 giacomo 218
    kern_gettime(&schedule_time);        
219
    /* we don't have to manage the capacity... because we are killing    
220
       ourselves */      
221
    if (cap_timer != NIL) {      
222
      event_delete(cap_timer);  
223
      cap_timer = NIL;  
224
    }
38 pj 225
 
2 pj 226
    scheduler();
227
}
228
 
229
/*
230
  This primitive autokills the excuting task; it was used to avoid
231
  that returning from a task cause a jmp to an unpredictable location.
232
 
233
  Now it is obsolete, the task_create_stub do all the works.
234
 
235
  It is used by the Posix layer to implement pthread_exit
236
*/
237
void task_abort(void *returnvalue)
238
{
318 giacomo 239
    SYS_FLAGS f;
2 pj 240
 
318 giacomo 241
    f = kern_fsave();
242
 
2 pj 243
    task_makefree(returnvalue);
244
 
245
    ll_context_to(proc_table[exec_shadow].context);
246
}
247
 
248
/*+
249
  This primitive kills the i-th task, free the descriptor, and the
250
  memory for the stack
251
 
252
  look also at kern_init in kern.c!!!
253
+*/
254
int task_kill(PID i)
255
{
256
    int j;        /* a counter */
318 giacomo 257
    SYS_FLAGS f;
2 pj 258
 
318 giacomo 259
    f = kern_fsave();
2 pj 260
    if (proc_table[i].control & NO_KILL ||
261
        proc_table[i].status == FREE) {
14 pj 262
      errno = EINVALID_KILL;
318 giacomo 263
      kern_frestore(f);
2 pj 264
      return -1;
265
    }
266
 
267
    if (proc_table[i].control & KILL_REQUEST) {
268
      /* the task was already killed before... do nothing!!! */
318 giacomo 269
      kern_frestore(f);
2 pj 270
      return 0;
271
    }
272
 
273
    /* if cancellation is enabled and asyncronous (not deferred!),
274
       and it is a suicide, kill now, otherwise set the cancellation bit */
275
    if (i == exec_shadow &&
276
        proc_table[i].control & KILL_ENABLED &&
277
        !(proc_table[i].control & KILL_DEFERRED)) {
278
      task_makefree(TASK_CANCELED);
279
 
280
      ll_context_to(proc_table[exec_shadow].context);
281
      // never returns!!!
282
    }
283
 
284
    /* check if the task is blocked on a cancellation point */
285
    for (j=0; j<cancellation_points; j++)
286
       if (cancellation_table[j].test(i,cancellation_table[j].arg))
287
         break;
288
 
289
//    kern_printf("Û%d", proc_table[i].control);
290
 
291
    proc_table[i].control |= KILL_REQUEST;
292
 
318 giacomo 293
    kern_frestore(f);
2 pj 294
    return 0;
295
}
296
 
297
 
298
 
299
/* similar to task_kill */
300
int group_kill(WORD g)
301
{
302
    BYTE autokill;
303
    register PID i;
318 giacomo 304
    SYS_FLAGS f;
2 pj 305
 
306
    int j;        /* a counter */
307
 
308
    if (g == 0) {
14 pj 309
      errno = EINVALID_GROUP;
2 pj 310
      return -1;
311
    }
312
 
318 giacomo 313
    f = kern_fsave();
2 pj 314
 
315
    /* Detect suicide */
316
    autokill = (g == proc_table[exec].group);
317
 
318
    for (i=0 ; i <  MAX_PROC; i++) {
319
        if (proc_table[i].control & NO_KILL      ||
320
            proc_table[i].status == FREE         ||
321
            proc_table[i].control & KILL_REQUEST ||
322
            proc_table[i].group != g             )
323
          continue;
324
 
325
        /* if cancellation is enabled and asyncronous (not deferred!),
326
           and it is a suicide, kill now, otherwise set the cancellation bit */
327
        if (i == exec_shadow &&
328
            proc_table[i].control & KILL_ENABLED &&
329
            !(proc_table[i].control & KILL_DEFERRED)) {
330
          task_makefree(TASK_CANCELED);
331
          continue;
332
        }
333
 
334
        /* check if the task is blocked on a cancellation point */
335
        for (j=0; j<cancellation_points; j++)
336
           if (cancellation_table[j].test(i,cancellation_table[j].arg))
337
             break;
338
 
339
        proc_table[i].control |= KILL_REQUEST;
340
 
341
    }
342
 
343
    /* If we were killing ourselves we must switch context */
344
    /* without saving the actual one                       */
345
    if (autokill) {
346
      ll_context_to(proc_table[exec].context);
347
    }
348
    else
318 giacomo 349
      kern_frestore(f);
2 pj 350
 
351
    return 0;
352
}
353
 
354
 
355
/* this function is used into kernel_init to kill all the user tasks when
356
   the system goes to runlevel 2... */
357
void kill_user_tasks()
358
{
359
  PID k;
360
  int j;
361
 
362
  for (k=0; k<MAX_PROC; k++) {
363
    /* kill the task k!!! (see also task_kill in kill.c!!!) */
364
    if (proc_table[k].status == FREE ||
365
        proc_table[k].control & (KILL_REQUEST|NO_KILL|SYSTEM_TASK) )
366
      /* the task was already killed before... do nothing!!! */
367
      continue;
368
 
369
//    kern_printf("ÛKILLING %dÛ",k);
370
 
371
    /* check if the task is blocked on a cancellation point */
372
    for (j=0; j<cancellation_points; j++)
373
       if (cancellation_table[j].test(k,cancellation_table[j].arg))
374
         break;
375
 
376
    proc_table[k].control |= KILL_REQUEST;
377
  }
378
}