Date: Mon, 03 Feb 2003 17:19:15 +0100 From: rmkml <rmkml@wanadoo.fr> To: freebsd-hackers@FreeBSD.ORG Subject: vfork / execve / accept lock Message-ID: <3E3E9683.801036E1@wanadoo.fr> References: <20030203155505.49450.qmail@web13407.mail.yahoo.com>
next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format. --------------506CB5FA762C7949FD12AA38 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit here is a sample code (vfork_execve.c) to demonstrate a locking problem. The code launch 3 threads : 1 signal 2 endless do nothing 3 a socket server (bind to 127.0.0.1:12345) The server accept 3 cmd: 1) close => close cnx 2) sleep => use vfork /execv to launch external "/bin/sleep 20" to reproduce the lock: launch ./vfork_execve connect to server: =>telnet 127.1 12345 type quickly sleep close =>telnet 127.1 12345 ->close the process telnet and vfork_execve is locked until the first 'sleep' cmd has return. I've no idea why the process locks; maybe an implementation trouble or a bug. Any suggestions are welcome. Best Regards. --------------506CB5FA762C7949FD12AA38 Content-Type: text/plain; charset=us-ascii; name="Makefile" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="Makefile" CC=gcc CFLAGS= -ansi -Wall -I/usr/local/ssl/include SPEC_INC_BSD= -DUNDER_BSD CCFLAGS_BSD= -g2 $(CFLAGS) $(SPEC_INC_BSD) LIB_THREAD_LINUX= -lpthread LIB_THREAD_BSD= -pthread LIBS_SOLARIS= -lsocket -lnsl LIB_LINUX= LIB_BSD= CCFLAGS=$(CCFLAGS) LIBS= $(LIB_THREAD_LINUX) $(LIB_BSD) OBJ= $(SRC:.c=.o) all: vfork_execve vfork_execve2 vfork_execve: vfork_execve.o $(CC) -o vfork_execve $(LIBS) vfork_execve.o vfork_execve.o: vfork_execve.c $(CC) $(CCFLAGS) -o $*.o -c $*.c vfork_execve2: vfork_execve2.o $(CC) -o vfork_execve2 $(LIBS) vfork_execve2.o vfork_execve2.o: vfork_execve2.c $(CC) $(CCFLAGS) -o $*.o -c $*.c clean: @rm -f *.o y.tab.c lex.yy.c --------------506CB5FA762C7949FD12AA38 Content-Type: image/x-xbitmap; name="vfork_execve.c" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="vfork_execve.c" #define __EXTENSIONS__ #define _REENTRANT /* basic first 3-lines for threads */ #define _GNU_SOURCE #include <stdio.h> #include <pthread.h> #include <sys/types.h> #include <sys/wait.h> #include <signal.h> #include <unistd.h> #include <ctype.h> #include <stdlib.h> #include <sys/time.h> #include <fcntl.h> #include <errno.h> #include <sys/socket.h> #include <netinet/in.h> #include <unistd.h> #include <ctype.h> #include <strings.h> #include <sys/select.h> #include <arpa/inet.h> #include <signal.h> int strcasecmp(const char *s1, const char *s2); int strncasecmp(const char *s1, const char *s2, size_t n); int g_exit; void child_end(int signo); #define CMD_SLEEP 1 #define CMD_VFORK 2 /*******************************************************/ void exec_cmd(int cmd) { pid_t pid; pid = fork(); if (pid == 0) { char *arg[3]; /* setsid(); DON'T WORK */ if( cmd == CMD_SLEEP ) { arg[0] = "/bin/sleep"; arg[1] = "20"; arg[2] = NULL; } else { arg[0]="./vfork_execve2"; arg[1] = NULL; } execv(arg[0], arg); _exit(127); } else if (pid < 0) { printf("vfork failed.\n"); exit(1); } } /*******************************************************/ int select_fd (int fd, int maxtime, int writep) { fd_set fds, exceptfds; FD_ZERO (&fds); FD_SET (fd, &fds); FD_ZERO (&exceptfds); FD_SET (fd, &exceptfds); if( maxtime != 0 ) { struct timeval timeout; timeout.tv_sec = maxtime; timeout.tv_usec = 0; return select (fd + 1, writep ? NULL : &fds, writep ? &fds : NULL, &exceptfds, &timeout); } else { return select (fd + 1, writep ? NULL : &fds, writep ? &fds : NULL, &exceptfds, NULL); } } /*******************************************************/ int get_line_from_sock(int fd, char *buf, int len, int timeout) { register int res, cur=0; register char *ptr; if( !buf ) return(-1); ptr=buf; do { do { res = select_fd (fd, timeout, 0); } while (res == -1 && errno == EINTR); if (res <= 0) { return -1; } if( (res =read(fd, ptr, 1))>0 ) { if(*ptr == '\n' ) { *++ptr=0; break; } ptr++; cur++; len --; if( len == 1 ) { *++ptr=0; break; } } } while ( (len && res) || (res == -1 && errno == EINTR) ); return(cur); } static void *server(int fd) { char buf[500]; register int n; pthread_cleanup_push( (void (*)(void *)) close, (void *) fd); /** automatiquely close de socket when launching an external agent **/ fcntl(fd,F_SETFD, FD_CLOEXEC); for(;;) { printf("awainting command ....\n"); n = get_line_from_sock(fd, buf, 500, 30); if( n == -1 ) { printf("connection timeout.\n"); break; } else if (n == 0) { break; } buf[n-1]=0; if( !strncmp(buf, "close", 5)) break; else if( !strncmp(buf, "sleep",5) ) exec_cmd(CMD_SLEEP); else if( !strncmp(buf, "vfork",5) ) exec_cmd(CMD_VFORK); else { printf("unknow cmd '%s'\n", buf); } } pthread_cleanup_pop(1); return(0); } void *accept_thread(int fd) { int conn; pthread_attr_t attr; struct sockaddr_in caddr; int addrlen = sizeof( struct sockaddr_in); pthread_attr_init( &attr ); pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED); pthread_attr_setdetachstate( &attr, PTHREAD_SCOPE_SYSTEM); while( 1 ) { int n; pthread_t tid; conn = accept( fd, (struct sockaddr *) &caddr, &addrlen); if( conn == -1 ) { if( errno == EINTR ) { printf("accept was interrupted"); continue; } else break; } n = pthread_create( &tid, &attr, (void *(*)(void*))server, (void*) conn); if(n) { printf("ALERT: can't launch an another client thread!!"); close(conn); continue; } } pthread_attr_destroy(&attr); pthread_cleanup_pop( 1 ); return(NULL); } void *endless_thread(void *arg) { while (!g_exit) { printf("endless_thread say hello\n"); sleep(1); } pthread_exit(NULL); } void *sig_thread(void *arg) { sigset_t sigset; int sig, err; g_exit=0; pthread_sigmask(0, NULL, &sigset); sigaddset(&sigset, SIGINT); pthread_sigmask(SIG_BLOCK, &sigset, NULL); for ( ; ; ) { err = sigwait(&sigset, &sig); fprintf(stdout, "signal catched = %d\n", sig); if (err) { fprintf(stderr, "sigwait error\n"); pthread_exit(NULL); } switch (sig) { case SIGKILL: case SIGINT: case SIGTERM: g_exit = 1; pthread_exit(NULL); break; } } pthread_exit(NULL); } int main(int argc, char **argv) { pthread_t t0,t1,t2; struct sigaction sact; struct sockaddr_in saddr; int sock, port; int cne = 1; pthread_attr_t attr; if(argv[1]) port = atoi(argv[1]); else port = 12345; pthread_attr_init( &attr ); pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED); pthread_attr_setdetachstate( &attr, PTHREAD_SCOPE_SYSTEM); saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = inet_addr ("127.0.0.1"); saddr.sin_port = htons((unsigned short)port); memset(saddr.sin_zero, 0, sizeof(saddr.sin_zero)); if( (sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP) ) < 0 ) { printf("FATAL: Can't obtain a valid socket (bad parameters)."); exit(1); } if( setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &cne, sizeof(cne)) < 0 ) { printf("FATAL: Can't setsocket option (REUSEADDR)."); exit(1); } if( setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &cne, sizeof(int)) < 0 ) { printf("FATAL: Can't setsocket option (KEEPALIVE)."); exit(1); } fcntl(sock, F_SETFD, FD_CLOEXEC); if( bind(sock, (struct sockaddr*) &saddr, sizeof( saddr))) { printf("FATAL: Can't bind (errno:%d).", errno); exit(1); } if( listen( sock, 5) == -1) { printf("FATAL: Can't listen."); exit(1); } sact.sa_flags = 0; sact.sa_handler = child_end; sigaction(SIGCHLD, &sact, (struct sigaction*)NULL); pthread_create(&t0, NULL, sig_thread, NULL); pthread_create( &t1, &attr, (void *(*)(void*))accept_thread, (void*) sock); pthread_create(&t2, NULL, endless_thread, NULL); pthread_join(t2, NULL); pthread_attr_destroy(&attr); return 0; } void child_end(int signo) { if( signo == SIGCHLD ) { printf("receiving SIGCHLD\n"); while( waitpid(-1, 0, WNOHANG) > 0); } } --------------506CB5FA762C7949FD12AA38 Content-Type: image/x-xbitmap; name="vfork_execve2.c" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="vfork_execve2.c" #define __EXTENSIONS__ #define _REENTRANT /* basic first 3-lines for threads */ #define _GNU_SOURCE #include <stdio.h> #include <pthread.h> #include <sys/types.h> #include <sys/wait.h> #include <signal.h> #include <unistd.h> #include <ctype.h> #include <stdlib.h> #include <sys/time.h> #include <fcntl.h> #include <errno.h> #include <sys/socket.h> #include <netinet/in.h> #include <unistd.h> #include <ctype.h> #include <strings.h> #include <sys/select.h> #include <arpa/inet.h> #include <signal.h> int strcasecmp(const char *s1, const char *s2); int strncasecmp(const char *s1, const char *s2, size_t n); int g_exit; void child_end(int signo); void *exec_thread(void *arg); void *endless_thread(void *arg) { while (!g_exit) { printf("endless_thread say hello\n"); sleep(1); } pthread_exit(NULL); } void *exec_thread(void *arg) { pid_t pid; pid = fork(); if (pid == 0) { char *arg[] = {"/bin/sleep", "30", NULL}; execv("/bin/sleep", arg); _exit(127); } else if (pid < 0) { printf("vfork failed.\n"); exit(1); } printf("child exit...\n"); pthread_exit(NULL); } void *sig_thread(void *arg) { sigset_t sigset; int sig, err; g_exit=0; pthread_sigmask(0, NULL, &sigset); sigaddset(&sigset, SIGINT); pthread_sigmask(SIG_BLOCK, &sigset, NULL); for ( ; ; ) { err = sigwait(&sigset, &sig); fprintf(stdout, "signal catched = %d\n", sig); if (err) { fprintf(stderr, "sigwait error\n"); pthread_exit(NULL); } switch (sig) { case SIGCHLD: waitpid(-1, NULL, WNOHANG); fprintf(stdout, "SIGCHLD\n"); break; case SIGKILL: case SIGINT: case SIGTERM: g_exit = 1; pthread_exit(NULL); break; } } pthread_exit(NULL); } int main(int argc, char **argv) { pthread_t t0,t1,t2; struct sigaction sact; sact.sa_flags = 0; sact.sa_handler = child_end; sigaction(SIGCHLD, &sact, (struct sigaction*)NULL); pthread_create(&t0, NULL, sig_thread, NULL); pthread_create(&t1, NULL, endless_thread, NULL); pthread_create(&t2, NULL, exec_thread, NULL); pthread_join(t1, NULL); return 0; } void child_end(int signo) { if( signo == SIGCHLD ) { printf("receiving SIGCHLD\n"); while( waitpid(-1, 0, WNOHANG) > 0); } } --------------506CB5FA762C7949FD12AA38-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-hackers" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3E3E9683.801036E1>