[haiku-development] Problems with non-blocking sockets

  • From: Adrien Destugues <pulkomandy@xxxxxxxxx>
  • To: haiku-development@xxxxxxxxxxxxx
  • Date: Thu, 09 Jan 2014 18:39:12 +0100

One of the issues I'm currently trying to fix in Web+ is there are some 
annoying lockups when browsing. My investigation shows that what happens is:

- When navigating away from a page, WebKit will try to close all HTTP 
connections that may still be running. This includes the page still being 
loaded, and XmlHttpRequests generated later on.
- In our network backend, this is done by calling the Stop() method. This 
method is synchronous: it sets a flag to inform the request thread that 
it's time to stop, closes the socket, then waits for the thread to actually 
terminate. When the method returns, it's safe to delete the connection 
object.
- As Stop closes the socket, if the protocol thread was waiting on a read() 
or write() call, it gets woken up and exits as expected.
- When the thread is still waiting on the initial connect(), however, this 
doesn't quite work. connect() isn't unlocked by close().

My first attempt to fix this was to use the "non-blocking connect" pattern, 
that is, set the socket to non-blocking mode, call connect() (this returns 
with EINPROGRESS), then call select() to wait for the connection to 
establish. This way, it should be possible to interrupt select() with a 
call to close(). However, I hit https://dev.haiku-os.org/ticket/2963 , 
which prevents this from working on Haiku (the select call will return 
immediately, and there is no way to tell if the connection was succesful or 
not).

The most obvious solution would be to fix that, I tried to do this, and I 
managed to get the select() call to wait, but not to stop waiting when 
something happens. I think the "blocking mode" code from Connect() must be 
split into a separate method (_WaitForConnection or something), and select 
would call this to watch for the remote answer.


I tried to think of a way to avoid the problem on WebKit side as well. I 
could make the Stop() method asynchronous again, but I'd hit the same 
problem when trying to delete the pending request. I could kill the thread 
instead of waiting for it to unlock. Or, I could change the code so the 
request deletes itself when it's done, but there's a risk of callers 
keeping dangling pointers to it. Also, the request also allows access to 
the result of the request (HTTP status code, etc), so we must not delete it 
before the user has extracted all relevant information.

Using BReferenceable is not an option, as BUrlRequest is a public API, and 
BReferenceable is not (yet). I'm not sure it would be the best solution, 
anyway.


So, I'm looking for:
- Help with solving #2963,
- Comments on the various solutions and which is the one to implement.
-- 
Adrien.

Other related posts: