]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_proc.c
xnu-344.tar.gz
[apple/xnu.git] / bsd / kern / kern_proc.c
1 /*
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
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 */
86 struct uidinfo {
87 LIST_ENTRY(uidinfo) ui_hash;
88 uid_t ui_uid;
89 long ui_proccnt;
90 };
91 #define UIHASH(uid) (&uihashtbl[(uid) & uihash])
92 LIST_HEAD(uihashhead, uidinfo) *uihashtbl;
93 u_long uihash; /* size of hash table - 1 */
94
95 /*
96 * Other process lists
97 */
98 struct pidhashhead *pidhashtbl;
99 u_long pidhash;
100 struct pgrphashhead *pgrphashtbl;
101 u_long pgrphash;
102 struct proclist allproc;
103 struct proclist zombproc;
104
105 /*
106 * Initialize global process hashing structures.
107 */
108 void
109 procinit()
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 */
123 int
124 chgproccnt(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 */
160 int
161 inferior(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 }
170 /*
171 * Is p an inferior of t ?
172 */
173 int
174 isinferior(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 }
187
188 /*
189 * Locate a process by number
190 */
191 struct proc *
192 pfind(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 */
209 struct pgrp *
210 pgfind(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 */
225 int
226 enterpgrp(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);
251 if ((np = pfind(savepid)) == NULL || np != p) {
252 FREE_ZONE(pgrp, sizeof(struct pgrp), M_PGRP);
253 return (ESRCH);
254 }
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;
264 sess->s_sid = p->p_pid;
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 */
306 int
307 leavepgrp(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 */
321 void
322 pgdelete(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
335 void
336 sessrele(sess)
337 struct session *sess;
338 {
339 if (--sess->s_count == 0)
340 FREE_ZONE(sess, sizeof (struct session), M_SESSION);
341 }
342
343 static 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 */
355 void
356 fixjobc(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 */
395 static void
396 orphanpg(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
415 void
416 pgrpdump()
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
441 struct proc * current_proc_EXTERNAL()
442 {
443 return (current_proc());
444 }