Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 10 Sep 1998 09:46:24 -0400 (EDT)
From:      HighWind Software Information <info@highwind.com>
To:        tlambert@primenet.com
Cc:        eischen@vigrid.com, eischen@vigrid.com, tlambert@primenet.com, freebsd-current@FreeBSD.ORG
Subject:   Re: Thread Problems
Message-ID:  <199809101346.JAA16724@highwind.com>
In-Reply-To: <199809100537.WAA07306@usr06.primenet.com> (message from Terry Lambert on Thu, 10 Sep 1998 05:37:27 %2B0000 (GMT))

next in thread | previous in thread | raw e-mail | index | archive | help

Okay, I coded up a test program that ALWAYS reproduces this accept()
blocking problem we have been talking about.

Check it out:

% uname -a
FreeBSD zonda.highwind.com 3.0-19980831-SNAP FreeBSD 3.0-19980831-SNAP #0: Mon Aug 31 14:03:19 GMT 1998     root@make.ican.net:/usr/src/sys/compile/GENERIC  i386

My libc_r is EXTREMELY up-to-date. ~2 days old.

The program does the following:

1. spawns an a thread to loop on "accept"
2. fork/exec's a child talking down a socket pair
3. loops in main()

To compile:

g++ -o fbsd -D_REENTRANT -D_THREAD_SAFE -Wall -Werror -g fbsdtest.C -pthread

To run:

./fbsd 10000

It'll bind to port 10000, and start printing messages on stdout, then
from another window: "telnet localhost 10000".  You'll see the main()
thread STOP printing. ONLY the accept() thread will continue to work.

Help would be greatly appreciated... 

-Rob

----

/*****************************************************************************
File:     fbsdtest.C
Contents: FreeBSD accept and fork test
Created:  10-Sep-1998

*****************************************************************************/

#include <pthread.h>

#include <sys/socket.h>
#include <netinet/in.h>

#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

unsigned short port = 20000;

void *acceptThread(void *)
{
    // Create the socket
    int fd = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (fd == -1) { ::printf("socket failed"); }

    // Make it reusable
    int optval = 1;
    if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, 
		     reinterpret_cast<const char *>(&optval),
		     sizeof(optval)) == -1) {
	::printf("Reusable failed");
    }

    // Bind it
    sockaddr_in location;
    ::memset(&location, 0, sizeof(location));
    location.sin_family = AF_INET;
    location.sin_addr.s_addr = htonl(INADDR_ANY);
    location.sin_port = htons(port);
    if (::bind(fd, reinterpret_cast<sockaddr *>(&location),
	       sizeof(location)) == -1) {
	::printf("Bind failed");
    }

    // Listen on it
    if (::listen(fd, 128) == -1) {
	::printf("Listen failed");
    }

    // LOOP forever accepting and closing!
    while (true) {
	sockaddr_in info;
	int length = sizeof(info);

	int fd2 = ::accept(fd, reinterpret_cast<sockaddr *>(&info),
			   &length);
	::printf("Got an accept()\n");
	::close(fd2);
    }
}

pthread_t spawnBoundThread(void *(*function)(void *))
{
    pthread_t tid;
    pthread_attr_t attr;

    // Initialize thread attributes
    if (::pthread_attr_init(&attr)) {
	::printf("Init Failed");
	return 0;
    }

    // Set detached
    if (::pthread_attr_setdetachstate(&attr,
				      PTHREAD_CREATE_DETACHED)) {
	::printf("Detach failed");
	return 0;
    }

    // Set stack size
    if (::pthread_attr_setstacksize(&attr, 131072)) {
	::printf("Stack set failed");
	return 0;
    }

    // Spawn the thread
    if (::pthread_create(&tid, &attr, function, 0)) {
	::printf("Thread start failed");
	return 0;
    }
    
    // Cleanup thread attributes
    if (::pthread_attr_destroy(&attr)) {
	::printf("Cleanup failed");
	return 0;
    }

    // Return the thread id
    return tid;
}

int forkExec(const char *program, const char *arg1)
{
    // Create the socketpair;
    int fds[2];
    if (::socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) {
	return -1;
    }

    // FORK!! *Youch!*
    pid_t pid = ::fork();
    if (pid == -1) {
	if (::close(fds[0]) || ::close(fds[1])) {
	    return -1;
	}
	return -1;
    }

    if (!pid) { // In Child
	// Enter our own process group (avoids signal nastyness)
	if (::setsid() == -1) {
	    ::_exit(EXIT_FAILURE);
	}
	// Dup the descriptor to STDIN and STDOUT
	if (::dup2(fds[1], STDOUT_FILENO) == -1 ||
	    ::dup2(fds[1], STDIN_FILENO) == -1) {
	    ::_exit(EXIT_FAILURE);
	}
        // Close the other side of the socketpair.
        if (::close(fds[0])) {
	    ::_exit(EXIT_FAILURE);
        }
	// Run the appropriate program
	::execl(program, program, arg1, 0);
	::_exit(EXIT_FAILURE);
    }
    // In Parent
    if (::close(fds[1])) {
	return -1;
    }

    return fds[0];
}


int main(int, char **argv)
{
    port = atoi(argv[1]);

    // Setup 1 second timeout
    timeval timeout;
    timeout.tv_sec = 1;
    timeout.tv_usec = 0;

    spawnBoundThread(acceptThread);

    // Sleep for a second
    ::select(0, 0, 0, 0, &timeout); 

    int childFD = forkExec("/bin/sleep", "200");
    if (childFD == -1) { return EXIT_FAILURE; }

    while (true) {
	// Sleep for a second
	::select(0, 0, 0, 0, &timeout); 

	::printf("main() is still alive\n");
    }	
    ::close(childFD);

    return EXIT_SUCCESS;
}

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199809101346.JAA16724>