From 1c2e912cc3e1be4081334b9ce0114c10a72166c6 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 20 Mar 2012 10:57:41 +0100 Subject: [PATCH] Simplify search in ioctl table text data bss dec hex filename 236973 704 18944 256621 3ea6d strace.before 236929 704 18944 256577 3ea41 strace * ioctl.c (compare): Simplify generation of compare result. (ioctl_lookup): Pass key directly, not as part of dummy struct. (ioctl_next_match): More readable code. No logic changes. Signed-off-by: Denys Vlasenko --- ioctl.c | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/ioctl.c b/ioctl.c index 630a335e..b6380938 100644 --- a/ioctl.c +++ b/ioctl.c @@ -29,30 +29,50 @@ */ #include "defs.h" +#include #include static int compare(const void *a, const void *b) { - unsigned long code1 = ((struct ioctlent *) a)->code; + unsigned long code1 = (long) a; unsigned long code2 = ((struct ioctlent *) b)->code; - return (code1 > code2) ? 1 : (code1 < code2) ? -1 : 0; + + /* Simply returning (code1 - code2) may be wrong. + * Exmaple: 0xffffffff - 0 = 0xffffffff = -1. + * Need to shift both values down until they both fit + * in positive int. + */ + while ((code1|code2) > INT_MAX) { +#if INT_MAX == LONG_MAX + /* this case is easy */ + code1 >>= 1; + code2 >>= 1; + break; +#else + /* Remove INT_MAX worth of bits, then check again */ + code1 >>= sizeof(int) * 8 - 1; + code2 >>= sizeof(int) * 8 - 1; +#endif + } + return (int)code1 - (int)code2; } const struct ioctlent * ioctl_lookup(long code) { - struct ioctlent *iop, ioent; + struct ioctlent *iop; - ioent.code = code; - ioent.code &= (_IOC_NRMASK<<_IOC_NRSHIFT) | (_IOC_TYPEMASK<<_IOC_TYPESHIFT); - iop = (struct ioctlent *) bsearch((char *) &ioent, (char *) ioctlent, - nioctlents, sizeof(struct ioctlent), compare); - while (iop > ioctlent) - if ((--iop)->code != ioent.code) { + code &= (_IOC_NRMASK<<_IOC_NRSHIFT) | (_IOC_TYPEMASK<<_IOC_TYPESHIFT); + iop = bsearch((void*)code, ioctlent, + nioctlents, sizeof(ioctlent[0]), compare); + while (iop > ioctlent) { + iop--; + if (iop->code != code) { iop++; break; } + } return iop; } @@ -61,7 +81,8 @@ ioctl_next_match(const struct ioctlent *iop) { long code; - code = (iop++)->code; + code = iop->code; + iop++; if (iop < ioctlent + nioctlents && iop->code == code) return iop; return NULL; -- 2.40.0