select() on Windows

So I’ve run into a potentially difficult issue on Windows.

I have the test suite actually running. A few tests even passed surprisingly. But what doesn’t work is one-shot script commands. e.g. the following:

(lldb) script print “foo”

Running this deadlocks. The reason is related to the ConnectionFileDescriptor class. Basically, on Windows the select() API will only accept sockets, nothing else. It seems select() is only used from the BytesAvailable() function, but that it attempts to simultaneously check if data is available on a) the read file descriptor, which could be an arbitrary object (pipe, socket, file, etc), and b) optionally, a pipe.

Is this correct? There isn’t a great equivalent for this on Windows.

It’s possible to make it work, but at a minimum it’s going to involve re-implementing Pipe in terms of HANDLEs on Windows, because it’s the only way you can do non-blocking I/O on a Pipe.

For starters, we could just stub out an entirely separate implementation of the function on Windows that makes use of this new HANDLE-based Pipe class, but I imagine that’s going to get old pretty fast if we need to use select() in other places. I did search the code and only saw select() used in one other place, but perhaps at some point we’ll need to abstract this out into an actual platform-specific version of select. FWIW Windows does provide a rough equivalent, it just uses an entirely different API, and is completely HANDLE-based, so this approach will probably require some more work to make other types of objects (files, sockets, processes, etc) HANDLE-based instead of fd-based on Windows.

Thoughts? Suggestions?

Zachary Turner wrote:

So I've run into a potentially difficult issue on Windows.

I have the test suite actually running. A few tests even passed surprisingly. But what doesn't work is one-shot script commands. e.g. the following:

(lldb) script print "foo"

Running this deadlocks. The reason is related to the ConnectionFileDescriptor class. Basically, on Windows the select() API will only accept sockets, nothing else. It seems select() is only used from the BytesAvailable() function, but that it attempts to simultaneously check if data is available on a) the read file descriptor, which could be an arbitrary object (pipe, socket, file, etc), and b) optionally, a pipe.

Is this correct? There isn't a great equivalent for this on Windows.

It's possible to make it work, but at a minimum it's going to involve re-implementing Pipe in terms of HANDLEs on Windows, because it's the only way you can do non-blocking I/O on a Pipe.

For starters, we could just stub out an entirely separate implementation of the function on Windows that makes use of this new HANDLE-based Pipe class, but I imagine that's going to get old pretty fast if we need to use select() in other places. I did search the code and only saw select() used in one other place, but perhaps at some point we'll need to abstract this out into an actual platform-specific version of select. FWIW Windows does provide a rough equivalent, it just uses an entirely different API, and is completely HANDLE-based, so this approach will probably require some more work to make other types of objects (files, sockets, processes, etc) HANDLE-based instead of fd-based on Windows.

Thoughts? Suggestions?

Yes. As you allude to above: you'd need to reimplement in terms of WaitForMultipleObjects and friends using HANDLEs. My previous experience of doing a lot of cross-platform was that you always ended up with a chunk of *nix code using select/poll and Windows code with WaitForMultipleObjects. But it's not a straight swap (i.e. select for WFMO) - since with windows there are a few disparate APIs which map the object of choice (i.e the socket etc.) to a waitable HANDLE.

Matt

Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom
More information can be found at www.csr.com. Keep up to date with CSR on our technical blog, www.csr.com/blog, CSR people blog, www.csr.com/people, YouTube, www.youtube.com/user/CSRplc, Facebook, www.facebook.com/pages/CSR/191038434253534, or follow us on Twitter at www.twitter.com/CSR_plc.
New for 2014, you can now access the wide range of products powered by aptX at www.aptx.com.

For code in ConnectionFileDescriptor you can #ifdef code in/out for windows as needed.

There are only two places that use select:
1 - ConnectionFileDescriptor
2 - IOHandlerProcessSTDIO::Run()

The first case you can handle with #ifdef'ery as ConnectionFileDescriptor is a plug-in based mechanism, but it can be host specific since it is dealing with host files.

The second case, IOHandlerProcessSTDIO can be switched over to use a ConnectionFileDescriptor.

If there are too many differences you could make a new version of ConnectionFileDescriptor that gets compiled for windows only and use the processor to compile only one or the other. This would give you the freedom to replace all of the ConnectionFileDescriptor guts with windows specific stuff.

Greg