Subversion Repositories shark

Rev

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