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>