386BSD 0.1 development
[unix-history] / usr / src / sys.386bsd / kern / kern_proc.c
CommitLineData
f507b52a
WJ
1/*
2 * Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)kern_proc.c 7.16 (Berkeley) 6/28/91
34 */
35
36#include "param.h"
37#include "systm.h"
38#include "kernel.h"
39#include "proc.h"
40#include "buf.h"
41#include "acct.h"
42#include "wait.h"
43#include "file.h"
44#include "../ufs/quota.h"
45#include "uio.h"
46#include "malloc.h"
47#include "mbuf.h"
48#include "ioctl.h"
49#include "tty.h"
50
51/*
52 * Is p an inferior of the current process?
53 */
54inferior(p)
55 register struct proc *p;
56{
57
58 for (; p != curproc; p = p->p_pptr)
59 if (p->p_pid == 0)
60 return (0);
61 return (1);
62}
63
64/*
65 * Locate a process by number
66 */
67struct proc *
68pfind(pid)
69 register pid;
70{
71 register struct proc *p = pidhash[PIDHASH(pid)];
72
73 for (; p; p = p->p_hash)
74 if (p->p_pid == pid)
75 return (p);
76 return ((struct proc *)0);
77}
78
79/*
80 * Locate a process group by number
81 */
82struct pgrp *
83pgfind(pgid)
84 register pid_t pgid;
85{
86 register struct pgrp *pgrp = pgrphash[PIDHASH(pgid)];
87
88 for (; pgrp; pgrp = pgrp->pg_hforw)
89 if (pgrp->pg_id == pgid)
90 return (pgrp);
91 return ((struct pgrp *)0);
92}
93
94/*
95 * Move p to a new or existing process group (and session)
96 */
97enterpgrp(p, pgid, mksess)
98 register struct proc *p;
99 pid_t pgid;
100{
101 register struct pgrp *pgrp = pgfind(pgid);
102 register struct proc **pp;
103 register struct proc *cp;
104 int n;
105
106#ifdef DIAGNOSTIC
107 if (pgrp && mksess) /* firewalls */
108 panic("enterpgrp: setsid into non-empty pgrp");
109 if (SESS_LEADER(p))
110 panic("enterpgrp: session leader attempted setpgrp");
111#endif
112 if (pgrp == NULL) {
113 /*
114 * new process group
115 */
116#ifdef DIAGNOSTIC
117 if (p->p_pid != pgid)
118 panic("enterpgrp: new pgrp and pid != pgid");
119#endif
120 MALLOC(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP,
121 M_WAITOK);
122 if (mksess) {
123 register struct session *sess;
124
125 /*
126 * new session
127 */
128 MALLOC(sess, struct session *, sizeof(struct session),
129 M_SESSION, M_WAITOK);
130 sess->s_leader = p;
131 sess->s_count = 1;
132 sess->s_ttyvp = NULL;
133 sess->s_ttyp = NULL;
134 bcopy(p->p_session->s_login, sess->s_login,
135 sizeof(sess->s_login));
136 p->p_flag &= ~SCTTY;
137 pgrp->pg_session = sess;
138#ifdef DIAGNOSTIC
139 if (p != curproc)
140 panic("enterpgrp: mksession and p != curproc");
141#endif
142 } else {
143 pgrp->pg_session = p->p_session;
144 pgrp->pg_session->s_count++;
145 }
146 pgrp->pg_id = pgid;
147 pgrp->pg_hforw = pgrphash[n = PIDHASH(pgid)];
148 pgrphash[n] = pgrp;
149 pgrp->pg_jobc = 0;
150 pgrp->pg_mem = NULL;
151 } else if (pgrp == p->p_pgrp)
152 return;
153
154 /*
155 * Adjust eligibility of affected pgrps to participate in job control.
156 * Increment eligibility counts before decrementing, otherwise we
157 * could reach 0 spuriously during the first call.
158 */
159 fixjobc(p, pgrp, 1);
160 fixjobc(p, p->p_pgrp, 0);
161
162 /*
163 * unlink p from old process group
164 */
165 for (pp = &p->p_pgrp->pg_mem; *pp; pp = &(*pp)->p_pgrpnxt)
166 if (*pp == p) {
167 *pp = p->p_pgrpnxt;
168 goto done;
169 }
170 panic("enterpgrp: can't find p on old pgrp");
171done:
172 /*
173 * delete old if empty
174 */
175 if (p->p_pgrp->pg_mem == 0)
176 pgdelete(p->p_pgrp);
177 /*
178 * link into new one
179 */
180 p->p_pgrp = pgrp;
181 p->p_pgrpnxt = pgrp->pg_mem;
182 pgrp->pg_mem = p;
183}
184
185/*
186 * remove process from process group
187 */
188leavepgrp(p)
189 register struct proc *p;
190{
191 register struct proc **pp = &p->p_pgrp->pg_mem;
192
193 for (; *pp; pp = &(*pp)->p_pgrpnxt)
194 if (*pp == p) {
195 *pp = p->p_pgrpnxt;
196 goto done;
197 }
198 panic("leavepgrp: can't find p in pgrp");
199done:
200 if (!p->p_pgrp->pg_mem)
201 pgdelete(p->p_pgrp);
202 p->p_pgrp = 0;
203}
204
205/*
206 * delete a process group
207 */
208pgdelete(pgrp)
209 register struct pgrp *pgrp;
210{
211 register struct pgrp **pgp = &pgrphash[PIDHASH(pgrp->pg_id)];
212
213 if (pgrp->pg_session->s_ttyp != NULL &&
214 pgrp->pg_session->s_ttyp->t_pgrp == pgrp)
215 pgrp->pg_session->s_ttyp->t_pgrp = NULL;
216 for (; *pgp; pgp = &(*pgp)->pg_hforw)
217 if (*pgp == pgrp) {
218 *pgp = pgrp->pg_hforw;
219 goto done;
220 }
221 panic("pgdelete: can't find pgrp on hash chain");
222done:
223 if (--pgrp->pg_session->s_count == 0)
224 FREE(pgrp->pg_session, M_SESSION);
225 FREE(pgrp, M_PGRP);
226}
227
228static orphanpg();
229
230/*
231 * Adjust pgrp jobc counters when specified process changes process group.
232 * We count the number of processes in each process group that "qualify"
233 * the group for terminal job control (those with a parent in a different
234 * process group of the same session). If that count reaches zero, the
235 * process group becomes orphaned. Check both the specified process'
236 * process group and that of its children.
237 * entering == 0 => p is leaving specified group.
238 * entering == 1 => p is entering specified group.
239 */
240fixjobc(p, pgrp, entering)
241 register struct proc *p;
242 register struct pgrp *pgrp;
243 int entering;
244{
245 register struct pgrp *hispgrp;
246 register struct session *mysession = pgrp->pg_session;
247
248 /*
249 * Check p's parent to see whether p qualifies its own process
250 * group; if so, adjust count for p's process group.
251 */
252 if ((hispgrp = p->p_pptr->p_pgrp) != pgrp &&
253 hispgrp->pg_session == mysession)
254 if (entering)
255 pgrp->pg_jobc++;
256 else if (--pgrp->pg_jobc == 0)
257 orphanpg(pgrp);
258
259 /*
260 * Check this process' children to see whether they qualify
261 * their process groups; if so, adjust counts for children's
262 * process groups.
263 */
264 for (p = p->p_cptr; p; p = p->p_osptr)
265 if ((hispgrp = p->p_pgrp) != pgrp &&
266 hispgrp->pg_session == mysession &&
267 p->p_stat != SZOMB)
268 if (entering)
269 hispgrp->pg_jobc++;
270 else if (--hispgrp->pg_jobc == 0)
271 orphanpg(hispgrp);
272}
273
274/*
275 * A process group has become orphaned;
276 * if there are any stopped processes in the group,
277 * hang-up all process in that group.
278 */
279static
280orphanpg(pg)
281 struct pgrp *pg;
282{
283 register struct proc *p;
284
285 for (p = pg->pg_mem; p; p = p->p_pgrpnxt) {
286 if (p->p_stat == SSTOP) {
287 for (p = pg->pg_mem; p; p = p->p_pgrpnxt) {
288 psignal(p, SIGHUP);
289 psignal(p, SIGCONT);
290 }
291 return;
292 }
293 }
294}
295
296#ifdef debug
297/* DEBUG */
298pgrpdump()
299{
300 register struct pgrp *pgrp;
301 register struct proc *p;
302 register i;
303
304 for (i=0; i<PIDHSZ; i++) {
305 if (pgrphash[i]) {
306 printf("\tindx %d\n", i);
307 for (pgrp=pgrphash[i]; pgrp; pgrp=pgrp->pg_hforw) {
308 printf("\tpgrp %x, pgid %d, sess %x, sesscnt %d, mem %x\n",
309 pgrp, pgrp->pg_id, pgrp->pg_session,
310 pgrp->pg_session->s_count, pgrp->pg_mem);
311 for (p=pgrp->pg_mem; p; p=p->p_pgrpnxt) {
312 printf("\t\tpid %d addr %x pgrp %x\n",
313 p->p_pid, p, p->p_pgrp);
314 }
315 }
316
317 }
318 }
319}
320#endif /* debug */