Subversion Repositories shark

Rev

Rev 777 | Rev 1618 | 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
 ------------
914 pj 21
 CVS :        $Id: kill.c,v 1.10 2005-01-08 14:42:52 pj Exp $
2 pj 22
 
23
 File:        $File$
914 pj 24
 Revision:    $Revision: 1.10 $
25
 Last update: $Date: 2005-01-08 14:42:52 $
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
 
914 pj 89
      scheduler();
90
 
2 pj 91
      ll_context_to(proc_table[exec_shadow].context);
92
      // never returns!!!
93
    }
94
}
95
 
96
/*+ This function register a cancellation point into the system.
97
    Be careful!!! no check are performed... +*/
98
void register_cancellation_point(int (*func)(PID p, void *arg), void *arg)
99
{
100
  cancellation_table[cancellation_points].test = func;
101
  cancellation_table[cancellation_points].arg = arg;
102
  cancellation_points++;
103
}
104
 
105
 
106
/*+
107
   This function frees the current task descriptor.
108
   It deletes the context and call the task_end and
109
   res_detach functions.
110
+*/
111
void task_makefree(void *ret)
112
{
113
    RLEVEL l;        /* used for managing the res_detach... */
114
    LEVEL lev;       /* for readableness */
115
    PID p;           /* used for controlling shadows */
116
    PID i;           /* used for readableness instead of exec_shadow */
117
 
118
    i = exec_shadow;
327 giacomo 119
 
120
    /* Avoid a double call of task_makefree */
121
    proc_table[i].control |= TASK_MAKEFREE;
2 pj 122
 
123
    /* first, contol if the task is joinable and someone is waiting for him
124
       This checks has to be done before  the shadow check (see below)
125
       because the task join uses the shadow field!!! */
126
    if (proc_table[i].control & TASK_JOINABLE) {
127
      proc_table[i].return_value = ret;
128
      proc_table[i].control |= WAIT_FOR_JOIN;
129
      if (proc_table[i].waiting_for_me != NIL) {
130
        /* someone is waiting for me... wake up him!!!
131
           Note that if the task woken up is killed by someone, the current
132
           task remain undetached; it is correct, as specified in 16.2.3 */
133
        register PID x;
134
        LEVEL l;
135
 
136
        x = proc_table[i].waiting_for_me;
137
        l = proc_table[x].task_level;
38 pj 138
        level_table[l]->public_unblock(l,x);
2 pj 139
 
140
        proc_table[x].shadow = x;
141
      }
142
    }
143
 
144
/*  {
145
   int xxx;
146
   kern_printf("(makefree ");
147
   for (xxx = 0; xxx<7; xxx++) kern_printf("p%d s%d|",xxx, proc_table[xxx].shadow);
148
   kern_printf(")\n");
149
  }*/
150
 
151
    /* we control if the task has someone with the shadow equal to
152
       the task being canceled... */
153
    for (p = 0; p<MAX_PROC; p++)
154
      if (p != i && proc_table[p].shadow == i) {
14 pj 155
        kern_raise(XINVALID_KILL_SHADOW,i);
2 pj 156
        return;
157
      }
158
 
159
    /* we call the cleanups functions */
160
    while (proc_table[i].cleanup_stack) {
161
      kern_sti();
162
      proc_table[i].cleanup_stack->f(proc_table[i].cleanup_stack->a);
163
      kern_cli();
164
      proc_table[i].cleanup_stack = proc_table[i].cleanup_stack->next;
165
    }
166
 
167
    /* call the thread-specific destructors */
168
    call_task_specific_data_destructors();
169
 
170
    /* Free the used context space */
171
    kern_context_delete(proc_table[i].context);
172
 
173
    /* tracer stuff */
777 giacomo 174
    TRACER_LOGEVENT(FTrace_EVT_task_end,(unsigned short int)proc_table[i].context,(unsigned int)i);
2 pj 175
    //kern_printf("[k%i]",i);
176
 
177
    /* Free the used stack area */
178
    /* Warning! we could be executing on the stack we are */
179
    /* going to destroy; this should cause no problem as  */
180
    /* the task_kill() cannot be interrupted & the memory */
181
    /* released can only be reassigned when we exit the   */
182
    /* primitive!                                         */
183
    if (!(proc_table[i].control & STACKADDR_SPECIFIED))
184
      kern_free(proc_table[i].stack,proc_table[i].stacksize);
185
 
186
 
187
    for (l=0; l<res_levels; l++)
188
      resource_table[l]->res_detach(l,i);
189
 
190
    lev = proc_table[i].task_level;
38 pj 191
    level_table[lev]->public_end(lev,i);
2 pj 192
 
193
    /* THIS ASSIGNMENT MUST STAY HERE!!!
194
       if we move it near the scheduler (after the counter checks)
195
       the kernel doesn't work, because:
914 pj 196
       - if the task is the last one, a exit is called, but exec_shadow
197
         is != -1, so theexit calls the task_epilogue that reinsert
2 pj 198
         the KILLED task into the ready queue!!!
199
    */
200
    exec = exec_shadow = -1;
201
 
914 pj 202
    //DON'T REMOVE !!! BUG IF EXEC_SHADOW = -1
203
    //kern_epilogue_macro();
204
    /* there is no epilogue... */
205
    kern_gettime(&schedule_time);        
206
    /* we don't have to manage the capacity... because we are killing    
207
       ourselves */      
208
    if (cap_timer != NIL) {      
209
      event_delete(cap_timer);  
210
      cap_timer = NIL;  
211
    }
212
 
2 pj 213
    /* Decrement the Application task counter and end the system
214
       if necessary*/
215
    if (!(proc_table[i].control & SYSTEM_TASK)) {
216
      //kern_printf("Ûtask%dÛ",task_counter);
217
      task_counter--;
914 pj 218
      if (!task_counter && runlevel == RUNLEVEL_RUNNING) {
219
        _exit_has_been_called = EXIT_CALLED;
220
        ll_context_to(global_context);;
221
      }
2 pj 222
    }
223
    else if (!(proc_table[i].control & NO_KILL)) {
224
      //kern_printf("Ûsyst%dÛ",system_counter);
225
      system_counter--;
914 pj 226
      if (!system_counter && runlevel == RUNLEVEL_SHUTDOWN)
227
        ll_context_to(global_context);
2 pj 228
    }
229
}
230
 
231
/*
232
  This primitive autokills the excuting task; it was used to avoid
233
  that returning from a task cause a jmp to an unpredictable location.
234
 
235
  Now it is obsolete, the task_create_stub do all the works.
236
 
237
  It is used by the Posix layer to implement pthread_exit
238
*/
239
void task_abort(void *returnvalue)
240
{
318 giacomo 241
    SYS_FLAGS f;
2 pj 242
 
318 giacomo 243
    f = kern_fsave();
244
 
2 pj 245
    task_makefree(returnvalue);
246
 
247
    ll_context_to(proc_table[exec_shadow].context);
248
}
249
 
250
/*+
251
  This primitive kills the i-th task, free the descriptor, and the
252
  memory for the stack
253
 
254
  look also at kern_init in kern.c!!!
255
+*/
256
int task_kill(PID i)
257
{
258
    int j;        /* a counter */
318 giacomo 259
    SYS_FLAGS f;
2 pj 260
 
318 giacomo 261
    f = kern_fsave();
2 pj 262
    if (proc_table[i].control & NO_KILL ||
263
        proc_table[i].status == FREE) {
14 pj 264
      errno = EINVALID_KILL;
318 giacomo 265
      kern_frestore(f);
2 pj 266
      return -1;
267
    }
268
 
269
    if (proc_table[i].control & KILL_REQUEST) {
270
      /* the task was already killed before... do nothing!!! */
318 giacomo 271
      kern_frestore(f);
2 pj 272
      return 0;
273
    }
274
 
275
    /* if cancellation is enabled and asyncronous (not deferred!),
276
       and it is a suicide, kill now, otherwise set the cancellation bit */
277
    if (i == exec_shadow &&
278
        proc_table[i].control & KILL_ENABLED &&
279
        !(proc_table[i].control & KILL_DEFERRED)) {
280
      task_makefree(TASK_CANCELED);
281
 
282
      ll_context_to(proc_table[exec_shadow].context);
283
      // never returns!!!
284
    }
285
 
286
    /* check if the task is blocked on a cancellation point */
287
    for (j=0; j<cancellation_points; j++)
288
       if (cancellation_table[j].test(i,cancellation_table[j].arg))
289
         break;
290
 
291
//    kern_printf("Û%d", proc_table[i].control);
292
 
293
    proc_table[i].control |= KILL_REQUEST;
294
 
318 giacomo 295
    kern_frestore(f);
2 pj 296
    return 0;
297
}
298
 
299
 
300
 
301
/* similar to task_kill */
302
int group_kill(WORD g)
303
{
304
    BYTE autokill;
305
    register PID i;
318 giacomo 306
    SYS_FLAGS f;
2 pj 307
 
308
    int j;        /* a counter */
309
 
310
    if (g == 0) {
14 pj 311
      errno = EINVALID_GROUP;
2 pj 312
      return -1;
313
    }
314
 
318 giacomo 315
    f = kern_fsave();
2 pj 316
 
317
    /* Detect suicide */
318
    autokill = (g == proc_table[exec].group);
319
 
320
    for (i=0 ; i <  MAX_PROC; i++) {
321
        if (proc_table[i].control & NO_KILL      ||
322
            proc_table[i].status == FREE         ||
323
            proc_table[i].control & KILL_REQUEST ||
324
            proc_table[i].group != g             )
325
          continue;
326
 
327
        /* if cancellation is enabled and asyncronous (not deferred!),
328
           and it is a suicide, kill now, otherwise set the cancellation bit */
329
        if (i == exec_shadow &&
330
            proc_table[i].control & KILL_ENABLED &&
331
            !(proc_table[i].control & KILL_DEFERRED)) {
332
          task_makefree(TASK_CANCELED);
333
          continue;
334
        }
335
 
336
        /* check if the task is blocked on a cancellation point */
337
        for (j=0; j<cancellation_points; j++)
338
           if (cancellation_table[j].test(i,cancellation_table[j].arg))
339
             break;
340
 
341
        proc_table[i].control |= KILL_REQUEST;
342
 
343
    }
344
 
345
    /* If we were killing ourselves we must switch context */
346
    /* without saving the actual one                       */
347
    if (autokill) {
348
      ll_context_to(proc_table[exec].context);
349
    }
350
    else
318 giacomo 351
      kern_frestore(f);
2 pj 352
 
353
    return 0;
354
}
355
 
356
 
357
/* this function is used into kernel_init to kill all the user tasks when
358
   the system goes to runlevel 2... */
359
void kill_user_tasks()
360
{
361
  PID k;
362
  int j;
363
 
364
  for (k=0; k<MAX_PROC; k++) {
365
    /* kill the task k!!! (see also task_kill in kill.c!!!) */
366
    if (proc_table[k].status == FREE ||
367
        proc_table[k].control & (KILL_REQUEST|NO_KILL|SYSTEM_TASK) )
368
      /* the task was already killed before... do nothing!!! */
369
      continue;
370
 
371
//    kern_printf("ÛKILLING %dÛ",k);
372
 
373
    /* check if the task is blocked on a cancellation point */
374
    for (j=0; j<cancellation_points; j++)
375
       if (cancellation_table[j].test(k,cancellation_table[j].arg))
376
         break;
377
 
378
    proc_table[k].control |= KILL_REQUEST;
379
  }
380
}