]> granicus.if.org Git - strace/commitdiff
Simplify search in ioctl table
authorDenys Vlasenko <vda.linux@googlemail.com>
Tue, 20 Mar 2012 09:57:41 +0000 (10:57 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Tue, 20 Mar 2012 09:57:41 +0000 (10:57 +0100)
   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 <vda.linux@googlemail.com>
ioctl.c

diff --git a/ioctl.c b/ioctl.c
index 630a335e08ec83df08169614ff53e8540b3281a3..b63809386c97c17645523267f2092bd4ade0a614 100644 (file)
--- a/ioctl.c
+++ b/ioctl.c
  */
 
 #include "defs.h"
+#include <limits.h>
 #include <asm/ioctl.h>
 
 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;