<div dir="ltr">Hello Andy,<div><br></div><div>It doesn't seem to work.</div><div><br></div><div>In order to debug, I added the following printf in libwebsockets.c</div><div><div>#ifdef LWS_HAS_PPOLL</div><div><span style="white-space:pre-wrap">    </span>/*</div>


<div><span style="white-space:pre-wrap">  </span> * if we changed something in this pollfd...</div><div><span style="white-space:pre-wrap">     </span> *   ... and we're running in a different thread context</div><div>
<span style="white-space:pre-wrap">     </span> *     than the service thread...</div><div><span style="white-space:pre-wrap">      </span> *       ... and the service thread is waiting in ppoll()...</div><div><span style="white-space:pre-wrap">  </span> *          then fire a SIGUSR2 at the service thread to force it to</div>


<div><span style="white-space:pre-wrap">  </span> *             restart the ppoll() with our changed events</div><div><span style="white-space:pre-wrap"> </span> */</div><div><span style="white-space:pre-wrap">      </span>if (events != context->fds[wsi->position_in_fds_table].events) {</div>


<div><span style="white-space:pre-wrap">          </span>sampled_ppoll_tid = lws_idling_ppoll_tid;</div><div><span style="white-space:pre-wrap">                </span><b>printf("sampled_ppoll_tid: %d\n",sampled_ppoll_tid);</b></div>


<div><span style="white-space:pre-wrap">          </span>if (sampled_ppoll_tid) {</div><div><span style="white-space:pre-wrap">                 </span>tid = context->protocols[0].callback(context, NULL,</div><div><span style="white-space:pre-wrap">                           </span>     LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);</div>


<div><span style="white-space:pre-wrap">                  </span>if (tid != sampled_ppoll_tid)</div><div><span style="white-space:pre-wrap">                            </span><b>printf("kill(sampled_ppoll_tid, SIGUSR2)\n");</b></div><div><span style="white-space:pre-wrap">                               </span>kill(sampled_ppoll_tid, SIGUSR2);</div>


<div><span style="white-space:pre-wrap">          </span>}</div><div><span style="white-space:pre-wrap">        </span>}</div><div>#endif</div></div><div><br></div><div>Here below is the log I get when opening test.html while test-server.c is running (Enclosed my modified test-server.c with a asynchronous sending thread). Counter is increased to 1 and then 1 minute elapsed before it is increased to 2.</div>


<div><br></div><div><div>webserver PID : 24290</div><div>LWS_CALLBACK_GET_THREAD_ID pthread_self():-1657694464</div><div>START asynchronous sending</div><div>Thread PID : 24290</div><div>asynchronousSending pthread_self():-1678948608</div>


<div>LWS_CALLBACK_GET_THREAD_ID pthread_self():-1657694464</div><div>LWS_CALLBACK_GET_THREAD_ID pthread_self():-1657694464</div><div>LWS_CALLBACK_GET_THREAD_ID pthread_self():-1657694464</div><div>LWS_CALLBACK_GET_THREAD_ID pthread_self():-1657694464</div>


<div>    GET URI = /</div><div>    Host = <a href="http://192.168.1.6:7681" target="_blank">192.168.1.6:7681</a></div><div>    Connection = keep-alive</div><div>    Accept: = text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8</div>


<div>    Accept-Encoding: = gzip,deflate,sdch</div><div>    Accept-Language: = fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4</div><div>    Cache-Control: = max-age=0</div><div>    Cookie: = test=LWS_1388753472_194286_COOKIE</div><div>


LWS_CALLBACK_GET_THREAD_ID pthread_self():-1657694464</div><div>LWS_CALLBACK_GET_THREAD_ID pthread_self():-1657694464</div><div>LWS_CALLBACK_GET_THREAD_ID pthread_self():-1657694464</div><div>LWS_CALLBACK_GET_THREAD_ID pthread_self():-1657694464</div>


<div>LWS_CALLBACK_GET_THREAD_ID pthread_self():-1657694464</div><div>LWS_CALLBACK_GET_THREAD_ID pthread_self():-1657694464</div><div>LWS_CALLBACK_GET_THREAD_ID pthread_self():-1657694464</div><div>LWS_CALLBACK_GET_THREAD_ID pthread_self():-1657694464</div>


<div>LWS_CALLBACK_GET_THREAD_ID pthread_self():-1657694464</div><div>LWS_CALLBACK_GET_THREAD_ID pthread_self():-1657694464</div><div>sampled_ppoll_tid: -1657694464</div><div>LWS_CALLBACK_GET_THREAD_ID pthread_self():-1678948608</div>


<div>kill(sampled_ppoll_tid, SIGUSR2)</div><div>    GET URI = /libwebsockets.org-logo.png</div><div>    Host = <a href="http://192.168.1.6:7681" target="_blank">192.168.1.6:7681</a></div><div>    Connection = keep-alive</div>

<div>    Accept: = image/webp,*/*;q=0.8</div>
<div>    Accept-Encoding: = gzip,deflate,sdch</div><div>    Accept-Language: = fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4</div><div>    Cache-Control: = max-age=0</div><div>    Cookie: = test=LWS_1388753472_194286_COOKIE</div><div>


    Referer: = <a href="https://192.168.1.6:7681/" target="_blank">https://192.168.1.6:7681/</a></div><div>    GET URI = /xxx</div><div>    Host = <a href="http://192.168.1.6:7681" target="_blank">192.168.1.6:7681</a></div>

<div>    Connection = Upgrade</div>
<div>    Protocol = dumb-increment-protocol</div><div>    Upgrade = websocket</div><div>    Origin = <a href="https://192.168.1.6:7681" target="_blank">https://192.168.1.6:7681</a></div><div>    Key = flv4nyR7f+VEHFSWJXQxBA==</div>

<div>    Version = 13</div>
<div>    Extensions = x-webkit-deflate-frame</div><div>    Pragma: = no-cache</div><div>    Cache-Control: = no-cache</div><div>    Cookie: = test=LWS_1388753472_194286_COOKIE</div><div>LWS_CALLBACK_GET_THREAD_ID pthread_self():-1657694464</div>


<div>    GET URI = /xxx</div><div>    Host = <a href="http://192.168.1.6:7681" target="_blank">192.168.1.6:7681</a></div><div>    Connection = Upgrade</div><div>    Protocol = lws-mirror-protocol</div><div>    Upgrade = websocket</div>

<div>
    Origin = <a href="https://192.168.1.6:7681" target="_blank">https://192.168.1.6:7681</a></div><div>    Key = OXYhUJt7pkvdd72hJzPp5w==</div><div>    Version = 13</div><div>sampled_ppoll_tid: 0</div><div>LWS_CALLBACK_GET_THREAD_ID pthread_self():-1657694464</div>


<div>    Extensions = x-webkit-deflate-frame</div><div>    Pragma: = no-cache</div><div>    Cache-Control: = no-cache</div><div>    Cookie: = test=LWS_1388753472_194286_COOKIE</div><div>sampled_ppoll_tid: -1657694464</div>


<div>LWS_CALLBACK_GET_THREAD_ID pthread_self():-1678948608</div><div>kill(sampled_ppoll_tid, SIGUSR2)</div><div>LWS_CALLBACK_GET_THREAD_ID pthread_self():-1657694464</div><div>sampled_ppoll_tid: 0</div><div>LWS_CALLBACK_GET_THREAD_ID pthread_self():-1657694464</div>


<div>LWS_CALLBACK_GET_THREAD_ID pthread_self():-1657694464</div><div>LWS_CALLBACK_GET_THREAD_ID pthread_self():-1657694464</div><div>LWS_CALLBACK_GET_THREAD_ID pthread_self():-1657694464</div><div>    GET URI = /favicon.ico</div>


<div>    Host = <a href="http://192.168.1.6:7681" target="_blank">192.168.1.6:7681</a></div><div>    Connection = keep-alive</div><div>    Accept: = */*</div><div>    Accept-Encoding: = gzip,deflate,sdch</div><div>    Accept-Language: = fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4</div>


<div>    Cookie: = test=LWS_1388753472_194286_COOKIE</div><div>sampled_ppoll_tid: -1657694464</div><div>LWS_CALLBACK_GET_THREAD_ID pthread_self():-1678948608</div><div>kill(sampled_ppoll_tid, SIGUSR2)</div><div><br></div>


</div><div>I continue my investigation.</div><div><br></div><div>Thanks for your the patch anyway.</div><div><br></div><div>BR,</div><div>Thomas</div></div><div class="gmail_extra"><br><br><div class="gmail_quote">2014/1/3 "Andy Green (林安廸)" <span dir="ltr"><<a href="mailto:andy@warmcat.com" target="_blank">andy@warmcat.com</a>></span><br>

<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On 01/01/14 22:38, the mail apparently from Andy Green included:<div class="im"><br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
<br>
Thomas Spitz <<a href="mailto:thomas.spitz@hestia-france.com" target="_blank">thomas.spitz@hestia-france.<u></u>com</a>> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Hello Andy,<br>
<br>
Have you had some time trying to replace poll by ppoll in order to have<br>
poll triggered on signal from an external thread?<br>
</blockquote>
<br>
Not yet... in Taiwan the big holiday is Chinese New Year in a few weeks.  I'm still interested in doing it, the weekend is the most likely time.<br>
</blockquote>
<br></div>
Please have a look at this:<br>
<br>
<a href="http://git.libwebsockets.org/cgi-bin/cgit/libwebsockets/commit/?id=3b3fa9e2086da6157289141e0b6fe1e5035bad25" target="_blank">http://git.libwebsockets.org/<u></u>cgi-bin/cgit/libwebsockets/<u></u>commit/?id=<u></u>3b3fa9e2086da6157289141e0b6fe1<u></u>e5035bad25</a><br>


<br>
I didn't test it because I don't have a threaded user code, but it should be pretty close if not workable already.<br>
<br>
Note the comment in the commit log, you have to actively enable this code (I wasn't able to find a way for the compiler to understand if it had ppoll() or not).<br>
<br>
ppoll() is a GNU extension so if this is useful, we'll need to add it as a CMake-time option.<span class="HOEnZb"><font color="#888888"><br>
<br>
-Andy</font></span><div class="HOEnZb"><div class="h5"><br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
-Andy<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
At the present your lib works very well with intensive data submit from<br>
external thread.<br>
<br>
Happy new year to everyone.<br>
<br>
BR,<br>
<br>
Thomas<br>
<br>
<br>
On 25 Dec 2013 15:24, Andy Green (林安廸) <<a href="mailto:andy@warmcat.com" target="_blank">andy@warmcat.com</a>> wrote:<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
On 25/12/13 20:14, the mail apparently from Thomas Spitz included:<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
     The choices seem to boil down to this kind of "add a fake<br>
     descriptor" thing (although everything, including the "interrupt<br>
</blockquote></blockquote>
the<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
     poll" descriptor and the use of it should be defined inside the<br>
     library), or maybe change to use ppoll() and fire signals at it.<br>
<br>
ppoll() could be an interesting solution but it only interrupt the<br>
</blockquote></blockquote>
poll.<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
</blockquote>
<br>
I think that's all we need to do.<br>
<br>
Latency is only coming this way on an idle system where we are<br>
</blockquote>
sleeping in<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
the poll(), but another thread asked to change what a pollfd was<br>
</blockquote>
waiting on.<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
As you pointed out originally, under those circumstances the changed<br>
pollfd rules won't be seen and handled -- if every fd is idle for the<br>
events it started out with -- until the poll() timeout expires.<br>
<br>
Although in other use-cases this isn't that realistic as a problem,<br>
</blockquote>
since<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
some deal with tens of thousands of simultaneous connections and<br>
</blockquote>
usually<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
someone is breaking the poll after a short time for service, in other<br>
</blockquote>
use<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
cases it is realistic.  You can attack it by reducing the poll sleep<br>
</blockquote>
period<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
but then you're looking at maybe hundreds of wakes a second on what<br>
</blockquote>
should<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
be an idle system, needlessly bad for power.<br>
<br>
If we provided a way for those use-cases to have very long poll()<br>
</blockquote>
timeouts<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
and minimal latency it's good I think, so long as it doesn't burden<br>
</blockquote>
or make<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
problems when it's not wanted or needed.<br>
<br>
  I was thinking of interrupting poll() using a named pipe in which I<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
would have told lws which wsi it needs to write to. The complete<br>
</blockquote></blockquote>
process<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
would have been the following:<br>
<br>
</blockquote>
<br>
No it's not a good way... lws already has a good semantic in poll()<br>
</blockquote>
for<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
understanding who needed service.  This would be a lot of new stuff<br>
</blockquote>
doing<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
the same job that only works in the multithreaded case.<br>
<br>
  1) Before libwebsocket_create_context(), I create the named pipe.<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
2) For every client connection, I book for a shm<br>
in LWS_CALLBACK_ESTABLISHED through which I will share incoming data<br>
with my main thread<br>
3) My main thread process the incoming data and store the answer<br>
</blockquote></blockquote>
into<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
the shm. It then indicates lws that an answer is ready for a given<br>
</blockquote></blockquote>
wsi<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
indicating the ID of the shm in the named pipe<br>
4) lws poll() is interupted and it knows immediatly which wsi it<br>
</blockquote></blockquote>
needs<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
to write to thanks to the ID of the shm. If the wsi is closed in the<br>
meanwhile, lws indicate it to the shm in LWS_CALLBACK_CLOSED<br>
<br>
If I use ppoll(), I could keep almost the same principle but I would<br>
then need to add a SIGUSR1 and a handler OR loop through my client<br>
</blockquote></blockquote>
shm<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
array each time ppoll() got interupted with EINTR flag set...<br>
</blockquote></blockquote>
Finally I<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
am still wondering whether my solution is not simpler?<br>
<br>
</blockquote>
<br>
That solution is basically a threaded rewrite of lws not using<br>
</blockquote>
poll(). If<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
you're interested to do that I don't want to discourage you, but it's<br>
something different from lws then.  Of course lws is liberally<br>
</blockquote>
licensed so<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
you're welcome to build on it if you have a compatible license.<br>
<br>
However, if you think about larger scale servers, which do exist<br>
</blockquote>
using<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
lws, "knowing the exact (single) wsi" that woke it is not useful when<br>
</blockquote>
there<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
may be hundreds of fds needing service each poll().<br>
<br>
      Either way lws_change_pollfd() is central to the solution.<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
With my solution or even ppoll one, I don't see when I need to<br>
calllws_change_pollfd() especially as lws_change_pollfd needs a<br>
</blockquote></blockquote>
pointer<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
to wsi which I cannot give as my interrupt concerns the complete<br>
</blockquote></blockquote>
context<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
and not a special wsi...?I must miss a point.<br>
<br>
</blockquote>
<br>
lws_change_pollfd() is the point that any code which wants to change<br>
</blockquote>
the<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
events on a pollfd ends up at now.  And changing the event on a<br>
</blockquote>
pollfd is<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
the definition of the cause of latency (when poll() is idle and with<br>
relatively long timeout).<br>
<br>
So whether it is doing rx flow control or wait on being able to send,<br>
</blockquote>
that<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
function is the place to signal to break the poll() one way or the<br>
</blockquote>
other.<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
      If you pick a signal like SIGUSR1 and install a do-nothing<br>
</blockquote>
handler<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
     for it, firing SIGUSR1 at the process from itself in<br>
     lws_change_pollfd() and using ppoll() could be a really small<br>
</blockquote></blockquote>
and<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
     robust solution.<br>
     Since the signal is handled it doesn't do anything except<br>
</blockquote></blockquote>
interrupt<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
     the ppoll causing a pollfd reload.<br>
     You only need to fire the signal the first time anything wants<br>
</blockquote></blockquote>
to<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
     interrupt the wait *from another thread* (because if the lws<br>
</blockquote></blockquote>
thread<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
     is in poll(), it isn't doing anything else).  If a pollfd raced<br>
</blockquote></blockquote>
it<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
     and changed first, there's no problem with an additional signal<br>
     interrupting the next ppoll loop.<br>
<br>
Ideally, if it is not too much to ask, a simple example of code<br>
</blockquote></blockquote>
would be<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
ideal.<br>
<br>
</blockquote>
<br>
I may have some time tomorrow to give this a try.<br>
<br>
-Andy<br>
</blockquote></blockquote></blockquote>
<br>
</div></div></blockquote></div><br></div>