Fix infinite loops in x86/x86_64 tc_lock_lock
authorJosh Stone <jistone@redhat.com>
Thu, 24 Oct 2013 04:03:08 +0000 (21:03 -0700)
committerJosh Stone <jistone@redhat.com>
Thu, 24 Oct 2013 06:42:09 +0000 (23:42 -0700)
commitb0b816ef6260eb3d7f8f035571f8315a37e9016d
treeb5503c8fe8d12fdfc32e3015bd718fe48f3fcf1b
parent98da2f2d52d2a35882924a82788aae8efef68c3f
Fix infinite loops in x86/x86_64 tc_lock_lock

With -fvisibility=hidden, gcc gets too smart and inlines atomic_set into
tc_lock_lock.  The optimizer can't tell that the asm in atomic_set is
changing anything, because its input is a fixed pointer, not the
volatile value it points too.  So the x86_64 lock loop looks like this:

  34:   48 c7 c0 01 00 00 00    mov    $0x1,%rax
  3b:   48 89 d9                mov    %rbx,%rcx
  3e:   f0 48 87 01             lock xchg %rax,(%rcx)
  42:   48 89 c2                mov    %rax,%rdx
  45:   0f 1f 00                nopl   (%rax)
  48:   48 85 d2                test   %rdx,%rdx
  4b:   75 fb                   jne    48 <tc_lock_lock+0x28>

That is, on failure 4b jumps back to 48 forever.  It's also not really
correct to be using a 64-bit xchg, since the memory value is just int.
The 32-bit x86 version gets a similar loop with the xchg lifted out.

This patch greatly simplifies the asm, with its input "+m"(*val) ensuring
that gcc knows we're using the volatile value, and a broad "memory"
constraint so the lock can protect other data too.  That loop is now:

  11:   b9 01 00 00 00          mov    $0x1,%ecx
  16:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  1d:   00 00 00
  20:   89 ca                   mov    %ecx,%edx
  22:   87 13                   xchg   %edx,(%rbx)
  24:   85 d2                   test   %edx,%edx
  26:   75 f8                   jne    20 <tc_lock_lock+0x20>

Signed-off-by: Josh Stone <jistone@redhat.com>
dyninstAPI_RT/src/RTthread-x86-64.c
dyninstAPI_RT/src/RTthread-x86.c