[Libwebsockets] Execute callback on event loop thread
andy at warmcat.com
Sat Jul 24 14:14:13 CEST 2021
On 7/24/21 1:06 PM, Ivan Kolesnikov wrote:
> Thank you for your quick response!
> I tried the first solution and it works fine.
> I also look into the source code of __lws_system_attach and see that it
> is internally implemented using lws_cancel_service, just already
> implemented a queue instead of me. Maybe I will switch to it.
Yes it's based on top of lws_cancel_service(), it's originally designed
so that code started by a foreign thread may exit their original thread
after calling it, since we will call them back from lws thread context
and he can just run from lws context subsequently. It's basically doing
the same thing just different semantics.
> But I have one more problem. If I use libwebsockets with libuv, then
> lws_cancel_service devivers the event, but doesn't cause the exit from
> lws_service (without libuv it exits lws_service successfully). So my
> event loop cannot be terminated (I use a while loop on a volatile
> boolean flag, but this loop has no chance to check it except for the
> startup). How can I completely stop the event loop while using libuv
> either from the event loop thread (because I can send a callback now) or
> from any other thread.
Although using the event lib or using the default loop became a lot more
aligned some versions ago, there are still some small differences in how
user code must use them. If you have an existing loop outside of lws
you want lws to join, you don't event lws_service() at all. At creation
lws runs entirely off of callbacks from the loop, it does not have its
own service loop any more. Therefore you can't use the interrupted type
flag scheme from the examples, there is no outer loop like that.
See, eg, minimal-http-server-eventlib-foreign
> Best regards,
> Ivan Kolesnikov
> On Sat, Jul 24, 2021 at 8:04 AM Andy Green <andy at warmcat.com
> <mailto:andy at warmcat.com>> wrote:
> On 7/24/21 12:34 AM, Ivan Kolesnikov wrote:
> > Hi,
> > I have two threads in my application: the first is doing my own
> > and the second is running a loop with a lws_service call. And
> > I want to send some data via WebSocket from the first thread. But
> > WebSockets API is not thread-safe as I understand, so I want to
> > some callback which will do actual sending on the event loop thread.
> > Like as uv_async_t in libuv can do that.
> > Is there any API in libwebsockets which allows it to execute some
> > callback on event loop thread? Or is there a possibility to obtain a
> > uv_loop_t instance to use uv_async_t? (I am using libwebsockets with
> > libuv support enabled).
> The recommended way atm is prepare an object in memory shared by the
> threads and protected with your own locking with a list of what you
> to happen from lws thread context, and then call lws_cancel_service().
> This will wake the lws event loop thread by putting a byte in a pipe2()
> (unix) or sending a byte on a UDP socket created for that purpose
> (Windows and RTOS), and since those are monitored by the event loop
> whether it is the default one or libuv or any event library the same,
> this works the same and is safe across all the platforms and event lib
> combinations. It also means lws itself doesn't have to know your
> locking arrangements, since that only relates to the shared object you
> control only from your code.
> When the event loop wait wakes, it sees it woke from
> lws_cancel_service() and broadcasts LWS_CALLBACK_EVENT_WAIT_CANCELLED
> callback on all vhost-protocol combinations. You can pick that up on
> your protocol, lock your shared object and then perform whatever the
> other threads wanted to happen from there.
> There's also a scheme built on top of that available, that has
> closer to what you want but requires more set up. At init you provide
> an lws_system callback that has your locking around a call back into
> lws, you can then use that to manage a list of specified callbacks and
> opaque args that you can add to from other threads safely then without
> more locking, from your thread you call like
> lws_system_get_ops(context)->attach(context, 0, mycallback,
> my_void_ptr_arg, NULL);
> and later, when lws reaches OPERATIONAL state, you will get a callback
> to mycallback(my_void_ptr_arg). There is a minimal example showing the
> whole thing here
> > The another solution came to my mind also - use lws_sul_schedule to
> > schedule my callback within one microsecond, but it seems to be not
> > thread-safe too if libwebsockets compiled without SMP support
> (and SMP
> > cannot be enabled without pthread library which is not available on
> > Win32 MSVC target which is one of these I am compiling - I am using
> > threading support from libuv in my program, so I have no
> dependency on
> > pthread).
> Right SMP doesn't make things generally threadsafe somehow, it just
> enough using pthreads so lws is safe against itself when running n
> loops in different threads, and the internal lws code has to cooperate
> on shared data, eg, context or vhost -owned data.
More information about the Libwebsockets