NetBSD/sys/kern/kern_proc.c

378 lines
9.4 KiB
C
Raw Normal View History

1995-03-20 02:44:44 +03:00
/* $NetBSD: kern_proc.c,v 1.12 1995/03/19 23:44:49 mycroft Exp $ */
1993-03-21 12:45:37 +03:00
/*
1994-05-19 09:57:44 +04:00
* Copyright (c) 1982, 1986, 1989, 1991, 1993
* The Regents of the University of California. All rights reserved.
1993-03-21 12:45:37 +03:00
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)kern_proc.c 8.4 (Berkeley) 1/4/94
1993-03-21 12:45:37 +03:00
*/
1993-12-18 06:59:02 +03:00
#include <sys/param.h>
#include <sys/systm.h>
1994-05-19 09:57:44 +04:00
#include <sys/map.h>
1993-12-18 06:59:02 +03:00
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/acct.h>
#include <sys/wait.h>
#include <sys/file.h>
1994-06-08 15:28:29 +04:00
#include <ufs/ufs/quota.h>
1993-12-18 06:59:02 +03:00
#include <sys/uio.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/ioctl.h>
#include <sys/tty.h>
#include <sys/signalvar.h>
1993-12-18 06:59:02 +03:00
1994-05-19 09:57:44 +04:00
/*
* Structure associated with user cacheing.
*/
struct uidinfo {
LIST_ENTRY(uidinfo) ui_hash;
1994-05-19 09:57:44 +04:00
uid_t ui_uid;
long ui_proccnt;
};
#define UIHASH(uid) (&uihashtbl[(uid) & uihash])
LIST_HEAD(uihashhead, uidinfo) *uihashtbl;
u_long uihash; /* size of hash table - 1 */
1994-05-19 09:57:44 +04:00
/*
* Other process lists
1994-05-19 09:57:44 +04:00
*/
struct pidhashhead *pidhashtbl;
u_long pidhash;
struct pgrphashhead *pgrphashtbl;
u_long pgrphash;
struct proclist allproc;
struct proclist zombproc;
/*
* Initialize global process hashing structures.
*/
void
procinit()
1994-05-19 09:57:44 +04:00
{
1993-03-21 12:45:37 +03:00
LIST_INIT(&allproc);
LIST_INIT(&zombproc);
pidhashtbl = hashinit(maxproc / 4, M_PROC, &pidhash);
pgrphashtbl = hashinit(maxproc / 4, M_PROC, &pgrphash);
1994-05-19 09:57:44 +04:00
uihashtbl = hashinit(maxproc / 16, M_PROC, &uihash);
}
1993-03-21 12:45:37 +03:00
/*
1994-05-19 09:57:44 +04:00
* Change the count associated with number of processes
* a given user is using.
1993-03-21 12:45:37 +03:00
*/
int
1994-05-19 09:57:44 +04:00
chgproccnt(uid, diff)
uid_t uid;
int diff;
{
register struct uidinfo *uip;
register struct uihashhead *uipp;
1994-05-19 09:57:44 +04:00
uipp = UIHASH(uid);
for (uip = uipp->lh_first; uip != 0; uip = uip->ui_hash.le_next)
1994-05-19 09:57:44 +04:00
if (uip->ui_uid == uid)
break;
if (uip) {
uip->ui_proccnt += diff;
if (uip->ui_proccnt > 0)
return (uip->ui_proccnt);
if (uip->ui_proccnt < 0)
panic("chgproccnt: procs < 0");
LIST_REMOVE(uip, ui_hash);
1994-05-19 09:57:44 +04:00
FREE(uip, M_PROC);
return (0);
}
if (diff <= 0) {
if (diff == 0)
return(0);
panic("chgproccnt: lost user");
}
MALLOC(uip, struct uidinfo *, sizeof(*uip), M_PROC, M_WAITOK);
LIST_INSERT_HEAD(uipp, uip, ui_hash);
1994-05-19 09:57:44 +04:00
uip->ui_uid = uid;
uip->ui_proccnt = diff;
return (diff);
}
/*
* Is p an inferior of the current process?
*/
int
1993-03-21 12:45:37 +03:00
inferior(p)
register struct proc *p;
{
for (; p != curproc; p = p->p_pptr)
if (p->p_pid == 0)
return (0);
return (1);
}
/*
* Locate a process by number
*/
struct proc *
pfind(pid)
1994-05-04 07:41:12 +04:00
register pid_t pid;
1993-03-21 12:45:37 +03:00
{
1994-05-19 09:57:44 +04:00
register struct proc *p;
1993-03-21 12:45:37 +03:00
for (p = PIDHASH(pid)->lh_first; p != 0; p = p->p_hash.le_next)
1993-03-21 12:45:37 +03:00
if (p->p_pid == pid)
return (p);
1994-05-19 09:57:44 +04:00
return (NULL);
1993-03-21 12:45:37 +03:00
}
/*
* Locate a process group by number
*/
struct pgrp *
pgfind(pgid)
register pid_t pgid;
{
1994-05-19 09:57:44 +04:00
register struct pgrp *pgrp;
1993-03-21 12:45:37 +03:00
for (pgrp = PGRPHASH(pgid)->lh_first; pgrp != 0; pgrp = pgrp->pg_hash.le_next)
1993-03-21 12:45:37 +03:00
if (pgrp->pg_id == pgid)
return (pgrp);
1994-05-19 09:57:44 +04:00
return (NULL);
1993-03-21 12:45:37 +03:00
}
/*
* Move p to a new or existing process group (and session)
*/
int
1993-03-21 12:45:37 +03:00
enterpgrp(p, pgid, mksess)
register struct proc *p;
pid_t pgid;
int mksess;
1993-03-21 12:45:37 +03:00
{
register struct pgrp *pgrp = pgfind(pgid);
#ifdef DIAGNOSTIC
1994-05-19 09:57:44 +04:00
if (pgrp != NULL && mksess) /* firewalls */
1993-03-21 12:45:37 +03:00
panic("enterpgrp: setsid into non-empty pgrp");
if (SESS_LEADER(p))
panic("enterpgrp: session leader attempted setpgrp");
#endif
if (pgrp == NULL) {
1994-05-19 09:57:44 +04:00
pid_t savepid = p->p_pid;
struct proc *np;
1993-03-21 12:45:37 +03:00
/*
* new process group
*/
#ifdef DIAGNOSTIC
if (p->p_pid != pgid)
panic("enterpgrp: new pgrp and pid != pgid");
#endif
MALLOC(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP,
M_WAITOK);
1994-05-19 09:57:44 +04:00
if ((np = pfind(savepid)) == NULL || np != p)
return (ESRCH);
1993-03-21 12:45:37 +03:00
if (mksess) {
register struct session *sess;
/*
* new session
*/
MALLOC(sess, struct session *, sizeof(struct session),
M_SESSION, M_WAITOK);
1993-03-21 12:45:37 +03:00
sess->s_leader = p;
sess->s_count = 1;
sess->s_ttyvp = NULL;
sess->s_ttyp = NULL;
bcopy(p->p_session->s_login, sess->s_login,
sizeof(sess->s_login));
1994-05-04 07:41:12 +04:00
p->p_flag &= ~P_CONTROLT;
1993-03-21 12:45:37 +03:00
pgrp->pg_session = sess;
#ifdef DIAGNOSTIC
if (p != curproc)
panic("enterpgrp: mksession and p != curproc");
#endif
} else {
pgrp->pg_session = p->p_session;
pgrp->pg_session->s_count++;
}
pgrp->pg_id = pgid;
LIST_INIT(&pgrp->pg_members);
LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash);
1993-03-21 12:45:37 +03:00
pgrp->pg_jobc = 0;
} else if (pgrp == p->p_pgrp)
1994-05-19 09:57:44 +04:00
return (0);
1993-03-21 12:45:37 +03:00
/*
* Adjust eligibility of affected pgrps to participate in job control.
* Increment eligibility counts before decrementing, otherwise we
* could reach 0 spuriously during the first call.
*/
fixjobc(p, pgrp, 1);
fixjobc(p, p->p_pgrp, 0);
LIST_REMOVE(p, p_pglist);
if (p->p_pgrp->pg_members.lh_first == 0)
1993-03-21 12:45:37 +03:00
pgdelete(p->p_pgrp);
p->p_pgrp = pgrp;
LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist);
1994-05-19 09:57:44 +04:00
return (0);
1993-03-21 12:45:37 +03:00
}
/*
* remove process from process group
*/
int
1993-03-21 12:45:37 +03:00
leavepgrp(p)
register struct proc *p;
{
LIST_REMOVE(p, p_pglist);
if (p->p_pgrp->pg_members.lh_first == 0)
1993-03-21 12:45:37 +03:00
pgdelete(p->p_pgrp);
p->p_pgrp = 0;
1994-05-19 09:57:44 +04:00
return (0);
1993-03-21 12:45:37 +03:00
}
/*
1994-05-19 09:57:44 +04:00
* delete a process group
1993-03-21 12:45:37 +03:00
*/
void
1993-03-21 12:45:37 +03:00
pgdelete(pgrp)
register struct pgrp *pgrp;
{
if (pgrp->pg_session->s_ttyp != NULL &&
pgrp->pg_session->s_ttyp->t_pgrp == pgrp)
pgrp->pg_session->s_ttyp->t_pgrp = NULL;
LIST_REMOVE(pgrp, pg_hash);
1993-03-21 12:45:37 +03:00
if (--pgrp->pg_session->s_count == 0)
FREE(pgrp->pg_session, M_SESSION);
FREE(pgrp, M_PGRP);
}
static void orphanpg();
1993-03-21 12:45:37 +03:00
/*
* Adjust pgrp jobc counters when specified process changes process group.
* We count the number of processes in each process group that "qualify"
* the group for terminal job control (those with a parent in a different
* process group of the same session). If that count reaches zero, the
* process group becomes orphaned. Check both the specified process'
* process group and that of its children.
* entering == 0 => p is leaving specified group.
* entering == 1 => p is entering specified group.
*/
void
1993-03-21 12:45:37 +03:00
fixjobc(p, pgrp, entering)
register struct proc *p;
register struct pgrp *pgrp;
int entering;
{
register struct pgrp *hispgrp;
register struct session *mysession = pgrp->pg_session;
/*
* Check p's parent to see whether p qualifies its own process
* group; if so, adjust count for p's process group.
*/
if ((hispgrp = p->p_pptr->p_pgrp) != pgrp &&
hispgrp->pg_session == mysession)
if (entering)
pgrp->pg_jobc++;
else if (--pgrp->pg_jobc == 0)
orphanpg(pgrp);
/*
* Check this process' children to see whether they qualify
* their process groups; if so, adjust counts for children's
* process groups.
*/
for (p = p->p_children.lh_first; p != 0; p = p->p_sibling.le_next)
1993-03-21 12:45:37 +03:00
if ((hispgrp = p->p_pgrp) != pgrp &&
hispgrp->pg_session == mysession &&
p->p_stat != SZOMB)
if (entering)
hispgrp->pg_jobc++;
else if (--hispgrp->pg_jobc == 0)
orphanpg(hispgrp);
}
/*
* A process group has become orphaned;
* if there are any stopped processes in the group,
* hang-up all process in that group.
*/
static void
1993-03-21 12:45:37 +03:00
orphanpg(pg)
struct pgrp *pg;
{
register struct proc *p;
for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) {
1993-03-21 12:45:37 +03:00
if (p->p_stat == SSTOP) {
for (p = pg->pg_members.lh_first; p != 0;
p = p->p_pglist.le_next) {
1993-03-21 12:45:37 +03:00
psignal(p, SIGHUP);
psignal(p, SIGCONT);
}
return;
}
}
}
#ifdef DEBUG
1993-03-21 12:45:37 +03:00
pgrpdump()
{
register struct pgrp *pgrp;
register struct proc *p;
register i;
for (i = 0; i <= pgrphash; i++) {
if (pgrp = pgrphashtbl[i].lh_first) {
printf("\tindx %d\n", i);
for (; pgrp != 0; pgrp = pgrp->pg_hash.le_next) {
1995-03-20 02:44:44 +03:00
printf("\tpgrp %p, pgid %d, sess %p, sesscnt %d, mem %p\n",
pgrp, pgrp->pg_id, pgrp->pg_session,
pgrp->pg_session->s_count,
pgrp->pg_members.lh_first);
for (p = pgrp->pg_members.lh_first; p != 0;
p = p->p_pglist.le_next) {
1995-03-20 02:44:44 +03:00
printf("\t\tpid %d addr %p pgrp %p\n",
p->p_pid, p, p->p_pgrp);
}
}
1993-03-21 12:45:37 +03:00
}
}
}
#endif /* DEBUG */