This
is
a
guest
post
by
my
wife,
Holly.
In
the
software
industry,
some
problems
don't
have
Google-able
solutions.
Just
like
I
can't
Google
where
I
left
my
keys,
when
I
last
got
an
oil
change,
or
why
I
still
haven't
filed
my
taxes,
I
also
can't
Google
what
the
race
condition
is
in
my
code.
To
answer
these
questions,
I
must
look
inside
myself.
Usually.
"I
hope
your
trip
is
going
awesome
and
I
hate
to
bother
you,
but..."
This
tale
begins
in
2013.
Jeff
and
I
had
recently
gotten
married
and
were
on
our
honeymoon.
Our
team
was
rather...
small...
at
the
time,
so
we
left
the
storage
system
we
were
responsible
for
in
the
hands
of
Josh,
our
intern
of
four
months
or
so,
with
oversight
from
the
Ops
team.
Halfway
through
our
trip,
Josh
reluctantly
sent
us
an
email
with
details
of
an
assertion
failure
in
production
that
he
couldn't
debug:
sem_post()
was
supposed
to
return
0,
but
it
was
returning
-1.
It
had
happened
on
a
couple
servers
now,
and
only
started
after
we
left.
Jeff
and
I
didn't
have
the
resources
to
debug
it
remotely,
and
restarting
the
service
was
a
viable
workaround,
so
we
left
it
as
a
problem
for
our
return.
Over
the
next
four
months,
we
made
little
progress.
We
discovered
that
sem_post()
was
specifically
failing
with
EINVAL,
but
none
of
us
could
find
the
race
condition
in
the
code.
Because
that's
what
it
means
when
your
calls
to
concurrency
primitives
are
failing:
you
have
a
race
condition
because
you
are
bad
at
writing
concurrent
code.
Four
months
later,
Jeff
left
the
company
with
the
bug
still
unresolved.
Josh
(no
longer
an
intern)
and
I
continued
poring
over
the
code.
The
failure
was
rare
and
we
didn't
know
how
to
reproduce
it
--
it
happened
every
~500,000
server-hours,
and
given
the
size
of
our
fleet,
that
was
on
the
order
of
once
a
month
--
but
when
we
saw
it,
we
usually
spent
a
few
more
hours
trying
to
track
it
down.
No
dice.
It
seemed
that
we
were
bad
at
concurrent
programming,
and
even
worse
at
debugging.
Anger
makes
you
do
irrational
things
One
evening,
some
16
months
after
the
first
occurrence,
Josh
messaged
me.
He
said
he
thought
he
had
finally
found
our
elusive
race
condition!
Inside,
I
must
confess,
I
did
not
react
maturely.
I
was
not
relieved,
proud,
nor
excited.
I
was
incensed
to
hear
he
found
it,
after
I'd
sunk
so
much
time
into
this
utterly
impossible
bug.
Blinded
by
my
entirely
irrational
fury,
determined
to
prove
him
wrong
(did
I
mention
"irrational"?),
I
rage-Googled
the
problem.
(Again,
for
the
uninitiated,
this
is
equivalent
to
Googling
"where
did
I
leave
my
keys".
Race
conditions
are
a
problem
you
have
to
solve
yourself.
Perhaps
you
could
post
all
the
relevant
code
on
a
message
board
and
find
someone
willing
to
help
you
debug
your
specific
problem,
because
the
logic
is
unique
to
your
program
and
there's
no
Google-able
"general
solution"
to
your
errors
with
semaphores
beyond
"be
better
at
writing
concurrent
code.")
One
of
the
search
results
caught
my
eye.
Horses,
not
zebras
There's
a
saying
in
medical
schools:
"When
you
hear
hoofbeats,
think
of
horses,
not
zebras."
When
diagnosing
a
problem,
it
is
more
likely
that
the
issue
is
a
common
one
rather
than
a
rare
one.
If
you
have
a
runny
nose,
it's
probably
a
cold
and
not
a
cerebrospinal
fluid
leak.
If
you're
getting
errors
while
using
concurrency
primitives,
you
probably
wrote
the
code
wrong.
After
all,
concurrency
is
hard
and
life
isn't
an
episode
of
House,
M.D.
But
zebras
do
exist.
I
had
clicked
the
link
for
a
Bugzilla
issue
titled
sem_post/sem_wait
race
causing
sem_post
to
return
EINVAL
and
started
reading.
(Meanwhile,
Josh
told
me
"Never
mind,
I
didn't
find
it
after
all.")
The
bug
report
from
someone
named
Don
suggested
that
there
is
a
race
in
the
implementation
of
glibc
semaphore
primitives
themselves
causing
sem_post()
to
access
already-freed
memory
and
fail
with
EINVAL
(we
were
seeing
EINVAL!).
He
said
it's
hard
to
reproduce
(we
saw
it
once
per
hundreds
of
thousands
of
server
hours!).
He
could
reproduce
it
by
adding
a
sleep()
call
to
the
sem_post()
function
(which
was
farther
than
we'd
gotten!).
This
was
our
problem!
It
had
to
be!
Maybe
we
weren't
bad
at
writing
concurrent
code!
He
does
not
understand
your
question
because
he
is
assuming
you
are
an
idiot
One
problem
with
"think
of
horses,
not
zebras"
is
that
other
people
are
well
aware
of
the
concept.
Following
Don's
report
of
the
bug
was
an
exchange
with
Ulrich
(one
of
the
main
contributors/maintainers
for
glibc
at
the
time)
in
which
Ulrich
asked
"Why
would
this
at
all
be
a
bug?"
and
stated
"Your
code
is
wrong
in
assuming
what
it
does."
Don
patiently
outlined
his
thinking.
Ulrich
tersely
asserted
that
Don's
usage
was
illegal.
Don
made
one
final
plea
("Sorry
if
it
seems
I
am
belaboring
this"),
and
Ulrich
never
responded.
After
four
months,
someone
named
Pat
replied
to
Don,
and
opened
his
response
with
a
sentence
that
burned
itself
into
my
brain.
He
said,
"Ulrich
does
not
understand
your
question
because
he
is
assuming
you
are
an
idiot."
It's
not
an
entirely
unreasonable
assumption.
After
all,
what
is
more
likely?
Don
is
the
first
person
to
identify
"a
fundamental
race
rendering
semaphores
useless"
in
glibc,
a
library
whose
semaphores
have
been
used
by
a
great
many
people
for
a
great
many
years
seemingly
without
issue,
or
Don
is
kind
of
bad
at
concurrent
programming
and
the
issue
with
his
code
is
his
own?
Ulrich
decided
he
was
hearing
horses
and
didn't
look
for
zebras.
And
I
almost
can't
blame
him.
When
I
was
a
TA
for
freshman-
and
sophomore-level
programming
classes,
my
students
made
semi-regular
claims
that
"the
compiler
is
broken."
This
was
their
way
of
expressing
that
their
code
did
not
do
what
they
expected
it
to
do
or,
in
some
cases,
that
their
code
did
not
even
compile.
Of
course
the
compiler
isn't
broken!
These
are
freshmen
who
have
been
writing
C++
for
two
months
and
g++
had
been
compiling
it
since
before
they
were
born.
Is
it
more
likely
that
a
student
who
has
just
begun
to
learn
programming
has
a
syntax
error
or
a
bug
in
their
code,
or
that
they
have
found
a
heretofore
undiscovered
problem
with
software
that
has
been
used
by
millions
of
people
for
decades?
While
I
never
assumed
they
were
idiots
(my
students
were
wonderful;
one
was
the
best
man
at
our
aforementioned
wedding)
I
admit
I
gave
approximately
zero
credence
to
their
claims
of
having
discovered
a
compiler
bug,
just
as
Ulrich
gave
zero
credence
to
Don's
bug
report.
Over
a
decade
later,
I
try
to
channel
my
inner
Pat.
(A
mere
three
days
after
Pat
replied
in
support
of
Don's
claims,
a
fix
for
the
race
was
implemented
by
Rich
Felker.)
"Think
horses"
is
the
type
of
heuristic
that
keeps
me
from
wasting
too
much
time
on
absurd-sounding
claims,
but
at
the
same
time,
I
try
not
to
get
trampled
because
I
was
too
busy
assuming
the
guy
yelling
"Zebras!"
is
an
idiot.
I'm
not
perfect,
but
I'm
trying.
And
I'm
pretty
sure
none
of
my
freshmen
ever
found
a
real
compiler
bug
in
class...
In
the
end,
we
(Josh)
worked
around
the
sem_post()
race
condition,
replacing
the
fundamentally-broken
semaphores
with
locks
and
a
condition
variable,
because
we
were
already
running
an
outdated
version
of
glibc
and
knew
it
might
be
a
while
before
Ops
could
update
all
the
servers.
After
that
change,
we
never
saw
the
failure
again.
History
doesn't
repeat
itself,
but
it
rhymes
Why
am
I
writing
this
post
today?
Recently
my
team
had
an
issue
with
a
cloud
service
provider
(CSP)
that
we
use.
It
wasn't
related
to
race
conditions,
but
it
was
the
same
type
of
un-Google-able
problem.
We
assumed
the
issue
was
a
bug
in
our
code
and
tried
to
track
it
down.
After
a
while
with
no
real
leads,
and
a
problem
scope
that
continued
widening,
we
opened
a
case
with
the
CSP.
(Please
pardon
my
deliberate
ambiguity
in
this
section,
but
I
am
hesitant
to
divulge
as
many
details
about
an
issue
we
haven't
yet
fully
resolved
internally
as
I
did
for
a
decade-old
bug.)
We
suspected
a
hardware
issue,
they
insisted
it
was
a
software
issue
(first
ours,
but
later
conceded
it
might
be
theirs).
Six
weeks
of
back-and-forth
later,
the
glibc
semaphore
issue
crossed
my
mind,
and
I
Googled
my
un-Google-able
problem
once
again
(out
of
frustration,
but
not
out
of
rage).
One
of
the
results
was
a
tweet,
which
led
me
to
a
recent-ish
hardware
research
paper,
and
with
every
sentence
I
read,
I
became
more
and
more
convinced
that
the
issue
described
in
this
paper
was
exactly
what
we
were
experiencing.
Once
more,
I
had
Googled
the
impossible
and
found
a
plausible
explanation
that
lined
up
with
our
problem!
This
time,
however,
I
found
myself
in
Don's
shoes.
Because,
truly,
what
is
more
likely?
That
we
(a
not-terribly-significant
customer
of
the
large
CSP)
are
repeatedly
encountering
an
issue
caused
by
a
hardware
issue
that
is
both
sufficiently
rare
and
sufficiently
interesting
that
research
papers
are
being
written
about
it?
Or
that
we
(again,
a
rather
insignificant
customer)
are
idiots
who
have
written
some
buggy
software
or
are
using
some
buggy
libraries,
and
that's
the
source
of
all
of
our
problems?
After
another
five
weeks
of
meetings
in
which
we
provided
all
the
evidence
we
had
been
collecting,
including
sharing
the
paper
with
relevant
sections
highlighted,
and
imploring
them
to
look
into
it,
I
was
finally
confident
that
the
CSP
had
brought
the
right
people
--
hardware
people
--
to
our
sync-up.
Two
weeks
later,
they
were
able
to
show
us
the
results
of
the
tests
they
used
to
identify
the
specific
hardware
that
was
causing
our
issue.
They're
pulling
it
from
production,
which
should
mean
the
end
of
the
problem
for
us
and
any
other
customers
who
may
have
encountered
it.
Is
there
a
lesson
here?
I'm
not
sure.
But
if
I
had
a
nickel
for
every
time
Google
led
me
to
the
right
answer
for
an
un-Google-able
problem
only
to
encounter
challenges
getting
anyone
to
believe
the
diagnosis
because
it
is
vanishingly
unlikely,
I'd
have
two
nickels,
which
isn't
a
lot,
but
it's
weird
that
it
happened
twice.
Perhaps,
once
a
decade
or
so,
you
may
find
yourself
on
one
side
or
the
other
of
such
an
issue,
and
I
hope
that
you
can
channel
your
inner
Pat
to
a
speedier
resolution
than
these
cases
had.
P.S.
Early
on,
a
coworker
tried
diagnosing
this
issue
with
the
help
of
AI,
which
told
him
with
"highest
probability"
it
was
a
bug
with
the
(JIT)
compiler.
Call
me
a
hypocrite,
but
I
did
not
try
to
understand
its
explanation
because
I
was
assuming
that
it
was
an
idiot.