kern_proc.c revision 3451
1/* 2 * Copyright (c) 1982, 1986, 1989, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)kern_proc.c 8.4 (Berkeley) 1/4/94 34 * $Id: kern_proc.c,v 1.7 1994/10/02 04:45:48 davidg Exp $ 35 */ 36 37#include <sys/param.h> 38#include <sys/systm.h> 39#include <sys/kernel.h> 40#include <sys/proc.h> 41#include <sys/buf.h> 42#include <sys/acct.h> 43#include <sys/wait.h> 44#include <sys/file.h> 45#include <ufs/ufs/quota.h> 46#include <sys/uio.h> 47#include <sys/malloc.h> 48#include <sys/mbuf.h> 49#include <sys/ioctl.h> 50#include <sys/tty.h> 51#include <sys/signalvar.h> 52 53struct prochd qs[NQS]; /* as good a place as any... */ 54struct prochd rtqs[NQS]; /* Space for REALTIME queues too */ 55struct prochd idqs[NQS]; /* Space for IDLE queues too */ 56 57volatile struct proc *allproc; /* all processes */ 58struct proc *zombproc; /* just zombies */ 59 60void pgdelete __P((struct pgrp *)); 61void fixjobc __P((struct proc *, struct pgrp *, int)); 62 63/* 64 * Structure associated with user cacheing. 65 */ 66struct uidinfo { 67 struct uidinfo *ui_next; 68 struct uidinfo **ui_prev; 69 uid_t ui_uid; 70 long ui_proccnt; 71} **uihashtbl; 72u_long uihash; /* size of hash table - 1 */ 73#define UIHASH(uid) ((uid) & uihash) 74 75/* 76 * Allocate a hash table. 77 */ 78void 79usrinfoinit() 80{ 81 82 uihashtbl = hashinit(maxproc / 16, M_PROC, &uihash); 83} 84 85/* 86 * Change the count associated with number of processes 87 * a given user is using. 88 */ 89int 90chgproccnt(uid, diff) 91 uid_t uid; 92 int diff; 93{ 94 register struct uidinfo **uipp, *uip, *uiq; 95 96 uipp = &uihashtbl[UIHASH(uid)]; 97 for (uip = *uipp; uip; uip = uip->ui_next) 98 if (uip->ui_uid == uid) 99 break; 100 if (uip) { 101 uip->ui_proccnt += diff; 102 if (uip->ui_proccnt > 0) 103 return (uip->ui_proccnt); 104 if (uip->ui_proccnt < 0) 105 panic("chgproccnt: procs < 0"); 106 if ((uiq = uip->ui_next)) 107 uiq->ui_prev = uip->ui_prev; 108 *uip->ui_prev = uiq; 109 FREE(uip, M_PROC); 110 return (0); 111 } 112 if (diff <= 0) { 113 if (diff == 0) 114 return(0); 115 panic("chgproccnt: lost user"); 116 } 117 MALLOC(uip, struct uidinfo *, sizeof(*uip), M_PROC, M_WAITOK); 118 if ((uiq = *uipp)) 119 uiq->ui_prev = &uip->ui_next; 120 uip->ui_next = uiq; 121 uip->ui_prev = uipp; 122 *uipp = uip; 123 uip->ui_uid = uid; 124 uip->ui_proccnt = diff; 125 return (diff); 126} 127 128/* 129 * Is p an inferior of the current process? 130 */ 131int 132inferior(p) 133 register struct proc *p; 134{ 135 136 for (; p != curproc; p = p->p_pptr) 137 if (p->p_pid == 0) 138 return (0); 139 return (1); 140} 141 142/* 143 * Locate a process by number 144 */ 145struct proc * 146pfind(pid) 147 register pid_t pid; 148{ 149 register struct proc *p; 150 151 for (p = pidhash[PIDHASH(pid)]; p != NULL; p = p->p_hash) 152 if (p->p_pid == pid) 153 return (p); 154 return (NULL); 155} 156 157/* 158 * Locate a process group by number 159 */ 160struct pgrp * 161pgfind(pgid) 162 register pid_t pgid; 163{ 164 register struct pgrp *pgrp; 165 166 for (pgrp = pgrphash[PIDHASH(pgid)]; 167 pgrp != NULL; pgrp = pgrp->pg_hforw) 168 if (pgrp->pg_id == pgid) 169 return (pgrp); 170 return (NULL); 171} 172 173/* 174 * Move p to a new or existing process group (and session) 175 */ 176int 177enterpgrp(p, pgid, mksess) 178 register struct proc *p; 179 pid_t pgid; 180 int mksess; 181{ 182 register struct pgrp *pgrp = pgfind(pgid); 183 register struct proc **pp; 184 int n; 185 186#ifdef DIAGNOSTIC 187 if (pgrp != NULL && mksess) /* firewalls */ 188 panic("enterpgrp: setsid into non-empty pgrp"); 189 if (SESS_LEADER(p)) 190 panic("enterpgrp: session leader attempted setpgrp"); 191#endif 192 if (pgrp == NULL) { 193 pid_t savepid = p->p_pid; 194 struct proc *np; 195 /* 196 * new process group 197 */ 198#ifdef DIAGNOSTIC 199 if (p->p_pid != pgid) 200 panic("enterpgrp: new pgrp and pid != pgid"); 201#endif 202 MALLOC(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, 203 M_WAITOK); 204 if ((np = pfind(savepid)) == NULL || np != p) 205 return (ESRCH); 206 if (mksess) { 207 register struct session *sess; 208 209 /* 210 * new session 211 */ 212 MALLOC(sess, struct session *, sizeof(struct session), 213 M_SESSION, M_WAITOK); 214 sess->s_leader = p; 215 sess->s_count = 1; 216 sess->s_ttyvp = NULL; 217 sess->s_ttyp = NULL; 218 bcopy(p->p_session->s_login, sess->s_login, 219 sizeof(sess->s_login)); 220 p->p_flag &= ~P_CONTROLT; 221 pgrp->pg_session = sess; 222#ifdef DIAGNOSTIC 223 if (p != curproc) 224 panic("enterpgrp: mksession and p != curproc"); 225#endif 226 } else { 227 pgrp->pg_session = p->p_session; 228 pgrp->pg_session->s_count++; 229 } 230 pgrp->pg_id = pgid; 231 pgrp->pg_hforw = pgrphash[n = PIDHASH(pgid)]; 232 pgrphash[n] = pgrp; 233 pgrp->pg_jobc = 0; 234 pgrp->pg_mem = NULL; 235 } else if (pgrp == p->p_pgrp) 236 return (0); 237 238 /* 239 * Adjust eligibility of affected pgrps to participate in job control. 240 * Increment eligibility counts before decrementing, otherwise we 241 * could reach 0 spuriously during the first call. 242 */ 243 fixjobc(p, pgrp, 1); 244 fixjobc(p, p->p_pgrp, 0); 245 246 /* 247 * unlink p from old process group 248 */ 249 for (pp = &p->p_pgrp->pg_mem; *pp; pp = &(*pp)->p_pgrpnxt) { 250 if (*pp == p) { 251 *pp = p->p_pgrpnxt; 252 break; 253 } 254 } 255#ifdef DIAGNOSTIC 256 if (pp == NULL) 257 panic("enterpgrp: can't find p on old pgrp"); 258#endif 259 /* 260 * delete old if empty 261 */ 262 if (p->p_pgrp->pg_mem == 0) 263 pgdelete(p->p_pgrp); 264 /* 265 * link into new one 266 */ 267 p->p_pgrp = pgrp; 268 p->p_pgrpnxt = pgrp->pg_mem; 269 pgrp->pg_mem = p; 270 return (0); 271} 272 273/* 274 * remove process from process group 275 */ 276int 277leavepgrp(p) 278 register struct proc *p; 279{ 280 register struct proc **pp = &p->p_pgrp->pg_mem; 281 282 for (; *pp; pp = &(*pp)->p_pgrpnxt) { 283 if (*pp == p) { 284 *pp = p->p_pgrpnxt; 285 break; 286 } 287 } 288#ifdef DIAGNOSTIC 289 if (pp == NULL) 290 panic("leavepgrp: can't find p in pgrp"); 291#endif 292 if (!p->p_pgrp->pg_mem) 293 pgdelete(p->p_pgrp); 294 p->p_pgrp = 0; 295 return (0); 296} 297 298/* 299 * delete a process group 300 */ 301void 302pgdelete(pgrp) 303 register struct pgrp *pgrp; 304{ 305 register struct pgrp **pgp = &pgrphash[PIDHASH(pgrp->pg_id)]; 306 307 if (pgrp->pg_session->s_ttyp != NULL && 308 pgrp->pg_session->s_ttyp->t_pgrp == pgrp) 309 pgrp->pg_session->s_ttyp->t_pgrp = NULL; 310 for (; *pgp; pgp = &(*pgp)->pg_hforw) { 311 if (*pgp == pgrp) { 312 *pgp = pgrp->pg_hforw; 313 break; 314 } 315 } 316#ifdef DIAGNOSTIC 317 if (pgp == NULL) 318 panic("pgdelete: can't find pgrp on hash chain"); 319#endif 320 if (--pgrp->pg_session->s_count == 0) 321 FREE(pgrp->pg_session, M_SESSION); 322 FREE(pgrp, M_PGRP); 323} 324 325static void orphanpg(); 326 327/* 328 * Adjust pgrp jobc counters when specified process changes process group. 329 * We count the number of processes in each process group that "qualify" 330 * the group for terminal job control (those with a parent in a different 331 * process group of the same session). If that count reaches zero, the 332 * process group becomes orphaned. Check both the specified process' 333 * process group and that of its children. 334 * entering == 0 => p is leaving specified group. 335 * entering == 1 => p is entering specified group. 336 */ 337void 338fixjobc(p, pgrp, entering) 339 register struct proc *p; 340 register struct pgrp *pgrp; 341 int entering; 342{ 343 register struct pgrp *hispgrp; 344 register struct session *mysession = pgrp->pg_session; 345 346 /* 347 * Check p's parent to see whether p qualifies its own process 348 * group; if so, adjust count for p's process group. 349 */ 350 if ((hispgrp = p->p_pptr->p_pgrp) != pgrp && 351 hispgrp->pg_session == mysession) 352 if (entering) 353 pgrp->pg_jobc++; 354 else if (--pgrp->pg_jobc == 0) 355 orphanpg(pgrp); 356 357 /* 358 * Check this process' children to see whether they qualify 359 * their process groups; if so, adjust counts for children's 360 * process groups. 361 */ 362 for (p = p->p_cptr; p; p = p->p_osptr) 363 if ((hispgrp = p->p_pgrp) != pgrp && 364 hispgrp->pg_session == mysession && 365 p->p_stat != SZOMB) 366 if (entering) 367 hispgrp->pg_jobc++; 368 else if (--hispgrp->pg_jobc == 0) 369 orphanpg(hispgrp); 370} 371 372/* 373 * A process group has become orphaned; 374 * if there are any stopped processes in the group, 375 * hang-up all process in that group. 376 */ 377static void 378orphanpg(pg) 379 struct pgrp *pg; 380{ 381 register struct proc *p; 382 383 for (p = pg->pg_mem; p; p = p->p_pgrpnxt) { 384 if (p->p_stat == SSTOP) { 385 for (p = pg->pg_mem; p; p = p->p_pgrpnxt) { 386 psignal(p, SIGHUP); 387 psignal(p, SIGCONT); 388 } 389 return; 390 } 391 } 392} 393 394#ifdef debug 395/* DEBUG */ 396pgrpdump() 397{ 398 register struct pgrp *pgrp; 399 register struct proc *p; 400 register i; 401 402 for (i=0; i<PIDHSZ; i++) { 403 if (pgrphash[i]) { 404 printf("\tindx %d\n", i); 405 for (pgrp=pgrphash[i]; pgrp; pgrp=pgrp->pg_hforw) { 406 printf("\tpgrp %x, pgid %d, sess %x, sesscnt %d, mem %x\n", 407 pgrp, pgrp->pg_id, pgrp->pg_session, 408 pgrp->pg_session->s_count, pgrp->pg_mem); 409 for (p=pgrp->pg_mem; p; p=p->p_pgrpnxt) { 410 printf("\t\tpid %d addr %x pgrp %x\n", 411 p->p_pid, p, p->p_pgrp); 412 } 413 } 414 415 } 416 } 417} 418#endif /* debug */ 419