$Phantasm: delphijweb/research/freebsd/pid-tjr.diff,v 1.7 2004/08/14 18:02:04 delphij Exp $ Updated tjr's FreeBSD hashed PID allocator, which is a candidate for -CURRENT. The original patch was obtained from mailing list, and should be available from p4. Index: sys/kern/kern_exit.c =================================================================== RCS file: /home/fcvs/src/sys/kern/kern_exit.c,v retrieving revision 1.244 diff -u -r1.244 kern_exit.c --- sys/kern/kern_exit.c 30 Jul 2004 20:31:01 -0000 1.244 +++ sys/kern/kern_exit.c 1 Aug 2004 02:38:12 -0000 @@ -395,13 +395,12 @@ crfree(td->td_ucred); /* - * Remove proc from allproc queue and pidhash chain. + * Remove proc from allproc queue. * Place onto zombproc. Unlink from parent's child list. */ sx_xlock(&allproc_lock); LIST_REMOVE(p, p_list); LIST_INSERT_HEAD(&zombproc, p, p_list); - LIST_REMOVE(p, p_hash); sx_xunlock(&allproc_lock); sx_xlock(&proctree_lock); @@ -644,6 +643,7 @@ */ sx_xlock(&allproc_lock); LIST_REMOVE(p, p_list); /* off zombproc */ + LIST_REMOVE(p, p_hash); /* off pidhash chain */ sx_xunlock(&allproc_lock); LIST_REMOVE(p, p_sibling); leavepgrp(p); Index: sys/kern/kern_fork.c =================================================================== RCS file: /home/fcvs/src/sys/kern/kern_fork.c,v retrieving revision 1.233 diff -u -r1.233 kern_fork.c --- sys/kern/kern_fork.c 9 Aug 2004 18:21:12 -0000 1.233 +++ sys/kern/kern_fork.c 10 Aug 2004 03:38:51 -0000 @@ -154,9 +154,7 @@ * Random component to lastpid generation. We mix in a random factor to make * it a little harder to predict. We sanity check the modulus value to avoid * doing it in critical paths. Don't let it be too small or we pointlessly - * waste randomness entropy, and don't let it be impossibly large. Using a - * modulus that is too big causes a LOT more process table scans and slows - * down fork processing as the pidchecked caching is defeated. + * waste randomness entropy, and don't let it be impossibly large. */ static int randompid = 0; @@ -197,8 +195,8 @@ struct proc *p1, *p2, *pptr; uid_t uid; struct proc *newproc; - int ok, trypid; - static int curfail, pidchecked = 0; + int ok, trypid, wrapped; + static int curfail; static struct timeval lastfail; struct filedesc *fd; struct filedesc_to_leader *fdtol; @@ -206,6 +204,9 @@ struct kse *ke2; struct ksegrp *kg2; struct sigacts *newsigacts; + struct proc *pi; + struct pgrp *pgi; + struct session *si; int error; /* Can't copy and clear. */ @@ -327,8 +328,7 @@ nprocs++; /* - * Find an unused process ID. We remember a range of unused IDs - * ready to use (from lastpid+1 through pidchecked-1). + * Find an unused process ID. * * If RFHIGHPID is set (used during system boot), do not allocate * low-numbered pids. @@ -341,69 +341,45 @@ if (randompid) trypid += arc4random() % randompid; } -retry: - /* - * If the process ID prototype has wrapped around, - * restart somewhat above 0, as the low-numbered procs - * tend to include daemons that don't exit. - */ - if (trypid >= PID_MAX) { - trypid = trypid % PID_MAX; - if (trypid < 100) - trypid += 100; - pidchecked = 0; - } - if (trypid >= pidchecked) { - int doingzomb = 0; - - pidchecked = PID_MAX; + wrapped = 0; + while (!wrapped || trypid < lastpid + 1) { /* - * Scan the active and zombie procs to check whether this pid - * is in use. Remember the lowest pid that's greater - * than trypid, so we can avoid checking for a while. + * If the process ID prototype has wrapped around, + * restart somewhat above 0, as the low-numbered procs + * tend to include daemons that don't exit. */ - p2 = LIST_FIRST(&allproc); -again: - for (; p2 != NULL; p2 = LIST_NEXT(p2, p_list)) { - PROC_LOCK(p2); - while (p2->p_pid == trypid || - (p2->p_pgrp != NULL && - (p2->p_pgrp->pg_id == trypid || - (p2->p_session != NULL && - p2->p_session->s_sid == trypid)))) { - trypid++; - if (trypid >= pidchecked) { - PROC_UNLOCK(p2); - goto retry; - } - } - if (p2->p_pid > trypid && pidchecked > p2->p_pid) - pidchecked = p2->p_pid; - if (p2->p_pgrp != NULL) { - if (p2->p_pgrp->pg_id > trypid && - pidchecked > p2->p_pgrp->pg_id) - pidchecked = p2->p_pgrp->pg_id; - if (p2->p_session != NULL && - p2->p_session->s_sid > trypid && - pidchecked > p2->p_session->s_sid) - pidchecked = p2->p_session->s_sid; - } - PROC_UNLOCK(p2); + if (trypid >= PID_MAX) { + trypid = trypid % PID_MAX; + if (trypid < 100) + trypid += 100; + wrapped = 1; } - if (!doingzomb) { - doingzomb = 1; - p2 = LIST_FIRST(&zombproc); - goto again; + /* + * Check that the prospective ID hasn't already been used. + * Use the hash tables to avoid scanning allproc. + */ + LIST_FOREACH(pi, PIDHASH(trypid), p_hash) { + if (pi->p_pid == trypid) + goto trynext; + } + LIST_FOREACH(pgi, PGRPHASH(trypid), pg_hash) { + if (pgi->pg_id == trypid) + goto trynext; } + LIST_FOREACH(si, SESSHASH(trypid), s_hash) { + if (si->s_sid == trypid) + goto trynext; + } + break; +trynext: + trypid++; } sx_sunlock(&proctree_lock); /* * RFHIGHPID does not mess with the lastpid counter during boot. */ - if (flags & RFHIGHPID) - pidchecked = 0; - else + if (!(flags & RFHIGHPID)) lastpid = trypid; p2 = newproc; Index: sys/kern/kern_proc.c =================================================================== RCS file: /home/fcvs/src/sys/kern/kern_proc.c,v retrieving revision 1.215 diff -u -r1.215 kern_proc.c --- sys/kern/kern_proc.c 14 Aug 2004 17:15:16 -0000 1.215 +++ sys/kern/kern_proc.c 14 Aug 2004 18:00:37 -0000 @@ -86,6 +86,8 @@ u_long pidhash; struct pgrphashhead *pgrphashtbl; u_long pgrphash; +struct sesshashhead *sesshashtbl; +u_long sesshash; struct proclist allproc; struct proclist zombproc; struct sx allproc_lock; @@ -119,6 +121,7 @@ LIST_INIT(&zombproc); pidhashtbl = hashinit(maxproc / 4, M_PROC, &pidhash); pgrphashtbl = hashinit(maxproc / 4, M_PROC, &pgrphash); + sesshashtbl = hashinit(maxproc / 4, M_PROC, &sesshash); proc_zone = uma_zcreate("PROC", sched_sizeof_proc(), proc_ctor, proc_dtor, proc_init, proc_fini, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); @@ -256,7 +259,7 @@ sx_slock(&allproc_lock); LIST_FOREACH(p, PIDHASH(pid), p_hash) if (p->p_pid == pid) { - if (p->p_state == PRS_NEW) { + if (p->p_state == PRS_NEW && p->p_state != PRS_ZOMBIE) { p = NULL; break; } @@ -333,6 +336,7 @@ sess->s_ttyp = NULL; bcopy(p->p_session->s_login, sess->s_login, sizeof(sess->s_login)); + LIST_INSERT_HEAD(SESSHASH(sess->s_sid), sess, s_hash); pgrp->pg_session = sess; KASSERT(p == curproc, ("enterpgrp: mksession and p != curproc")); @@ -481,6 +485,7 @@ if (i == 0) { if (savesess->s_ttyp != NULL) ttyrel(savesess->s_ttyp); + LIST_REMOVE(savesess, s_hash); mtx_destroy(&savesess->s_mtx); FREE(savesess, M_SESSION); } @@ -844,8 +849,8 @@ struct proc *p; sx_slock(&allproc_lock); - LIST_FOREACH(p, &zombproc, p_list) - if (p->p_pid == pid) { + LIST_FOREACH(p, PIDHASH(pid), p_hash) + if (p->p_pid == pid && p->p_state == PRS_ZOMBIE) { PROC_LOCK(p); break; } Index: sys/sys/proc.h =================================================================== RCS file: /home/fcvs/src/sys/sys/proc.h,v retrieving revision 1.391 diff -u -r1.391 proc.h --- sys/sys/proc.h 9 Aug 2004 23:24:22 -0000 1.391 +++ sys/sys/proc.h 10 Aug 2004 03:38:51 -0000 @@ -69,6 +69,7 @@ * (c) const until freeing */ struct session { + LIST_ENTRY(session) s_hash; /* (e) Hash chain. */ int s_count; /* (m) Ref cnt; pgrps in session. */ struct proc *s_leader; /* (m + e) Session leader. */ struct vnode *s_ttyvp; /* (m) Vnode of controlling tty. */ @@ -843,6 +844,10 @@ extern LIST_HEAD(pgrphashhead, pgrp) *pgrphashtbl; extern u_long pgrphash; +#define SESSHASH(sid) (&sesshashtbl[(sid) & sesshash]) +extern LIST_HEAD(sesshashhead, session) *sesshashtbl; +extern u_long sesshash; + extern struct sx allproc_lock; extern struct sx proctree_lock; extern struct mtx pargs_ref_lock;