Date: Thu, 10 Sep 1998 12:54:13 -0400 From: "Daniel M. Eischen" <eischen@vigrid.com> To: info@highwind.com Cc: freebsd-current@FreeBSD.ORG, tlambert@primenet.com, eischen@vigrid.com Subject: Re: Thread Problems Message-ID: <35F80435.41C67EA6@vigrid.com>
next 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() > It looks like the problem lies in the threads implementation of fork and execve. When you fork, the child process gets a copy of the parents file descriptors, which includes the listen socket. When you exec, the threads library goes through its list of file descriptors and returns their mode to non-blocking (unless the application explicitly sets the mode to non-blocking). You can see this in uthread_execve.c: /* * Enter a loop to set all file descriptors to blocking * if they were not created as non-blocking: */ for (i = 0; i < _thread_dtablesize; i++) { /* Check if this file descriptor is in use: */ if (_thread_fd_table[i] != NULL && !(_thread_fd_table[i]->flags & O_NONBLOCK)) { /* Get the current flags: */ flags = _thread_sys_fcntl(i, F_GETFL, NULL); /* Clear the nonblocking file descriptor flag: */ _thread_sys_fcntl(i, F_SETFL, flags & ~O_NONBLOCK); } } I'm not exactly sure how the threads library should be fixed to Do The Right Thing, though. How can the threads library know what files are going to be used? Perhaps it can flag the file as a socket when it is created and not clear the non-blocking flag in this case... A simple solution that you can make in your application, is to close all relevent sockets after the fork and before the execl. When you close the file, it will not affect the non-blocking flag. Your code will have to make the sockets visible to the forkExec routine so it can close them. Another method is to perform the forkExec before you create the sockets, although this may not be possible in your real application. Dan Eischen eischen@vigrid.com *************** *** 16,26 **** #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 --- 16,27 ---- #include <unistd.h> unsigned short port = 20000; + int fd; void *acceptThread(void *) { // Create the socket ! fd = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (fd == -1) { ::printf("socket failed"); } // Make it reusable *************** *** 117,122 **** --- 118,126 ---- } if (!pid) { // In Child + // Close the socket + ::close (fd); + // Enter our own process group (avoids signal nastyness) if (::setsid() == -1) { ::_exit(EXIT_FAILURE); 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?35F80435.41C67EA6>