kejiewei / thread-sanitizer

Automatically exported from code.google.com/p/thread-sanitizer
0 stars 0 forks source link

Using pthread_getname_np to get thread names on Linux #36

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
On Linux, it is possible for a user to define a name for a thread via 
non-standard pthread_setname_np function. It would be nice if ThreadSanitizer 
would show these names in the information about data races (in addition to 
"thread T%d" text). GDB, for example, provides these names in the output of 
'info threads' command.

Original issue reported on code.google.com by yegor.de...@gmail.com on 21 Oct 2013 at 10:58

GoogleCodeExporter commented 9 years ago
Hm... I thought it works: 
Please check the test tsan/lit_tests/thread_name.cc

Original comment by konstant...@gmail.com on 21 Oct 2013 at 11:50

GoogleCodeExporter commented 9 years ago
Just checked -- it does actually work on my system (ubuntu 12.04).

Original comment by konstant...@gmail.com on 21 Oct 2013 at 11:52

GoogleCodeExporter commented 9 years ago
Hi Konstantin, thanks for the reply.

Indeed, the test works with fine clang 3.3 on Debian Testing. However, in the 
case of my project, thread names are not shown:

(gdb) b __tsan::PrintReport
Breakpoint 1 at 0x4ef60
(gdb) run
[...]
Breakpoint 1, 0x00007f4f424fbf60 in __tsan::PrintReport(__tsan::ReportDesc 
const*) ()
(gdb) info threads
  Id   Target Id         Frame
  9    Thread 0x7f4f402f8040 (LWP 26999) "worker1" 0x00007f4f41161047 in sched_yield () at ../sysdeps/unix/syscall-template.S:81
  8    Thread 0x7f4f4038e040 (LWP 26998) "queue_2_0_0" pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
  7    Thread 0x7f4f40413040 (LWP 26997) "queue_0_0_0" pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
  6    Thread 0x7f4f40498040 (LWP 26996) "worker3" __lll_lock_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:135
* 5    Thread 0x7f4f42377040 (LWP 26995) "worker2" 0x00007f4f424fbf60 in 
__tsan::PrintReport(__tsan::ReportDesc const*) ()
  4    Thread 0x7f4f423fc040 (LWP 26994) "worker1" syscall () at ../sysdeps/unix/sysv/linux/x86_64/syscall.S:38
  2    Thread 0x7f4f4109d700 (LWP 26985) "alltoall" 0x00007f4f4115749d in nanosleep () at ../sysdeps/unix/syscall-template.S:81
  1    Thread 0x7f4f42484040 (LWP 26979) "alltoall" __lll_lock_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:135
(gdb) c
Continuing.
==================
WARNING: ThreadSanitizer: data race (pid=26979)
  Read of size 4 at 0x7d0c0000a7f4 by thread T3:
[...]
  Previous write of size 8 at 0x7d0c0000a7f0 by thread T2 (mutexes: write M14):
[...]
  Thread T3 (tid=26995, running) created by main thread at:
[...]
  Thread T2 (tid=26994, running) created by main thread at:
[...]

It is strange that GDB sees them, but TSan later does not. I will try to come 
up with a minimal example then...

Original comment by yegor.de...@gmail.com on 21 Oct 2013 at 12:20

GoogleCodeExporter commented 9 years ago
What is the OS and glibc where you build clang/compiler-rt and where you get 
this behavior? 

What will be the output if you run 
  objdump  -d ./a.out | grep prctl
(replace a.out with your binary)

Original comment by konstant...@gmail.com on 21 Oct 2013 at 1:00

GoogleCodeExporter commented 9 years ago
It looks like the problem arises when one sets name of a thread A from a 
different thread B. On the following example TSan does not print thread names:

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

int Global;

void *Thread1(void *x) {
  sleep(1);
  Global++;
  return NULL;
}

void *Thread2(void *x) {
  sleep(1);
  Global--;
  return NULL;
}

int main() {
  pthread_t t[2];
  pthread_create(&t[0], NULL, Thread1, NULL);
  pthread_create(&t[1], NULL, Thread2, NULL);
  if (pthread_setname_np(t[0], "Thread1") != 0) { fprintf(stderr, "first pthread_setname_np failed!\n"); }
  if (pthread_setname_np(t[1], "Thread2") != 0) { fprintf(stderr, "second pthread_setname_np failed!\n"); }
  pthread_join(t[0], NULL);
  pthread_join(t[1], NULL);
}

GDB, as in my previous messages, correctly shows thread names.

Original comment by yegor.de...@gmail.com on 21 Oct 2013 at 1:03

GoogleCodeExporter commented 9 years ago
Just built a recent clang (llvm rev. 192976, clang rev. 192971, compiler-rt 
rev. 192975) using clang 3.3. Thread names are still not shown in the example 
above.

All this happens on today's Debian GNU/Linux Testing with libc6 2.17-93: 
http://packages.debian.org/testing/libc6-dev

[yegor@tomato tmp]$ clang -fPIC -pie -fsanitize=thread -o my_thread_name 
my_thread_name.cc
00000000000180f0 <arch_prctl@plt>:
   1a945:       e8 d6 4e 01 00          callq  2f820 <__interceptor_prctl>
   1a982:       e8 99 4e 01 00          callq  2f820 <__interceptor_prctl>
000000000001ad20 <_ZN11__sanitizer14internal_prctlEimmmm>:
   1d59e:       e8 7d d7 ff ff          callq  1ad20 <_ZN11__sanitizer14internal_prctlEimmmm>
   1d5bc:       e8 5f d7 ff ff          callq  1ad20 <_ZN11__sanitizer14internal_prctlEimmmm>
   1d654:       e8 c7 d6 ff ff          callq  1ad20 <_ZN11__sanitizer14internal_prctlEimmmm>
   1d6ba:       e8 61 d6 ff ff          callq  1ad20 <_ZN11__sanitizer14internal_prctlEimmmm>
000000000002f820 <__interceptor_prctl>:
   2f858:       75 2a                   jne    2f884 <__interceptor_prctl+0x64>
   2f89c:       48 8d 05 05 7d a3 00    lea    0xa37d05(%rip),%rax        # a675a8 <_ZN14__interception10real_prctlE>
   2f8a9:       0f 84 af 00 00 00       je     2f95e <__interceptor_prctl+0x13e>
   2f8d4:       7f 37                   jg     2f90d <__interceptor_prctl+0xed>
   2f8d9:       75 32                   jne    2f90d <__interceptor_prctl+0xed>
   2f921:       75 25                   jne    2f948 <__interceptor_prctl+0x128>
   2f94b:       75 2b                   jne    2f978 <__interceptor_prctl+0x158>
   33264:       48 8d 35 3d 43 a3 00    lea    0xa3433d(%rip),%rsi        # a675a8 <_ZN14__interception10real_prctlE>
   3326b:       48 8d 15 ae c5 ff ff    lea    -0x3a52(%rip),%rdx        # 2f820 <__interceptor_prctl>
   33272:       48 8d 0d a7 c5 ff ff    lea    -0x3a59(%rip),%rcx        # 2f820 <__interceptor_prctl>
   46b72:       e8 79 15 fd ff          callq  180f0 <arch_prctl@plt>

Original comment by yegor.de...@gmail.com on 21 Oct 2013 at 1:17

GoogleCodeExporter commented 9 years ago
Ah... I remember that.
The code of pthread_setname_np in glibc 
(nptl/sysdeps/unix/sysv/linux/pthread_setname.c) looks like this:
  if (pd == THREAD_SELF)
    return prctl (PR_SET_NAME, name) ? errno : 0;
  <LOTS of code follows>

We only handle the pd == THREAD_SELF

I don't have a quick solution for the other case. :( 

Original comment by konstant...@gmail.com on 21 Oct 2013 at 1:18

GoogleCodeExporter commented 9 years ago
for the reference, this is what pthread_setname_np does.

  const struct pthread *pd = (const struct pthread *) th;
...
#define FMT "/proc/self/task/%u/comm"
  char fname[sizeof (FMT) + 8];
  sprintf (fname, FMT, (unsigned int) pd->tid);

  int fd = open_not_cancel_2 (fname, O_RDWR);
  if (fd == -1)
    return errno;

  int res = 0;
  ssize_t n = TEMP_FAILURE_RETRY (write_not_cancel (fd, name, name_len));
  if (n < 0)
    res = errno;
  else if (n != name_len)
    res = EIO;

  close_not_cancel_no_status (fd);

We can intercept pthread_setname_np and then read the contents
of /proc/self/task/%u/comm

I don't remember if we already tried that. 

Original comment by konstant...@gmail.com on 21 Oct 2013 at 1:23

GoogleCodeExporter commented 9 years ago
Is rereading of /proc/.../comm really necessary? I will try the option with 
intercepting pthread_setname_np...

Original comment by yegor.de...@gmail.com on 21 Oct 2013 at 1:51

GoogleCodeExporter commented 9 years ago
If you intercept pthread_setname_np which happens in thread A and changes
thread B's name, you will need to map from B's pthread_t object to 
tsan's internal thread object. 
I am not sure this is trivial (but of course doable)

Same problem is with reading /proc/.../comm, but we can probably do it in the 
thread B
(but when??)

Dmitry? 

Original comment by konstant...@gmail.com on 21 Oct 2013 at 2:00

GoogleCodeExporter commented 9 years ago
Fixed by r193602.

Original comment by dvyu...@google.com on 29 Oct 2013 at 10:34

GoogleCodeExporter commented 9 years ago
Adding Project:ThreadSanitizer as part of GitHub migration.

Original comment by gli...@google.com on 30 Jul 2015 at 9:21