Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 9 Sep 1998 20:23:07 -0400 (EDT)
From:      Daniel Eischen <eischen@vigrid.com>
To:        eischen@vigrid.com, tlambert@primenet.com
Cc:        freebsd-current@FreeBSD.ORG, info@highwind.com
Subject:   Re: Thread Problems
Message-ID:  <199809100023.UAA19743@pcnet1.pcnet.com>

next in thread | raw e-mail | index | archive | help
> > It does seem that the listen socket somehow became blocking,
> > but it isn't apparent by looking at the code.  Is a
> > fcntl(fd, F_SETFL, O_NONBLOCK) sufficient to set a socket

I should have said _thread_sys_fcntl(fd, F_SETFL, O_NONBLOCK)

> > non-blocking across multiple accepts?
> 
> No.
> 
> You are getting confused here between the non-blocking flag on
> the actual fd, and the non-blocking flag maintained in user space
> threading to determine how a call should be multiplexed.

No, I understand that :-)  I've looked at and modified the threads
library enough so that I understand that much anyways.

> That is, if a socket is created via socket(3) (the threads library
> socket(3) is a wrapper for socket(2)), the socket(2) socket will
> be non-blocking, but the socket(3) socket will be "blocking" (that
> is, a call to it will block the thread making the call until the
> call can be completed successfully).
> 
> This is the difference between "blocking the thread" and "blocking
> the process".
> 
> If a "blocking" call is made (i.e., a call on a "blocking" fd, from
> the thread's perspective), then it will block.
> 
> The socket option inheritance issue applies to the inheritance of
> user space flags, as well, which I don't think the threads library
> successfully wraps.

Yes, fcntl is wrapped so that it ORs the users requested flags
with O_NONBLOCK.  If the program is setting the O_NONBLOCK then
this will be saved and remembered in the threads file descriptor
table.  When the threads library sets the file to non-blocking
it doesn't set the O_NONBLOCK flag in the file descriptor table.

Look at the code:

  (from uthread_accept.c)

		/* Enter a loop to wait for a connection request: */
		while ((ret = _thread_sys_accept(fd, name, namelen)) < 0) {
			/* Check if the socket is to block: */
			if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0 && (errno == EWOULDBLOCK || errno == EAGAIN)) {
				/* Save the socket file descriptor: */
				_thread_run->data.fd.fd = fd;
				_thread_run->data.fd.fname = __FILE__;
				_thread_run->data.fd.branch = __LINE__;

				/* Set the timeout: */
				_thread_kern_set_timeout(NULL);

				/* Schedule the next thread: */
				_thread_kern_sched_state(PS_FDR_WAIT, __FILE__, __LINE__);

				/* Check if the wait was interrupted: */
				if (errno == EINTR) {
					/* Return an error status: */
					ret = -1;
					break;
				}
			} else {
				/*
				 * Another error has occurred, so exit the
				 * loop here: 
				 */
				break;
			}
		}

_thread_fd_table[fd]->flags should only have O_NONBLOCK set if the user
application set it so.  Regardless, the file was made non-blocking when
it was created with socket(3).  The code seems to do the right thing --
as long as the socket is still non-blocking.

> If the server code expects the "non-blocking" flag, as set within
> the context of a thread, so that the call will not result in a
> threads context switch, to be non-blocking after derivation from
> another socket where the flag was set, then this could be the problem.

What do you mean by "derivation from another socket"?  dup/dup2/fcntl?
Aren't these suppose to preserve the O_NONBLOCK flag?  The threads
library preserves the user space flags, but if the O_NONBLOCK flag
isn't set by the application, then it relies on the system call to
preserve the flag.

I tried to repeat the reported problem, but couldn't.  I had 
one thread listening for client connections, a worker thread
(printing a message once a second), and main.  The thread
listening for client connections would create a thread to
handle the connection and go back to accepting more connections.
I couldn't make it fail - the worker thread was always spewing
out messages once a second.  I even tried using fork to
process each client request that came in - that worked also.

It'd be nice to see a sample program that reproduced the problem.
I can send info@highwind.com my test program if he wants to try
to hack it up to demonstrate the problem.

Dan Eischen
eischen@vigrid.com

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?199809100023.UAA19743>