RE: PROBLEM: I/O system call never returns if file desc is closed in the

2001-06-07 Thread David Schwartz


> At 22:35 +0100 2001-06-06, Alan Cox wrote:

> >  > This report describes a problem in the usage of file
> >  > descriptors across

> >>  multiple threads. When one thread closes a file descriptor, another
> >>  thread which waits for an I/O on that file descriptor is not notified
> >>  and blocks forever.

> >THe I/O does not block forever, it blocks until completed.

> That's still "forever" if you don't specify a timeout in the select.

If you don't want to block until an operation completes, then don't ask to!

> >The actual final
> >closure of the object occurs when the last operation on it exits

> Select is defined as to return, with the appropriate bit set, if/when
> a nonblocking read/write on the file descriptor won't block. You'd
> get EBADF in this case, therefore causing the select to return would
> be a Good Thing.

That is not quite correct. That is a good approximate definition of
'select's behavior, but it is not exact. As for your assertion that a
noblocking read/write wouldn't block, that's not necessarily true. Remember,
the 'close' may not have taken affect yet, since the descriptor is still in
use by virtue of being selected on.

> A related problem is that the second thread my be inside a blocking
> read() instead of a select() call. It'd never continue.  :-(

Perfect. Doing this is absolutely, positively wrong and the more you are
punished for it, the better. It's as wrong as calling 'free' on a chunk of
memory when another thread may be usign it. It is impossible to make this
work safely, as another thread could open a socket or file and get the same
descriptor write before the call to 'read' is entered. There's no possible
way to do this because there is no 'unlock a mutex and read' operation.

> HOWEVER: IMHO it's bad design to distribute the responsibility for
> file descriptors between threads.

Why? That's a great design and it's absolutely essential in many cases.
Suppose, for example, I have two descriptors I want to write to. If I assign
one thread to each socket permanently, then I'm 100% guaranteed a context
switch every time I change which socket I'm writing to, so if there's lots
of small bits of data going out both of them, my performance will suck. But
if I assign one thread to both socket descriptors, I'm guaranteed that one
connection will stall if the the application-level send queue for the other
has been swapped out to disk. Not distributing network I/O across threads
dynamically is a recipe for either low performance or bursty performance.

DS

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/



Re: PROBLEM: I/O system call never returns if file desc is closed in the

2001-06-07 Thread Florian Weimer

Alexander Viro <[EMAIL PROTECTED]> writes:

> On 7 Jun 2001, Florian Weimer wrote:
> 
> > Matthias Urlichs <[EMAIL PROTECTED]> writes:
> > 
> > > Select is defined as to return, with the appropriate bit set, if/when
> > > a nonblocking read/write on the file descriptor won't block. You'd get
> > > EBADF in this case, therefore causing the select to return would be a
> > > Good Thing.
> > 
> > How do you avoid race conditions if more than one thread is creating
> > file descriptors?  I think you can only do that under very special
> > circumstances, and it definitely requires some synchronization.
> 
> The same way as you do it for many threads doing any allocations.

There's a subtle difference: For malloc(), libc has a mutex (or
whatever), but for open(), socket() etc., no locking is performed, and
many libc functions create (and destroy) descriptors imlicitely.  

I still don't see how you can write maintainable and reliable software
with asynchronous close().  For example, if some select() call returns
EBADF after an asynchronous close(), you would have to scan the
descriptors to find the offending one, but in the meantime, it has
been reused by another thread.  What do you do in this case?

-- 
Florian Weimer[EMAIL PROTECTED]
University of Stuttgart   http://cert.uni-stuttgart.de/
RUS-CERT  +49-711-685-5973/fax +49-711-685-5898
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/



Re: PROBLEM: I/O system call never returns if file desc is closed in the

2001-06-07 Thread Florian Weimer

Alexander Viro [EMAIL PROTECTED] writes:

 On 7 Jun 2001, Florian Weimer wrote:
 
  Matthias Urlichs [EMAIL PROTECTED] writes:
  
   Select is defined as to return, with the appropriate bit set, if/when
   a nonblocking read/write on the file descriptor won't block. You'd get
   EBADF in this case, therefore causing the select to return would be a
   Good Thing.
  
  How do you avoid race conditions if more than one thread is creating
  file descriptors?  I think you can only do that under very special
  circumstances, and it definitely requires some synchronization.
 
 The same way as you do it for many threads doing any allocations.

There's a subtle difference: For malloc(), libc has a mutex (or
whatever), but for open(), socket() etc., no locking is performed, and
many libc functions create (and destroy) descriptors imlicitely.  

I still don't see how you can write maintainable and reliable software
with asynchronous close().  For example, if some select() call returns
EBADF after an asynchronous close(), you would have to scan the
descriptors to find the offending one, but in the meantime, it has
been reused by another thread.  What do you do in this case?

-- 
Florian Weimer[EMAIL PROTECTED]
University of Stuttgart   http://cert.uni-stuttgart.de/
RUS-CERT  +49-711-685-5973/fax +49-711-685-5898
-
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/



RE: PROBLEM: I/O system call never returns if file desc is closed in the

2001-06-07 Thread David Schwartz


 At 22:35 +0100 2001-06-06, Alan Cox wrote:

This report describes a problem in the usage of file
descriptors across

   multiple threads. When one thread closes a file descriptor, another
   thread which waits for an I/O on that file descriptor is not notified
   and blocks forever.

 THe I/O does not block forever, it blocks until completed.

 That's still forever if you don't specify a timeout in the select.

If you don't want to block until an operation completes, then don't ask to!

 The actual final
 closure of the object occurs when the last operation on it exits

 Select is defined as to return, with the appropriate bit set, if/when
 a nonblocking read/write on the file descriptor won't block. You'd
 get EBADF in this case, therefore causing the select to return would
 be a Good Thing.

That is not quite correct. That is a good approximate definition of
'select's behavior, but it is not exact. As for your assertion that a
noblocking read/write wouldn't block, that's not necessarily true. Remember,
the 'close' may not have taken affect yet, since the descriptor is still in
use by virtue of being selected on.

 A related problem is that the second thread my be inside a blocking
 read() instead of a select() call. It'd never continue.  :-(

Perfect. Doing this is absolutely, positively wrong and the more you are
punished for it, the better. It's as wrong as calling 'free' on a chunk of
memory when another thread may be usign it. It is impossible to make this
work safely, as another thread could open a socket or file and get the same
descriptor write before the call to 'read' is entered. There's no possible
way to do this because there is no 'unlock a mutex and read' operation.

 HOWEVER: IMHO it's bad design to distribute the responsibility for
 file descriptors between threads.

Why? That's a great design and it's absolutely essential in many cases.
Suppose, for example, I have two descriptors I want to write to. If I assign
one thread to each socket permanently, then I'm 100% guaranteed a context
switch every time I change which socket I'm writing to, so if there's lots
of small bits of data going out both of them, my performance will suck. But
if I assign one thread to both socket descriptors, I'm guaranteed that one
connection will stall if the the application-level send queue for the other
has been swapped out to disk. Not distributing network I/O across threads
dynamically is a recipe for either low performance or bursty performance.

DS

-
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/



Re: PROBLEM: I/O system call never returns if file desc is closed in the

2001-06-06 Thread Florian Weimer

Matthias Urlichs <[EMAIL PROTECTED]> writes:

> Select is defined as to return, with the appropriate bit set, if/when
> a nonblocking read/write on the file descriptor won't block. You'd get
> EBADF in this case, therefore causing the select to return would be a
> Good Thing.

How do you avoid race conditions if more than one thread is creating
file descriptors?  I think you can only do that under very special
circumstances, and it definitely requires some synchronization.

-- 
Florian Weimer[EMAIL PROTECTED]
University of Stuttgart   http://cert.uni-stuttgart.de/
RUS-CERT  +49-711-685-5973/fax +49-711-685-5898
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/



Re: PROBLEM: I/O system call never returns if file desc is closed in the

2001-06-06 Thread Florian Weimer

Matthias Urlichs [EMAIL PROTECTED] writes:

 Select is defined as to return, with the appropriate bit set, if/when
 a nonblocking read/write on the file descriptor won't block. You'd get
 EBADF in this case, therefore causing the select to return would be a
 Good Thing.

How do you avoid race conditions if more than one thread is creating
file descriptors?  I think you can only do that under very special
circumstances, and it definitely requires some synchronization.

-- 
Florian Weimer[EMAIL PROTECTED]
University of Stuttgart   http://cert.uni-stuttgart.de/
RUS-CERT  +49-711-685-5973/fax +49-711-685-5898
-
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/