further optimize getc/putc when locking is needed
authorRich Felker <dalias@aerifal.cx>
Thu, 18 Oct 2018 16:47:26 +0000 (12:47 -0400)
committerRich Felker <dalias@aerifal.cx>
Thu, 18 Oct 2018 17:09:33 +0000 (13:09 -0400)
check whether the lock is free before loading the calling thread's
tid. if so, just use a dummy tid value that cannot compare equal to
any actual thread id (because it's one bit wider). this also avoids
the need to save the tid and pass it to locking_getc or locking_putc,
reducing register pressure.

this change might slightly hurt the case where the caller already
holds the lock, but it does not affect the single-threaded case, and
may significantly improve the multi-threaded case, especially on archs
where loading the thread pointer is disproportionately expensive like
early mips and arm ISA levels. but even on i386 it helps, at least on
some machines; I measured roughly a 10-15% improvement.

src/stdio/getc.h
src/stdio/putc.h

index 0657ab6f65142d94b7370e1f0ffe70013750f657..e24f9905c1f8c1c360e1a51da7ec515a5a596ae3 100644 (file)
@@ -4,9 +4,9 @@
 #ifdef __GNUC__
 __attribute__((__noinline__))
 #endif
-static int locking_getc(FILE *f, int tid)
+static int locking_getc(FILE *f)
 {
-       if (a_cas(&f->lock, 0, tid)) __lockfile(f);
+       if (a_cas(&f->lock, 0, MAYBE_WAITERS-1)) __lockfile(f);
        int c = getc_unlocked(f);
        if (a_swap(&f->lock, 0) & MAYBE_WAITERS)
                __wake(&f->lock, 1, 1);
@@ -15,8 +15,8 @@ static int locking_getc(FILE *f, int tid)
 
 static inline int do_getc(FILE *f)
 {
-       int tid, l = f->lock;
-       if (l < 0 || (l & ~MAYBE_WAITERS) == (tid=__pthread_self()->tid))
+       int l = f->lock;
+       if (l < 0 || l && (l & ~MAYBE_WAITERS) == __pthread_self()->tid)
                return getc_unlocked(f);
-       return locking_getc(f, tid);
+       return locking_getc(f);
 }
index a37937e8715d932bad73067673fc7d791093941f..2014c4ec4af9c68c283d5e8cb7b2a094eab436fa 100644 (file)
@@ -4,9 +4,9 @@
 #ifdef __GNUC__
 __attribute__((__noinline__))
 #endif
-static int locking_putc(int c, FILE *f, int tid)
+static int locking_putc(int c, FILE *f)
 {
-       if (a_cas(&f->lock, 0, tid)) __lockfile(f);
+       if (a_cas(&f->lock, 0, MAYBE_WAITERS-1)) __lockfile(f);
        c = putc_unlocked(c, f);
        if (a_swap(&f->lock, 0) & MAYBE_WAITERS)
                __wake(&f->lock, 1, 1);
@@ -15,8 +15,8 @@ static int locking_putc(int c, FILE *f, int tid)
 
 static inline int do_putc(int c, FILE *f)
 {
-       int tid, l = f->lock;
-       if (l < 0 || (l & ~MAYBE_WAITERS) == (tid=__pthread_self()->tid))
+       int l = f->lock;
+       if (l < 0 || l && (l & ~MAYBE_WAITERS) == __pthread_self()->tid)
                return putc_unlocked(c, f);
-       return locking_putc(c, f, tid);
+       return locking_putc(c, f);
 }