Deleted Added
full compact
kern_proc.c (1817) kern_proc.c (2112)
1/*
2 * Copyright (c) 1982, 1986, 1989, 1991, 1993
3 * The Regents of the University of California. 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 8.4 (Berkeley) 1/4/94
1/*
2 * Copyright (c) 1982, 1986, 1989, 1991, 1993
3 * The Regents of the University of California. 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 8.4 (Berkeley) 1/4/94
34 * $Id$
34 * $Id: kern_proc.c,v 1.3 1994/08/02 07:42:07 davidg Exp $
35 */
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/map.h>
40#include <sys/kernel.h>
41#include <sys/proc.h>
42#include <sys/buf.h>
43#include <sys/acct.h>
44#include <sys/wait.h>
45#include <sys/file.h>
46#include <ufs/ufs/quota.h>
47#include <sys/uio.h>
48#include <sys/malloc.h>
49#include <sys/mbuf.h>
50#include <sys/ioctl.h>
51#include <sys/tty.h>
52
35 */
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/map.h>
40#include <sys/kernel.h>
41#include <sys/proc.h>
42#include <sys/buf.h>
43#include <sys/acct.h>
44#include <sys/wait.h>
45#include <sys/file.h>
46#include <ufs/ufs/quota.h>
47#include <sys/uio.h>
48#include <sys/malloc.h>
49#include <sys/mbuf.h>
50#include <sys/ioctl.h>
51#include <sys/tty.h>
52
53volatile struct proc *allproc; /* all processes */
54struct proc *zombproc; /* just zombies */
55
53void pgdelete __P((struct pgrp *));
54void fixjobc __P((struct proc *, struct pgrp *, int));
55
56/*
57 * Structure associated with user cacheing.
58 */
59struct uidinfo {
60 struct uidinfo *ui_next;
61 struct uidinfo **ui_prev;
62 uid_t ui_uid;
63 long ui_proccnt;
64} **uihashtbl;
65u_long uihash; /* size of hash table - 1 */
66#define UIHASH(uid) ((uid) & uihash)
67
68/*
69 * Allocate a hash table.
70 */
71void
72usrinfoinit()
73{
74
75 uihashtbl = hashinit(maxproc / 16, M_PROC, &uihash);
76}
77
78/*
79 * Change the count associated with number of processes
80 * a given user is using.
81 */
82int
83chgproccnt(uid, diff)
84 uid_t uid;
85 int diff;
86{
87 register struct uidinfo **uipp, *uip, *uiq;
88
89 uipp = &uihashtbl[UIHASH(uid)];
90 for (uip = *uipp; uip; uip = uip->ui_next)
91 if (uip->ui_uid == uid)
92 break;
93 if (uip) {
94 uip->ui_proccnt += diff;
95 if (uip->ui_proccnt > 0)
96 return (uip->ui_proccnt);
97 if (uip->ui_proccnt < 0)
98 panic("chgproccnt: procs < 0");
99 if (uiq = uip->ui_next)
100 uiq->ui_prev = uip->ui_prev;
101 *uip->ui_prev = uiq;
102 FREE(uip, M_PROC);
103 return (0);
104 }
105 if (diff <= 0) {
106 if (diff == 0)
107 return(0);
108 panic("chgproccnt: lost user");
109 }
110 MALLOC(uip, struct uidinfo *, sizeof(*uip), M_PROC, M_WAITOK);
111 if (uiq = *uipp)
112 uiq->ui_prev = &uip->ui_next;
113 uip->ui_next = uiq;
114 uip->ui_prev = uipp;
115 *uipp = uip;
116 uip->ui_uid = uid;
117 uip->ui_proccnt = diff;
118 return (diff);
119}
120
121/*
122 * Is p an inferior of the current process?
123 */
124int
125inferior(p)
126 register struct proc *p;
127{
128
129 for (; p != curproc; p = p->p_pptr)
130 if (p->p_pid == 0)
131 return (0);
132 return (1);
133}
134
135/*
136 * Locate a process by number
137 */
138struct proc *
139pfind(pid)
140 register pid_t pid;
141{
142 register struct proc *p;
143
144 for (p = pidhash[PIDHASH(pid)]; p != NULL; p = p->p_hash)
145 if (p->p_pid == pid)
146 return (p);
147 return (NULL);
148}
149
150/*
151 * Locate a process group by number
152 */
153struct pgrp *
154pgfind(pgid)
155 register pid_t pgid;
156{
157 register struct pgrp *pgrp;
158
159 for (pgrp = pgrphash[PIDHASH(pgid)];
160 pgrp != NULL; pgrp = pgrp->pg_hforw)
161 if (pgrp->pg_id == pgid)
162 return (pgrp);
163 return (NULL);
164}
165
166/*
167 * Move p to a new or existing process group (and session)
168 */
169int
170enterpgrp(p, pgid, mksess)
171 register struct proc *p;
172 pid_t pgid;
173 int mksess;
174{
175 register struct pgrp *pgrp = pgfind(pgid);
176 register struct proc **pp;
177 int n;
178
179#ifdef DIAGNOSTIC
180 if (pgrp != NULL && mksess) /* firewalls */
181 panic("enterpgrp: setsid into non-empty pgrp");
182 if (SESS_LEADER(p))
183 panic("enterpgrp: session leader attempted setpgrp");
184#endif
185 if (pgrp == NULL) {
186 pid_t savepid = p->p_pid;
187 struct proc *np;
188 /*
189 * new process group
190 */
191#ifdef DIAGNOSTIC
192 if (p->p_pid != pgid)
193 panic("enterpgrp: new pgrp and pid != pgid");
194#endif
195 MALLOC(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP,
196 M_WAITOK);
197 if ((np = pfind(savepid)) == NULL || np != p)
198 return (ESRCH);
199 if (mksess) {
200 register struct session *sess;
201
202 /*
203 * new session
204 */
205 MALLOC(sess, struct session *, sizeof(struct session),
206 M_SESSION, M_WAITOK);
207 sess->s_leader = p;
208 sess->s_count = 1;
209 sess->s_ttyvp = NULL;
210 sess->s_ttyp = NULL;
211 bcopy(p->p_session->s_login, sess->s_login,
212 sizeof(sess->s_login));
213 p->p_flag &= ~P_CONTROLT;
214 pgrp->pg_session = sess;
215#ifdef DIAGNOSTIC
216 if (p != curproc)
217 panic("enterpgrp: mksession and p != curproc");
218#endif
219 } else {
220 pgrp->pg_session = p->p_session;
221 pgrp->pg_session->s_count++;
222 }
223 pgrp->pg_id = pgid;
224 pgrp->pg_hforw = pgrphash[n = PIDHASH(pgid)];
225 pgrphash[n] = pgrp;
226 pgrp->pg_jobc = 0;
227 pgrp->pg_mem = NULL;
228 } else if (pgrp == p->p_pgrp)
229 return (0);
230
231 /*
232 * Adjust eligibility of affected pgrps to participate in job control.
233 * Increment eligibility counts before decrementing, otherwise we
234 * could reach 0 spuriously during the first call.
235 */
236 fixjobc(p, pgrp, 1);
237 fixjobc(p, p->p_pgrp, 0);
238
239 /*
240 * unlink p from old process group
241 */
242 for (pp = &p->p_pgrp->pg_mem; *pp; pp = &(*pp)->p_pgrpnxt) {
243 if (*pp == p) {
244 *pp = p->p_pgrpnxt;
245 break;
246 }
247 }
248#ifdef DIAGNOSTIC
249 if (pp == NULL)
250 panic("enterpgrp: can't find p on old pgrp");
251#endif
252 /*
253 * delete old if empty
254 */
255 if (p->p_pgrp->pg_mem == 0)
256 pgdelete(p->p_pgrp);
257 /*
258 * link into new one
259 */
260 p->p_pgrp = pgrp;
261 p->p_pgrpnxt = pgrp->pg_mem;
262 pgrp->pg_mem = p;
263 return (0);
264}
265
266/*
267 * remove process from process group
268 */
269int
270leavepgrp(p)
271 register struct proc *p;
272{
273 register struct proc **pp = &p->p_pgrp->pg_mem;
274
275 for (; *pp; pp = &(*pp)->p_pgrpnxt) {
276 if (*pp == p) {
277 *pp = p->p_pgrpnxt;
278 break;
279 }
280 }
281#ifdef DIAGNOSTIC
282 if (pp == NULL)
283 panic("leavepgrp: can't find p in pgrp");
284#endif
285 if (!p->p_pgrp->pg_mem)
286 pgdelete(p->p_pgrp);
287 p->p_pgrp = 0;
288 return (0);
289}
290
291/*
292 * delete a process group
293 */
294void
295pgdelete(pgrp)
296 register struct pgrp *pgrp;
297{
298 register struct pgrp **pgp = &pgrphash[PIDHASH(pgrp->pg_id)];
299
300 if (pgrp->pg_session->s_ttyp != NULL &&
301 pgrp->pg_session->s_ttyp->t_pgrp == pgrp)
302 pgrp->pg_session->s_ttyp->t_pgrp = NULL;
303 for (; *pgp; pgp = &(*pgp)->pg_hforw) {
304 if (*pgp == pgrp) {
305 *pgp = pgrp->pg_hforw;
306 break;
307 }
308 }
309#ifdef DIAGNOSTIC
310 if (pgp == NULL)
311 panic("pgdelete: can't find pgrp on hash chain");
312#endif
313 if (--pgrp->pg_session->s_count == 0)
314 FREE(pgrp->pg_session, M_SESSION);
315 FREE(pgrp, M_PGRP);
316}
317
318static void orphanpg();
319
320/*
321 * Adjust pgrp jobc counters when specified process changes process group.
322 * We count the number of processes in each process group that "qualify"
323 * the group for terminal job control (those with a parent in a different
324 * process group of the same session). If that count reaches zero, the
325 * process group becomes orphaned. Check both the specified process'
326 * process group and that of its children.
327 * entering == 0 => p is leaving specified group.
328 * entering == 1 => p is entering specified group.
329 */
330void
331fixjobc(p, pgrp, entering)
332 register struct proc *p;
333 register struct pgrp *pgrp;
334 int entering;
335{
336 register struct pgrp *hispgrp;
337 register struct session *mysession = pgrp->pg_session;
338
339 /*
340 * Check p's parent to see whether p qualifies its own process
341 * group; if so, adjust count for p's process group.
342 */
343 if ((hispgrp = p->p_pptr->p_pgrp) != pgrp &&
344 hispgrp->pg_session == mysession)
345 if (entering)
346 pgrp->pg_jobc++;
347 else if (--pgrp->pg_jobc == 0)
348 orphanpg(pgrp);
349
350 /*
351 * Check this process' children to see whether they qualify
352 * their process groups; if so, adjust counts for children's
353 * process groups.
354 */
355 for (p = p->p_cptr; p; p = p->p_osptr)
356 if ((hispgrp = p->p_pgrp) != pgrp &&
357 hispgrp->pg_session == mysession &&
358 p->p_stat != SZOMB)
359 if (entering)
360 hispgrp->pg_jobc++;
361 else if (--hispgrp->pg_jobc == 0)
362 orphanpg(hispgrp);
363}
364
365/*
366 * A process group has become orphaned;
367 * if there are any stopped processes in the group,
368 * hang-up all process in that group.
369 */
370static void
371orphanpg(pg)
372 struct pgrp *pg;
373{
374 register struct proc *p;
375
376 for (p = pg->pg_mem; p; p = p->p_pgrpnxt) {
377 if (p->p_stat == SSTOP) {
378 for (p = pg->pg_mem; p; p = p->p_pgrpnxt) {
379 psignal(p, SIGHUP);
380 psignal(p, SIGCONT);
381 }
382 return;
383 }
384 }
385}
386
387#ifdef debug
388/* DEBUG */
389pgrpdump()
390{
391 register struct pgrp *pgrp;
392 register struct proc *p;
393 register i;
394
395 for (i=0; i<PIDHSZ; i++) {
396 if (pgrphash[i]) {
397 printf("\tindx %d\n", i);
398 for (pgrp=pgrphash[i]; pgrp; pgrp=pgrp->pg_hforw) {
399 printf("\tpgrp %x, pgid %d, sess %x, sesscnt %d, mem %x\n",
400 pgrp, pgrp->pg_id, pgrp->pg_session,
401 pgrp->pg_session->s_count, pgrp->pg_mem);
402 for (p=pgrp->pg_mem; p; p=p->p_pgrpnxt) {
403 printf("\t\tpid %d addr %x pgrp %x\n",
404 p->p_pid, p, p->p_pgrp);
405 }
406 }
407
408 }
409 }
410}
411#endif /* debug */
56void pgdelete __P((struct pgrp *));
57void fixjobc __P((struct proc *, struct pgrp *, int));
58
59/*
60 * Structure associated with user cacheing.
61 */
62struct uidinfo {
63 struct uidinfo *ui_next;
64 struct uidinfo **ui_prev;
65 uid_t ui_uid;
66 long ui_proccnt;
67} **uihashtbl;
68u_long uihash; /* size of hash table - 1 */
69#define UIHASH(uid) ((uid) & uihash)
70
71/*
72 * Allocate a hash table.
73 */
74void
75usrinfoinit()
76{
77
78 uihashtbl = hashinit(maxproc / 16, M_PROC, &uihash);
79}
80
81/*
82 * Change the count associated with number of processes
83 * a given user is using.
84 */
85int
86chgproccnt(uid, diff)
87 uid_t uid;
88 int diff;
89{
90 register struct uidinfo **uipp, *uip, *uiq;
91
92 uipp = &uihashtbl[UIHASH(uid)];
93 for (uip = *uipp; uip; uip = uip->ui_next)
94 if (uip->ui_uid == uid)
95 break;
96 if (uip) {
97 uip->ui_proccnt += diff;
98 if (uip->ui_proccnt > 0)
99 return (uip->ui_proccnt);
100 if (uip->ui_proccnt < 0)
101 panic("chgproccnt: procs < 0");
102 if (uiq = uip->ui_next)
103 uiq->ui_prev = uip->ui_prev;
104 *uip->ui_prev = uiq;
105 FREE(uip, M_PROC);
106 return (0);
107 }
108 if (diff <= 0) {
109 if (diff == 0)
110 return(0);
111 panic("chgproccnt: lost user");
112 }
113 MALLOC(uip, struct uidinfo *, sizeof(*uip), M_PROC, M_WAITOK);
114 if (uiq = *uipp)
115 uiq->ui_prev = &uip->ui_next;
116 uip->ui_next = uiq;
117 uip->ui_prev = uipp;
118 *uipp = uip;
119 uip->ui_uid = uid;
120 uip->ui_proccnt = diff;
121 return (diff);
122}
123
124/*
125 * Is p an inferior of the current process?
126 */
127int
128inferior(p)
129 register struct proc *p;
130{
131
132 for (; p != curproc; p = p->p_pptr)
133 if (p->p_pid == 0)
134 return (0);
135 return (1);
136}
137
138/*
139 * Locate a process by number
140 */
141struct proc *
142pfind(pid)
143 register pid_t pid;
144{
145 register struct proc *p;
146
147 for (p = pidhash[PIDHASH(pid)]; p != NULL; p = p->p_hash)
148 if (p->p_pid == pid)
149 return (p);
150 return (NULL);
151}
152
153/*
154 * Locate a process group by number
155 */
156struct pgrp *
157pgfind(pgid)
158 register pid_t pgid;
159{
160 register struct pgrp *pgrp;
161
162 for (pgrp = pgrphash[PIDHASH(pgid)];
163 pgrp != NULL; pgrp = pgrp->pg_hforw)
164 if (pgrp->pg_id == pgid)
165 return (pgrp);
166 return (NULL);
167}
168
169/*
170 * Move p to a new or existing process group (and session)
171 */
172int
173enterpgrp(p, pgid, mksess)
174 register struct proc *p;
175 pid_t pgid;
176 int mksess;
177{
178 register struct pgrp *pgrp = pgfind(pgid);
179 register struct proc **pp;
180 int n;
181
182#ifdef DIAGNOSTIC
183 if (pgrp != NULL && mksess) /* firewalls */
184 panic("enterpgrp: setsid into non-empty pgrp");
185 if (SESS_LEADER(p))
186 panic("enterpgrp: session leader attempted setpgrp");
187#endif
188 if (pgrp == NULL) {
189 pid_t savepid = p->p_pid;
190 struct proc *np;
191 /*
192 * new process group
193 */
194#ifdef DIAGNOSTIC
195 if (p->p_pid != pgid)
196 panic("enterpgrp: new pgrp and pid != pgid");
197#endif
198 MALLOC(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP,
199 M_WAITOK);
200 if ((np = pfind(savepid)) == NULL || np != p)
201 return (ESRCH);
202 if (mksess) {
203 register struct session *sess;
204
205 /*
206 * new session
207 */
208 MALLOC(sess, struct session *, sizeof(struct session),
209 M_SESSION, M_WAITOK);
210 sess->s_leader = p;
211 sess->s_count = 1;
212 sess->s_ttyvp = NULL;
213 sess->s_ttyp = NULL;
214 bcopy(p->p_session->s_login, sess->s_login,
215 sizeof(sess->s_login));
216 p->p_flag &= ~P_CONTROLT;
217 pgrp->pg_session = sess;
218#ifdef DIAGNOSTIC
219 if (p != curproc)
220 panic("enterpgrp: mksession and p != curproc");
221#endif
222 } else {
223 pgrp->pg_session = p->p_session;
224 pgrp->pg_session->s_count++;
225 }
226 pgrp->pg_id = pgid;
227 pgrp->pg_hforw = pgrphash[n = PIDHASH(pgid)];
228 pgrphash[n] = pgrp;
229 pgrp->pg_jobc = 0;
230 pgrp->pg_mem = NULL;
231 } else if (pgrp == p->p_pgrp)
232 return (0);
233
234 /*
235 * Adjust eligibility of affected pgrps to participate in job control.
236 * Increment eligibility counts before decrementing, otherwise we
237 * could reach 0 spuriously during the first call.
238 */
239 fixjobc(p, pgrp, 1);
240 fixjobc(p, p->p_pgrp, 0);
241
242 /*
243 * unlink p from old process group
244 */
245 for (pp = &p->p_pgrp->pg_mem; *pp; pp = &(*pp)->p_pgrpnxt) {
246 if (*pp == p) {
247 *pp = p->p_pgrpnxt;
248 break;
249 }
250 }
251#ifdef DIAGNOSTIC
252 if (pp == NULL)
253 panic("enterpgrp: can't find p on old pgrp");
254#endif
255 /*
256 * delete old if empty
257 */
258 if (p->p_pgrp->pg_mem == 0)
259 pgdelete(p->p_pgrp);
260 /*
261 * link into new one
262 */
263 p->p_pgrp = pgrp;
264 p->p_pgrpnxt = pgrp->pg_mem;
265 pgrp->pg_mem = p;
266 return (0);
267}
268
269/*
270 * remove process from process group
271 */
272int
273leavepgrp(p)
274 register struct proc *p;
275{
276 register struct proc **pp = &p->p_pgrp->pg_mem;
277
278 for (; *pp; pp = &(*pp)->p_pgrpnxt) {
279 if (*pp == p) {
280 *pp = p->p_pgrpnxt;
281 break;
282 }
283 }
284#ifdef DIAGNOSTIC
285 if (pp == NULL)
286 panic("leavepgrp: can't find p in pgrp");
287#endif
288 if (!p->p_pgrp->pg_mem)
289 pgdelete(p->p_pgrp);
290 p->p_pgrp = 0;
291 return (0);
292}
293
294/*
295 * delete a process group
296 */
297void
298pgdelete(pgrp)
299 register struct pgrp *pgrp;
300{
301 register struct pgrp **pgp = &pgrphash[PIDHASH(pgrp->pg_id)];
302
303 if (pgrp->pg_session->s_ttyp != NULL &&
304 pgrp->pg_session->s_ttyp->t_pgrp == pgrp)
305 pgrp->pg_session->s_ttyp->t_pgrp = NULL;
306 for (; *pgp; pgp = &(*pgp)->pg_hforw) {
307 if (*pgp == pgrp) {
308 *pgp = pgrp->pg_hforw;
309 break;
310 }
311 }
312#ifdef DIAGNOSTIC
313 if (pgp == NULL)
314 panic("pgdelete: can't find pgrp on hash chain");
315#endif
316 if (--pgrp->pg_session->s_count == 0)
317 FREE(pgrp->pg_session, M_SESSION);
318 FREE(pgrp, M_PGRP);
319}
320
321static void orphanpg();
322
323/*
324 * Adjust pgrp jobc counters when specified process changes process group.
325 * We count the number of processes in each process group that "qualify"
326 * the group for terminal job control (those with a parent in a different
327 * process group of the same session). If that count reaches zero, the
328 * process group becomes orphaned. Check both the specified process'
329 * process group and that of its children.
330 * entering == 0 => p is leaving specified group.
331 * entering == 1 => p is entering specified group.
332 */
333void
334fixjobc(p, pgrp, entering)
335 register struct proc *p;
336 register struct pgrp *pgrp;
337 int entering;
338{
339 register struct pgrp *hispgrp;
340 register struct session *mysession = pgrp->pg_session;
341
342 /*
343 * Check p's parent to see whether p qualifies its own process
344 * group; if so, adjust count for p's process group.
345 */
346 if ((hispgrp = p->p_pptr->p_pgrp) != pgrp &&
347 hispgrp->pg_session == mysession)
348 if (entering)
349 pgrp->pg_jobc++;
350 else if (--pgrp->pg_jobc == 0)
351 orphanpg(pgrp);
352
353 /*
354 * Check this process' children to see whether they qualify
355 * their process groups; if so, adjust counts for children's
356 * process groups.
357 */
358 for (p = p->p_cptr; p; p = p->p_osptr)
359 if ((hispgrp = p->p_pgrp) != pgrp &&
360 hispgrp->pg_session == mysession &&
361 p->p_stat != SZOMB)
362 if (entering)
363 hispgrp->pg_jobc++;
364 else if (--hispgrp->pg_jobc == 0)
365 orphanpg(hispgrp);
366}
367
368/*
369 * A process group has become orphaned;
370 * if there are any stopped processes in the group,
371 * hang-up all process in that group.
372 */
373static void
374orphanpg(pg)
375 struct pgrp *pg;
376{
377 register struct proc *p;
378
379 for (p = pg->pg_mem; p; p = p->p_pgrpnxt) {
380 if (p->p_stat == SSTOP) {
381 for (p = pg->pg_mem; p; p = p->p_pgrpnxt) {
382 psignal(p, SIGHUP);
383 psignal(p, SIGCONT);
384 }
385 return;
386 }
387 }
388}
389
390#ifdef debug
391/* DEBUG */
392pgrpdump()
393{
394 register struct pgrp *pgrp;
395 register struct proc *p;
396 register i;
397
398 for (i=0; i<PIDHSZ; i++) {
399 if (pgrphash[i]) {
400 printf("\tindx %d\n", i);
401 for (pgrp=pgrphash[i]; pgrp; pgrp=pgrp->pg_hforw) {
402 printf("\tpgrp %x, pgid %d, sess %x, sesscnt %d, mem %x\n",
403 pgrp, pgrp->pg_id, pgrp->pg_session,
404 pgrp->pg_session->s_count, pgrp->pg_mem);
405 for (p=pgrp->pg_mem; p; p=p->p_pgrpnxt) {
406 printf("\t\tpid %d addr %x pgrp %x\n",
407 p->p_pid, p, p->p_pgrp);
408 }
409 }
410
411 }
412 }
413}
414#endif /* debug */