1 /* $OpenBSD: kern_proc.c,v 1.18 2004/01/29 17:19:42 millert 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 /* 53 * Structure associated with user cacheing. 54 */ 55 struct uidinfo { 56 LIST_ENTRY(uidinfo) ui_hash; 57 uid_t ui_uid; 58 long ui_proccnt; 59 }; 60 #define UIHASH(uid) (&uihashtbl[(uid) & uihash]) 61 LIST_HEAD(uihashhead, uidinfo) *uihashtbl; 62 u_long uihash; /* size of hash table - 1 */ 63 64 /* 65 * Other process lists 66 */ 67 struct pidhashhead *pidhashtbl; 68 u_long pidhash; 69 struct pgrphashhead *pgrphashtbl; 70 u_long pgrphash; 71 struct proclist allproc; 72 struct proclist zombproc; 73 74 struct pool proc_pool; 75 struct pool rusage_pool; 76 struct pool ucred_pool; 77 struct pool pgrp_pool; 78 struct pool session_pool; 79 struct pool pcred_pool; 80 81 /* 82 * Locking of this proclist is special; it's accessed in a 83 * critical section of process exit, and thus locking it can't 84 * modify interrupt state. We use a simple spin lock for this 85 * proclist. Processes on this proclist are also on zombproc; 86 * we use the p_hash member to linkup to deadproc. 87 */ 88 struct simplelock deadproc_slock; 89 struct proclist deadproc; /* dead, but not yet undead */ 90 91 static void orphanpg(struct pgrp *); 92 #ifdef DEBUG 93 void pgrpdump(void); 94 #endif 95 96 /* 97 * Initialize global process hashing structures. 98 */ 99 void 100 procinit() 101 { 102 103 LIST_INIT(&allproc); 104 LIST_INIT(&zombproc); 105 106 LIST_INIT(&deadproc); 107 simple_lock_init(&deadproc_slock); 108 109 pidhashtbl = hashinit(maxproc / 4, M_PROC, M_WAITOK, &pidhash); 110 pgrphashtbl = hashinit(maxproc / 4, M_PROC, M_WAITOK, &pgrphash); 111 uihashtbl = hashinit(maxproc / 16, M_PROC, M_WAITOK, &uihash); 112 113 pool_init(&proc_pool, sizeof(struct proc), 0, 0, 0, "procpl", 114 &pool_allocator_nointr); 115 pool_init(&rusage_pool, sizeof(struct rusage), 0, 0, 0, "zombiepl", 116 &pool_allocator_nointr); 117 pool_init(&ucred_pool, sizeof(struct ucred), 0, 0, 0, "ucredpl", 118 &pool_allocator_nointr); 119 pool_init(&pgrp_pool, sizeof(struct pgrp), 0, 0, 0, "pgrppl", 120 &pool_allocator_nointr); 121 pool_init(&session_pool, sizeof(struct session), 0, 0, 0, "sessionpl", 122 &pool_allocator_nointr); 123 pool_init(&pcred_pool, sizeof(struct pcred), 0, 0, 0, "pcredpl", 124 &pool_allocator_nointr); 125 } 126 127 /* 128 * Change the count associated with number of processes 129 * a given user is using. 130 */ 131 int 132 chgproccnt(uid, diff) 133 uid_t uid; 134 int diff; 135 { 136 register struct uidinfo *uip; 137 register struct uihashhead *uipp; 138 139 uipp = UIHASH(uid); 140 for (uip = uipp->lh_first; uip != 0; uip = uip->ui_hash.le_next) 141 if (uip->ui_uid == uid) 142 break; 143 if (uip) { 144 uip->ui_proccnt += diff; 145 if (uip->ui_proccnt > 0) 146 return (uip->ui_proccnt); 147 if (uip->ui_proccnt < 0) 148 panic("chgproccnt: procs < 0"); 149 LIST_REMOVE(uip, ui_hash); 150 FREE(uip, M_PROC); 151 return (0); 152 } 153 if (diff <= 0) { 154 if (diff == 0) 155 return(0); 156 panic("chgproccnt: lost user"); 157 } 158 MALLOC(uip, struct uidinfo *, sizeof(*uip), M_PROC, M_WAITOK); 159 LIST_INSERT_HEAD(uipp, uip, ui_hash); 160 uip->ui_uid = uid; 161 uip->ui_proccnt = diff; 162 return (diff); 163 } 164 165 /* 166 * Is p an inferior of the current process? 167 */ 168 int 169 inferior(p) 170 register struct proc *p; 171 { 172 173 for (; p != curproc; p = p->p_pptr) 174 if (p->p_pid == 0) 175 return (0); 176 return (1); 177 } 178 179 /* 180 * Locate a process by number 181 */ 182 struct proc * 183 pfind(pid) 184 register pid_t pid; 185 { 186 register struct proc *p; 187 188 for (p = PIDHASH(pid)->lh_first; p != 0; p = p->p_hash.le_next) 189 if (p->p_pid == pid) 190 return (p); 191 return (NULL); 192 } 193 194 /* 195 * Locate a process group by number 196 */ 197 struct pgrp * 198 pgfind(pgid) 199 register pid_t pgid; 200 { 201 register struct pgrp *pgrp; 202 203 for (pgrp = PGRPHASH(pgid)->lh_first; pgrp != 0; pgrp = pgrp->pg_hash.le_next) 204 if (pgrp->pg_id == pgid) 205 return (pgrp); 206 return (NULL); 207 } 208 209 /* 210 * Move p to a new or existing process group (and session) 211 */ 212 int 213 enterpgrp(p, pgid, mksess) 214 register struct proc *p; 215 pid_t pgid; 216 int mksess; 217 { 218 register struct pgrp *pgrp = pgfind(pgid); 219 220 #ifdef DIAGNOSTIC 221 if (pgrp != NULL && mksess) /* firewalls */ 222 panic("enterpgrp: setsid into non-empty pgrp"); 223 if (SESS_LEADER(p)) 224 panic("enterpgrp: session leader attempted setpgrp"); 225 #endif 226 if (pgrp == NULL) { 227 pid_t savepid = p->p_pid; 228 struct proc *np; 229 /* 230 * new process group 231 */ 232 #ifdef DIAGNOSTIC 233 if (p->p_pid != pgid) 234 panic("enterpgrp: new pgrp and pid != pgid"); 235 #endif 236 if ((np = pfind(savepid)) == NULL || np != p) 237 return (ESRCH); 238 pgrp = pool_get(&pgrp_pool, PR_WAITOK); 239 if (mksess) { 240 register struct session *sess; 241 242 /* 243 * new session 244 */ 245 sess = pool_get(&session_pool, PR_WAITOK); 246 sess->s_leader = p; 247 sess->s_count = 1; 248 sess->s_ttyvp = NULL; 249 sess->s_ttyp = NULL; 250 bcopy(p->p_session->s_login, sess->s_login, 251 sizeof(sess->s_login)); 252 p->p_flag &= ~P_CONTROLT; 253 pgrp->pg_session = sess; 254 #ifdef DIAGNOSTIC 255 if (p != curproc) 256 panic("enterpgrp: mksession and p != curproc"); 257 #endif 258 } else { 259 pgrp->pg_session = p->p_session; 260 pgrp->pg_session->s_count++; 261 } 262 pgrp->pg_id = pgid; 263 LIST_INIT(&pgrp->pg_members); 264 LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash); 265 pgrp->pg_jobc = 0; 266 } else if (pgrp == p->p_pgrp) 267 return (0); 268 269 /* 270 * Adjust eligibility of affected pgrps to participate in job control. 271 * Increment eligibility counts before decrementing, otherwise we 272 * could reach 0 spuriously during the first call. 273 */ 274 fixjobc(p, pgrp, 1); 275 fixjobc(p, p->p_pgrp, 0); 276 277 LIST_REMOVE(p, p_pglist); 278 if (p->p_pgrp->pg_members.lh_first == 0) 279 pgdelete(p->p_pgrp); 280 p->p_pgrp = pgrp; 281 LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist); 282 return (0); 283 } 284 285 /* 286 * remove process from process group 287 */ 288 int 289 leavepgrp(p) 290 register struct proc *p; 291 { 292 293 LIST_REMOVE(p, p_pglist); 294 if (p->p_pgrp->pg_members.lh_first == 0) 295 pgdelete(p->p_pgrp); 296 p->p_pgrp = 0; 297 return (0); 298 } 299 300 /* 301 * delete a process group 302 */ 303 void 304 pgdelete(pgrp) 305 register struct pgrp *pgrp; 306 { 307 308 if (pgrp->pg_session->s_ttyp != NULL && 309 pgrp->pg_session->s_ttyp->t_pgrp == pgrp) 310 pgrp->pg_session->s_ttyp->t_pgrp = NULL; 311 LIST_REMOVE(pgrp, pg_hash); 312 SESSRELE(pgrp->pg_session); 313 pool_put(&pgrp_pool, pgrp); 314 } 315 316 /* 317 * Adjust pgrp jobc counters when specified process changes process group. 318 * We count the number of processes in each process group that "qualify" 319 * the group for terminal job control (those with a parent in a different 320 * process group of the same session). If that count reaches zero, the 321 * process group becomes orphaned. Check both the specified process' 322 * process group and that of its children. 323 * entering == 0 => p is leaving specified group. 324 * entering == 1 => p is entering specified group. 325 */ 326 void 327 fixjobc(p, pgrp, entering) 328 register struct proc *p; 329 register struct pgrp *pgrp; 330 int entering; 331 { 332 register struct pgrp *hispgrp; 333 register struct session *mysession = pgrp->pg_session; 334 335 /* 336 * Check p's parent to see whether p qualifies its own process 337 * group; if so, adjust count for p's process group. 338 */ 339 if ((hispgrp = p->p_pptr->p_pgrp) != pgrp && 340 hispgrp->pg_session == mysession) { 341 if (entering) 342 pgrp->pg_jobc++; 343 else if (--pgrp->pg_jobc == 0) 344 orphanpg(pgrp); 345 } 346 347 /* 348 * Check this process' children to see whether they qualify 349 * their process groups; if so, adjust counts for children's 350 * process groups. 351 */ 352 for (p = p->p_children.lh_first; p != 0; p = p->p_sibling.le_next) 353 if ((hispgrp = p->p_pgrp) != pgrp && 354 hispgrp->pg_session == mysession && 355 P_ZOMBIE(p) == 0) { 356 if (entering) 357 hispgrp->pg_jobc++; 358 else if (--hispgrp->pg_jobc == 0) 359 orphanpg(hispgrp); 360 } 361 } 362 363 /* 364 * A process group has become orphaned; 365 * if there are any stopped processes in the group, 366 * hang-up all process in that group. 367 */ 368 static void 369 orphanpg(pg) 370 struct pgrp *pg; 371 { 372 register struct proc *p; 373 374 for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) { 375 if (p->p_stat == SSTOP) { 376 for (p = pg->pg_members.lh_first; p != 0; 377 p = p->p_pglist.le_next) { 378 psignal(p, SIGHUP); 379 psignal(p, SIGCONT); 380 } 381 return; 382 } 383 } 384 } 385 386 void 387 proc_printit(struct proc *p, const char *modif, int (*pr)(const char *, ...)) 388 { 389 static const char *const pstat[] = { 390 "idle", "run", "sleep", "stop", "zombie", "dead" 391 }; 392 char pstbuf[5]; 393 const char *pst = pstbuf; 394 395 if (p->p_stat < 1 || p->p_stat > sizeof(pstat) / sizeof(pstat[0])) 396 snprintf(pstbuf, sizeof(pstbuf), "%d", p->p_stat); 397 else 398 pst = pstat[(int)p->p_stat - 1]; 399 400 (*pr)("PROC (%s) pid=%d stat=%s flags=%b\n", 401 p->p_comm, p->p_pid, pst, p->p_flag, P_BITS); 402 (*pr)(" pri=%u, usrpri=%u, nice=%d\n", 403 p->p_priority, p->p_usrpri, p->p_nice); 404 (*pr)(" forw=%p, back=%p, list=%p,%p\n", 405 p->p_forw, p->p_back, p->p_list.le_next, p->p_list.le_prev); 406 (*pr)(" user=%p, vmspace=%p\n", 407 p->p_addr, p->p_vmspace); 408 (*pr)(" estcpu=%u, cpticks=%d, pctcpu=%u.%u%, swtime=%u\n", 409 p->p_estcpu, p->p_cpticks, p->p_pctcpu / 100, p->p_pctcpu % 100, 410 p->p_swtime); 411 (*pr)(" user=%llu, sys=%llu, intr=%llu\n", 412 p->p_uticks, p->p_sticks, p->p_iticks); 413 } 414 415 #ifdef DEBUG 416 void 417 pgrpdump() 418 { 419 register struct pgrp *pgrp; 420 register struct proc *p; 421 register int i; 422 423 for (i = 0; i <= pgrphash; i++) { 424 if ((pgrp = pgrphashtbl[i].lh_first) != NULL) { 425 printf("\tindx %d\n", i); 426 for (; pgrp != 0; pgrp = pgrp->pg_hash.le_next) { 427 printf("\tpgrp %p, pgid %d, sess %p, sesscnt %d, mem %p\n", 428 pgrp, pgrp->pg_id, pgrp->pg_session, 429 pgrp->pg_session->s_count, 430 pgrp->pg_members.lh_first); 431 for (p = pgrp->pg_members.lh_first; p != 0; 432 p = p->p_pglist.le_next) { 433 printf("\t\tpid %d addr %p pgrp %p\n", 434 p->p_pid, p, p->p_pgrp); 435 } 436 } 437 } 438 } 439 } 440 #endif /* DEBUG */ 441