This improves the cache. Basically, it's kind of like four way associative now, with LRU replacement. Also we can cache nameless entries instead of going back to getpwuid every time.
Index: gen/pwcache.c =================================================================== RCS file: /cvs/src/lib/libc/gen/pwcache.c,v retrieving revision 1.10 diff -u -p -r1.10 pwcache.c --- gen/pwcache.c 26 Oct 2015 15:04:51 -0000 1.10 +++ gen/pwcache.c 26 Oct 2015 15:37:13 -0000 @@ -35,32 +35,52 @@ #include <stdio.h> #include <string.h> -#define NCACHE 64 /* power of 2 */ +#define NCACHE 16 /* power of 2 */ +#define NLINES 4 /* associativity */ #define MASK (NCACHE - 1) /* bits to store with */ +#define IDX(x, i) ((x & MASK) + i * NCACHE) char * user_from_uid(uid_t uid, int nouser) { static struct ncache { uid_t uid; + short noname; char name[_PW_NAME_LEN + 1]; - } c_uid[NCACHE]; + } c_uid[NLINES * NCACHE]; static char nbuf[15]; /* 32 bits == 10 digits */ struct passwd *pw; struct ncache *cp; + unsigned int i; - cp = c_uid + (uid & MASK); - if (cp->uid != uid || !*cp->name) { - if ((pw = getpwuid(uid)) == NULL) { - if (nouser) - return (NULL); - (void)snprintf(nbuf, sizeof(nbuf), "%u", uid); - return (nbuf); + for (i = 0; i < NLINES; i++) { + cp = &c_uid[IDX(uid, i)]; + if (!*cp->name) { +fillit: + cp->uid = uid; + if ((pw = getpwuid(uid)) == NULL) { + snprintf(cp->name, sizeof(cp->name), "%u", uid); + cp->noname = 1; + } else { + strlcpy(cp->name, pw->pw_name, sizeof(cp->name)); + } } - cp->uid = uid; - strlcpy(cp->name, pw->pw_name, sizeof(cp->name)); + if (cp->uid == uid) { + if (nouser && cp->noname) + return NULL; + return cp->name; + } + } + /* move everybody down a slot */ + for (i = 0; i < NLINES - 1; i++) { + struct ncache *next; + + cp = &c_uid[IDX(uid, i)]; + next = &c_uid[IDX(uid, i + 1)]; + memcpy(next, cp, sizeof(*cp)); } - return (cp->name); + cp = &c_uid[IDX(uid, 0)]; + goto fillit; } char * @@ -68,22 +88,40 @@ group_from_gid(gid_t gid, int nogroup) { static struct ncache { gid_t gid; + short noname; char name[_PW_NAME_LEN + 1]; - } c_gid[NCACHE]; + } c_gid[NLINES * NCACHE]; static char nbuf[15]; /* 32 bits == 10 digits */ struct group *gr; struct ncache *cp; + unsigned int i; - cp = c_gid + (gid & MASK); - if (cp->gid != gid || !*cp->name) { - if ((gr = getgrgid(gid)) == NULL) { - if (nogroup) - return (NULL); - (void)snprintf(nbuf, sizeof(nbuf), "%u", gid); - return (nbuf); + for (i = 0; i < NLINES; i++) { + cp = &c_gid[IDX(gid, i)]; + if (!*cp->name) { +fillit: + cp->gid = gid; + if ((gr = getgrgid(gid)) == NULL) { + snprintf(cp->name, sizeof(cp->name), "%u", gid); + cp->noname = 1; + } else { + strlcpy(cp->name, gr->gr_name, sizeof(cp->name)); + } } - cp->gid = gid; - strlcpy(cp->name, gr->gr_name, sizeof(cp->name)); + if (cp->gid == gid) { + if (nogroup && cp->noname) + return NULL; + return cp->name; + } + } + /* move everybody down a slot */ + for (i = 0; i < NLINES - 1; i++) { + struct ncache *next; + + cp = &c_gid[IDX(gid, i)]; + next = &c_gid[IDX(gid, i + 1)]; + memcpy(next, cp, sizeof(*cp)); } - return (cp->name); + cp = &c_gid[IDX(gid, 0)]; + goto fillit; }