Testing procedure ================= Using following named pipe testing program, the testing process is as follow
In console A, run pipetest-server $ ./pipetest-server pipetest-server got req (req from CL-A) pipetest-server got req (req from CL-B) In console B, run pipetest-client $ ./pipetest-client CL-A 20000000 pipetest-client: CL-A: got rsp ack rsp waiting for 20000000 microseconds... ending... $ ./pipetest-client CL-B 20000000 pipetest-client: CL-B: got rsp ack rsp waiting for 20000000 microseconds... ending... The above is the expected result. But in uClibc, after "./pipetest-client CL-B 20000000", It hung, and there is no " pipetest-server got req (req from CL-B)" on pipetest-server. This works on x86_64 host using glibc, and also works on MIPS using glibc-1.8.2, but it failed on MIPS using uClibc-0.9.32-rc3. Testing programs pipetest-server.c ================================== Here is testing program pipetest-server.c #include <stdlib.h> #include <stdio.h> #include <signal.h> #include <unistd.h> #include <sys/stat.h> #include <sys/select.h> #define REQNAME "/tmp/pipetest_req" #define RSPNAME "/tmp/pipetest_rsp" int main( int argc, char **argv) { int rc = 0; FILE *pReq= 0; FILE *pRsp= 0; char buff[128]; // Remove any existing file remove( REQNAME ); remove( RSPNAME ); rc= mknod( REQNAME, S_IFIFO|0666, 0); if ( rc ) goto exit; rc= mknod( RSPNAME, S_IFIFO|0666, 0); if ( rc ) goto exit; pReq= fopen( REQNAME, "r" ); if ( pReq ) { fd_set rfds; int fd= fileno( pReq ); pRsp= fopen( RSPNAME, "w" ); for( ; ; ) { FD_ZERO(&rfds); FD_SET(fd, &rfds); rc= select( fd+1, &rfds, 0, 0, 0); // Read next request if ( fgets( buff, sizeof(buff), pReq ) != NULL ) { printf( "pipetest-server got req (%s)\n", buff ); fprintf( pRsp, "ack rsp\n" ); fflush( pRsp ); } } } exit: return rc; } Testing programs pipetest-client.c ================================== Here is testing program pipetest-client.c #include <stdlib.h> #include <stdio.h> #include <signal.h> #include <unistd.h> #define REQNAME "/tmp/pipetest_req" #define RSPNAME "/tmp/pipetest_rsp" int readIPCResponse( FILE *file, char *buff, int buffSize ) { int retryCount= 0; while( retryCount < 10 ) { if ( fgets( buff, buffSize, file ) != NULL ) { return 1; } usleep( 5000 ); ++retryCount; } return 0; } int main( int argc, char **argv) { int rc = 0; FILE *pReq= 0; FILE *pRsp= 0; int timeout= 10000000; char *arg= 0; char buff[128]; arg = ( argc < 2 ) ? "ClientA" : argv[1]; timeout= ( argc < 3 ) ? 10000000 : atoi(argv[2]); pReq= fopen( REQNAME, "w" ); if ( pReq ) { pRsp= fopen( RSPNAME, "r" ); if ( pRsp ) { fprintf( pReq, "req from %s\n", arg ); fflush( pReq ); rc= readIPCResponse( pRsp, buff, sizeof(buff) ); if ( rc ) { printf( "pipetest-client: %s: got rsp %s\n", arg, buff ); } printf( "waiting for %d microseconds...\n", timeout ); usleep( timeout ); printf( "ending...\n" ); fclose( pRsp ); } fclose( pReq ); } return rc; } Debugging result ================= My debugging showed that in pipetest-server.c, after "./pipetest-client CL-A 20000000" finished, fgets() return NULL forever. The problem is that after "./pipetest-client CL-A 20000000" finished, in stream associated with FIFO "/tmp/pipetest_req", fgets() will call __stdio_READ() internally 24 size_t attribute_hidden __stdio_READ(register FILE *stream, 25 unsigned char *buf, size_t bufsize) 26 { 27 ssize_t rv = 0; 28 36 if (!__FEOF_UNLOCKED(stream)) { 37 if (bufsize > SSIZE_MAX) { 38 bufsize = SSIZE_MAX; 39 } 40 41 #ifdef __UCLIBC_MJN3_ONLY__ 42 #warning EINTR? 43 #endif 44 /* RETRY: */ 45 if ((rv = __READ(stream, (char *) buf, bufsize)) <= 0) { 46 if (rv == 0) { 47 __STDIO_STREAM_SET_EOF(stream); At line 45, rv return 0, then at line 47, it set __FLAG_EOF in stream->__modeflags. After "./pipetest-client CL-B 20000000" was started, it writed " req from CL-B" to FIFO "/tmp/pipetest_req", but since __FLAG_EOF was set in stream->__modeflags in above stream, it failed at line 36, and no longer call __READ() at line 45 to read new message from FIFO. The problem is that FIFO is a special file type, and the conventional EOF is useless, and should not be set. My proposed fix is to avoid setting __FLAG_EOF for stream associated with FIFO after sender was closed. My patch ======== This is my patch to fix it. Sorry that git server of uClibc.org is down today, so I cannot generate diff using git. The patch worked well in my testing case. In order to call fstat(fd, stat) inside libc, I have to copy and paste fstat.c into _READ.c, it is not nice, but I want to get your input on whether this is the right direction or not at this moment. Thanks, Jian diff -Naur -p uClibc-old/libc/stdio/_READ.c uClibc-new/libc/stdio/_READ.c --- uClibc-old/libc/stdio/_READ.c 2011-06-01 14:10:29.904699508 -0700 +++ uClibc-new/libc/stdio/_READ.c 2011-06-01 14:17:15.057396809 -0700 @@ -6,7 +6,25 @@ */ #include "_stdio.h" +#include <sys/syscall.h> +#include <unistd.h> +#include <sys/stat.h> +#include "xstatconv.h" +#define __NR___syscall_fstat __NR_fstat +static __inline__ _syscall2(int, __syscall_fstat, int, fd, struct kernel_stat *, buf) + +int _my_fstat(int fd, struct stat *buf) +{ + int result; + struct kernel_stat kbuf; + + result = __syscall_fstat(fd, &kbuf); + if (result == 0) { + __xstat_conv(&kbuf, buf); + } + return result; +} /* Given a reading stream without its end-of-file indicator set and * with no buffered input or ungots, read at most 'bufsize' bytes @@ -44,7 +62,16 @@ size_t attribute_hidden __stdio_READ(reg /* RETRY: */ if ((rv = __READ(stream, (char *) buf, bufsize)) <= 0) { if (rv == 0) { - __STDIO_STREAM_SET_EOF(stream); + struct stat stat; + + if( (stream->__modeflags & __FLAG_FIFOFILE) || + _my_fstat(stream->__filedes, &stat) >= 0) { + if(S_ISFIFO(stat.st_mode)) + stream->__modeflags |= __FLAG_FIFOFILE; + } + + if(!(stream->__modeflags & __FLAG_FIFOFILE)) + __STDIO_STREAM_SET_EOF(stream); } else { /* if (errno == EINTR) goto RETRY; */ __STDIO_STREAM_SET_ERROR(stream); diff -Naur -p uClibc-old/libc/sysdeps/linux/common/bits/uClibc_stdio.h uClibc-new/libc/sysdeps/linux/common/bits/uClibc_stdio.h --- uClibc-old/libc/sysdeps/linux/common/bits/uClibc_stdio.h 2011-06-01 14:09:55.974786150 -0700 +++ uClibc-new/libc/sysdeps/linux/common/bits/uClibc_stdio.h 2011-06-01 14:17:13.216060881 -0700 @@ -331,6 +331,7 @@ struct __STDIO_FILE_STRUCT { #define __FLAG_FREEBUF 0x4000U #define __FLAG_LARGEFILE 0x8000U /* fixed! == 0_LARGEFILE for linux */ #define __FLAG_FAILED_FREOPEN __FLAG_LARGEFILE +#define __FLAG_FIFOFILE 0x1000U /* handle FIFO differently */ /* Note: In no-buffer mode, it would be possible to pack the necessary * flags into one byte. Since we wouldn't be buffering and there would _______________________________________________ uClibc mailing list uClibc@uclibc.org http://lists.busybox.net/mailman/listinfo/uclibc