[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#226716: libc6: TLS doesn't work with LD_ASSUME_KERNEL < 2.6.0



Package: libc6
Version: 2.3.2.ds1-10
Severity: important

TLS doesn't work properly with LD_ASSUME_KERNEL < 2.6.0.  I don't have
a machine with 2.4 kernel currently, so I can't say whether it's only
broken on 2.6 kernels when setting LD_ASSUME_KERNEL or whether it's
broken on older kernels too.

The appended code creates 5 additional threads.  Each of these and the
main thread set a thread-local variable to unique numbers.  When
execution continues after the barrier, all threads still should see
the value they stored to the thread-local variable.

This works fine on 2.6 kernels without setting LD_ASSUME_KERNEL to
something less than 2.6.0:

,----
| % gcc -Wall -D_GNU_SOURCE -pthread tls.c -o tls
| % ./tls
| BEFORE_BARRIER: primordial thread: tls_var is 0 (0x4000f8fc)
| BEFORE BARRIER: thread 1: test tls_var == 1 (0x40810bcc)
| BEFORE BARRIER: thread 2: test tls_var == 2 (0x41011bcc)
| BEFORE BARRIER: thread 3: test tls_var == 3 (0x41812bcc)
| BEFORE BARRIER: thread 4: test tls_var == 4 (0x42013bcc)
| BEFORE BARRIER: thread 5: test tls_var == 5 (0x42814bcc)
| AFTER BARRIER:  thread 1: test tls_var == 1 (0x40810bcc) OK
| AFTER BARRIER:  thread 2: test tls_var == 2 (0x41011bcc) OK
| AFTER BARRIER:  thread 5: test tls_var == 5 (0x42814bcc) OK
| AFTER BARRIER:  thread 3: test tls_var == 3 (0x41812bcc) OK
| AFTER BARRIER:  thread 4: test tls_var == 4 (0x42013bcc) OK
| AFTER BARRIER:  primordial thread: tls_var is 0 (0x4000f8fc) OK
`----

But if I set LD_ASSUME_KERNEL to something less than 2.6.0, the
variable isn't thread-local at all.  After the barrier all threads see
the value used by last thread doing 'tls_var = i'.  Also note that the
address of tls_var is the same in all threads:

,----
| % LD_ASSUME_KERNEL=2.4.1 ./tls 
| BEFORE_BARRIER: primordial thread: tls_var is 0 (0x400608bc)
| BEFORE BARRIER: thread 1: test tls_var == 1 (0x400608bc)
| BEFORE BARRIER: thread 2: test tls_var == 2 (0x400608bc)
| BEFORE BARRIER: thread 3: test tls_var == 3 (0x400608bc)
| BEFORE BARRIER: thread 4: test tls_var == 4 (0x400608bc)
| BEFORE BARRIER: thread 5: test tls_var == 5 (0x400608bc)
| AFTER BARRIER:  thread 1: test tls_var == 5 (0x400608bc) BROKEN
| AFTER BARRIER:  thread 2: test tls_var == 5 (0x400608bc) BROKEN
| AFTER BARRIER:  thread 3: test tls_var == 5 (0x400608bc) BROKEN
| AFTER BARRIER:  thread 5: test tls_var == 5 (0x400608bc) OK
| AFTER BARRIER:  thread 4: test tls_var == 5 (0x400608bc) BROKEN
| AFTER BARRIER:  primordial thread: tls_var is 5 (0x400608bc) BROKEN
`----

[If this is broken on 2.4 kernels too, then this may explain the
problems some people had with the TLS version of NVIDIA's GL stuff.]


// tls.c
#include <pthread.h>
#include <stdio.h>

#define THREADS 5

pthread_barrier_t barrier;
pthread_t threads[THREADS];

__thread int tls_var;

void *f(void *num)
{
    int i = (int) num;
    int value_before;

    tls_var = i;
    value_before = tls_var;
 
    printf("BEFORE BARRIER: thread %d: test tls_var == %d (%p)\n",
           i, tls_var, &tls_var);

    pthread_barrier_wait(&barrier);

    printf("AFTER BARRIER:  thread %d: test tls_var == %d (%p) %s\n",
           i, tls_var, &tls_var, tls_var == value_before ? "OK" : "BROKEN");

    return NULL;
}

int main(int argc, char *argv[])
{
    int i;
    int value_before;

    pthread_barrier_init(&barrier, NULL, THREADS);

    tls_var = 0;
    value_before = tls_var;

    printf("BEFORE_BARRIER: primordial thread: tls_var is %d (%p)\n",
           tls_var, &tls_var); 

    for (i = 0; i < THREADS; i++) {
        pthread_create(&threads[i], NULL, f, (void*) i + 1);
    }

    for (i = 0; i < THREADS; i++) {
        pthread_join(threads[i], NULL);
    }

    pthread_barrier_destroy(&barrier);

    printf("AFTER BARRIER:  primordial thread: tls_var is %d (%p) %s\n",
           tls_var, &tls_var, tls_var == value_before ? "OK" : "BROKEN");

    return 0;
}


-- System Information:
Debian Release: testing/unstable
Architecture: i386
Kernel: Linux arthur 2.6.1-rc1-mm2 #1 SMP Mon Jan 5 20:59:14 CET 2004 i686
Locale: LANG=C, LC_CTYPE=C

Versions of packages libc6 depends on:
ii  libdb1-compat                 2.1.3-7    The Berkeley database routines [gl

-- no debconf information




Reply to: