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