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>
