Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 1 Sep 2006 11:16:30 -0700
From:      Marcel Moolenaar <xcllnt@mac.com>
To:        ppc@FreeBSD.org
Subject:   Status of threading and TLS
Message-ID:  <933C0437-DDF8-4A61-83BA-F4920D9E6E96@mac.com>

next in thread | raw e-mail | index | archive | help
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@mac.com





Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?933C0437-DDF8-4A61-83BA-F4920D9E6E96>