]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_proc.c
xnu-344.2.tar.gz
[apple/xnu.git] / bsd / kern / kern_proc.c
CommitLineData
1c79356b 1/*
9bccf70c 2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
23/*
24 * Copyright (c) 1982, 1986, 1989, 1991, 1993
25 * The Regents of the University of California. All rights reserved.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * This product includes software developed by the University of
38 * California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * SUCH DAMAGE.
54 *
55 * @(#)kern_proc.c 8.4 (Berkeley) 1/4/94
56 */
57/* HISTORY
58 * 04-Aug-97 Umesh Vaishampayan (umeshv@apple.com)
59 * Added current_proc_EXTERNAL() function for the use of kernel
60 * lodable modules.
61 *
62 * 05-Jun-95 Mac Gillon (mgillon) at NeXT
63 * New version based on 3.3NS and 4.4
64 */
65
66
67#include <sys/param.h>
68#include <sys/systm.h>
69#include <sys/kernel.h>
70#include <sys/proc.h>
71#include <sys/buf.h>
72#include <sys/acct.h>
73#include <sys/wait.h>
74#include <sys/file.h>
75#include <ufs/ufs/quota.h>
76#include <sys/uio.h>
77#include <sys/malloc.h>
78#include <sys/mbuf.h>
79#include <sys/ioctl.h>
80#include <sys/tty.h>
81#include <sys/signalvar.h>
82
83/*
84 * Structure associated with user cacheing.
85 */
86struct uidinfo {
87 LIST_ENTRY(uidinfo) ui_hash;
88 uid_t ui_uid;
89 long ui_proccnt;
90};
91#define UIHASH(uid) (&uihashtbl[(uid) & uihash])
92LIST_HEAD(uihashhead, uidinfo) *uihashtbl;
93u_long uihash; /* size of hash table - 1 */
94
95/*
96 * Other process lists
97 */
98struct pidhashhead *pidhashtbl;
99u_long pidhash;
100struct pgrphashhead *pgrphashtbl;
101u_long pgrphash;
102struct proclist allproc;
103struct proclist zombproc;
104
105/*
106 * Initialize global process hashing structures.
107 */
108void
109procinit()
110{
111
112 LIST_INIT(&allproc);
113 LIST_INIT(&zombproc);
114 pidhashtbl = hashinit(maxproc / 4, M_PROC, &pidhash);
115 pgrphashtbl = hashinit(maxproc / 4, M_PROC, &pgrphash);
116 uihashtbl = hashinit(maxproc / 16, M_PROC, &uihash);
117}
118
119/*
120 * Change the count associated with number of processes
121 * a given user is using.
122 */
123int
124chgproccnt(uid, diff)
125 uid_t uid;
126 int diff;
127{
128 register struct uidinfo *uip;
129 register struct uihashhead *uipp;
130
131 uipp = UIHASH(uid);
132 for (uip = uipp->lh_first; uip != 0; uip = uip->ui_hash.le_next)
133 if (uip->ui_uid == uid)
134 break;
135 if (uip) {
136 uip->ui_proccnt += diff;
137 if (uip->ui_proccnt > 0)
138 return (uip->ui_proccnt);
139 if (uip->ui_proccnt < 0)
140 panic("chgproccnt: procs < 0");
141 LIST_REMOVE(uip, ui_hash);
142 FREE_ZONE(uip, sizeof *uip, M_PROC);
143 return (0);
144 }
145 if (diff <= 0) {
146 if (diff == 0)
147 return(0);
148 panic("chgproccnt: lost user");
149 }
150 MALLOC_ZONE(uip, struct uidinfo *, sizeof(*uip), M_PROC, M_WAITOK);
151 LIST_INSERT_HEAD(uipp, uip, ui_hash);
152 uip->ui_uid = uid;
153 uip->ui_proccnt = diff;
154 return (diff);
155}
156
157/*
158 * Is p an inferior of the current process?
159 */
160int
161inferior(p)
162 register struct proc *p;
163{
164
165 for (; p != current_proc(); p = p->p_pptr)
166 if (p->p_pid == 0)
167 return (0);
168 return (1);
169}
9bccf70c
A
170/*
171 * Is p an inferior of t ?
172 */
173int
174isinferior(p, t)
175 register struct proc *p;
176 register struct proc *t;
177{
178
179 /* if p==t they are not inferior */
180 if (p == t)
181 return(0);
182 for (; p != t; p = p->p_pptr)
183 if (p->p_pid == 0)
184 return (0);
185 return (1);
186}
1c79356b
A
187
188/*
189 * Locate a process by number
190 */
191struct proc *
192pfind(pid)
193 register pid_t pid;
194{
195 register struct proc *p;
196
197 if (!pid)
198 return (kernproc);
199
200 for (p = PIDHASH(pid)->lh_first; p != 0; p = p->p_hash.le_next)
201 if (p->p_pid == pid)
202 return (p);
203 return (NULL);
204}
205
206/*
207 * Locate a process group by number
208 */
209struct pgrp *
210pgfind(pgid)
211 register pid_t pgid;
212{
213 register struct pgrp *pgrp;
214
215 for (pgrp = PGRPHASH(pgid)->lh_first; pgrp != 0; pgrp = pgrp->pg_hash.le_next)
216 if (pgrp->pg_id == pgid)
217 return (pgrp);
218 return (NULL);
219}
220
221
222/*
223 * Move p to a new or existing process group (and session)
224 */
225int
226enterpgrp(p, pgid, mksess)
227 register struct proc *p;
228 pid_t pgid;
229 int mksess;
230{
231 register struct pgrp *pgrp = pgfind(pgid);
232
233#if DIAGNOSTIC
234 if (pgrp != NULL && mksess) /* firewalls */
235 panic("enterpgrp: setsid into non-empty pgrp");
236 if (SESS_LEADER(p))
237 panic("enterpgrp: session leader attempted setpgrp");
238#endif
239 if (pgrp == NULL) {
240 pid_t savepid = p->p_pid;
241 struct proc *np;
242 /*
243 * new process group
244 */
245#if DIAGNOSTIC
246 if (p->p_pid != pgid)
247 panic("enterpgrp: new pgrp and pid != pgid");
248#endif
249 MALLOC_ZONE(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP,
250 M_WAITOK);
9bccf70c
A
251 if ((np = pfind(savepid)) == NULL || np != p) {
252 FREE_ZONE(pgrp, sizeof(struct pgrp), M_PGRP);
1c79356b 253 return (ESRCH);
9bccf70c 254 }
1c79356b
A
255 if (mksess) {
256 register struct session *sess;
257
258 /*
259 * new session
260 */
261 MALLOC_ZONE(sess, struct session *,
262 sizeof(struct session), M_SESSION, M_WAITOK);
263 sess->s_leader = p;
9bccf70c 264 sess->s_sid = p->p_pid;
1c79356b
A
265 sess->s_count = 1;
266 sess->s_ttyvp = NULL;
267 sess->s_ttyp = NULL;
268 bcopy(p->p_session->s_login, sess->s_login,
269 sizeof(sess->s_login));
270 p->p_flag &= ~P_CONTROLT;
271 pgrp->pg_session = sess;
272#if DIAGNOSTIC
273 if (p != current_proc())
274 panic("enterpgrp: mksession and p != curproc");
275#endif
276 } else {
277 pgrp->pg_session = p->p_session;
278 pgrp->pg_session->s_count++;
279 }
280 pgrp->pg_id = pgid;
281 LIST_INIT(&pgrp->pg_members);
282 LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash);
283 pgrp->pg_jobc = 0;
284 } else if (pgrp == p->p_pgrp)
285 return (0);
286
287 /*
288 * Adjust eligibility of affected pgrps to participate in job control.
289 * Increment eligibility counts before decrementing, otherwise we
290 * could reach 0 spuriously during the first call.
291 */
292 fixjobc(p, pgrp, 1);
293 fixjobc(p, p->p_pgrp, 0);
294
295 LIST_REMOVE(p, p_pglist);
296 if (p->p_pgrp->pg_members.lh_first == 0)
297 pgdelete(p->p_pgrp);
298 p->p_pgrp = pgrp;
299 LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist);
300 return (0);
301}
302
303/*
304 * remove process from process group
305 */
306int
307leavepgrp(p)
308 register struct proc *p;
309{
310
311 LIST_REMOVE(p, p_pglist);
312 if (p->p_pgrp->pg_members.lh_first == 0)
313 pgdelete(p->p_pgrp);
314 p->p_pgrp = 0;
315 return (0);
316}
317
318/*
319 * delete a process group
320 */
321void
322pgdelete(pgrp)
323 register struct pgrp *pgrp;
324{
325
326 if (pgrp->pg_session->s_ttyp != NULL &&
327 pgrp->pg_session->s_ttyp->t_pgrp == pgrp)
328 pgrp->pg_session->s_ttyp->t_pgrp = NULL;
329 LIST_REMOVE(pgrp, pg_hash);
330 if (--pgrp->pg_session->s_count == 0)
331 FREE_ZONE(pgrp->pg_session, sizeof(struct session), M_SESSION);
332 FREE_ZONE(pgrp, sizeof *pgrp, M_PGRP);
333}
334
335void
336sessrele(sess)
337 struct session *sess;
338{
339 if (--sess->s_count == 0)
340 FREE_ZONE(sess, sizeof (struct session), M_SESSION);
341}
342
343static void orphanpg();
344
345/*
346 * Adjust pgrp jobc counters when specified process changes process group.
347 * We count the number of processes in each process group that "qualify"
348 * the group for terminal job control (those with a parent in a different
349 * process group of the same session). If that count reaches zero, the
350 * process group becomes orphaned. Check both the specified process'
351 * process group and that of its children.
352 * entering == 0 => p is leaving specified group.
353 * entering == 1 => p is entering specified group.
354 */
355void
356fixjobc(p, pgrp, entering)
357 register struct proc *p;
358 register struct pgrp *pgrp;
359 int entering;
360{
361 register struct pgrp *hispgrp;
362 register struct session *mysession = pgrp->pg_session;
363
364 /*
365 * Check p's parent to see whether p qualifies its own process
366 * group; if so, adjust count for p's process group.
367 */
368 if ((hispgrp = p->p_pptr->p_pgrp) != pgrp &&
369 hispgrp->pg_session == mysession)
370 if (entering)
371 pgrp->pg_jobc++;
372 else if (--pgrp->pg_jobc == 0)
373 orphanpg(pgrp);
374
375 /*
376 * Check this process' children to see whether they qualify
377 * their process groups; if so, adjust counts for children's
378 * process groups.
379 */
380 for (p = p->p_children.lh_first; p != 0; p = p->p_sibling.le_next)
381 if ((hispgrp = p->p_pgrp) != pgrp &&
382 hispgrp->pg_session == mysession &&
383 p->p_stat != SZOMB)
384 if (entering)
385 hispgrp->pg_jobc++;
386 else if (--hispgrp->pg_jobc == 0)
387 orphanpg(hispgrp);
388}
389
390/*
391 * A process group has become orphaned;
392 * if there are any stopped processes in the group,
393 * hang-up all process in that group.
394 */
395static void
396orphanpg(pg)
397 struct pgrp *pg;
398{
399 register struct proc *p;
400
401 for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) {
402 if (p->p_stat == SSTOP) {
403 for (p = pg->pg_members.lh_first; p != 0;
404 p = p->p_pglist.le_next) {
405 pt_setrunnable(p);
406 psignal(p, SIGHUP);
407 psignal(p, SIGCONT);
408 }
409 return;
410 }
411 }
412}
413
414#ifdef DEBUG
415void
416pgrpdump()
417{
418 register struct pgrp *pgrp;
419 register struct proc *p;
420 register i;
421
422 for (i = 0; i <= pgrphash; i++) {
423 if (pgrp = pgrphashtbl[i].lh_first) {
424 printf("\tindx %d\n", i);
425 for (; pgrp != 0; pgrp = pgrp->pg_hash.le_next) {
426 printf("\tpgrp 0x%08x, pgid %d, sess %p, sesscnt %d, mem %p\n",
427 pgrp, pgrp->pg_id, pgrp->pg_session,
428 pgrp->pg_session->s_count,
429 pgrp->pg_members.lh_first);
430 for (p = pgrp->pg_members.lh_first; p != 0;
431 p = p->p_pglist.le_next) {
432 printf("\t\tpid %d addr 0x%08x pgrp 0x%08x\n",
433 p->p_pid, p, p->p_pgrp);
434 }
435 }
436 }
437 }
438}
439#endif /* DEBUG */
440
441struct proc * current_proc_EXTERNAL()
442{
443 return (current_proc());
444}