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>
index | next in thread | previous in thread | raw e-mail
[-- Attachment #1 --]
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.
[-- Attachment #2 --]
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
[-- Attachment #3 --]
#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);
}
}
[-- Attachment #4 --]
#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);
}
}
help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3E3E9683.801036E1>
