Status of threading and TLS
Marcel Moolenaar
xcllnt at mac.com
Fri Sep 1 18:17:10 UTC 2006
All,
I've been working on TLS for both ia64 and powerpc and all is well...
except
for one nasty bugger on powerpc.
Here's the status on powerpc:
TLS for non-threaded statically linked applications: working
TLS for non-threaded dynamically linked applications: working
TLS for statically linked 1:1 (libthr): working
TLS for dynamically linked 1:1 (libthr): working
TLS for statically linked M:N (libpthread): bugger!
TLS for dynamically linked M:N (libpthread: bugger!
The bugger for libpthread is that register r2 (the TLS pointer)
is off by 8 bytes. I have no idea where that happens and I've been
going over the code a hundred times. It's obvious that I either
developed a blind spot, or I'm not looking in the right place.
I need your help before I can have malloc(3) use TLS safely!
To demon strate the problem, assume the following program:
\begin{verbatim}
#include <pthread.h>
#include <stdio.h>
int __thread i = -1;
static void *
thread(void *arg)
{
int j;
j = (int)arg;
return (arg);
}
int
main(int argc, char *argv[])
{
pthread_t pt;
int err;
err = pthread_create(&pt, NULL, thread, i);
pthread_join(pt, NULL);
return (0);
}
\end{verbatim}
If I link it with libthr, run it in the debugger with breakpoints on
main() and thread(), I can inspect register r2:
:
:
(gdb) run
Starting program: /nfs/home/marcel/t
Breakpoint 1, main (argc=1, argv=0x7fffdc04) at t.c:21
21 err = pthread_create(&pt, NULL, thread, i);
(gdb) p $r2
$1 = 27308344
(gdb) p ((int *)($r2 - 0x7008))[0]
$2 = 27279680
(gdb) p ((int *)($r2 - 0x7008))[2]
$3 = -1
The magic above means the following:
r2 holds the address of the thread pointer of the main thread
$2 holds the address of the DTV. The DTV is at TLS[0]
$3 holds the value of the thread local variable i. It is -1.
Now, to see how this pans out for the first thread:
(gdb) c
Continuing.
Breakpoint 2, thread (arg=0xffffffff) at t.c:11
11 j = (int)arg;
(gdb) p $r2
$4 = 27308376
(gdb) p ((int *)($r2 - 0x7008))[0]
$5 = 27279712
(gdb) p ((int *)($r2 - 0x7008))[2]
$6 = -1
Expected results.
Now, if I link against libpthread I get the following:
:
:
(gdb) run
Starting program: /nfs/home/marcel/t
Breakpoint 1, main (argc=1, argv=0x7fffdc04) at t.c:21
21 err = pthread_create(&pt, NULL, thread, i);
(gdb) p $r2
$1 = 27493528
(gdb) p ((int *)($r2 - 0x7008))[0]
$2 = 0
(gdb) p ((int *)($r2 - 0x7008))[2]
$3 = 27279680
This is wrong. But...
(gdb) p ((int *)($r2 - 0x7008))[4]
$4 = -1
It appears that register r2 is off by 8 bytes. Let me double
check. DTV entry 2 should point to the thread local variable
i (lucky us):
(gdb) p /x ((int *)$3)[2]
$5 = 0x1a314a0
(gdb) p &((int *)($r2 - 0x7008))[4]
$6 = (int *) 0x1a314a0
Yup.
Now how this happens, I don't know.
If anyone has any suggestions why for libpthread we end up
with r2 off by 8 bytes, I'm happy to hear it...
--
Marcel Moolenaar
xcllnt at mac.com
More information about the freebsd-ppc
mailing list