OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [kernel/] [exit.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 *  linux/kernel/exit.c
3
 *
4
 *  Copyright (C) 1991, 1992  Linus Torvalds
5
 */
6
 
7
/*
8
 * uClinux revisions for NO_MM
9
 * Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>,
10
 *                     The Silver Hammer Group, Ltd.
11
 */
12
 
13
#undef DEBUG_PROC_TREE
14
 
15
#include <linux/wait.h>
16
#include <linux/errno.h>
17
#include <linux/signal.h>
18
#include <linux/sched.h>
19
#include <linux/kernel.h>
20
#include <linux/resource.h>
21
#include <linux/mm.h>
22
#include <linux/tty.h>
23
#include <linux/malloc.h>
24
#include <linux/interrupt.h>
25
 
26
#include <asm/segment.h>
27
#include <asm/pgtable.h>
28
 
29
extern void sem_exit (void);
30
extern int acct_process (long exitcode);
31
extern void kerneld_exit(void);
32
 
33
int getrusage(struct task_struct *, int, struct rusage *);
34
 
35
static inline void generate(unsigned long sig, struct task_struct * p)
36
{
37
        unsigned long flags;
38
        unsigned long mask = 1 << (sig-1);
39
        struct sigaction * sa = sig + p->sig->action - 1;
40
 
41
        /*
42
         * Optimize away the signal, if it's a signal that can
43
         * be handled immediately (ie non-blocked and untraced)
44
         * and that is ignored (either explicitly or by default)
45
         */
46
        save_flags(flags); cli();
47
        if (!(mask & p->blocked) && !(p->flags & PF_PTRACED)) {
48
                /* don't bother with ignored signals (but SIGCHLD is special) */
49
                if (sa->sa_handler == SIG_IGN && sig != SIGCHLD) {
50
                        restore_flags(flags);
51
                        return;
52
                }
53
                /* some signals are ignored by default.. (but SIGCONT already did its deed) */
54
                if ((sa->sa_handler == SIG_DFL) &&
55
                    (sig == SIGCONT || sig == SIGCHLD || sig == SIGWINCH || sig == SIGURG)) {
56
                        restore_flags(flags);
57
                        return;
58
                }
59
        }
60
        p->signal |= mask;
61
        if (p->state == TASK_INTERRUPTIBLE && (p->signal & ~p->blocked))
62
                wake_up_process(p);
63
        restore_flags(flags);
64
}
65
 
66
/*
67
 * Force a signal that the process can't ignore: if necessary
68
 * we unblock the signal and change any SIG_IGN to SIG_DFL.
69
 */
70
void force_sig(unsigned long sig, struct task_struct * p)
71
{
72
        sig--;
73
        if (p->sig) {
74
                unsigned long flags;
75
                unsigned long mask = 1UL << sig;
76
                struct sigaction *sa = p->sig->action + sig;
77
 
78
                save_flags(flags); cli();
79
                p->signal |= mask;
80
                p->blocked &= ~mask;
81
                if (sa->sa_handler == SIG_IGN)
82
                        sa->sa_handler = SIG_DFL;
83
                if (p->state == TASK_INTERRUPTIBLE)
84
                        wake_up_process(p);
85
                restore_flags(flags);
86
        }
87
}
88
 
89
 
90
int send_sig(unsigned long sig,struct task_struct * p,int priv)
91
{
92
        unsigned long flags;
93
 
94
        if (!p || sig > 32)
95
                return -EINVAL;
96
        if (!priv && ((sig != SIGCONT) || (current->session != p->session)) &&
97
            (current->euid ^ p->suid) && (current->euid ^ p->uid) &&
98
            (current->uid ^ p->suid) && (current->uid ^ p->uid) &&
99
            !suser())
100
                return -EPERM;
101
        if (!sig)
102
                return 0;
103
        /*
104
         * Forget it if the process is already zombie'd.
105
         */
106
        if (!p->sig)
107
                return 0;
108
        save_flags(flags); cli();
109
        if ((sig == SIGKILL) || (sig == SIGCONT)) {
110
                if (p->state == TASK_STOPPED)
111
                        wake_up_process(p);
112
                p->exit_code = 0;
113
                p->signal &= ~( (1<<(SIGSTOP-1)) | (1<<(SIGTSTP-1)) |
114
                                (1<<(SIGTTIN-1)) | (1<<(SIGTTOU-1)) );
115
        }
116
        if (sig == SIGSTOP || sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU)
117
                p->signal &= ~(1<<(SIGCONT-1));
118
        restore_flags(flags);
119
 
120
        /* Actually generate the signal */
121
        generate(sig,p);
122
        return 0;
123
}
124
 
125
void notify_parent(struct task_struct * tsk, int signal)
126
{
127
        send_sig(signal, tsk->p_pptr, 1);
128
        wake_up_interruptible(&tsk->p_pptr->wait_chldexit);
129
}
130
 
131
void release(struct task_struct * p)
132
{
133
        int i;
134
 
135
        if (!p)
136
                return;
137
        if (p == current) {
138
                printk("task releasing itself\n");
139
                return;
140
        }
141
        for (i=1 ; i<NR_TASKS ; i++)
142
                if (task[i] == p) {
143
                        nr_tasks--;
144
                        task[i] = NULL;
145
                        REMOVE_LINKS(p);
146
                        release_thread(p);
147
                        if (STACK_MAGIC != *(unsigned long *)p->kernel_stack_page)
148
                                printk(KERN_ALERT "release: %s kernel stack corruption. Aiee\n", p->comm);
149
                        free_kernel_stack(p->kernel_stack_page);
150
                        current->cmin_flt += p->min_flt + p->cmin_flt;
151
                        current->cmaj_flt += p->maj_flt + p->cmaj_flt;
152
                        current->cnswap += p->nswap + p->cnswap;
153
                        kfree(p);
154
                        return;
155
                }
156
        panic("trying to release non-existent task");
157
}
158
 
159
#ifdef DEBUG_PROC_TREE
160
/*
161
 * Check to see if a task_struct pointer is present in the task[] array
162
 * Return 0 if found, and 1 if not found.
163
 */
164
int bad_task_ptr(struct task_struct *p)
165
{
166
        int     i;
167
 
168
        if (!p)
169
                return 0;
170
        for (i=0 ; i<NR_TASKS ; i++)
171
                if (task[i] == p)
172
                        return 0;
173
        return 1;
174
}
175
 
176
/*
177
 * This routine scans the pid tree and makes sure the rep invariant still
178
 * holds.  Used for debugging only, since it's very slow....
179
 *
180
 * It looks a lot scarier than it really is.... we're doing nothing more
181
 * than verifying the doubly-linked list found in p_ysptr and p_osptr,
182
 * and checking it corresponds with the process tree defined by p_cptr and
183
 * p_pptr;
184
 */
185
void audit_ptree(void)
186
{
187
        int     i;
188
 
189
        for (i=1 ; i<NR_TASKS ; i++) {
190
                if (!task[i])
191
                        continue;
192
                if (bad_task_ptr(task[i]->p_pptr))
193
                        printk("Warning, pid %d's parent link is bad\n",
194
                                task[i]->pid);
195
                if (bad_task_ptr(task[i]->p_cptr))
196
                        printk("Warning, pid %d's child link is bad\n",
197
                                task[i]->pid);
198
                if (bad_task_ptr(task[i]->p_ysptr))
199
                        printk("Warning, pid %d's ys link is bad\n",
200
                                task[i]->pid);
201
                if (bad_task_ptr(task[i]->p_osptr))
202
                        printk("Warning, pid %d's os link is bad\n",
203
                                task[i]->pid);
204
                if (task[i]->p_pptr == task[i])
205
                        printk("Warning, pid %d parent link points to self\n",
206
                                task[i]->pid);
207
                if (task[i]->p_cptr == task[i])
208
                        printk("Warning, pid %d child link points to self\n",
209
                                task[i]->pid);
210
                if (task[i]->p_ysptr == task[i])
211
                        printk("Warning, pid %d ys link points to self\n",
212
                                task[i]->pid);
213
                if (task[i]->p_osptr == task[i])
214
                        printk("Warning, pid %d os link points to self\n",
215
                                task[i]->pid);
216
                if (task[i]->p_osptr) {
217
                        if (task[i]->p_pptr != task[i]->p_osptr->p_pptr)
218
                                printk(
219
                        "Warning, pid %d older sibling %d parent is %d\n",
220
                                task[i]->pid, task[i]->p_osptr->pid,
221
                                task[i]->p_osptr->p_pptr->pid);
222
                        if (task[i]->p_osptr->p_ysptr != task[i])
223
                                printk(
224
                "Warning, pid %d older sibling %d has mismatched ys link\n",
225
                                task[i]->pid, task[i]->p_osptr->pid);
226
                }
227
                if (task[i]->p_ysptr) {
228
                        if (task[i]->p_pptr != task[i]->p_ysptr->p_pptr)
229
                                printk(
230
                        "Warning, pid %d younger sibling %d parent is %d\n",
231
                                task[i]->pid, task[i]->p_osptr->pid,
232
                                task[i]->p_osptr->p_pptr->pid);
233
                        if (task[i]->p_ysptr->p_osptr != task[i])
234
                                printk(
235
                "Warning, pid %d younger sibling %d has mismatched os link\n",
236
                                task[i]->pid, task[i]->p_ysptr->pid);
237
                }
238
                if (task[i]->p_cptr) {
239
                        if (task[i]->p_cptr->p_pptr != task[i])
240
                                printk(
241
                        "Warning, pid %d youngest child %d has mismatched parent link\n",
242
                                task[i]->pid, task[i]->p_cptr->pid);
243
                        if (task[i]->p_cptr->p_ysptr)
244
                                printk(
245
                        "Warning, pid %d youngest child %d has non-NULL ys link\n",
246
                                task[i]->pid, task[i]->p_cptr->pid);
247
                }
248
        }
249
}
250
#endif /* DEBUG_PROC_TREE */
251
 
252
/*
253
 * This checks not only the pgrp, but falls back on the pid if no
254
 * satisfactory pgrp is found. I dunno - gdb doesn't work correctly
255
 * without this...
256
 */
257
int session_of_pgrp(int pgrp)
258
{
259
        struct task_struct *p;
260
        int fallback;
261
 
262
        fallback = -1;
263
        for_each_task(p) {
264
                if (p->session <= 0)
265
                        continue;
266
                if (p->pgrp == pgrp)
267
                        return p->session;
268
                if (p->pid == pgrp)
269
                        fallback = p->session;
270
        }
271
        return fallback;
272
}
273
 
274
/*
275
 * kill_pg() sends a signal to a process group: this is what the tty
276
 * control characters do (^C, ^Z etc)
277
 */
278
int kill_pg(int pgrp, int sig, int priv)
279
{
280
        struct task_struct *p;
281
        int err,retval = -ESRCH;
282
        int found = 0;
283
 
284
        if (sig<0 || sig>32 || pgrp<=0)
285
                return -EINVAL;
286
        for_each_task(p) {
287
                if (p->pgrp == pgrp) {
288
                        if ((err = send_sig(sig,p,priv)) != 0)
289
                                retval = err;
290
                        else
291
                                found++;
292
                }
293
        }
294
        return(found ? 0 : retval);
295
}
296
 
297
/*
298
 * kill_sl() sends a signal to the session leader: this is used
299
 * to send SIGHUP to the controlling process of a terminal when
300
 * the connection is lost.
301
 */
302
int kill_sl(int sess, int sig, int priv)
303
{
304
        struct task_struct *p;
305
        int err,retval = -ESRCH;
306
        int found = 0;
307
 
308
        if (sig<0 || sig>32 || sess<=0)
309
                return -EINVAL;
310
        for_each_task(p) {
311
                if (p->session == sess && p->leader) {
312
                        if ((err = send_sig(sig,p,priv)) != 0)
313
                                retval = err;
314
                        else
315
                                found++;
316
                }
317
        }
318
        return(found ? 0 : retval);
319
}
320
 
321
int kill_proc(int pid, int sig, int priv)
322
{
323
        struct task_struct *p;
324
 
325
        if (sig<0 || sig>32)
326
                return -EINVAL;
327
        for_each_task(p) {
328
                if (p && p->pid == pid)
329
                        return send_sig(sig,p,priv);
330
        }
331
        return(-ESRCH);
332
}
333
 
334
/*
335
 * POSIX specifies that kill(-1,sig) is unspecified, but what we have
336
 * is probably wrong.  Should make it like BSD or SYSV.
337
 */
338
asmlinkage int sys_kill(int pid,int sig)
339
{
340
        int err, retval = 0, count = 0;
341
 
342
        if (!pid)
343
                return(kill_pg(current->pgrp,sig,0));
344
        if (pid == -1) {
345
                struct task_struct * p;
346
                for_each_task(p) {
347
                        if (p->pid > 1 && p != current) {
348
                                ++count;
349
                                if ((err = send_sig(sig,p,0)) != -EPERM)
350
                                        retval = err;
351
                        }
352
                }
353
                return(count ? retval : -ESRCH);
354
        }
355
        if (pid < 0)
356
                return(kill_pg(-pid,sig,0));
357
        /* Normal kill */
358
        return(kill_proc(pid,sig,0));
359
}
360
 
361
/*
362
 * Determine if a process group is "orphaned", according to the POSIX
363
 * definition in 2.2.2.52.  Orphaned process groups are not to be affected
364
 * by terminal-generated stop signals.  Newly orphaned process groups are
365
 * to receive a SIGHUP and a SIGCONT.
366
 *
367
 * "I ask you, have you ever known what it is to be an orphan?"
368
 */
369
static int will_become_orphaned_pgrp(int pgrp, struct task_struct * ignored_task)
370
{
371
        struct task_struct *p;
372
 
373
        for_each_task(p) {
374
                if ((p == ignored_task) || (p->pgrp != pgrp) ||
375
                    (p->state == TASK_ZOMBIE) ||
376
                    (p->p_pptr->pid == 1))
377
                        continue;
378
                if ((p->p_pptr->pgrp != pgrp) &&
379
                    (p->p_pptr->session == p->session))
380
                        return 0;
381
        }
382
        return(1);      /* (sighing) "Often!" */
383
}
384
 
385
int is_orphaned_pgrp(int pgrp)
386
{
387
        return will_become_orphaned_pgrp(pgrp, 0);
388
}
389
 
390
static inline int has_stopped_jobs(int pgrp)
391
{
392
        struct task_struct * p;
393
 
394
        for_each_task(p) {
395
                if (p->pgrp != pgrp)
396
                        continue;
397
                if (p->state == TASK_STOPPED)
398
                        return(1);
399
        }
400
        return(0);
401
}
402
 
403
static inline void forget_original_parent(struct task_struct * father)
404
{
405
        struct task_struct * p;
406
 
407
        for_each_task(p) {
408
                if (p->p_opptr == father) {
409
                        p->exit_signal = SIGCHLD;
410
                        p->p_opptr = task[smp_num_cpus] ? : task[0];     /* init */
411
                }
412
        }
413
}
414
 
415
static inline void close_files(struct files_struct * files)
416
{
417
        int i, j;
418
 
419
        j = 0;
420
        for (;;) {
421
                unsigned long set = files->open_fds.fds_bits[j];
422
                i = j * __NFDBITS;
423
                j++;
424
                if (i >= NR_OPEN)
425
                        break;
426
                while (set) {
427
                        if (set & 1) {
428
                                struct file * file = files->fd[i];
429
                                if (file) {
430
                                        files->fd[i] = NULL;
431
                                        close_fp(file);
432
                                }
433
                        }
434
                        i++;
435
                        set >>= 1;
436
                }
437
        }
438
}
439
 
440
static inline void __exit_files(struct task_struct *tsk)
441
{
442
        struct files_struct * files = tsk->files;
443
 
444
        if (files) {
445
                tsk->files = NULL;
446
                if (!--files->count) {
447
                        close_files(files);
448
                        kfree(files);
449
                }
450
        }
451
}
452
 
453
void exit_files(struct task_struct *tsk)
454
{
455
  __exit_files(tsk);
456
}
457
 
458
static inline void __exit_fs(struct task_struct *tsk)
459
{
460
        struct fs_struct * fs = tsk->fs;
461
 
462
        if (fs) {
463
                tsk->fs = NULL;
464
                if (!--fs->count) {
465
                        iput(fs->root);
466
                        iput(fs->pwd);
467
                        kfree(fs);
468
                }
469
        }
470
}
471
 
472
void exit_fs(struct task_struct *tsk)
473
{
474
  __exit_fs(tsk);
475
}
476
 
477
static inline void __exit_sighand(struct task_struct *tsk)
478
{
479
        struct signal_struct * sig = tsk->sig;
480
 
481
        if (sig) {
482
                tsk->sig = NULL;
483
                if (!--sig->count) {
484
                        kfree(sig);
485
                }
486
        }
487
}
488
 
489
void exit_sighand(struct task_struct *tsk)
490
{
491
        __exit_sighand(tsk);
492
}
493
 
494
static inline void __exit_mm(struct task_struct * tsk)
495
{
496
#ifndef NO_MM
497
        struct mm_struct * mm = tsk->mm;
498
 
499
        /* Set us up to use the kernel mm state */
500
        if (mm != &init_mm) {
501
                flush_cache_mm(mm);
502
                flush_tlb_mm(mm);
503
                tsk->mm = &init_mm;
504
                tsk->swappable = 0;
505
                SET_PAGE_DIR(tsk, swapper_pg_dir);
506
 
507
                /* free the old state - not used any more */
508
                if (!--mm->count) {
509
                        exit_mmap(mm);
510
                        free_page_tables(mm);
511
                        kfree(mm);
512
                }
513
        }
514
#else /* NO_MM */
515
        struct mm_struct * mm = tsk->mm;
516
 
517
        /* Set us up to use the kernel mm state */
518
        if (mm != &init_mm) {
519
 
520
                /* Wake up parent that vforked me */
521
                wake_up(&tsk->p_opptr->mm->vforkwait);
522
 
523
                tsk->mm = &init_mm;
524
                tsk->swappable = 0;
525
 
526
                /* free the old state - not used any more */
527
                if (!--mm->count) {
528
                        exit_mmap(mm);
529
                        kfree(mm);
530
                }
531
        }
532
#endif /* NO_MM */
533
}
534
 
535
void exit_mm(struct task_struct *tsk)
536
{
537
        __exit_mm(tsk);
538
}
539
 
540
/*
541
 * Send signals to all our closest relatives so that they know
542
 * to properly mourn us..
543
 */
544
static void exit_notify(void)
545
{
546
        struct task_struct * p;
547
 
548
        forget_original_parent(current);
549
        /*
550
         * Check to see if any process groups have become orphaned
551
         * as a result of our exiting, and if they have any stopped
552
         * jobs, send them a SIGHUP and then a SIGCONT.  (POSIX 3.2.2.2)
553
         *
554
         * Case i: Our father is in a different pgrp than we are
555
         * and we were the only connection outside, so our pgrp
556
         * is about to become orphaned.
557
         */
558
        if ((current->p_pptr->pgrp != current->pgrp) &&
559
            (current->p_pptr->session == current->session) &&
560
            will_become_orphaned_pgrp(current->pgrp, current) &&
561
            has_stopped_jobs(current->pgrp)) {
562
                kill_pg(current->pgrp,SIGHUP,1);
563
                kill_pg(current->pgrp,SIGCONT,1);
564
        }
565
        /* Let father know we died */
566
        notify_parent(current, current->exit_signal);
567
 
568
        /*
569
         * This loop does two things:
570
         *
571
         * A.  Make init inherit all the child processes
572
         * B.  Check to see if any process groups have become orphaned
573
         *      as a result of our exiting, and if they have any stopped
574
         *      jobs, send them a SIGHUP and then a SIGCONT.  (POSIX 3.2.2.2)
575
         */
576
        while ((p = current->p_cptr) != NULL) {
577
                current->p_cptr = p->p_osptr;
578
                p->p_ysptr = NULL;
579
                p->flags &= ~(PF_PTRACED|PF_TRACESYS);
580
 
581
                p->p_pptr = p->p_opptr;
582
                p->p_osptr = p->p_pptr->p_cptr;
583
                if (p->p_osptr)
584
                        p->p_osptr->p_ysptr = p;
585
                p->p_pptr->p_cptr = p;
586
                if (p->state == TASK_ZOMBIE)
587
                        notify_parent(p, p->exit_signal);
588
 
589
                /*
590
                 * process group orphan check
591
                 * Case ii: Our child is in a different pgrp
592
                 * than we are, and it was the only connection
593
                 * outside, so the child pgrp is now orphaned.
594
                 */
595
                if ((p->pgrp != current->pgrp) &&
596
                    (p->session == current->session) &&
597
                    is_orphaned_pgrp(p->pgrp) &&
598
                    has_stopped_jobs(p->pgrp)) {
599
                        kill_pg(p->pgrp,SIGHUP,1);
600
                        kill_pg(p->pgrp,SIGCONT,1);
601
                }
602
        }
603
        if (current->leader)
604
                disassociate_ctty(1);
605
}
606
 
607
NORET_TYPE void do_exit(long code)
608
{
609
        if (intr_count) {
610
                printk("Aiee, killing interrupt handler\n");
611
                intr_count = 0;
612
        }
613
fake_volatile:
614
        acct_process(code);
615
        current->flags |= PF_EXITING;
616
        del_timer(&current->real_timer);
617
        sem_exit();
618
        kerneld_exit();
619
        __exit_mm(current);
620
        __exit_files(current);
621
        __exit_fs(current);
622
        __exit_sighand(current);
623
        exit_thread();
624
        current->state = TASK_ZOMBIE;
625
        current->exit_code = code;
626
        exit_notify();
627
#ifdef DEBUG_PROC_TREE
628
        audit_ptree();
629
#endif
630
        if (current->exec_domain && current->exec_domain->use_count)
631
                (*current->exec_domain->use_count)--;
632
        if (current->binfmt && current->binfmt->use_count)
633
                (*current->binfmt->use_count)--;
634
        schedule();
635
/*
636
 * In order to get rid of the "volatile function does return" message
637
 * I did this little loop that confuses gcc to think do_exit really
638
 * is volatile. In fact it's schedule() that is volatile in some
639
 * circumstances: when current->state = ZOMBIE, schedule() never
640
 * returns.
641
 *
642
 * In fact the natural way to do all this is to have the label and the
643
 * goto right after each other, but I put the fake_volatile label at
644
 * the start of the function just in case something /really/ bad
645
 * happens, and the schedule returns. This way we can try again. I'm
646
 * not paranoid: it's just that everybody is out to get me.
647
 */
648
        goto fake_volatile;
649
}
650
 
651
asmlinkage int sys_exit(int error_code)
652
{
653
        do_exit((error_code&0xff)<<8);
654
}
655
 
656
asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru)
657
{
658
        int flag, retval;
659
        struct wait_queue wait = { current, NULL };
660
        struct task_struct *p;
661
 
662
        if (stat_addr) {
663
                flag = verify_area(VERIFY_WRITE, stat_addr, sizeof(*stat_addr));
664
                if (flag)
665
                        return flag;
666
        }
667
        if (ru) {
668
                flag = verify_area(VERIFY_WRITE, ru, sizeof(*ru));
669
                if (flag)
670
                        return flag;
671
        }
672
        if (options & ~(WNOHANG|WUNTRACED|__WCLONE))
673
            return -EINVAL;
674
 
675
        add_wait_queue(&current->wait_chldexit,&wait);
676
repeat:
677
        flag=0;
678
        for (p = current->p_cptr ; p ; p = p->p_osptr) {
679
                if (pid>0) {
680
                        if (p->pid != pid)
681
                                continue;
682
                } else if (!pid) {
683
                        if (p->pgrp != current->pgrp)
684
                                continue;
685
                } else if (pid != -1) {
686
                        if (p->pgrp != -pid)
687
                                continue;
688
                }
689
                /* If you are tracing a process, then you don't need to get the
690
                 * WCLONE bit right -- useful for strace and gdb
691
                 */
692
                if (!(p->flags & (PF_PTRACED|PF_TRACESYS))) {
693
                        /* wait for cloned processes iff the __WCLONE flag is set */
694
                        if ((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
695
                                continue;
696
                }
697
                flag = 1;
698
                switch (p->state) {
699
                        case TASK_STOPPED:
700
                                if (!p->exit_code)
701
                                        continue;
702
                                if (!(options & WUNTRACED) && !(p->flags & PF_PTRACED))
703
                                        continue;
704
                                if (ru != NULL)
705
                                        getrusage(p, RUSAGE_BOTH, ru);
706
                                if (stat_addr)
707
                                        put_user((p->exit_code << 8) | 0x7f,
708
                                                stat_addr);
709
                                p->exit_code = 0;
710
                                retval = p->pid;
711
                                goto end_wait4;
712
                        case TASK_ZOMBIE:
713
                                current->cutime += p->utime + p->cutime;
714
                                current->cstime += p->stime + p->cstime;
715
                                if (ru != NULL)
716
                                        getrusage(p, RUSAGE_BOTH, ru);
717
                                if (stat_addr)
718
                                        put_user(p->exit_code, stat_addr);
719
                                retval = p->pid;
720
                                if (p->p_opptr != p->p_pptr) {
721
                                        REMOVE_LINKS(p);
722
                                        p->p_pptr = p->p_opptr;
723
                                        SET_LINKS(p);
724
                                        notify_parent(p, p->exit_signal);
725
                                } else
726
                                        release(p);
727
#ifdef DEBUG_PROC_TREE
728
                                audit_ptree();
729
#endif
730
                                goto end_wait4;
731
                        default:
732
                                continue;
733
                }
734
        }
735
        if (flag) {
736
                retval = 0;
737
                if (options & WNOHANG)
738
                        goto end_wait4;
739
                retval = -ERESTARTSYS;
740
                if (current->signal & ~current->blocked)
741
                        goto end_wait4;
742
                current->state=TASK_INTERRUPTIBLE;
743
                schedule();
744
                goto repeat;
745
        }
746
        retval = -ECHILD;
747
end_wait4:
748
        remove_wait_queue(&current->wait_chldexit,&wait);
749
        return retval;
750
}
751
 
752
#ifndef __alpha__
753
 
754
/*
755
 * sys_waitpid() remains for compatibility. waitpid() should be
756
 * implemented by calling sys_wait4() from libc.a.
757
 */
758
asmlinkage int sys_waitpid(pid_t pid,unsigned int * stat_addr, int options)
759
{
760
        return sys_wait4(pid, stat_addr, options, NULL);
761
}
762
 
763
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.