Subversion Repositories shark

Rev

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