Line data Source code
1 : /* $OpenBSD: kern_proc.c,v 1.84 2018/06/21 13:58:21 visa 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/rwlock.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 : #include <sys/vnode.h>
52 :
53 : struct rwlock uidinfolk;
54 : #define UIHASH(uid) (&uihashtbl[(uid) & uihash])
55 : LIST_HEAD(uihashhead, uidinfo) *uihashtbl;
56 : u_long uihash; /* size of hash table - 1 */
57 :
58 : /*
59 : * Other process lists
60 : */
61 : struct tidhashhead *tidhashtbl;
62 : u_long tidhash;
63 : struct pidhashhead *pidhashtbl;
64 : u_long pidhash;
65 : struct pgrphashhead *pgrphashtbl;
66 : u_long pgrphash;
67 : struct processlist allprocess;
68 : struct processlist zombprocess;
69 : struct proclist allproc;
70 :
71 : struct pool proc_pool;
72 : struct pool process_pool;
73 : struct pool rusage_pool;
74 : struct pool ucred_pool;
75 : struct pool pgrp_pool;
76 : struct pool session_pool;
77 :
78 : void pgdelete(struct pgrp *);
79 : void fixjobc(struct process *, struct pgrp *, int);
80 :
81 : static void orphanpg(struct pgrp *);
82 : #ifdef DEBUG
83 : void pgrpdump(void);
84 : #endif
85 :
86 : /*
87 : * Initialize global process hashing structures.
88 : */
89 : void
90 0 : procinit(void)
91 : {
92 0 : LIST_INIT(&allprocess);
93 0 : LIST_INIT(&zombprocess);
94 0 : LIST_INIT(&allproc);
95 :
96 0 : rw_init(&uidinfolk, "uidinfo");
97 :
98 0 : tidhashtbl = hashinit(maxthread / 4, M_PROC, M_NOWAIT, &tidhash);
99 0 : pidhashtbl = hashinit(maxprocess / 4, M_PROC, M_NOWAIT, &pidhash);
100 0 : pgrphashtbl = hashinit(maxprocess / 4, M_PROC, M_NOWAIT, &pgrphash);
101 0 : uihashtbl = hashinit(maxprocess / 16, M_PROC, M_NOWAIT, &uihash);
102 0 : if (!tidhashtbl || !pidhashtbl || !pgrphashtbl || !uihashtbl)
103 0 : panic("procinit: malloc");
104 :
105 0 : pool_init(&proc_pool, sizeof(struct proc), 0, IPL_NONE,
106 : PR_WAITOK, "procpl", NULL);
107 0 : pool_init(&process_pool, sizeof(struct process), 0, IPL_NONE,
108 : PR_WAITOK, "processpl", NULL);
109 0 : pool_init(&rusage_pool, sizeof(struct rusage), 0, IPL_NONE,
110 : PR_WAITOK, "zombiepl", NULL);
111 0 : pool_init(&ucred_pool, sizeof(struct ucred), 0, IPL_MPFLOOR,
112 : PR_WAITOK, "ucredpl", NULL);
113 0 : pool_init(&pgrp_pool, sizeof(struct pgrp), 0, IPL_NONE,
114 : PR_WAITOK, "pgrppl", NULL);
115 0 : pool_init(&session_pool, sizeof(struct session), 0, IPL_NONE,
116 : PR_WAITOK, "sessionpl", NULL);
117 0 : }
118 :
119 : /*
120 : * This returns with `uidinfolk' held: caller must call uid_release()
121 : * after making whatever change they needed.
122 : */
123 : struct uidinfo *
124 0 : uid_find(uid_t uid)
125 : {
126 : struct uidinfo *uip, *nuip;
127 : struct uihashhead *uipp;
128 :
129 0 : uipp = UIHASH(uid);
130 0 : rw_enter_write(&uidinfolk);
131 0 : LIST_FOREACH(uip, uipp, ui_hash)
132 0 : if (uip->ui_uid == uid)
133 : break;
134 0 : if (uip)
135 0 : return (uip);
136 0 : rw_exit_write(&uidinfolk);
137 0 : nuip = malloc(sizeof(*nuip), M_PROC, M_WAITOK|M_ZERO);
138 0 : rw_enter_write(&uidinfolk);
139 0 : LIST_FOREACH(uip, uipp, ui_hash)
140 0 : if (uip->ui_uid == uid)
141 : break;
142 0 : if (uip) {
143 0 : free(nuip, M_PROC, sizeof(*nuip));
144 0 : return (uip);
145 : }
146 0 : nuip->ui_uid = uid;
147 0 : LIST_INSERT_HEAD(uipp, nuip, ui_hash);
148 :
149 0 : return (nuip);
150 0 : }
151 :
152 : void
153 0 : uid_release(struct uidinfo *uip)
154 : {
155 0 : rw_exit_write(&uidinfolk);
156 0 : }
157 :
158 : /*
159 : * Change the count associated with number of threads
160 : * a given user is using.
161 : */
162 : int
163 0 : chgproccnt(uid_t uid, int diff)
164 : {
165 : struct uidinfo *uip;
166 : long count;
167 :
168 0 : uip = uid_find(uid);
169 0 : count = (uip->ui_proccnt += diff);
170 0 : uid_release(uip);
171 0 : if (count < 0)
172 0 : panic("chgproccnt: procs < 0");
173 0 : return count;
174 : }
175 :
176 : /*
177 : * Is pr an inferior of parent?
178 : */
179 : int
180 0 : inferior(struct process *pr, struct process *parent)
181 : {
182 :
183 0 : for (; pr != parent; pr = pr->ps_pptr)
184 0 : if (pr->ps_pid == 0 || pr->ps_pid == 1)
185 0 : return (0);
186 0 : return (1);
187 0 : }
188 :
189 : /*
190 : * Locate a proc (thread) by number
191 : */
192 : struct proc *
193 0 : tfind(pid_t tid)
194 : {
195 : struct proc *p;
196 :
197 0 : LIST_FOREACH(p, TIDHASH(tid), p_hash)
198 0 : if (p->p_tid == tid)
199 0 : return (p);
200 0 : return (NULL);
201 0 : }
202 :
203 : /*
204 : * Locate a process by number
205 : */
206 : struct process *
207 0 : prfind(pid_t pid)
208 : {
209 : struct process *pr;
210 :
211 0 : LIST_FOREACH(pr, PIDHASH(pid), ps_hash)
212 0 : if (pr->ps_pid == pid)
213 0 : return (pr);
214 0 : return (NULL);
215 0 : }
216 :
217 : /*
218 : * Locate a process group by number
219 : */
220 : struct pgrp *
221 0 : pgfind(pid_t pgid)
222 : {
223 : struct pgrp *pgrp;
224 :
225 0 : LIST_FOREACH(pgrp, PGRPHASH(pgid), pg_hash)
226 0 : if (pgrp->pg_id == pgid)
227 0 : return (pgrp);
228 0 : return (NULL);
229 0 : }
230 :
231 : /*
232 : * Locate a zombie process
233 : */
234 : struct process *
235 0 : zombiefind(pid_t pid)
236 : {
237 : struct process *pr;
238 :
239 0 : LIST_FOREACH(pr, &zombprocess, ps_list)
240 0 : if (pr->ps_pid == pid)
241 0 : return (pr);
242 0 : return (NULL);
243 0 : }
244 :
245 : /*
246 : * Move process to a new process group. If a session is provided
247 : * then it's a new session to contain this process group; otherwise
248 : * the process is staying within its existing session.
249 : */
250 : void
251 0 : enternewpgrp(struct process *pr, struct pgrp *pgrp, struct session *newsess)
252 : {
253 : #ifdef DIAGNOSTIC
254 0 : if (SESS_LEADER(pr))
255 0 : panic("%s: session leader attempted setpgrp", __func__);
256 : #endif
257 :
258 0 : if (newsess != NULL) {
259 : /*
260 : * New session. Initialize it completely
261 : */
262 0 : timeout_set(&newsess->s_verauthto, zapverauth, newsess);
263 0 : newsess->s_leader = pr;
264 0 : newsess->s_count = 1;
265 0 : newsess->s_ttyvp = NULL;
266 0 : newsess->s_ttyp = NULL;
267 0 : memcpy(newsess->s_login, pr->ps_session->s_login,
268 : sizeof(newsess->s_login));
269 0 : atomic_clearbits_int(&pr->ps_flags, PS_CONTROLT);
270 0 : pgrp->pg_session = newsess;
271 : #ifdef DIAGNOSTIC
272 0 : if (pr != curproc->p_p)
273 0 : panic("%s: mksession but not curproc", __func__);
274 : #endif
275 : } else {
276 0 : pgrp->pg_session = pr->ps_session;
277 0 : pgrp->pg_session->s_count++;
278 : }
279 0 : pgrp->pg_id = pr->ps_pid;
280 0 : LIST_INIT(&pgrp->pg_members);
281 0 : LIST_INSERT_HEAD(PGRPHASH(pr->ps_pid), pgrp, pg_hash);
282 0 : pgrp->pg_jobc = 0;
283 :
284 0 : enterthispgrp(pr, pgrp);
285 0 : }
286 :
287 : /*
288 : * move process to an existing process group
289 : */
290 : void
291 0 : enterthispgrp(struct process *pr, struct pgrp *pgrp)
292 : {
293 0 : struct pgrp *savepgrp = pr->ps_pgrp;
294 :
295 : /*
296 : * Adjust eligibility of affected pgrps to participate in job control.
297 : * Increment eligibility counts before decrementing, otherwise we
298 : * could reach 0 spuriously during the first call.
299 : */
300 0 : fixjobc(pr, pgrp, 1);
301 0 : fixjobc(pr, savepgrp, 0);
302 :
303 0 : LIST_REMOVE(pr, ps_pglist);
304 0 : pr->ps_pgrp = pgrp;
305 0 : LIST_INSERT_HEAD(&pgrp->pg_members, pr, ps_pglist);
306 0 : if (LIST_EMPTY(&savepgrp->pg_members))
307 0 : pgdelete(savepgrp);
308 0 : }
309 :
310 : /*
311 : * remove process from process group
312 : */
313 : void
314 0 : leavepgrp(struct process *pr)
315 : {
316 :
317 0 : if (pr->ps_session->s_verauthppid == pr->ps_pid)
318 0 : zapverauth(pr->ps_session);
319 0 : LIST_REMOVE(pr, ps_pglist);
320 0 : if (LIST_EMPTY(&pr->ps_pgrp->pg_members))
321 0 : pgdelete(pr->ps_pgrp);
322 0 : pr->ps_pgrp = 0;
323 0 : }
324 :
325 : /*
326 : * delete a process group
327 : */
328 : void
329 0 : pgdelete(struct pgrp *pgrp)
330 : {
331 :
332 0 : if (pgrp->pg_session->s_ttyp != NULL &&
333 0 : pgrp->pg_session->s_ttyp->t_pgrp == pgrp)
334 0 : pgrp->pg_session->s_ttyp->t_pgrp = NULL;
335 0 : LIST_REMOVE(pgrp, pg_hash);
336 0 : SESSRELE(pgrp->pg_session);
337 0 : pool_put(&pgrp_pool, pgrp);
338 0 : }
339 :
340 : void
341 0 : zapverauth(void *v)
342 : {
343 0 : struct session *sess = v;
344 0 : sess->s_verauthuid = 0;
345 0 : sess->s_verauthppid = 0;
346 0 : }
347 :
348 : /*
349 : * Adjust pgrp jobc counters when specified process changes process group.
350 : * We count the number of processes in each process group that "qualify"
351 : * the group for terminal job control (those with a parent in a different
352 : * process group of the same session). If that count reaches zero, the
353 : * process group becomes orphaned. Check both the specified process'
354 : * process group and that of its children.
355 : * entering == 0 => pr is leaving specified group.
356 : * entering == 1 => pr is entering specified group.
357 : * XXX need proctree lock
358 : */
359 : void
360 0 : fixjobc(struct process *pr, struct pgrp *pgrp, int entering)
361 : {
362 : struct pgrp *hispgrp;
363 0 : struct session *mysession = pgrp->pg_session;
364 :
365 : /*
366 : * Check pr's parent to see whether pr qualifies its own process
367 : * group; if so, adjust count for pr's process group.
368 : */
369 0 : if ((hispgrp = pr->ps_pptr->ps_pgrp) != pgrp &&
370 0 : hispgrp->pg_session == mysession) {
371 0 : if (entering)
372 0 : pgrp->pg_jobc++;
373 0 : else if (--pgrp->pg_jobc == 0)
374 0 : orphanpg(pgrp);
375 : }
376 :
377 : /*
378 : * Check this process' children to see whether they qualify
379 : * their process groups; if so, adjust counts for children's
380 : * process groups.
381 : */
382 0 : LIST_FOREACH(pr, &pr->ps_children, ps_sibling)
383 0 : if ((hispgrp = pr->ps_pgrp) != pgrp &&
384 0 : hispgrp->pg_session == mysession &&
385 0 : (pr->ps_flags & PS_ZOMBIE) == 0) {
386 0 : if (entering)
387 0 : hispgrp->pg_jobc++;
388 0 : else if (--hispgrp->pg_jobc == 0)
389 0 : orphanpg(hispgrp);
390 : }
391 0 : }
392 :
393 : void
394 0 : killjobc(struct process *pr)
395 : {
396 0 : if (SESS_LEADER(pr)) {
397 : struct session *sp = pr->ps_session;
398 :
399 0 : if (sp->s_ttyvp) {
400 : struct vnode *ovp;
401 :
402 : /*
403 : * Controlling process.
404 : * Signal foreground pgrp,
405 : * drain controlling terminal
406 : * and revoke access to controlling terminal.
407 : */
408 0 : if (sp->s_ttyp->t_session == sp) {
409 0 : if (sp->s_ttyp->t_pgrp)
410 0 : pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1);
411 0 : ttywait(sp->s_ttyp);
412 : /*
413 : * The tty could have been revoked
414 : * if we blocked.
415 : */
416 0 : if (sp->s_ttyvp)
417 0 : VOP_REVOKE(sp->s_ttyvp, REVOKEALL);
418 : }
419 0 : ovp = sp->s_ttyvp;
420 0 : sp->s_ttyvp = NULL;
421 0 : if (ovp)
422 0 : vrele(ovp);
423 : /*
424 : * s_ttyp is not zero'd; we use this to
425 : * indicate that the session once had a
426 : * controlling terminal. (for logging and
427 : * informational purposes)
428 : */
429 0 : }
430 0 : sp->s_leader = NULL;
431 0 : }
432 0 : fixjobc(pr, pr->ps_pgrp, 0);
433 0 : }
434 :
435 : /*
436 : * A process group has become orphaned;
437 : * if there are any stopped processes in the group,
438 : * hang-up all process in that group.
439 : */
440 : static void
441 0 : orphanpg(struct pgrp *pg)
442 : {
443 : struct process *pr;
444 :
445 0 : LIST_FOREACH(pr, &pg->pg_members, ps_pglist) {
446 0 : if (pr->ps_mainproc->p_stat == SSTOP) {
447 0 : LIST_FOREACH(pr, &pg->pg_members, ps_pglist) {
448 0 : prsignal(pr, SIGHUP);
449 0 : prsignal(pr, SIGCONT);
450 : }
451 0 : return;
452 : }
453 : }
454 0 : }
455 :
456 : #ifdef DDB
457 : void
458 0 : proc_printit(struct proc *p, const char *modif,
459 : int (*pr)(const char *, ...) __attribute__((__format__(__kprintf__,1,2))))
460 : {
461 : static const char *const pstat[] = {
462 : "idle", "run", "sleep", "stop", "zombie", "dead", "onproc"
463 : };
464 0 : char pstbuf[5];
465 0 : const char *pst = pstbuf;
466 :
467 :
468 0 : if (p->p_stat < 1 || p->p_stat > sizeof(pstat) / sizeof(pstat[0]))
469 0 : snprintf(pstbuf, sizeof(pstbuf), "%d", p->p_stat);
470 : else
471 0 : pst = pstat[(int)p->p_stat - 1];
472 :
473 0 : (*pr)("PROC (%s) pid=%d stat=%s\n", p->p_p->ps_comm, p->p_tid, pst);
474 0 : (*pr)(" flags process=%b proc=%b\n",
475 0 : p->p_p->ps_flags, PS_BITS, p->p_flag, P_BITS);
476 0 : (*pr)(" pri=%u, usrpri=%u, nice=%d\n",
477 0 : p->p_priority, p->p_usrpri, p->p_p->ps_nice);
478 0 : (*pr)(" forw=%p, list=%p,%p\n",
479 0 : TAILQ_NEXT(p, p_runq), p->p_list.le_next, p->p_list.le_prev);
480 0 : (*pr)(" process=%p user=%p, vmspace=%p\n",
481 0 : p->p_p, p->p_addr, p->p_vmspace);
482 0 : (*pr)(" estcpu=%u, cpticks=%d, pctcpu=%u.%u\n",
483 0 : p->p_estcpu, p->p_cpticks, p->p_pctcpu / 100, p->p_pctcpu % 100);
484 0 : (*pr)(" user=%u, sys=%u, intr=%u\n",
485 0 : p->p_uticks, p->p_sticks, p->p_iticks);
486 0 : }
487 : #include <machine/db_machdep.h>
488 :
489 : #include <ddb/db_output.h>
490 :
491 : void
492 0 : db_kill_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
493 : {
494 : struct process *pr;
495 0 : struct sigaction sa;
496 : struct proc *p;
497 :
498 0 : pr = prfind(addr);
499 0 : if (pr == NULL) {
500 0 : db_printf("%ld: No such process", addr);
501 0 : return;
502 : }
503 :
504 0 : p = TAILQ_FIRST(&pr->ps_threads);
505 :
506 : /* Send uncatchable SIGABRT for coredump */
507 0 : memset(&sa, 0, sizeof sa);
508 0 : sa.sa_handler = SIG_DFL;
509 0 : setsigvec(p, SIGABRT, &sa);
510 0 : atomic_clearbits_int(&p->p_sigmask, sigmask(SIGABRT));
511 0 : psignal(p, SIGABRT);
512 0 : }
513 :
514 : void
515 0 : db_show_all_procs(db_expr_t addr, int haddr, db_expr_t count, char *modif)
516 : {
517 : char *mode;
518 : int skipzomb = 0;
519 : int has_kernel_lock = 0;
520 : struct proc *p;
521 : struct process *pr, *ppr;
522 :
523 0 : if (modif[0] == 0)
524 0 : modif[0] = 'n'; /* default == normal mode */
525 :
526 : mode = "mawno";
527 0 : while (*mode && *mode != modif[0])
528 0 : mode++;
529 0 : if (*mode == 0 || *mode == 'm') {
530 0 : db_printf("usage: show all procs [/a] [/n] [/w]\n");
531 0 : db_printf("\t/a == show process address info\n");
532 0 : db_printf("\t/n == show normal process info [default]\n");
533 0 : db_printf("\t/w == show process pgrp/wait info\n");
534 0 : db_printf("\t/o == show normal info for non-idle SONPROC\n");
535 0 : return;
536 : }
537 :
538 0 : pr = LIST_FIRST(&allprocess);
539 :
540 0 : switch (*mode) {
541 :
542 : case 'a':
543 0 : db_printf(" TID %-9s %18s %18s %18s\n",
544 : "COMMAND", "STRUCT PROC *", "UAREA *", "VMSPACE/VM_MAP");
545 0 : break;
546 : case 'n':
547 0 : db_printf(" PID %6s %5s %5s S %10s %-12s %-15s\n",
548 : "TID", "PPID", "UID", "FLAGS", "WAIT", "COMMAND");
549 0 : break;
550 : case 'w':
551 0 : db_printf(" TID %-15s %-5s %18s %s\n",
552 : "COMMAND", "PGRP", "WAIT-CHANNEL", "WAIT-MSG");
553 0 : break;
554 : case 'o':
555 : skipzomb = 1;
556 0 : db_printf(" TID %5s %5s %10s %10s %3s %-30s\n",
557 : "PID", "UID", "PRFLAGS", "PFLAGS", "CPU", "COMMAND");
558 0 : break;
559 : }
560 :
561 0 : while (pr != NULL) {
562 0 : ppr = pr->ps_pptr;
563 :
564 0 : TAILQ_FOREACH(p, &pr->ps_threads, p_thr_link) {
565 : #ifdef MULTIPROCESSOR
566 0 : if (__mp_lock_held(&kernel_lock, p->p_cpu))
567 0 : has_kernel_lock = 1;
568 : else
569 : has_kernel_lock = 0;
570 : #endif
571 0 : if (p->p_stat) {
572 0 : if (*mode == 'o') {
573 0 : if (p->p_stat != SONPROC)
574 : continue;
575 0 : if (p->p_cpu != NULL && p->p_cpu->
576 0 : ci_schedstate.spc_idleproc == p)
577 : continue;
578 : }
579 :
580 0 : if (*mode == 'n') {
581 0 : db_printf("%c%5d ", (p == curproc ?
582 0 : '*' : ' '), pr->ps_pid);
583 0 : } else {
584 0 : db_printf("%c%6d ", (p == curproc ?
585 0 : '*' : ' '), p->p_tid);
586 : }
587 :
588 0 : switch (*mode) {
589 :
590 : case 'a':
591 0 : db_printf("%-9.9s %18p %18p %18p\n",
592 0 : pr->ps_comm, p, p->p_addr, p->p_vmspace);
593 0 : break;
594 :
595 : case 'n':
596 0 : db_printf("%6d %5d %5d %d %#10x "
597 : "%-12.12s %-15s\n",
598 0 : p->p_tid, ppr ? ppr->ps_pid : -1,
599 0 : pr->ps_ucred->cr_ruid, p->p_stat,
600 0 : p->p_flag | pr->ps_flags,
601 0 : (p->p_wchan && p->p_wmesg) ?
602 0 : p->p_wmesg : "", pr->ps_comm);
603 0 : break;
604 :
605 : case 'w':
606 0 : db_printf("%-15s %-5d %18p %s\n",
607 0 : pr->ps_comm, (pr->ps_pgrp ?
608 0 : pr->ps_pgrp->pg_id : -1),
609 0 : p->p_wchan,
610 0 : (p->p_wchan && p->p_wmesg) ?
611 : p->p_wmesg : "");
612 0 : break;
613 :
614 : case 'o':
615 0 : db_printf("%5d %5d %#10x %#10x %3d"
616 : "%c %-31s\n",
617 0 : pr->ps_pid, pr->ps_ucred->cr_ruid,
618 0 : pr->ps_flags, p->p_flag,
619 0 : CPU_INFO_UNIT(p->p_cpu),
620 0 : has_kernel_lock ? 'K' : ' ',
621 0 : pr->ps_comm);
622 0 : break;
623 :
624 : }
625 : }
626 : }
627 0 : pr = LIST_NEXT(pr, ps_list);
628 0 : if (pr == NULL && skipzomb == 0) {
629 : skipzomb = 1;
630 0 : pr = LIST_FIRST(&zombprocess);
631 0 : }
632 : }
633 0 : }
634 : #endif
635 :
636 : #ifdef DEBUG
637 : void
638 : pgrpdump(void)
639 : {
640 : struct pgrp *pgrp;
641 : struct process *pr;
642 : int i;
643 :
644 : for (i = 0; i <= pgrphash; i++) {
645 : if (!LIST_EMPTY(&pgrphashtbl[i])) {
646 : printf("\tindx %d\n", i);
647 : LIST_FOREACH(pgrp, &pgrphashtbl[i], pg_hash) {
648 : printf("\tpgrp %p, pgid %d, sess %p, sesscnt %d, mem %p\n",
649 : pgrp, pgrp->pg_id, pgrp->pg_session,
650 : pgrp->pg_session->s_count,
651 : LIST_FIRST(&pgrp->pg_members));
652 : LIST_FOREACH(pr, &pgrp->pg_members, ps_pglist) {
653 : printf("\t\tpid %d addr %p pgrp %p\n",
654 : pr->ps_pid, pr, pr->ps_pgrp);
655 : }
656 : }
657 : }
658 : }
659 : }
660 : #endif /* DEBUG */
|