Subversion Repositories shark

Rev

Rev 38 | Rev 326 | 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
 ------------
318 giacomo 21
 CVS :        $Id: kill.c,v 1.4 2003-11-05 15:05:11 giacomo Exp $
2 pj 22
 
23
 File:        $File$
318 giacomo 24
 Revision:    $Revision: 1.4 $
25
 Last update: $Date: 2003-11-05 15:05:11 $
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
{
318 giacomo 226
    SYS_FLAGS f;
2 pj 227
 
318 giacomo 228
    f = kern_fsave();
229
 
2 pj 230
    task_makefree(returnvalue);
231
 
232
    ll_context_to(proc_table[exec_shadow].context);
233
}
234
 
235
/*+
236
  This primitive kills the i-th task, free the descriptor, and the
237
  memory for the stack
238
 
239
  look also at kern_init in kern.c!!!
240
+*/
241
int task_kill(PID i)
242
{
243
    int j;        /* a counter */
318 giacomo 244
    SYS_FLAGS f;
2 pj 245
 
318 giacomo 246
    f = kern_fsave();
2 pj 247
    if (proc_table[i].control & NO_KILL ||
248
        proc_table[i].status == FREE) {
14 pj 249
      errno = EINVALID_KILL;
318 giacomo 250
      kern_frestore(f);
2 pj 251
      return -1;
252
    }
253
 
254
    if (proc_table[i].control & KILL_REQUEST) {
255
      /* the task was already killed before... do nothing!!! */
318 giacomo 256
      kern_frestore(f);
2 pj 257
      return 0;
258
    }
259
 
260
    /* if cancellation is enabled and asyncronous (not deferred!),
261
       and it is a suicide, kill now, otherwise set the cancellation bit */
262
    if (i == exec_shadow &&
263
        proc_table[i].control & KILL_ENABLED &&
264
        !(proc_table[i].control & KILL_DEFERRED)) {
265
      task_makefree(TASK_CANCELED);
266
 
267
      ll_context_to(proc_table[exec_shadow].context);
268
      // never returns!!!
269
    }
270
 
271
    /* check if the task is blocked on a cancellation point */
272
    for (j=0; j<cancellation_points; j++)
273
       if (cancellation_table[j].test(i,cancellation_table[j].arg))
274
         break;
275
 
276
//    kern_printf("Û%d", proc_table[i].control);
277
 
278
    proc_table[i].control |= KILL_REQUEST;
279
 
318 giacomo 280
    kern_frestore(f);
2 pj 281
    return 0;
282
}
283
 
284
 
285
 
286
/* similar to task_kill */
287
int group_kill(WORD g)
288
{
289
    BYTE autokill;
290
    register PID i;
318 giacomo 291
    SYS_FLAGS f;
2 pj 292
 
293
    int j;        /* a counter */
294
 
295
    if (g == 0) {
14 pj 296
      errno = EINVALID_GROUP;
2 pj 297
      return -1;
298
    }
299
 
318 giacomo 300
    f = kern_fsave();
2 pj 301
 
302
    /* Detect suicide */
303
    autokill = (g == proc_table[exec].group);
304
 
305
    for (i=0 ; i <  MAX_PROC; i++) {
306
        if (proc_table[i].control & NO_KILL      ||
307
            proc_table[i].status == FREE         ||
308
            proc_table[i].control & KILL_REQUEST ||
309
            proc_table[i].group != g             )
310
          continue;
311
 
312
        /* if cancellation is enabled and asyncronous (not deferred!),
313
           and it is a suicide, kill now, otherwise set the cancellation bit */
314
        if (i == exec_shadow &&
315
            proc_table[i].control & KILL_ENABLED &&
316
            !(proc_table[i].control & KILL_DEFERRED)) {
317
          task_makefree(TASK_CANCELED);
318
          continue;
319
        }
320
 
321
        /* check if the task is blocked on a cancellation point */
322
        for (j=0; j<cancellation_points; j++)
323
           if (cancellation_table[j].test(i,cancellation_table[j].arg))
324
             break;
325
 
326
        proc_table[i].control |= KILL_REQUEST;
327
 
328
    }
329
 
330
    /* If we were killing ourselves we must switch context */
331
    /* without saving the actual one                       */
332
    if (autokill) {
333
      ll_context_to(proc_table[exec].context);
334
    }
335
    else
318 giacomo 336
      kern_frestore(f);
2 pj 337
 
338
    return 0;
339
}
340
 
341
 
342
/* this function is used into kernel_init to kill all the user tasks when
343
   the system goes to runlevel 2... */
344
void kill_user_tasks()
345
{
346
  PID k;
347
  int j;
348
 
349
  for (k=0; k<MAX_PROC; k++) {
350
    /* kill the task k!!! (see also task_kill in kill.c!!!) */
351
    if (proc_table[k].status == FREE ||
352
        proc_table[k].control & (KILL_REQUEST|NO_KILL|SYSTEM_TASK) )
353
      /* the task was already killed before... do nothing!!! */
354
      continue;
355
 
356
//    kern_printf("ÛKILLING %dÛ",k);
357
 
358
    /* check if the task is blocked on a cancellation point */
359
    for (j=0; j<cancellation_points; j++)
360
       if (cancellation_table[j].test(k,cancellation_table[j].arg))
361
         break;
362
 
363
    proc_table[k].control |= KILL_REQUEST;
364
  }
365
}