errno is not thread-safe in uClibc-0.9.30?
Pan ruochen
panruochen at gmail.com
Tue Jul 20 09:05:17 UTC 2010
Hi All,
I am developing with uClibc-0.9.30. I came accoss very strange problems
relating to `errno'.
----------------------------------------------------------------------------
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define NUM_THREADS 6
void *thread(void *threadid)
{
int i;
struct stat stat_buf;
for(i=0; i<100; i++) {
int ret = stat("/lib/The_DIR_NOT_EXIST", &stat_buf);
if(ret < 0) {
fprintf(stderr, "inv errno %d, ret=%d\n", errno, ret);
abort();
}
sleep(1);
}
return (void *)NULL;
}
int main (int argc, char *argv[])
{
pthread_t threads[NUM_THREADS];
int rc, i;
srand(time(NULL));
for(i=0; i<NUM_THREADS; i++){
rc = pthread_create(&threads[i], NULL, thread, (void *)i);
if (rc) {
printf("pthread_create() failed: %d\n", rc);
}
}
for(i=0; i<100; i++) {
opendir("/The_DIR_NOT_EXIST");
usleep(1);
}
sleep(5);
for(i=0; i<NUM_THREADS; i++){
pthread_join(threads[i], NULL);
}
return 0;
}
----------------------------------------------------------------------------
The application will fail on `stat' function while the errno is equal to zero!!
The results don't conform to the descriptions about `stat' function.
The same thing happens to any other ANSI C library functions instead of `stat'.
Then I read the unassembly code of uClibc-0.9.30.so
and find the following:
----------------------------------------------------------------------------
0000ebe0 <stat>:
ebe0: 3c1c0006 lui gp,0x6
ebe4: 279cb810 addiu gp,gp,-18416
ebe8: 0399e021 addu gp,gp,t9
ebec: 27bdff48 addiu sp,sp,-184
ebf0: afbf00b4 sw ra,180(sp)
ebf4: afb100b0 sw s1,176(sp)
ebf8: afb000ac sw s0,172(sp)
ebfc: afbc0010 sw gp,16(sp)
ec00: 27a60018 addiu a2,sp,24
ec04: 00a08821 move s1,a1
ec08: 00c02821 move a1,a2
ec0c: 2402100a li v0,4106
ec10: 0000000c syscall
ec14: 10e00008 beqz a3,ec38 <stat+0x58>
ec18: 00408021 move s0,v0
ec1c: 8f99801c lw t9,-32740(gp) /*PRC:__errno_location*/
ec20: 0320f809 jalr t9 <__errno_location>
ec24: 00000000 nop
ec28: 8fbc0010 lw gp,16(sp)
ec2c: ac500000 sw s0,0(v0)
...
00013910 <__errno_location>:
13910: 3c1c0005 lui gp,0x5
13914: 279c6ae0 addiu gp,gp,27360
13918: 0399e021 addu gp,gp,t9
1391c: 03e00008 jr ra
13920: 8f828180 lw v0,-32384(gp)
----------------------------------------------------------------------------
Here errno is implemented as a global variable and not thread-safe.
There is another implementation of `__errno_location' in libpthread.so.
----------------------------------------------------------------------------
00004584 <__errno_location>:
4584: 3c1c0002 lui gp,0x2
4588: 279c3e4c addiu gp,gp,15948
458c: 0399e021 addu gp,gp,t9
4590: 27bdffe0 addiu sp,sp,-32
4594: afbf001c sw ra,28(sp)
4598: afbc0010 sw gp,16(sp)
459c: 8f9980c0 lw t9,-32576(gp) /*PRC:thread_self*/
45a0: 0320f809 jalr t9 <thread_self>
45a4: 00000000 nop
45a8: 8fbf001c lw ra,28(sp)
45ac: 8fbc0010 lw gp,16(sp)
45b0: 8c420044 lw v0,68(v0)
45b4: 03e00008 jr ra
45b8: 27bd0020 addiu sp,sp,32
45bc: 00000000 nop
----------------------------------------------------------------------------
There is stll chance that `errno' is thread-safe if the ELF loader is
smart enough
to fix the location -32740(gp) insied libuClibc.so when the shared
library libpthread.so is loaded.
I don't know whether the loader can do this. If it can, how should I
configure kernel or uClibc options?
Or has this bug been fix in the later version?
Best Regards,
PRC
Jul 20,2010
More information about the uClibc
mailing list