Date: Wed, 20 Dec 2006 15:48:59 +0000 (GMT) From: Robert Watson <rwatson@FreeBSD.org> To: Daniel Eischen <deischen@freebsd.org> Cc: David Xu <davidxu@freebsd.org>, freebsd-arch@freebsd.org Subject: Re: close() of active socket does not work on FreeBSD 6 Message-ID: <20061220153126.G85384@fledge.watson.org> In-Reply-To: <Pine.GSO.4.64.0612130918140.13170@sea.ntplx.net> References: <32874.1165905843@critter.freebsd.dk> <Pine.GSO.4.64.0612121543220.8780@sea.ntplx.net> <200612132010.49601.davidxu@freebsd.org> <Pine.GSO.4.64.0612130918140.13170@sea.ntplx.net>
next in thread | previous in thread | raw e-mail | index | archive | help
On Wed, 13 Dec 2006, Daniel Eischen wrote: > [CC trimmed] > > On Wed, 13 Dec 2006, David Xu wrote: > >> On Wednesday 13 December 2006 04:49, Daniel Eischen wrote: >>> >>> Well, if threads waiting on IO are interruptable by signals, can't we make >>> a new signal that's only used by the kernel and send it to all threads >>> waiting on IO for that descriptor? When it gets out to actually setup the >>> signal handler, it just resumes like it is returning from an SA_RESTART >>> signal handler (which according to another posting would reissue the IO >>> command and get EBADF). >> >> Even if you have implemented the close() with the interruption, another >> thread openning a file still can reuse the file handle immediately, >> according to specifications, the lowest free file handle will be returned, >> if SA_RESTART is used, the interrupted thread restart the syscall, it will >> be using a wrong file, I think even if we have implemented the feature in >> kernel, useland threads still has serious race to fix. > > If you use a special signal that is only used for this purpose, there is no > reason you have to try the IO operation again. You can just return EBADF. > > Anyway, this was just a thought/idea. I don't mean to argue against any of > the other reasons why this isn't a good idea. Whatever may be implemented to solve this issue will require a fairly serious re-working of how we implement file descriptor reference counting in the kernel. Do you propose similar "cancellation" of other system calls blocked on the file descriptor, including select(), etc? Typically these system calls interact with the underlying object associated with the file descriptor, not the file descriptor itself, and often, they act directly on the object and release the file descriptor before performing their operation. I think before we can put any reasonable implementation proposal on the table, we need a clear set of requirements: - What is the scope of cancellation? Are we cancelling oustanding simultaneous I/O operations on the same fd index in the process, use of any fd pointing at the same open file entry in the process (i.e., all dup'd instances), or the same open file entry across all processes? I've been presuming only use of the same fd index in the same process is relevant, but if so, let's make sure we state that. If not, what do we mean? - Exactly which potentially blocking operations will be cancelled as a result of close() of an "in use" file descriptor? read()? write()? sendfile()? connect()? ioctl()? select()? poll()? close()? Is the set of possible cancellation points equal to the existing set of interruptible sleeps? Notice that in our current implementation, objects are often reached using a file descriptor, but then separately referenced for the duration of the operation, with the file descriptor being released. This means that we currently don't maintain any useful list of threads currently interacting with the file descriptor, and only have a limited notion of which threads are interacting with the underlying object. - What semantics are expected regarding the underlying object when an operation is cancelled due to simultaneous close() on the same file descriptor? Keep in mind that the underlying object may be referenced by other file descriptor indexes pointing at the same open file state (shared offset, etc). For example, if we cancel connect(), is it safe to say that what we've done is cancel the wait for connect() to complete, rather than the connection operation itself, which may continue and be visible on other file descriptor indexes referencing the same object, or to other processes also referencing it? While providing Solaris-like semantics here makes some amount of sense, this is a very tricky area, and one where we're still refining performance behavior, reference counting behavior, etc. I don't think there will be any easy answers, and we need to think through the semantic and performance implications of any change very carefully before starting to implement. Robert N M Watson Computer Laboratory University of Cambridge
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20061220153126.G85384>