Annotation of sys/kern/kern_proc.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: kern_proc.c,v 1.34 2007/08/04 02:43:54 ckuethe Exp $ */
2: /* $NetBSD: kern_proc.c,v 1.14 1996/02/09 18:59:41 christos Exp $ */
3:
4: /*
5: * Copyright (c) 1982, 1986, 1989, 1991, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. Neither the name of the University nor the names of its contributors
17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: *
32: * @(#)kern_proc.c 8.4 (Berkeley) 1/4/94
33: */
34:
35: #include <sys/param.h>
36: #include <sys/systm.h>
37: #include <sys/kernel.h>
38: #include <sys/proc.h>
39: #include <sys/buf.h>
40: #include <sys/acct.h>
41: #include <sys/wait.h>
42: #include <sys/file.h>
43: #include <ufs/ufs/quota.h>
44: #include <sys/uio.h>
45: #include <sys/malloc.h>
46: #include <sys/mbuf.h>
47: #include <sys/ioctl.h>
48: #include <sys/tty.h>
49: #include <sys/signalvar.h>
50: #include <sys/pool.h>
51:
52: #define UIHASH(uid) (&uihashtbl[(uid) & uihash])
53: LIST_HEAD(uihashhead, uidinfo) *uihashtbl;
54: u_long uihash; /* size of hash table - 1 */
55:
56: /*
57: * Other process lists
58: */
59: struct pidhashhead *pidhashtbl;
60: u_long pidhash;
61: struct pgrphashhead *pgrphashtbl;
62: u_long pgrphash;
63: struct proclist allproc;
64: struct proclist zombproc;
65:
66: struct pool proc_pool;
67: struct pool process_pool;
68: struct pool rusage_pool;
69: struct pool ucred_pool;
70: struct pool pgrp_pool;
71: struct pool session_pool;
72: struct pool pcred_pool;
73:
74: static void orphanpg(struct pgrp *);
75: #ifdef DEBUG
76: void pgrpdump(void);
77: #endif
78:
79: /*
80: * Initialize global process hashing structures.
81: */
82: void
83: procinit(void)
84: {
85: LIST_INIT(&allproc);
86: LIST_INIT(&zombproc);
87:
88:
89: pidhashtbl = hashinit(maxproc / 4, M_PROC, M_NOWAIT, &pidhash);
90: pgrphashtbl = hashinit(maxproc / 4, M_PROC, M_NOWAIT, &pgrphash);
91: uihashtbl = hashinit(maxproc / 16, M_PROC, M_NOWAIT, &uihash);
92: if (!pidhashtbl || !pgrphashtbl || !uihashtbl)
93: panic("procinit: malloc");
94:
95: pool_init(&proc_pool, sizeof(struct proc), 0, 0, 0, "procpl",
96: &pool_allocator_nointr);
97: pool_init(&process_pool, sizeof(struct process), 0, 0, 0, "processpl",
98: &pool_allocator_nointr);
99: pool_init(&rusage_pool, sizeof(struct rusage), 0, 0, 0, "zombiepl",
100: &pool_allocator_nointr);
101: pool_init(&ucred_pool, sizeof(struct ucred), 0, 0, 0, "ucredpl",
102: &pool_allocator_nointr);
103: pool_init(&pgrp_pool, sizeof(struct pgrp), 0, 0, 0, "pgrppl",
104: &pool_allocator_nointr);
105: pool_init(&session_pool, sizeof(struct session), 0, 0, 0, "sessionpl",
106: &pool_allocator_nointr);
107: pool_init(&pcred_pool, sizeof(struct pcred), 0, 0, 0, "pcredpl",
108: &pool_allocator_nointr);
109: }
110:
111: /*
112: * Change the count associated with number of processes
113: * a given user is using.
114: */
115: struct uidinfo *
116: uid_find(uid_t uid)
117: {
118: struct uidinfo *uip, *nuip;
119: struct uihashhead *uipp;
120:
121: uipp = UIHASH(uid);
122: LIST_FOREACH(uip, uipp, ui_hash)
123: if (uip->ui_uid == uid)
124: break;
125: if (uip)
126: return (uip);
127: MALLOC(nuip, struct uidinfo *, sizeof(*nuip), M_PROC, M_WAITOK);
128: /* may have slept, have to check again */
129: LIST_FOREACH(uip, uipp, ui_hash)
130: if (uip->ui_uid == uid)
131: break;
132: if (uip) {
133: free(nuip, M_PROC);
134: return (uip);
135: }
136: bzero(nuip, sizeof(*nuip));
137: nuip->ui_uid = uid;
138: LIST_INSERT_HEAD(uipp, nuip, ui_hash);
139:
140: return (nuip);
141: }
142:
143: int
144: chgproccnt(uid_t uid, int diff)
145: {
146: struct uidinfo *uip;
147:
148: uip = uid_find(uid);
149: uip->ui_proccnt += diff;
150: if (uip->ui_proccnt < 0)
151: panic("chgproccnt: procs < 0");
152: return (uip->ui_proccnt);
153: }
154:
155: /*
156: * Is p an inferior of the current process?
157: */
158: int
159: inferior(struct proc *p)
160: {
161:
162: for (; p != curproc; p = p->p_pptr)
163: if (p->p_pid == 0)
164: return (0);
165: return (1);
166: }
167:
168: /*
169: * Locate a process by number
170: */
171: struct proc *
172: pfind(pid_t pid)
173: {
174: struct proc *p;
175:
176: LIST_FOREACH(p, PIDHASH(pid), p_hash)
177: if (p->p_pid == pid)
178: return (p);
179: return (NULL);
180: }
181:
182: /*
183: * Locate a process group by number
184: */
185: struct pgrp *
186: pgfind(pid_t pgid)
187: {
188: struct pgrp *pgrp;
189:
190: LIST_FOREACH(pgrp, PGRPHASH(pgid), pg_hash)
191: if (pgrp->pg_id == pgid)
192: return (pgrp);
193: return (NULL);
194: }
195:
196: /*
197: * Move p to a new or existing process group (and session)
198: */
199: int
200: enterpgrp(struct proc *p, pid_t pgid, int mksess)
201: {
202: struct pgrp *pgrp = pgfind(pgid);
203:
204: #ifdef DIAGNOSTIC
205: if (pgrp != NULL && mksess) /* firewalls */
206: panic("enterpgrp: setsid into non-empty pgrp");
207: if (SESS_LEADER(p))
208: panic("enterpgrp: session leader attempted setpgrp");
209: #endif
210: if (pgrp == NULL) {
211: pid_t savepid = p->p_pid;
212: struct proc *np;
213: /*
214: * new process group
215: */
216: #ifdef DIAGNOSTIC
217: if (p->p_pid != pgid)
218: panic("enterpgrp: new pgrp and pid != pgid");
219: #endif
220: if ((np = pfind(savepid)) == NULL || np != p)
221: return (ESRCH);
222: pgrp = pool_get(&pgrp_pool, PR_WAITOK);
223: if (mksess) {
224: struct session *sess;
225:
226: /*
227: * new session
228: */
229: sess = pool_get(&session_pool, PR_WAITOK);
230: sess->s_leader = p;
231: sess->s_count = 1;
232: sess->s_ttyvp = NULL;
233: sess->s_ttyp = NULL;
234: bcopy(p->p_session->s_login, sess->s_login,
235: sizeof(sess->s_login));
236: atomic_clearbits_int(&p->p_flag, P_CONTROLT);
237: pgrp->pg_session = sess;
238: #ifdef DIAGNOSTIC
239: if (p != curproc)
240: panic("enterpgrp: mksession and p != curproc");
241: #endif
242: } else {
243: pgrp->pg_session = p->p_session;
244: pgrp->pg_session->s_count++;
245: }
246: pgrp->pg_id = pgid;
247: LIST_INIT(&pgrp->pg_members);
248: LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash);
249: pgrp->pg_jobc = 0;
250: } else if (pgrp == p->p_pgrp)
251: return (0);
252:
253: /*
254: * Adjust eligibility of affected pgrps to participate in job control.
255: * Increment eligibility counts before decrementing, otherwise we
256: * could reach 0 spuriously during the first call.
257: */
258: fixjobc(p, pgrp, 1);
259: fixjobc(p, p->p_pgrp, 0);
260:
261: LIST_REMOVE(p, p_pglist);
262: if (LIST_EMPTY(&p->p_pgrp->pg_members))
263: pgdelete(p->p_pgrp);
264: p->p_pgrp = pgrp;
265: LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist);
266: return (0);
267: }
268:
269: /*
270: * remove process from process group
271: */
272: int
273: leavepgrp(struct proc *p)
274: {
275:
276: LIST_REMOVE(p, p_pglist);
277: if (LIST_EMPTY(&p->p_pgrp->pg_members))
278: pgdelete(p->p_pgrp);
279: p->p_pgrp = 0;
280: return (0);
281: }
282:
283: /*
284: * delete a process group
285: */
286: void
287: pgdelete(struct pgrp *pgrp)
288: {
289:
290: if (pgrp->pg_session->s_ttyp != NULL &&
291: pgrp->pg_session->s_ttyp->t_pgrp == pgrp)
292: pgrp->pg_session->s_ttyp->t_pgrp = NULL;
293: LIST_REMOVE(pgrp, pg_hash);
294: SESSRELE(pgrp->pg_session);
295: pool_put(&pgrp_pool, pgrp);
296: }
297:
298: /*
299: * Adjust pgrp jobc counters when specified process changes process group.
300: * We count the number of processes in each process group that "qualify"
301: * the group for terminal job control (those with a parent in a different
302: * process group of the same session). If that count reaches zero, the
303: * process group becomes orphaned. Check both the specified process'
304: * process group and that of its children.
305: * entering == 0 => p is leaving specified group.
306: * entering == 1 => p is entering specified group.
307: */
308: void
309: fixjobc(struct proc *p, struct pgrp *pgrp, int entering)
310: {
311: struct pgrp *hispgrp;
312: struct session *mysession = pgrp->pg_session;
313:
314: /*
315: * Check p's parent to see whether p qualifies its own process
316: * group; if so, adjust count for p's process group.
317: */
318: if ((hispgrp = p->p_pptr->p_pgrp) != pgrp &&
319: hispgrp->pg_session == mysession) {
320: if (entering)
321: pgrp->pg_jobc++;
322: else if (--pgrp->pg_jobc == 0)
323: orphanpg(pgrp);
324: }
325:
326: /*
327: * Check this process' children to see whether they qualify
328: * their process groups; if so, adjust counts for children's
329: * process groups.
330: */
331: LIST_FOREACH(p, &p->p_children, p_sibling)
332: if ((hispgrp = p->p_pgrp) != pgrp &&
333: hispgrp->pg_session == mysession &&
334: P_ZOMBIE(p) == 0) {
335: if (entering)
336: hispgrp->pg_jobc++;
337: else if (--hispgrp->pg_jobc == 0)
338: orphanpg(hispgrp);
339: }
340: }
341:
342: /*
343: * A process group has become orphaned;
344: * if there are any stopped processes in the group,
345: * hang-up all process in that group.
346: */
347: static void
348: orphanpg(struct pgrp *pg)
349: {
350: struct proc *p;
351:
352: LIST_FOREACH(p, &pg->pg_members, p_pglist) {
353: if (p->p_stat == SSTOP) {
354: LIST_FOREACH(p, &pg->pg_members, p_pglist) {
355: psignal(p, SIGHUP);
356: psignal(p, SIGCONT);
357: }
358: return;
359: }
360: }
361: }
362:
363: #ifdef DDB
364: void
365: proc_printit(struct proc *p, const char *modif, int (*pr)(const char *, ...))
366: {
367: static const char *const pstat[] = {
368: "idle", "run", "sleep", "stop", "zombie", "dead", "onproc"
369: };
370: char pstbuf[5];
371: const char *pst = pstbuf;
372:
373: if (p->p_stat < 1 || p->p_stat > sizeof(pstat) / sizeof(pstat[0]))
374: snprintf(pstbuf, sizeof(pstbuf), "%d", p->p_stat);
375: else
376: pst = pstat[(int)p->p_stat - 1];
377:
378: (*pr)("PROC (%s) pid=%d stat=%s flags=%b\n",
379: p->p_comm, p->p_pid, pst, p->p_flag, P_BITS);
380: (*pr)(" pri=%u, usrpri=%u, nice=%d\n",
381: p->p_priority, p->p_usrpri, p->p_nice);
382: (*pr)(" forw=%p, back=%p, list=%p,%p\n",
383: p->p_forw, p->p_back, p->p_list.le_next, p->p_list.le_prev);
384: (*pr)(" user=%p, vmspace=%p\n",
385: p->p_addr, p->p_vmspace);
386: (*pr)(" estcpu=%u, cpticks=%d, pctcpu=%u.%u%, swtime=%u\n",
387: p->p_estcpu, p->p_cpticks, p->p_pctcpu / 100, p->p_pctcpu % 100,
388: p->p_swtime);
389: (*pr)(" user=%llu, sys=%llu, intr=%llu\n",
390: p->p_uticks, p->p_sticks, p->p_iticks);
391: }
392: #include <machine/db_machdep.h>
393:
394: #include <ddb/db_interface.h>
395: #include <ddb/db_output.h>
396:
397: void
398: db_show_all_procs(db_expr_t addr, int haddr, db_expr_t count, char *modif)
399: {
400: char *mode;
401: int doingzomb = 0;
402: struct proc *p, *pp;
403:
404: if (modif[0] == 0)
405: modif[0] = 'n'; /* default == normal mode */
406:
407: mode = "mawn";
408: while (*mode && *mode != modif[0])
409: mode++;
410: if (*mode == 0 || *mode == 'm') {
411: db_printf("usage: show all procs [/a] [/n] [/w]\n");
412: db_printf("\t/a == show process address info\n");
413: db_printf("\t/n == show normal process info [default]\n");
414: db_printf("\t/w == show process wait/emul info\n");
415: return;
416: }
417:
418: p = LIST_FIRST(&allproc);
419:
420: switch (*mode) {
421:
422: case 'a':
423: db_printf(" PID %-10s %18s %18s %18s\n",
424: "COMMAND", "STRUCT PROC *", "UAREA *", "VMSPACE/VM_MAP");
425: break;
426: case 'n':
427: db_printf(" PID %5s %5s %5s S %10s %-12s %-16s\n",
428: "PPID", "PGRP", "UID", "FLAGS", "WAIT", "COMMAND");
429: break;
430: case 'w':
431: db_printf(" PID %-16s %-8s %18s %s\n",
432: "COMMAND", "EMUL", "WAIT-CHANNEL", "WAIT-MSG");
433: break;
434: }
435:
436: while (p != 0) {
437: pp = p->p_pptr;
438: if (p->p_stat) {
439:
440: db_printf("%c%5d ", p == curproc ? '*' : ' ',
441: p->p_pid);
442:
443: switch (*mode) {
444:
445: case 'a':
446: db_printf("%-10.10s %18p %18p %18p\n",
447: p->p_comm, p, p->p_addr, p->p_vmspace);
448: break;
449:
450: case 'n':
451: db_printf("%5d %5d %5d %d %#10x "
452: "%-12.12s %-16s\n",
453: pp ? pp->p_pid : -1, p->p_pgrp->pg_id,
454: p->p_cred->p_ruid, p->p_stat, p->p_flag,
455: (p->p_wchan && p->p_wmesg) ?
456: p->p_wmesg : "", p->p_comm);
457: break;
458:
459: case 'w':
460: db_printf("%-16s %-8s %18p %s\n", p->p_comm,
461: p->p_emul->e_name, p->p_wchan,
462: (p->p_wchan && p->p_wmesg) ?
463: p->p_wmesg : "");
464: break;
465:
466: }
467: }
468: p = LIST_NEXT(p, p_list);
469: if (p == 0 && doingzomb == 0) {
470: doingzomb = 1;
471: p = LIST_FIRST(&zombproc);
472: }
473: }
474: }
475: #endif
476:
477: #ifdef DEBUG
478: void
479: pgrpdump(void)
480: {
481: struct pgrp *pgrp;
482: struct proc *p;
483: int i;
484:
485: for (i = 0; i <= pgrphash; i++) {
486: if (!LIST_EMPTY(&pgrphashtbl[i])) {
487: printf("\tindx %d\n", i);
488: LIST_FOREACH(pgrp, &pgrphashtbl[i], pg_hash) {
489: printf("\tpgrp %p, pgid %d, sess %p, sesscnt %d, mem %p\n",
490: pgrp, pgrp->pg_id, pgrp->pg_session,
491: pgrp->pg_session->s_count,
492: LIST_FIRST(&pgrp->pg_members));
493: LIST_FOREACH(p, &pgrp->pg_members, p_pglist) {
494: printf("\t\tpid %d addr %p pgrp %p\n",
495: p->p_pid, p, p->p_pgrp);
496: }
497: }
498: }
499: }
500: }
501: #endif /* DEBUG */
CVSweb