Fix from Yuval Yurom:
[unix-history] / sys / kern / kern_proc.c
CommitLineData
15637ed4
RG
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 *
600f7f07
RG
33 * from: @(#)kern_proc.c 7.16 (Berkeley) 6/28/91
34 * $Id$
15637ed4
RG
35 */
36
37#include "param.h"
38#include "systm.h"
39#include "kernel.h"
40#include "proc.h"
41#include "buf.h"
42#include "acct.h"
43#include "wait.h"
44#include "file.h"
45#include "../ufs/quota.h"
46#include "uio.h"
47#include "malloc.h"
48#include "mbuf.h"
49#include "ioctl.h"
50#include "tty.h"
51
52/*
53 * Is p an inferior of the current process?
54 */
55inferior(p)
56 register struct proc *p;
57{
58
59 for (; p != curproc; p = p->p_pptr)
60 if (p->p_pid == 0)
61 return (0);
62 return (1);
63}
64
65/*
66 * Locate a process by number
67 */
68struct proc *
69pfind(pid)
70 register pid;
71{
72 register struct proc *p = pidhash[PIDHASH(pid)];
73
74 for (; p; p = p->p_hash)
75 if (p->p_pid == pid)
76 return (p);
77 return ((struct proc *)0);
78}
79
80/*
81 * Locate a process group by number
82 */
83struct pgrp *
84pgfind(pgid)
85 register pid_t pgid;
86{
87 register struct pgrp *pgrp = pgrphash[PIDHASH(pgid)];
88
89 for (; pgrp; pgrp = pgrp->pg_hforw)
90 if (pgrp->pg_id == pgid)
91 return (pgrp);
92 return ((struct pgrp *)0);
93}
94
95/*
96 * Move p to a new or existing process group (and session)
97 */
98enterpgrp(p, pgid, mksess)
99 register struct proc *p;
100 pid_t pgid;
101{
102 register struct pgrp *pgrp = pgfind(pgid);
103 register struct proc **pp;
104 register struct proc *cp;
105 int n;
106
107#ifdef DIAGNOSTIC
108 if (pgrp && mksess) /* firewalls */
109 panic("enterpgrp: setsid into non-empty pgrp");
110 if (SESS_LEADER(p))
111 panic("enterpgrp: session leader attempted setpgrp");
112#endif
113 if (pgrp == NULL) {
114 /*
115 * new process group
116 */
117#ifdef DIAGNOSTIC
118 if (p->p_pid != pgid)
119 panic("enterpgrp: new pgrp and pid != pgid");
120#endif
121 MALLOC(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP,
122 M_WAITOK);
123 if (mksess) {
124 register struct session *sess;
125
126 /*
127 * new session
128 */
129 MALLOC(sess, struct session *, sizeof(struct session),
130 M_SESSION, M_WAITOK);
131 sess->s_leader = p;
132 sess->s_count = 1;
133 sess->s_ttyvp = NULL;
134 sess->s_ttyp = NULL;
135 bcopy(p->p_session->s_login, sess->s_login,
136 sizeof(sess->s_login));
137 p->p_flag &= ~SCTTY;
138 pgrp->pg_session = sess;
139#ifdef DIAGNOSTIC
140 if (p != curproc)
141 panic("enterpgrp: mksession and p != curproc");
142#endif
143 } else {
144 pgrp->pg_session = p->p_session;
145 pgrp->pg_session->s_count++;
146 }
147 pgrp->pg_id = pgid;
148 pgrp->pg_hforw = pgrphash[n = PIDHASH(pgid)];
149 pgrphash[n] = pgrp;
150 pgrp->pg_jobc = 0;
151 pgrp->pg_mem = NULL;
152 } else if (pgrp == p->p_pgrp)
153 return;
154
155 /*
156 * Adjust eligibility of affected pgrps to participate in job control.
157 * Increment eligibility counts before decrementing, otherwise we
158 * could reach 0 spuriously during the first call.
159 */
160 fixjobc(p, pgrp, 1);
161 fixjobc(p, p->p_pgrp, 0);
162
163 /*
164 * unlink p from old process group
165 */
166 for (pp = &p->p_pgrp->pg_mem; *pp; pp = &(*pp)->p_pgrpnxt)
167 if (*pp == p) {
168 *pp = p->p_pgrpnxt;
169 goto done;
170 }
171 panic("enterpgrp: can't find p on old pgrp");
172done:
173 /*
174 * delete old if empty
175 */
176 if (p->p_pgrp->pg_mem == 0)
177 pgdelete(p->p_pgrp);
178 /*
179 * link into new one
180 */
181 p->p_pgrp = pgrp;
182 p->p_pgrpnxt = pgrp->pg_mem;
183 pgrp->pg_mem = p;
184}
185
186/*
187 * remove process from process group
188 */
189leavepgrp(p)
190 register struct proc *p;
191{
192 register struct proc **pp = &p->p_pgrp->pg_mem;
193
194 for (; *pp; pp = &(*pp)->p_pgrpnxt)
195 if (*pp == p) {
196 *pp = p->p_pgrpnxt;
197 goto done;
198 }
199 panic("leavepgrp: can't find p in pgrp");
200done:
201 if (!p->p_pgrp->pg_mem)
202 pgdelete(p->p_pgrp);
203 p->p_pgrp = 0;
204}
205
206/*
207 * delete a process group
208 */
209pgdelete(pgrp)
210 register struct pgrp *pgrp;
211{
212 register struct pgrp **pgp = &pgrphash[PIDHASH(pgrp->pg_id)];
213
214 if (pgrp->pg_session->s_ttyp != NULL &&
215 pgrp->pg_session->s_ttyp->t_pgrp == pgrp)
216 pgrp->pg_session->s_ttyp->t_pgrp = NULL;
217 for (; *pgp; pgp = &(*pgp)->pg_hforw)
218 if (*pgp == pgrp) {
219 *pgp = pgrp->pg_hforw;
220 goto done;
221 }
222 panic("pgdelete: can't find pgrp on hash chain");
223done:
224 if (--pgrp->pg_session->s_count == 0)
225 FREE(pgrp->pg_session, M_SESSION);
226 FREE(pgrp, M_PGRP);
227}
228
229static orphanpg();
230
231/*
232 * Adjust pgrp jobc counters when specified process changes process group.
233 * We count the number of processes in each process group that "qualify"
234 * the group for terminal job control (those with a parent in a different
235 * process group of the same session). If that count reaches zero, the
236 * process group becomes orphaned. Check both the specified process'
237 * process group and that of its children.
238 * entering == 0 => p is leaving specified group.
239 * entering == 1 => p is entering specified group.
240 */
241fixjobc(p, pgrp, entering)
242 register struct proc *p;
243 register struct pgrp *pgrp;
244 int entering;
245{
246 register struct pgrp *hispgrp;
247 register struct session *mysession = pgrp->pg_session;
248
249 /*
250 * Check p's parent to see whether p qualifies its own process
251 * group; if so, adjust count for p's process group.
252 */
253 if ((hispgrp = p->p_pptr->p_pgrp) != pgrp &&
254 hispgrp->pg_session == mysession)
255 if (entering)
256 pgrp->pg_jobc++;
257 else if (--pgrp->pg_jobc == 0)
258 orphanpg(pgrp);
259
260 /*
261 * Check this process' children to see whether they qualify
262 * their process groups; if so, adjust counts for children's
263 * process groups.
264 */
265 for (p = p->p_cptr; p; p = p->p_osptr)
266 if ((hispgrp = p->p_pgrp) != pgrp &&
267 hispgrp->pg_session == mysession &&
268 p->p_stat != SZOMB)
269 if (entering)
270 hispgrp->pg_jobc++;
271 else if (--hispgrp->pg_jobc == 0)
272 orphanpg(hispgrp);
273}
274
275/*
276 * A process group has become orphaned;
277 * if there are any stopped processes in the group,
278 * hang-up all process in that group.
279 */
280static
281orphanpg(pg)
282 struct pgrp *pg;
283{
284 register struct proc *p;
285
286 for (p = pg->pg_mem; p; p = p->p_pgrpnxt) {
287 if (p->p_stat == SSTOP) {
288 for (p = pg->pg_mem; p; p = p->p_pgrpnxt) {
289 psignal(p, SIGHUP);
290 psignal(p, SIGCONT);
291 }
292 return;
293 }
294 }
295}
296
297#ifdef debug
298/* DEBUG */
299pgrpdump()
300{
301 register struct pgrp *pgrp;
302 register struct proc *p;
303 register i;
304
305 for (i=0; i<PIDHSZ; i++) {
306 if (pgrphash[i]) {
307 printf("\tindx %d\n", i);
308 for (pgrp=pgrphash[i]; pgrp; pgrp=pgrp->pg_hforw) {
309 printf("\tpgrp %x, pgid %d, sess %x, sesscnt %d, mem %x\n",
310 pgrp, pgrp->pg_id, pgrp->pg_session,
311 pgrp->pg_session->s_count, pgrp->pg_mem);
312 for (p=pgrp->pg_mem; p; p=p->p_pgrpnxt) {
313 printf("\t\tpid %d addr %x pgrp %x\n",
314 p->p_pid, p, p->p_pgrp);
315 }
316 }
317
318 }
319 }
320}
321#endif /* debug */