<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">
<html><body style='font-family: Arial,Helvetica,sans-serif'>
<p> </p>
<p> </p>
<div> </div>
<p>Em 18/08/2014 08:00, Andy Green escreveu:</p>
<blockquote type="cite" style="padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px"><!-- html ignored --><!-- head ignored --><!-- meta ignored -->
<pre>On 18 August 2014 17:59:52 GMT+08:00, Roger Light <<a href="mailto:roger@atchoo.org">roger@atchoo.org</a>> wrote:</pre>
<blockquote type="cite" style="padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px">On Mon, Aug 18, 2014 at 10:19 AM, Andy Green <<a href="mailto:andy@warmcat.com">andy@warmcat.com</a>> wrote:
<blockquote type="cite" style="padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px">On 18 August 2014 17:00:17 GMT+08:00, Roger Light <<a href="mailto:roger@atchoo.org">roger@atchoo.org</a>></blockquote>
wrote:
<blockquote type="cite" style="padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px">
<blockquote type="cite" style="padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px">I believe I could trigger the assert easily on Linux by calling libwebsocket_write() without checking lws_send_pipe_choked() first. I was checking that the socket was available to write, then attempting to write as much as possible until it blocked. So crudely, and iirc: case LWS_CALLBACK_SERVER_WRITEABLE: /* Gives assert */ while(have_data){ count = libwebsockets_write(len); if(count < 0) return 0; if(wlen != len) break; }</blockquote>
Yeah you can't do that. Say you send a lot each time like 1MByte. The kernel won't accept that much for buffering, so a partial send is</blockquote>
guaranteed.
<blockquote type="cite" style="padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px">Once lws took on dealing with your partial send, flushing the</blockquote>
buffered remainder
<blockquote type="cite" style="padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px">has to take priority over everything else, since it has to get sent</blockquote>
first before anything else. If I'm reading what Nilson said correctly, he has configured lws so that he is dealing with partial writes, not the library. The same is true in my case. In that situation I would expect to be able to call</blockquote>
<pre>What did you actually do to "configure lws so [you] are dealing with partial writes"?<br /><br />In my case I set no_buffer_all_partial_tx to 0 in the libwebsocket_protocols struct so that wsi->u.ws.clean_buffer is 1 (set at line 279) and so the condition at line 172 is satisfied. BTW, the header file says I should set it to 1 if I want to handle partials... what is the correct value? Is that the intended purpose of no_buffer_all_partial_tx?</pre>
<pre><br /><br /><br /></pre>
<blockquote type="cite" style="padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px">libwebsockets_write() in a loop as above, and monitor the return code and possible errno so that I knew when the kernel buffers were full. If I replace libwebsockets_write() with just write() then the loop above is valid, I just need to handle the return code differently to detect EAGAIN and actual errors.
<blockquote type="cite" style="padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px">When there was a partial send, a writable callback is scheduled</blockquote>
automatically, and
<blockquote type="cite" style="padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px">before the user callback is notified, lws checks to see if there is a</blockquote>
pending partial send.
<blockquote type="cite" style="padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px">If so, it will send as much of the pending buffer as the kernel will</blockquote>
take. If it was
<blockquote type="cite" style="padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px">everything, then the partial send is marked as emptied out and the</blockquote>
next writeable
<blockquote type="cite" style="padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px">callback will get passed through to the user code again to start</blockquote>
sending something new.
<blockquote type="cite" style="padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px">What your asserting code does is ignore all that and just sit</blockquote>
looping, blocking and
<blockquote type="cite" style="padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px">spamming more new stuff into libwebsockets_write() every time without</blockquote>
going around
<blockquote type="cite" style="padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px">the service loop and let it dump what it buffered.</blockquote>
What the loop does is expect libwebsockets_write() to tell me if a write wasn't possible, just the way that write() and send() do.
<blockquote type="cite" style="padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px">On the other hand -->
<blockquote type="cite" style="padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px">case LWS_CALLBACK_SERVER_WRITEABLE: /* No assert */ while(have_data && !lws_send_pipe_choked()){ count = libwebsockets_write(len); if(count < 0) return 0; if(wlen != len) break; }</blockquote>
This makes sense because the test for if we can write means that the</blockquote>
send()
<blockquote type="cite" style="padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px">libwebsockets_write() eventually does never returns -EWOULDBLOCK or</blockquote>
whatever,
<blockquote type="cite" style="padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px">because we already checked he can actually send.</blockquote>
I'd suggest this is the wrong approach. You're adding the requirement for an extra poll() call for each additional time</blockquote>
<pre>I justed talked about why the two chunks of code acted differently, from looking at that code, not created a "requirement".</pre>
<blockquote type="cite" style="padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px">libwebsockets_write() is called, versus having one extra call to libwebsockets_write() that returns to say the socket wasn't writeable. Put another way, if poll tells me that I can write, I can write until I'm told not to. I don't need to check poll again after each time I call write().</blockquote>
<pre>Yes ignoring all that, the code is not reliable anyway, since the choked state of the pipe may change aynchronously due to whatever else in going on in the system.  But it's still useful to loop and pack the pipe while it's relatively empty and you have many small writes.

I'm happy if you think you identified a problem, and know how to fix it, but I'm still not sure what it is yet.  (Maybe it's simpler to send a patch?)

-Andy</pre>
<blockquote type="cite" style="padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px">Cheers, Roger</blockquote>
</blockquote>
</body></html>