diff --git a/READMEs/README.lws_sul.md b/READMEs/README.lws_sul.md new file mode 100644 index 000000000..1908f1005 --- /dev/null +++ b/READMEs/README.lws_sul.md @@ -0,0 +1,62 @@ +# `lws_sul` scheduler api + +Since v3.2 lws no longer requires periodic checking for timeouts and +other events. A new system was refactored in where future events are +scheduled on to a single, unified, sorted linked-list in time order, +with everything at us resolution. + +This makes it very cheap to know when the next scheduled event is +coming and restrict the poll wait to match, or for event libraries +set a timer to wake at the earliest event when returning to the +event loop. + +Everything that was checked periodically was converted to use `lws_sul` +and schedule its own later event. The end result is when lws is idle, +it will stay asleep in the poll wait until a network event or the next +scheduled `lws_sul` event happens, which is optimal for power. + +# Side effect for older code + +If your older code uses `lws_service_fd()`, it used to be necessary +to call this with a NULL pollfd periodically to indicate you wanted +to let the background checks happen. `lws_sul` eliminates the whole +concept of periodic checking and NULL is no longer a valid pollfd +value for this and related apis. + +# Using `lws_sul` in user code + +See `minimal-http-client-multi` for an example of using the `lws_sul` +scheduler from your own code; it uses it to spread out connection +attempts so they are staggered in time. You must create an +`lws_sorted_usec_list_t` object somewhere, eg, in you own existing object. + +``` +static lws_sorted_usec_list_t sul_stagger; +``` + +Create your own callback for the event... the argument points to the sul object +used when the callback was scheduled. You can use pointer arithmetic to translate +that to your own struct when the `lws_sorted_usec_list_t` was a member of the +same struct. + +``` +static void +stagger_cb(lws_sorted_usec_list_t *sul) +{ +... +} +``` + +When you want to schedule the callback, use `lws_sul_schedule()`... this will call +it 10ms in the future + +``` + lws_sul_schedule(context, 0, &sul_stagger, stagger_cb, 10 * LWS_US_PER_MS); +``` + +In the case you destroy your object and need to cancel the scheduled callback, use + +``` + lws_sul_schedule(context, 0, &sul_stagger, NULL, LWS_SET_TIMER_USEC_CANCEL); +``` + diff --git a/include/libwebsockets/lws-service.h b/include/libwebsockets/lws-service.h index 6c9253697..4b969d70e 100644 --- a/include/libwebsockets/lws-service.h +++ b/include/libwebsockets/lws-service.h @@ -45,7 +45,7 @@ * 2) Call the receive callback for incoming frame data received by * server or client connections. * - * Since v4.0 internally the timeout wait is ignored, the lws scheduler is + * Since v3.2 internally the timeout wait is ignored, the lws scheduler is * smart enough to stay asleep until an event is queued. */ LWS_VISIBLE LWS_EXTERN int @@ -94,7 +94,7 @@ lws_cancel_service(struct lws_context *context); * lws_service_fd() - Service polled socket with something waiting * \param context: Websocket context * \param pollfd: The pollfd entry describing the socket fd and which events - * happened, or NULL to tell lws to do only timeout servicing. + * happened * * This function takes a pollfd that has POLLIN or POLLOUT activity and * services it according to the state of the associated @@ -111,6 +111,10 @@ lws_cancel_service(struct lws_context *context); * If the socket is foreign to lws, it leaves revents alone. So you can * see if you should service yourself by checking the pollfd revents * after letting lws try to service it. + * + * lws before v3.2 allowed pollfd to be NULL, to indicate that background + * periodic processing should be done. Since v3.2, lws schedules any items + * that need handling in the future using lws_sul and NULL is no longer valid. */ LWS_VISIBLE LWS_EXTERN int lws_service_fd(struct lws_context *context, struct lws_pollfd *pollfd);