Skip site navigation (1)Skip section navigation (2)
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>