Under Macos, program compiled by apple clang can't read the latest TLS data in pthread_key_create destructor, while if it is compiled by gcc at the same environment, it works as expected.
Here is a self-contained example:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void foo(void); /* Functions that use the TLS data */
void bar(void);
#define checkResults(string, val) { \
if (val) { \
printf("Failed with %d at %s", val, string); \
exit(1); \
} \
}
#define NUMTHREADS 2
static pthread_key_t s_key;
__thread int TLS_data1;
__thread int TLS_data2;
void dtor(void* args) {
printf("In dtor, TLS_data1=%d, TLS_data2=%d\n", TLS_data1, TLS_data2);
}
typedef struct {
int data1;
int data2;
} threadparm_t;
void *theThread(void *parm)
{
int rc;
threadparm_t *gData;
pthread_setspecific(s_key, parm);
printf("Thread %.16llx: Entered\n", pthread_self());
gData = (threadparm_t *)parm;
TLS_data1 = gData->data1;
TLS_data2 = gData->data2;
foo();
return NULL;
}
void foo() {
printf("Thread %.16llx: foo(), TLS data=%d %d\n",
pthread_self(), TLS_data1, TLS_data2);
bar();
}
void bar() {
printf("Thread %.16llx: bar(), TLS data=%d %d\n",
pthread_self(), TLS_data1, TLS_data2);
return;
}
int main(int argc, char **argv)
{
pthread_t thread[NUMTHREADS];
int rc=0;
int i;
threadparm_t gData[NUMTHREADS];
pthread_key_create(&s_key, dtor);
printf("Enter Testcase - %s\n", argv[0]);
printf("Create/start threads\n");
for (i=0; i < NUMTHREADS; i++) {
/* Create per-thread TLS data and pass it to the thread */
gData[i].data1 = i;
gData[i].data2 = (i+1)*2;
rc = pthread_create(&thread[i], NULL, theThread, &gData[i]);
checkResults("pthread_create()\n", rc);
}
printf("Wait for the threads to complete, and release their resources\n");
for (i=0; i < NUMTHREADS; i++) {
rc = pthread_join(thread[i], NULL);
checkResults("pthread_join()\n", rc);
}
printf("Main completed\n");
return 0;
}
In macos, use command clang example.c
to compile the program and run it, you can get following result(My clang version is Apple LLVM version 8.0.0 (clang-800.0.42.1)):
Enter Testcase - ./a.out
Create/start threads
Wait for the threads to complete, and release their resources
Thread 0000700000081000: Entered
Thread 0000700000104000: Entered
Thread 0000700000104000: foo(), TLS data=1 4
Thread 0000700000104000: bar(), TLS data=1 4
In dtor, TLS_data1=0, TLS_data2=0
Thread 0000700000081000: foo(), TLS data=0 2
Thread 0000700000081000: bar(), TLS data=0 2
In dtor, TLS_data1=0, TLS_data2=0
Main completed
You can see that in dtor the tls can not be read correctly, then use gcc instead(under macos or linux),you can get the result:
Enter Testcase - ./a.out
Create/start threads
Wait for the threads to complete, and release their resources
Thread 0000700000081000: Entered
Thread 0000700000104000: Entered
Thread 0000700000104000: foo(), TLS data=1 4
Thread 0000700000104000: bar(), TLS data=1 4
In dtor, TLS_data1=1, TLS_data2=4
Thread 0000700000081000: foo(), TLS data=0 2
Thread 0000700000081000: bar(), TLS data=0 2
In dtor, TLS_data1=0, TLS_data2=2
Main completed
Now, the tls data can be read correctly by destructor. My question is how to set apple clang compiler to make the result right?