* Copyright (c) 1982, 1986, 1989, 1991, 1993
* The Regents of the University of California. All rights reserved.
* %sccs.include.redist.c%
* @(#)kern_exit.c 8.1 (Berkeley) %G%
#include <sys/resource.h>
#include <sys/resourcevar.h>
__dead
void cpu_exit
__P((struct proc
*));
__dead
void exit1
__P((struct proc
*, int));
exit1(p
, W_EXITCODE(uap
->rval
, 0));
* Exit: deallocate address space and other resources, change proc state
* to zombie, and unlink proc from allproc and parent's lists. Save exit
* status and rusage for wait(). Check for child processes and orphan them.
register struct proc
*q
, *nq
;
register struct proc
**pp
;
register struct vmspace
*vm
;
panic("init died (signal %d, exit %d)",
WTERMSIG(rv
), WEXITSTATUS(rv
));
MALLOC(p
->p_ru
, struct rusage
*, sizeof(struct rusage
),
* If parent is waiting for us to exit or exec,
* SPPWAIT is set; we will wakeup the parent below.
p
->p_flag
&= ~(STRC
|SPPWAIT
);
untimeout(realitexpire
, (caddr_t
)p
);
* Close open files and release open-file table.
/* The next two chunks should probably be moved to vmspace_exit. */
* Release user portion of address space.
* This releases references to vnodes,
* which could cause I/O if the file has been unlinked.
* Need to do this early enough that we can still sleep.
* Can't free the entire vmspace as the kernel stack
* may be mapped within that space also.
(void) vm_map_remove(&vm
->vm_map
, VM_MIN_ADDRESS
,
register struct session
*sp
= p
->p_session
;
* Signal foreground pgrp,
* drain controlling terminal
* and revoke access to controlling terminal.
if (sp
->s_ttyp
->t_session
== sp
) {
pgsignal(sp
->s_ttyp
->t_pgrp
, SIGHUP
, 1);
(void) ttywait(sp
->s_ttyp
);
* s_ttyp is not zero'd; we use this to indicate
* that the session once had a controlling terminal.
* (for logging and informational purposes)
fixjobc(p
, p
->p_pgrp
, 0);
p
->p_rlimit
[RLIMIT_FSIZE
].rlim_cur
= RLIM_INFINITY
;
p
->p_traceflag
= 0; /* don't trace the vrele() */
* Remove proc from allproc queue and pidhash chain.
* Place onto zombproc. Unlink from parent's child list.
if (*p
->p_prev
= p
->p_nxt
)
p
->p_nxt
->p_prev
= p
->p_prev
;
p
->p_nxt
->p_prev
= &p
->p_nxt
;
for (pp
= &pidhash
[PIDHASH(p
->p_pid
)]; *pp
; pp
= &(*pp
)->p_hash
)
if (p
->p_cptr
) /* only need this if any child is S_ZOMB */
wakeup((caddr_t
) initproc
);
for (q
= p
->p_cptr
; q
!= NULL
; q
= nq
) {
initproc
->p_cptr
->p_ysptr
= q
;
q
->p_osptr
= initproc
->p_cptr
;
* Traced processes are killed
* since their existence means someone is screwing up.
* Save exit status and final rusage info, adding in child rusage
*p
->p_ru
= p
->p_stats
->p_ru
;
calcru(p
, &p
->p_ru
->ru_utime
, &p
->p_ru
->ru_stime
, NULL
);
ruadd(p
->p_ru
, &p
->p_stats
->p_cru
);
* Notify parent that we're gone.
psignal(p
->p_pptr
, SIGCHLD
);
wakeup((caddr_t
)p
->p_pptr
);
/* move this to cpu_exit */
p
->p_addr
->u_pcb
.pcb_savacc
.faddr
= (float *)NULL
;
* Clear curproc after we've done all operations
* that could block, and before tearing down the rest
* of the process state that might be used from clock, etc.
* Also, can't clear curproc while we're still runnable,
* as we're not on a run queue (we are current, just not
* a proper proc any longer!).
* Other substructures are freed from wait().
if (--p
->p_limit
->p_refcnt
== 0)
FREE(p
->p_limit
, M_SUBPROC
);
* Finally, call machine-dependent code to release the remaining
* resources including address space, the kernel stack and pcb.
* The address space is released by "vmspace_free(p->p_vmspace)";
* This is machine-dependent, as we may have to change stacks
* or ensure that the current one isn't reallocated before we
* finish. cpu_exit will end with a call to cpu_swtch(), finishing
* our execution (pun intended).
#if defined(hp300) || defined(luna68k)
#include <machine/frame.h>
#define GETPS(rp) ((struct frame *)(rp))->f_sr
#define GETPS(rp) (rp)[PS]
register struct wait_args
*uap
;
if ((GETPS(p
->p_md
.md_regs
) & PSL_ALLCC
) != PSL_ALLCC
) {
uap
->options
= p
->p_md
.md_regs
[R0
];
uap
->rusage
= (struct rusage
*)p
->p_md
.md_regs
[R1
];
return (wait1(p
, uap
, retval
));
return (wait1(p
, uap
, retval
));
* Wait: check child processes to see if any have exited,
* stopped under trace, or (optionally) stopped by a signal.
* Pass back status and deallocate exited child's proc structure.
register struct wait_args
*uap
;
register struct proc
*p
, *t
;
if (uap
->options
&~ (WUNTRACED
|WNOHANG
))
for (p
= q
->p_cptr
; p
; p
= p
->p_osptr
) {
if (uap
->pid
!= WAIT_ANY
&&
p
->p_pid
!= uap
->pid
&& p
->p_pgid
!= -uap
->pid
)
if (p
->p_stat
== SZOMB
) {
status
= p
->p_xstat
; /* convert to int */
if (error
= copyout((caddr_t
)&status
,
(caddr_t
)uap
->status
, sizeof(status
)))
if (uap
->rusage
&& (error
= copyout((caddr_t
)p
->p_ru
,
(caddr_t
)uap
->rusage
, sizeof (struct rusage
))))
* If we got the child via a ptrace 'attach',
* we need to give it back to the old parent.
if (p
->p_oppid
&& (t
= pfind(p
->p_oppid
))) {
ruadd(&q
->p_stats
->p_cru
, p
->p_ru
);
* Decrement the count of procs running with this uid.
(void)chgproccnt(p
->p_cred
->p_ruid
, -1);
if (--p
->p_cred
->p_refcnt
== 0) {
crfree(p
->p_cred
->pc_ucred
);
FREE(p
->p_cred
, M_SUBPROC
);
* Finally finished with old proc entry.
* Unlink it from its process group and free it.
if (*p
->p_prev
= p
->p_nxt
) /* off zombproc */
p
->p_nxt
->p_prev
= p
->p_prev
;
if ((q
= p
->p_pptr
)->p_cptr
== p
)
* Give machine-dependent layer a chance
* to free anything that cpu_exit couldn't
* release while still running in process context.
if (p
->p_stat
== SSTOP
&& (p
->p_flag
& SWTED
) == 0 &&
(p
->p_flag
& STRC
|| uap
->options
& WUNTRACED
)) {
retval
[1] = W_STOPCODE(p
->p_xstat
);
status
= W_STOPCODE(p
->p_xstat
);
error
= copyout((caddr_t
)&status
,
(caddr_t
)uap
->status
, sizeof(status
));
if (uap
->options
& WNOHANG
) {
if (error
= tsleep((caddr_t
)q
, PWAIT
| PCATCH
, "wait", 0))
* make process 'parent' the new parent of process 'child'.
proc_reparent(child
, parent
)
register struct proc
*child
;
register struct proc
*parent
;
if (child
->p_pptr
== parent
)
/* fix up the child linkage for the old parent */
if (child
->p_pptr
->p_cptr
== child
)
child
->p_pptr
->p_cptr
= o
;
/* fix up child linkage for new parent */