From 286cf4357a2fe2540cf38837c59f946d2b0d7263 Mon Sep 17 00:00:00 2001 From: Andy Green Date: Thu, 28 May 2020 12:48:17 +0100 Subject: [PATCH] sul: multiple timer domains Adapt the pt sul owner list to be an array, and define two different lists, one that acts like before and is the default for existing users, and another that has the ability to cooperate with systemwide suspend to restrict the interval spent suspended so that it will wake in time for the earliest thing on this wake-suspend sul list. Clean the api a bit and add lws_sul_cancel() that only needs the sul as the argument. Add a flag for client creation info to indicate that this client connection is important enough that, eg, validity checking it to detect silently dead connections should go on the wake-suspend sul list. That flag is exposed in secure streams policy so it can be added to a streamtype with "swake_validity": true Deprecate out the old vhost timer stuff that predates sul. Add a flag LWS_WITH_DEPRECATED_THINGS in cmake so users can get it back temporarily before it will be removed in a v4.2. Adapt all remaining in-tree users of it to use explicit suls. --- CMakeLists.txt | 2 +- READMEs/README.lws_sul.md | 37 ++++ include/libwebsockets/lws-client.h | 4 +- .../libwebsockets/lws-secure-streams-policy.h | 4 + include/libwebsockets/lws-sequencer.h | 2 + include/libwebsockets/lws-system.h | 4 + include/libwebsockets/lws-timeout-timer.h | 101 ++++++++-- lib/core-net/connect.c | 3 + lib/core-net/private-lib-core-net.h | 20 +- lib/core-net/sequencer.c | 19 +- lib/core-net/sorted-usec-list.c | 182 +++++++++++------- lib/core-net/vhost.c | 3 +- lib/core-net/wsi-timeout.c | 25 ++- lib/core/context.c | 14 +- lib/event-libs/glib/glib.c | 3 +- lib/event-libs/libev/libev.c | 6 +- lib/event-libs/libevent/libevent.c | 6 +- lib/event-libs/libuv/libuv.c | 6 +- lib/plat/freertos/freertos-service.c | 4 +- lib/plat/optee/network.c | 4 +- lib/plat/unix/unix-init.c | 7 +- lib/plat/unix/unix-service.c | 2 +- lib/plat/unix/unix-spawn.c | 9 +- lib/plat/windows/windows-service.c | 4 +- lib/plat/windows/windows-spawn.c | 17 +- lib/roles/cgi/ops-cgi.c | 8 +- lib/roles/dbus/dbus.c | 9 +- lib/roles/http/client/client-handshake.c | 6 +- lib/roles/mqtt/mqtt.c | 9 +- lib/roles/mqtt/ops-mqtt.c | 3 +- lib/roles/ws/server-ws.c | 3 +- lib/secure-streams/README.md | 8 + lib/secure-streams/policy-json.c | 7 + lib/secure-streams/protocols/ss-h1.c | 6 +- lib/secure-streams/protocols/ss-mqtt.c | 2 +- lib/secure-streams/protocols/ss-raw.c | 2 +- lib/secure-streams/protocols/ss-ws.c | 5 +- lib/secure-streams/secure-streams-client.c | 3 +- lib/secure-streams/secure-streams.c | 9 +- lib/system/dhcpclient/dhcpclient.c | 18 +- lib/system/ntpclient/ntpclient.c | 6 +- lib/tls/tls-server.c | 10 +- lwsws/main.c | 2 +- .../minimal-ws-proxy/protocol_lws_minimal.c | 37 ++-- .../CMakeLists.txt | 12 +- .../minimal-dbus-ws-proxy-testclient.c | 113 +++++------ .../minimal-http-client.c | 3 +- .../minimal-http-server.c | 3 +- .../raw/minimal-raw-serial/minimal-raw-file.c | 2 +- .../minimal-secure-streams-alexa/alexa.c | 9 +- .../minimal-secure-streams-avs/avs.c | 8 +- .../minimal-secure-streams-client-tx.c | 3 +- .../protocol_lws_minimal_client_echo.c | 52 ++--- .../protocol_lws_minimal_pmd_bulk.c | 40 ++-- .../minimal-ws-client-tx/minimal-ws-client.c | 36 ++-- .../protocol_lws_minimal_threadpool.c | 39 ++-- plugins/protocol_lws_server_status.c | 21 +- 57 files changed, 568 insertions(+), 414 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ec0e8d5fe..3bb871453 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -218,7 +218,7 @@ option(LWS_WITH_LEJP_CONF "With LEJP configuration parser as used by lwsws" OFF) option(LWS_WITH_ZLIB "Include zlib support (required for extensions)" OFF) option(LWS_WITH_BUNDLED_ZLIB "Use bundled zlib version (Windows only)" ${LWS_WITH_BUNDLED_ZLIB_DEFAULT}) option(LWS_WITH_MINIZ "Use miniz instead of zlib" OFF) -option(LWS_WITH_DEPRECATED_LWS_DLL "Migrate to lws_dll2 instead ASAP" OFF) +option(LWS_WITH_DEPRECATED_THINGS "Temporary workaround for deprecated apis" OFF) option(LWS_WITH_SEQUENCER "lws_seq_t support" ON) option(LWS_WITH_EXTERNAL_POLL "Support external POLL integration using callback messages (not recommended)" OFF) option(LWS_WITH_LWS_DSH "Support lws_dsh_t Disordered Shared Heap" OFF) diff --git a/READMEs/README.lws_sul.md b/READMEs/README.lws_sul.md index 1908f1005..f1cae4e2b 100644 --- a/READMEs/README.lws_sul.md +++ b/READMEs/README.lws_sul.md @@ -60,3 +60,40 @@ In the case you destroy your object and need to cancel the scheduled callback, u lws_sul_schedule(context, 0, &sul_stagger, NULL, LWS_SET_TIMER_USEC_CANCEL); ``` +# lws_sul2 and system suspend + +In v4.1, alongside the existing `lws_sul` apis there is a refactor and additional +functionality aimed at negotiating system suspend, while remaining completely +backwards-compatible with v3.2+ lws_sul apis. + +Devicewide suspend is basically the withdrawal of CPU availability for an unbounded +amount of time, so what may have been scheduled by the user code may miss its time +slot because the cpu was down and nothing is getting serviced. Whether that is +actively desirable, OK, a big disaster, or a failure that will be corrected at other +layers at the cost of, eg, some additional latency, depends on the required device +behaviours and the function of the user code that was scheduled, and its meaning to +the system. + +Before v4.1, lws just offers the same scheduling service for everything both internal +and arranged by user code, and has no way to know what is critical for the device to +operate as intended, and so must force wake from suspend, or if for that scheduled +event 'failure [to get the event] is an option'. + +For example locally-initiated periodic keepalive pings not happening may allow +persistently dead (ie, no longer passing data) connections to remain unrenewed, but +eventually when suspend ends for another reason, the locally-initiated PING probes +will resume and it will be discovered and if the connectivity allows, corrected. + +If the device's function can handle the latency of there being no connectivity in +suspend under those conditions until it wakes for another reason, it's OK for these +kind of timeouts to be suppressed during suspend and basically take the power saving +instead. If for a particular device it's intolerable to ever have a silently dead +connection for more than a very short time compared to suspend durations, then these +kind of timeouts must have the priority to wake the whole device from suspend so +they continue to operate unimpeded. + +That is just one example, lws offers generic scheduler services the user code can +exploit for any purpose, including mission-critical ones. The changes give the user +code a way to tell lws if a particular scheduled event is important enough to the +system operation to wake the system from devicewide suspend. + diff --git a/include/libwebsockets/lws-client.h b/include/libwebsockets/lws-client.h index e957b3a37..b8693f181 100644 --- a/include/libwebsockets/lws-client.h +++ b/include/libwebsockets/lws-client.h @@ -58,7 +58,9 @@ enum lws_client_connect_ssl_connection_flags { * HTTP/2: always possible... uses parallel streams */ LCCSCF_MUXABLE_STREAM = (1 << 17), - LCCSCF_H2_PRIOR_KNOWLEDGE = (1 << 18) + LCCSCF_H2_PRIOR_KNOWLEDGE = (1 << 18), + LCCSCF_WAKE_SUSPEND__VALIDITY = (1 << 19), + /* our validity checks are important enough to wake from suspend */ }; /** struct lws_client_connect_info - parameters to connect with when using diff --git a/include/libwebsockets/lws-secure-streams-policy.h b/include/libwebsockets/lws-secure-streams-policy.h index 86ed2de0f..7b798d5ec 100644 --- a/include/libwebsockets/lws-secure-streams-policy.h +++ b/include/libwebsockets/lws-secure-streams-policy.h @@ -116,6 +116,10 @@ enum { /**< set up lws_system client cert */ LWSSSPOLF_LOCAL_SINK = (1 << 13), /**< expected to bind to a local sink only */ + LWSSSPOLF_WAKE_SUSPEND__VALIDITY = (1 << 14), + /**< this stream's idle validity checks are critical enough we + * should arrange to wake from suspend to perform them + */ }; typedef struct lws_ss_trust_store { diff --git a/include/libwebsockets/lws-sequencer.h b/include/libwebsockets/lws-sequencer.h index a08f61328..7189788b9 100644 --- a/include/libwebsockets/lws-sequencer.h +++ b/include/libwebsockets/lws-sequencer.h @@ -87,6 +87,8 @@ typedef struct lws_seq_info { lws_seq_event_cb cb; /* seq callback */ const char *name; /* seq name */ const lws_retry_bo_t *retry; /* retry policy */ + uint8_t wakesuspend:1; /* important enough to + * wake system */ } lws_seq_info_t; /** diff --git a/include/libwebsockets/lws-system.h b/include/libwebsockets/lws-system.h index 1f4370685..bf946e474 100644 --- a/include/libwebsockets/lws-system.h +++ b/include/libwebsockets/lws-system.h @@ -169,6 +169,10 @@ typedef struct lws_system_ops { * Start the check that proceeds asynchronously, and report the results * by calling lws_captive_portal_detect_result() api */ + + uint32_t wake_latency_us; + /**< time taken for this device to wake from suspend, in us + */ } lws_system_ops_t; /** diff --git a/include/libwebsockets/lws-timeout-timer.h b/include/libwebsockets/lws-timeout-timer.h index 75f59ddb6..5eb975988 100644 --- a/include/libwebsockets/lws-timeout-timer.h +++ b/include/libwebsockets/lws-timeout-timer.h @@ -146,6 +146,8 @@ lws_set_timeout_us(struct lws *wsi, enum pending_timeout reason, lws_usec_t us); LWS_VISIBLE LWS_EXTERN void lws_set_timer_usecs(struct lws *wsi, lws_usec_t usecs); +#if defined(LWS_WITH_DEPRECATED_THINGS) + /* * lws_timed_callback_vh_protocol() - calls back a protocol on a vhost after * the specified delay in seconds @@ -155,6 +157,8 @@ lws_set_timer_usecs(struct lws *wsi, lws_usec_t usecs); * \param reason: callback reason * \param secs: how many seconds in the future to do the callback. * + * DEPRECATED since v4.1 + * * Callback the specified protocol with a fake wsi pointing to the specified * vhost and protocol, with the specified reason, at the specified time in the * future. @@ -168,7 +172,8 @@ lws_set_timer_usecs(struct lws *wsi, lws_usec_t usecs); LWS_VISIBLE LWS_EXTERN int lws_timed_callback_vh_protocol(struct lws_vhost *vh, const struct lws_protocols *prot, - int reason, int secs); + int reason, int secs) +LWS_WARN_DEPRECATED; /* * lws_timed_callback_vh_protocol_us() - calls back a protocol on a vhost after @@ -179,6 +184,8 @@ lws_timed_callback_vh_protocol(struct lws_vhost *vh, * \param reason: callback reason * \param us: how many us in the future to do the callback. * + * DEPRECATED since v4.1 + * * Callback the specified protocol with a fake wsi pointing to the specified * vhost and protocol, with the specified reason, at the specified time in the * future. @@ -192,7 +199,10 @@ lws_timed_callback_vh_protocol(struct lws_vhost *vh, LWS_VISIBLE LWS_EXTERN int lws_timed_callback_vh_protocol_us(struct lws_vhost *vh, const struct lws_protocols *prot, int reason, - lws_usec_t us); + lws_usec_t us) +LWS_WARN_DEPRECATED; + +#endif struct lws_sorted_usec_list; @@ -200,34 +210,98 @@ typedef void (*sul_cb_t)(struct lws_sorted_usec_list *sul); typedef struct lws_sorted_usec_list { struct lws_dll2 list; /* simplify the code by keeping this at start */ - sul_cb_t cb; lws_usec_t us; + sul_cb_t cb; + uint32_t latency_us; /* us it may safely be delayed */ } lws_sorted_usec_list_t; +/* + * There are multiple sul owners to allow accounting for, a) events that must + * wake from suspend, and b) events that can be missued due to suspend + */ +#define LWS_COUNT_PT_SUL_OWNERS 2 + +#define LWSSULLI_MISS_IF_SUSPENDED 0 +#define LWSSULLI_WAKE_IF_SUSPENDED 1 /* - * lws_sul_schedule() - schedule a callback + * lws_sul2_schedule() - schedule a callback * * \param context: the lws_context * \param tsi: the thread service index (usually 0) + * \param flags: LWSSULLI_... * \param sul: pointer to the sul element - * \param cb: the scheduled callback - * \param us: the delay before the callback arrives, or - * LWS_SET_TIMER_USEC_CANCEL to cancel it. * * Generic callback-at-a-later time function. The callback happens on the * event loop thread context. * * Although the api has us resultion, the actual resolution depends on the - * platform and is commonly 1ms. + * platform and may be, eg, 1ms. * * This doesn't allocate and doesn't fail. * - * You can call it again with another us value to change the delay. + * If flags contains LWSSULLI_WAKE_IF_SUSPENDED, the scheduled event is placed + * on a sul owner list that, if the system has entered low power suspend mode, + * tries to arrange that the system should wake from platform suspend just + * before the event is due. Scheduled events without this flag will be missed + * in the case the system is in suspend and nothing else happens to have woken + * it. + * + * You can call it again with another us value to change the delay or move the + * event to a different owner (ie, wake or miss on suspend). */ LWS_VISIBLE LWS_EXTERN void -lws_sul_schedule(struct lws_context *context, int tsi, - lws_sorted_usec_list_t *sul, sul_cb_t cb, lws_usec_t us); +lws_sul2_schedule(struct lws_context *context, int tsi, int flags, + lws_sorted_usec_list_t *sul); + +/* + * lws_sul_cancel() - cancel scheduled callback + * + * \param sul: pointer to the sul element + * + * If it's scheduled, remove the sul from its owning sorted list. + * If not scheduled, it's a NOP. + */ +LWS_VISIBLE LWS_EXTERN void +lws_sul_cancel(lws_sorted_usec_list_t *sul); + +/* + * lws_sul_earliest_wakeable_event() - get earliest wake-from-suspend event + * + * \param ctx: the lws context + * \param pearliest: pointer to lws_usec_t to take the result + * + * Either returns 1 if no pending event, or 0 and sets *pearliest to the + * MONOTONIC time of the current earliest next expected event. + */ +LWS_VISIBLE LWS_EXTERN int +lws_sul_earliest_wakeable_event(struct lws_context *ctx, lws_usec_t *pearliest); + +/* + * For backwards compatibility + * + * If us is LWS_SET_TIMER_USEC_CANCEL, the sul is removed from the scheduler. + * New code can use lws_sul_cancel() + */ + +#define lws_sul_schedule(ctx, tsi, sul, _cb, _us) {\ + if ((lws_usec_t)_us == (lws_usec_t)LWS_SET_TIMER_USEC_CANCEL) \ + lws_sul_cancel(sul); \ + else { \ + (sul)->cb = _cb; \ + (sul)->us = lws_now_usecs() + _us; \ + lws_sul2_schedule(ctx, tsi, LWSSULLI_MISS_IF_SUSPENDED, sul); \ + }} + +#define lws_sul_schedule_wakesuspend(ctx, tsi, sul, _cb, _us) {\ + if ((lws_usec_t)_us == (lws_usec_t)LWS_SET_TIMER_USEC_CANCEL) \ + lws_sul_cancel(sul); \ + else { \ + (sul)->cb = _cb; \ + (sul)->us = lws_now_usecs() + _us; \ + lws_sul2_schedule(ctx, tsi, LWSSULLI_WAKE_IF_SUSPENDED, sul); \ + }} + /* * lws_validity_confirmed() - reset the validity timer for a network connection @@ -257,10 +331,9 @@ lws_validity_confirmed(struct lws *wsi); */ LWS_VISIBLE LWS_EXTERN int -__lws_sul_insert(lws_dll2_owner_t *own, lws_sorted_usec_list_t *sul, - lws_usec_t us); +__lws_sul_insert(lws_dll2_owner_t *own, lws_sorted_usec_list_t *sul); LWS_VISIBLE LWS_EXTERN lws_usec_t -__lws_sul_service_ripe(lws_dll2_owner_t *own, lws_usec_t usnow); +__lws_sul_service_ripe(lws_dll2_owner_t *own, int own_len, lws_usec_t usnow); ///@} diff --git a/lib/core-net/connect.c b/lib/core-net/connect.c index 320abc179..6c517c70e 100644 --- a/lib/core-net/connect.c +++ b/lib/core-net/connect.c @@ -77,6 +77,9 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i) wsi->detlat.earliest_write_req_pre_write = lws_now_usecs(); #endif + if (i->ssl_connection & LCCSCF_WAKE_SUSPEND__VALIDITY) + wsi->conn_validity_wakesuspend = 1; + wsi->vhost = NULL; if (!i->vhost) { struct lws_vhost *v = i->context->vhost_list; diff --git a/lib/core-net/private-lib-core-net.h b/lib/core-net/private-lib-core-net.h index cb04c32ad..559d1aca0 100644 --- a/lib/core-net/private-lib-core-net.h +++ b/lib/core-net/private-lib-core-net.h @@ -77,6 +77,10 @@ enum lws_ssl_capable_status { LWS_SSL_CAPABLE_MORE_SERVICE = -4, /* general retry */ }; +#define __lws_sul_insert_us(owner, sul, _us) \ + (sul)->us = lws_now_usecs() + _us; \ + __lws_sul_insert(owner, sul) + /* * @@ -267,12 +271,11 @@ struct client_info_stash { #define LWS_H2_FRAME_HEADER_LENGTH 9 -int -__lws_sul_insert(lws_dll2_owner_t *own, lws_sorted_usec_list_t *sul, - lws_usec_t us); lws_usec_t -__lws_sul_service_ripe(lws_dll2_owner_t *own, lws_usec_t usnow); +__lws_sul_service_ripe(lws_dll2_owner_t *own, int num_own, lws_usec_t usnow); + +#if defined(LWS_WITH_DEPRECATED_THINGS) struct lws_timed_vh_protocol { struct lws_timed_vh_protocol *next; @@ -283,6 +286,8 @@ struct lws_timed_vh_protocol { int tsi_req; }; +#endif + /* * lws_dsh */ @@ -367,7 +372,7 @@ struct lws_context_per_thread { lws_dll2_owner_t ss_client_owner; #endif - struct lws_dll2_owner pt_sul_owner; + struct lws_dll2_owner pt_sul_owner[LWS_COUNT_PT_SUL_OWNERS]; #if defined (LWS_WITH_SEQUENCER) lws_sorted_usec_list_t sul_seq_heartbeat; @@ -572,7 +577,9 @@ struct lws_vhost { struct lws_vhost_tls tls; #endif +#if defined(LWS_WITH_DEPRECATED_THINGS) struct lws_timed_vh_protocol *timed_vh_protocol_list; +#endif void *user; int listen_port; @@ -800,6 +807,7 @@ struct lws { unsigned int validity_hup:1; unsigned int skip_fallback:1; unsigned int file_desc:1; + unsigned int conn_validity_wakesuspend:1; unsigned int could_have_pending:1; /* detect back-to-back writes */ unsigned int outer_will_close:1; @@ -1160,8 +1168,10 @@ void lws_sum_stats(const struct lws_context *ctx, struct lws_conn_stats *cs); #endif +#if defined(LWS_WITH_DEPRECATED_THINGS) int __lws_timed_callback_remove(struct lws_vhost *vh, struct lws_timed_vh_protocol *p); +#endif int LWS_WARN_UNUSED_RESULT __insert_wsi_socket_into_fds(struct lws_context *context, struct lws *wsi); diff --git a/lib/core-net/sequencer.c b/lib/core-net/sequencer.c index d2da6ba3c..42b43cd33 100644 --- a/lib/core-net/sequencer.c +++ b/lib/core-net/sequencer.c @@ -53,7 +53,8 @@ typedef struct lws_sequencer { lws_usec_t time_created; lws_usec_t timeout; /* 0 or time we timeout */ - char going_down; + uint8_t going_down:1; + uint8_t wakesuspend:1; } lws_seq_t; #define QUEUE_SANITY_LIMIT 10 @@ -77,8 +78,8 @@ lws_sul_seq_heartbeat_cb(lws_sorted_usec_list_t *sul) /* schedule the next one */ - __lws_sul_insert(&pt->pt_sul_owner, &pt->sul_seq_heartbeat, - LWS_US_PER_SEC); + __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED], + &pt->sul_seq_heartbeat, LWS_US_PER_SEC); } int @@ -87,8 +88,8 @@ lws_seq_pt_init(struct lws_context_per_thread *pt) pt->sul_seq_heartbeat.cb = lws_sul_seq_heartbeat_cb; /* schedule the first heartbeat */ - __lws_sul_insert(&pt->pt_sul_owner, &pt->sul_seq_heartbeat, - LWS_US_PER_SEC); + __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED], + &pt->sul_seq_heartbeat, LWS_US_PER_SEC); return 0; } @@ -106,6 +107,7 @@ lws_seq_create(lws_seq_info_t *i) seq->pt = pt; seq->name = i->name; seq->retry = i->retry; + seq->wakesuspend = i->wakesuspend; *i->puser = (void *)&seq[1]; @@ -242,7 +244,8 @@ lws_seq_queue_event(lws_seq_t *seq, lws_seq_events_t e, void *data, void *aux) lws_dll2_add_tail(&seqe->seq_event_list, &seq->seq_event_owner); seq->sul_pending.cb = lws_seq_sul_pending_cb; - __lws_sul_insert(&seq->pt->pt_sul_owner, &seq->sul_pending, 1); + __lws_sul_insert_us(&seq->pt->pt_sul_owner[seq->wakesuspend], + &seq->sul_pending, 1); lws_pt_unlock(seq->pt); /* } pt ------------------------------------- */ @@ -300,8 +303,10 @@ lws_seq_timeout_us(lws_seq_t *seq, lws_usec_t us) { seq->sul_timeout.cb = lws_seq_sul_timeout_cb; /* list is always at the very top of the sul */ - return __lws_sul_insert(&seq->pt->pt_sul_owner, + __lws_sul_insert_us(&seq->pt->pt_sul_owner[seq->wakesuspend], (lws_sorted_usec_list_t *)&seq->sul_timeout.list, us); + + return 0; } lws_seq_t * diff --git a/lib/core-net/sorted-usec-list.c b/lib/core-net/sorted-usec-list.c index d12a33124..04de59168 100644 --- a/lib/core-net/sorted-usec-list.c +++ b/lib/core-net/sorted-usec-list.c @@ -43,69 +43,57 @@ sul_compare(const lws_dll2_t *d, const lws_dll2_t *i) return 0; } +/* + * notice owner was chosen already, and sul->us was already computed + */ + int -__lws_sul_insert(lws_dll2_owner_t *own, lws_sorted_usec_list_t *sul, - lws_usec_t us) +__lws_sul_insert(lws_dll2_owner_t *own, lws_sorted_usec_list_t *sul) { - lws_usec_t now = lws_now_usecs(); lws_dll2_remove(&sul->list); - if (us == LWS_SET_TIMER_USEC_CANCEL) { - /* we are clearing the timeout */ - sul->us = 0; - - return 0; - } - - sul->us = now + us; assert(sul->cb); /* * we sort the pt's list of sequencers with pending timeouts, so it's - * cheap to check it every second + * cheap to check it every poll wait */ lws_dll2_add_sorted(&sul->list, own, sul_compare); -#if 0 // defined(_DEBUG) - { - lws_usec_t worst = 0; - int n = 1; - - lwsl_info("%s: own %p: count %d\n", __func__, own, own->count); - - lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp, - lws_dll2_get_head(own)) { - lws_sorted_usec_list_t *sul = (lws_sorted_usec_list_t *)p; - lwsl_info("%s: %d: %llu (+%lld)\n", __func__, n++, - (unsigned long long)sul->us, - (long long)(sul->us - now)); - if (sul->us < worst) { - lwsl_err("%s: wrongly sorted sul entry!\n", - __func__); - assert(0); - } - worst = sul->us; - } lws_end_foreach_dll_safe(p, tp); - } -#endif - return 0; } void -lws_sul_schedule(struct lws_context *context, int tsi, - lws_sorted_usec_list_t *sul, sul_cb_t cb, lws_usec_t us) +lws_sul_cancel(lws_sorted_usec_list_t *sul) +{ + lws_dll2_remove(&sul->list); + + /* we are clearing the timeout and leaving ourselves detached */ + sul->us = 0; +} + +void +lws_sul2_schedule(struct lws_context *context, int tsi, int flags, + lws_sorted_usec_list_t *sul) { struct lws_context_per_thread *pt = &context->pt[tsi]; - sul->cb = cb; - - __lws_sul_insert(&pt->pt_sul_owner, sul, us); + __lws_sul_insert( + &pt->pt_sul_owner[!!(flags & LWSSULLI_WAKE_IF_SUSPENDED)], sul); } +/* + * own points to the first in an array of length own_len + * + * While any sul list owner has a "ripe", ie, ready to handle sul we do them + * strictly in order of sul time. When nobody has a ripe sul we return 0, if + * actually nobody has any sul, or the interval between usnow and the next + * earliest scheduled event on any list. + */ + lws_usec_t -__lws_sul_service_ripe(lws_dll2_owner_t *own, lws_usec_t usnow) +__lws_sul_service_ripe(lws_dll2_owner_t *own, int own_len, lws_usec_t usnow) { struct lws_context_per_thread *pt = (struct lws_context_per_thread *) lws_container_of(own, struct lws_context_per_thread, @@ -114,36 +102,94 @@ __lws_sul_service_ripe(lws_dll2_owner_t *own, lws_usec_t usnow) if (pt->attach_owner.count) lws_system_do_attach(pt); - while (lws_dll2_get_head(own)) { - - /* .list is always first member in lws_sorted_usec_list_t */ - lws_sorted_usec_list_t *sul = (lws_sorted_usec_list_t *) - lws_dll2_get_head(own); - - assert(sul->us); /* shouldn't be on the list otherwise */ - - if (sul->us > usnow) - return sul->us - usnow; - - /* his moment has come... remove him from timeout list */ - lws_dll2_remove(&sul->list); - sul->us = 0; - pt->inside_lws_service = 1; - sul->cb(sul); - pt->inside_lws_service = 0; - - /* - * The callback may have done any mixture of delete - * and add sul entries... eg, close a wsi may pull out - * multiple entries making iterating it statefully - * unsafe. Always restart at the current head of list. - */ - } + /* must be at least 1 */ + assert(own_len); /* - * Nothing left to take care of in the list (cannot return 0 otherwise - * because we will service anything equal to usnow rather than return) + * Of the own_len sul owning lists, the earliest next sul could be on + * any of them. We have to find it and handle each in turn until no + * ripe sul left on any owning list, and we can exit. + * + * This ensures the ripe sul are handled strictly in the right order no + * matter which owning list they are on. */ + do { + lws_sorted_usec_list_t *hit = NULL; + lws_usec_t lowest; + int n = 0; + + for (n = 0; n < own_len; n++) { + lws_sorted_usec_list_t *sul; + if (!own[n].count) + continue; + sul = (lws_sorted_usec_list_t *) + lws_dll2_get_head(&own[n]); + + if (!hit || sul->us <= lowest) { + hit = sul; + lowest = sul->us; + } + } + + if (!hit) + return 0; + + if (lowest > usnow) + return lowest - usnow; + + /* his moment has come... remove him from his owning list */ + + lws_dll2_remove(&hit->list); + hit->us = 0; + + pt->inside_lws_service = 1; + hit->cb(hit); + pt->inside_lws_service = 0; + + } while (1); + + /* unreachable */ + + return 0; +} + +/* + * Earliest wakeable event on any pt + */ + +int +lws_sul_earliest_wakeable_event(struct lws_context *ctx, lws_usec_t *pearliest) +{ + struct lws_context_per_thread *pt; + int n = 0, hit = -1; + lws_usec_t lowest; + + for (n = 0; n < ctx->count_threads; n++) { + pt = &ctx->pt[n]; + + lws_pt_lock(pt, __func__); + + if (pt->pt_sul_owner[LWSSULLI_WAKE_IF_SUSPENDED].count) { + lws_sorted_usec_list_t *sul = (lws_sorted_usec_list_t *) + lws_dll2_get_head(&pt->pt_sul_owner[ + LWSSULLI_WAKE_IF_SUSPENDED]); + + if (hit == -1 || sul->us < lowest) { + hit = n; + lowest = sul->us; + } + } + + lws_pt_unlock(pt); + } + + + if (hit == -1) + /* there is no pending event */ + return 1; + + *pearliest = lowest; + return 0; } diff --git a/lib/core-net/vhost.c b/lib/core-net/vhost.c index c0b6de2ee..dd6349d07 100644 --- a/lib/core-net/vhost.c +++ b/lib/core-net/vhost.c @@ -1098,13 +1098,14 @@ __lws_vhost_destroy2(struct lws_vhost *vh) } lws_end_foreach_dll_safe(d, d1); #endif +#if defined(LWS_WITH_DEPRECATED_THINGS) /* * destroy any pending timed events */ while (vh->timed_vh_protocol_list) __lws_timed_callback_remove(vh, vh->timed_vh_protocol_list); - +#endif /* * let the protocols destroy the per-vhost protocol objects */ diff --git a/lib/core-net/wsi-timeout.c b/lib/core-net/wsi-timeout.c index cfbb7d2b1..7fd294493 100644 --- a/lib/core-net/wsi-timeout.c +++ b/lib/core-net/wsi-timeout.c @@ -61,7 +61,8 @@ __lws_set_timer_usecs(struct lws *wsi, lws_usec_t us) struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; wsi->sul_hrtimer.cb = lws_sul_hrtimer_cb; - __lws_sul_insert(&pt->pt_sul_owner, &wsi->sul_hrtimer, us); + __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED], + &wsi->sul_hrtimer, us); } void @@ -126,8 +127,9 @@ __lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs) struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; wsi->sul_timeout.cb = lws_sul_wsitimeout_cb; - __lws_sul_insert(&pt->pt_sul_owner, &wsi->sul_timeout, - ((lws_usec_t)secs) * LWS_US_PER_SEC); + __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED], + &wsi->sul_timeout, + ((lws_usec_t)secs) * LWS_US_PER_SEC); lwsl_debug("%s: %p: %d secs, reason %d\n", __func__, wsi, secs, reason); @@ -178,7 +180,8 @@ lws_set_timeout_us(struct lws *wsi, enum pending_timeout reason, lws_usec_t us) return; lws_pt_lock(pt, __func__); - __lws_sul_insert(&pt->pt_sul_owner, &wsi->sul_timeout, us); + __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED], + &wsi->sul_timeout, us); lwsl_notice("%s: %p: %llu us, reason %d\n", __func__, wsi, (unsigned long long)us, reason); @@ -187,6 +190,8 @@ lws_set_timeout_us(struct lws *wsi, enum pending_timeout reason, lws_usec_t us) lws_pt_unlock(pt); } +#if defined(LWS_WITH_DEPRECATED_THINGS) + /* requires context + vh lock */ int @@ -276,6 +281,8 @@ lws_timed_callback_vh_protocol(struct lws_vhost *vh, ((lws_usec_t)secs) * LWS_US_PER_SEC); } +#endif + static void lws_validity_cb(lws_sorted_usec_list_t *sul) { @@ -308,8 +315,9 @@ lws_validity_cb(lws_sorted_usec_list_t *sul) assert(rbo->secs_since_valid_hangup > rbo->secs_since_valid_ping); wsi->validity_hup = 1; - __lws_sul_insert(&pt->pt_sul_owner, &wsi->sul_validity, - ((uint64_t)rbo->secs_since_valid_hangup - + __lws_sul_insert_us(&pt->pt_sul_owner[!!wsi->conn_validity_wakesuspend], + &wsi->sul_validity, + ((uint64_t)rbo->secs_since_valid_hangup - rbo->secs_since_valid_ping) * LWS_US_PER_SEC); } @@ -339,8 +347,9 @@ _lws_validity_confirmed_role(struct lws *wsi) rbo->secs_since_valid_ping, wsi->validity_hup); - __lws_sul_insert(&pt->pt_sul_owner, &wsi->sul_validity, - ((uint64_t)(wsi->validity_hup ? + __lws_sul_insert_us(&pt->pt_sul_owner[!!wsi->conn_validity_wakesuspend], + &wsi->sul_validity, + ((uint64_t)(wsi->validity_hup ? rbo->secs_since_valid_hangup : rbo->secs_since_valid_ping)) * LWS_US_PER_SEC); } diff --git a/lib/core/context.c b/lib/core/context.c index 489da5d4f..425acc0ec 100644 --- a/lib/core/context.c +++ b/lib/core/context.c @@ -62,7 +62,8 @@ lws_sul_stats_cb(lws_sorted_usec_list_t *sul) lws_stats_log_dump(pt->context); - __lws_sul_insert(&pt->pt_sul_owner, &pt->sul_stats, 10 * LWS_US_PER_SEC); + __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED], + &pt->sul_stats, 10 * LWS_US_PER_SEC); } #endif #if defined(LWS_WITH_PEER_LIMITS) @@ -74,7 +75,8 @@ lws_sul_peer_limits_cb(lws_sorted_usec_list_t *sul) lws_peer_cull_peer_wait_list(pt->context); - __lws_sul_insert(&pt->pt_sul_owner, &pt->sul_peer_limits, 10 * LWS_US_PER_SEC); + __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED], + &pt->sul_peer_limits, 10 * LWS_US_PER_SEC); } #endif @@ -742,13 +744,13 @@ lws_create_context(const struct lws_context_creation_info *info) #if defined(LWS_WITH_STATS) context->pt[0].sul_stats.cb = lws_sul_stats_cb; - __lws_sul_insert(&context->pt[0].pt_sul_owner, &context->pt[0].sul_stats, - 10 * LWS_US_PER_SEC); + __lws_sul_insert_us(&context->pt[0].pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED], + &context->pt[0].sul_stats, 10 * LWS_US_PER_SEC); #endif #if defined(LWS_WITH_PEER_LIMITS) context->pt[0].sul_peer_limits.cb = lws_sul_peer_limits_cb; - __lws_sul_insert(&context->pt[0].pt_sul_owner, - &context->pt[0].sul_peer_limits, 10 * LWS_US_PER_SEC); + __lws_sul_insert_us(&context->pt[0].pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED], + &context->pt[0].sul_peer_limits, 10 * LWS_US_PER_SEC); #endif #if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP) diff --git a/lib/event-libs/glib/glib.c b/lib/event-libs/glib/glib.c index ada7627db..386f144f2 100644 --- a/lib/event-libs/glib/glib.c +++ b/lib/event-libs/glib/glib.c @@ -157,7 +157,8 @@ lws_glib_hrtimer_cb(void *p) lws_usec_t us; lws_pt_lock(pt, __func__); - us = __lws_sul_service_ripe(&pt->pt_sul_owner, lws_now_usecs()); + us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS, + lws_now_usecs()); if (us) { ms = us / LWS_US_PER_MS; if (!ms) diff --git a/lib/event-libs/libev/libev.c b/lib/event-libs/libev/libev.c index f58b8f914..e9248c84c 100644 --- a/lib/event-libs/libev/libev.c +++ b/lib/event-libs/libev/libev.c @@ -32,7 +32,8 @@ lws_ev_hrtimer_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents) lws_usec_t us; lws_pt_lock(pt, __func__); - us = __lws_sul_service_ripe(&pt->pt_sul_owner, lws_now_usecs()); + us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS, + lws_now_usecs()); if (us) { ev_timer_set(&pt->ev.hrtimer, ((float)us) / 1000000.0, 0); ev_timer_start(pt->ev.io_loop, &pt->ev.hrtimer); @@ -60,7 +61,8 @@ lws_ev_idle_cb(struct ev_loop *loop, struct ev_idle *handle, int revents) /* account for hrtimer */ lws_pt_lock(pt, __func__); - us = __lws_sul_service_ripe(&pt->pt_sul_owner, lws_now_usecs()); + us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS, + lws_now_usecs()); if (us) { ev_timer_set(&pt->ev.hrtimer, ((float)us) / 1000000.0, 0); ev_timer_start(pt->ev.io_loop, &pt->ev.hrtimer); diff --git a/lib/event-libs/libevent/libevent.c b/lib/event-libs/libevent/libevent.c index 786c4f88f..bd59d30f8 100644 --- a/lib/event-libs/libevent/libevent.c +++ b/lib/event-libs/libevent/libevent.c @@ -32,7 +32,8 @@ lws_event_hrtimer_cb(int fd, short event, void *p) lws_usec_t us; lws_pt_lock(pt, __func__); - us = __lws_sul_service_ripe(&pt->pt_sul_owner, lws_now_usecs()); + us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS, + lws_now_usecs()); if (us) { tv.tv_sec = us / LWS_US_PER_SEC; tv.tv_usec = us - (tv.tv_sec * LWS_US_PER_SEC); @@ -76,7 +77,8 @@ lws_event_idle_timer_cb(int fd, short event, void *p) /* account for hrtimer */ lws_pt_lock(pt, __func__); - us = __lws_sul_service_ripe(&pt->pt_sul_owner, lws_now_usecs()); + us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS, + lws_now_usecs()); if (us) { tv.tv_sec = us / LWS_US_PER_SEC; tv.tv_usec = us - (tv.tv_sec * LWS_US_PER_SEC); diff --git a/lib/event-libs/libuv/libuv.c b/lib/event-libs/libuv/libuv.c index 2b0883e61..ac116a821 100644 --- a/lib/event-libs/libuv/libuv.c +++ b/lib/event-libs/libuv/libuv.c @@ -36,7 +36,8 @@ lws_uv_sultimer_cb(uv_timer_t *timer lws_usec_t us; lws_pt_lock(pt, __func__); - us = __lws_sul_service_ripe(&pt->pt_sul_owner, lws_now_usecs()); + us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS, + lws_now_usecs()); if (us) uv_timer_start(&pt->uv.sultimer, lws_uv_sultimer_cb, LWS_US_TO_MS(us), 0); @@ -66,7 +67,8 @@ lws_uv_idle(uv_idle_t *handle /* account for sultimer */ lws_pt_lock(pt, __func__); - us = __lws_sul_service_ripe(&pt->pt_sul_owner, lws_now_usecs()); + us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS, + lws_now_usecs()); if (us) uv_timer_start(&pt->uv.sultimer, lws_uv_sultimer_cb, LWS_US_TO_MS(us), 0); diff --git a/lib/plat/freertos/freertos-service.c b/lib/plat/freertos/freertos-service.c index d36b1ec1e..f528bd1d4 100644 --- a/lib/plat/freertos/freertos-service.c +++ b/lib/plat/freertos/freertos-service.c @@ -110,7 +110,9 @@ again: lws_pt_lock(pt, __func__); /* don't stay in poll wait longer than next hr timeout */ - us = __lws_sul_service_ripe(&pt->pt_sul_owner, lws_now_usecs()); + us = __lws_sul_service_ripe(pt->pt_sul_owner, + LWS_COUNT_PT_SUL_OWNERS, + lws_now_usecs()); if (us && us < timeout_us) timeout_us = us; diff --git a/lib/plat/optee/network.c b/lib/plat/optee/network.c index 767c25499..05427df35 100644 --- a/lib/plat/optee/network.c +++ b/lib/plat/optee/network.c @@ -128,7 +128,9 @@ again: lws_pt_lock(pt, __func__); /* don't stay in poll wait longer than next hr timeout */ - us = __lws_sul_service_ripe(&pt->pt_sul_owner, lws_now_usecs()); + us = __lws_sul_service_ripe(pt->pt_sul_owner, + LWS_COUNT_PT_SUL_OWNERS, + lws_now_usecs()); if (us && us < timeout_us) timeout_us = us; diff --git a/lib/plat/unix/unix-init.c b/lib/plat/unix/unix-init.c index 6abe4c7ba..0f78e1a0b 100644 --- a/lib/plat/unix/unix-init.c +++ b/lib/plat/unix/unix-init.c @@ -75,7 +75,8 @@ lws_sul_plat_unix(lws_sorted_usec_list_t *sul) lws_context_unlock(context); #endif - __lws_sul_insert(&pt->pt_sul_owner, &pt->sul_plat, 30 * LWS_US_PER_SEC); + __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED], + &pt->sul_plat, 30 * LWS_US_PER_SEC); } #endif @@ -141,8 +142,8 @@ lws_plat_init(struct lws_context *context, /* we only need to do this on pt[0] */ context->pt[0].sul_plat.cb = lws_sul_plat_unix; - __lws_sul_insert(&context->pt[0].pt_sul_owner, &context->pt[0].sul_plat, - 30 * LWS_US_PER_SEC); + __lws_sul_insert_us(&context->pt[0].pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED], + &context->pt[0].sul_plat, 30 * LWS_US_PER_SEC); #endif return 0; diff --git a/lib/plat/unix/unix-service.c b/lib/plat/unix/unix-service.c index c0984b293..c7edfa68b 100644 --- a/lib/plat/unix/unix-service.c +++ b/lib/plat/unix/unix-service.c @@ -113,7 +113,7 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi) /* * service ripe scheduled events, and limit wait to next expected one */ - us = __lws_sul_service_ripe(&pt->pt_sul_owner, us); + us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS, us); if (us && us < timeout_us) timeout_us = us; diff --git a/lib/plat/unix/unix-spawn.c b/lib/plat/unix/unix-spawn.c index 3f6ffbd84..b19605784 100644 --- a/lib/plat/unix/unix-spawn.c +++ b/lib/plat/unix/unix-spawn.c @@ -108,10 +108,8 @@ lws_spawn_piped_destroy(struct lws_spawn_piped **_lsp) lws_dll2_remove(&lsp->dll); - lws_sul_schedule(lsp->info.vh->context, lsp->info.tsi, &lsp->sul, - NULL, LWS_SET_TIMER_USEC_CANCEL); - lws_sul_schedule(lsp->info.vh->context, lsp->info.tsi, &lsp->sul_reap, - NULL, LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&lsp->sul); + lws_sul_cancel(&lsp->sul_reap); for (n = 0; n < 3; n++) { #if 0 @@ -188,8 +186,7 @@ lws_spawn_reap(struct lws_spawn_piped *lsp) /* we reached the reap point, no need for timeout wait */ - lws_sul_schedule(lsp->info.vh->context, lsp->info.tsi, &lsp->sul, NULL, - LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&lsp->sul); /* * All the stdwsi went down, nothing more is coming... it's over diff --git a/lib/plat/windows/windows-service.c b/lib/plat/windows/windows-service.c index ae16d9731..51eb2d273 100644 --- a/lib/plat/windows/windows-service.c +++ b/lib/plat/windows/windows-service.c @@ -133,7 +133,9 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi) lws_pt_lock(pt, __func__); /* don't stay in poll wait longer than next hr timeout */ - us = __lws_sul_service_ripe(&pt->pt_sul_owner, lws_now_usecs()); + us = __lws_sul_service_ripe(pt->pt_sul_owner, + LWS_COUNT_PT_SUL_OWNERS, + lws_now_usecs()); if (us && us < timeout_us) timeout_us = us; diff --git a/lib/plat/windows/windows-spawn.c b/lib/plat/windows/windows-spawn.c index fcc11c6b8..73487231e 100644 --- a/lib/plat/windows/windows-spawn.c +++ b/lib/plat/windows/windows-spawn.c @@ -125,14 +125,9 @@ lws_spawn_piped_destroy(struct lws_spawn_piped **_lsp) lws_dll2_remove(&lsp->dll); - lws_sul_schedule(lsp->info.vh->context, lsp->info.tsi, &lsp->sul, - NULL, LWS_SET_TIMER_USEC_CANCEL); - - lws_sul_schedule(lsp->context, 0, &lsp->sul_reap, NULL, - LWS_SET_TIMER_USEC_CANCEL); - - lws_sul_schedule(lsp->context, 0, &lsp->sul_poll, NULL, - LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&lsp->sul); + lws_sul_cancel(&lsp->sul_reap); + lws_sul_cancel(&lsp->sul_poll); lwsl_warn("%s: deleting lsp\n", __func__); @@ -192,8 +187,7 @@ lws_spawn_reap(struct lws_spawn_piped *lsp) /* we reached the reap point, no need for timeout wait */ - lws_sul_schedule(lsp->info.vh->context, lsp->info.tsi, &lsp->sul, NULL, - LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&lsp->sul); /* * All the stdwsi went down, nothing more is coming... it's over @@ -517,8 +511,7 @@ lws_spawn_piped(const struct lws_spawn_piped_info *i) bail3: - lws_sul_schedule(context, 0, &lsp->sul_poll, NULL, - LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&lsp->sul_poll); while (--n >= 0) __remove_wsi_socket_from_fds(lsp->stdwsi[n]); diff --git a/lib/roles/cgi/ops-cgi.c b/lib/roles/cgi/ops-cgi.c index 4da28ba70..97794197f 100644 --- a/lib/roles/cgi/ops-cgi.c +++ b/lib/roles/cgi/ops-cgi.c @@ -92,8 +92,8 @@ lws_cgi_sul_cb(lws_sorted_usec_list_t *sul) lws_cgi_kill_terminated(pt); - __lws_sul_insert_us(&pt->pt_sul_owner, &pt->sul_cgi, - 3 * LWS_US_PER_SEC); + __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED], + &pt->sul_cgi, 3 * LWS_US_PER_SEC); } static int @@ -105,8 +105,8 @@ rops_pt_init_destroy_cgi(struct lws_context *context, pt->sul_cgi.cb = lws_cgi_sul_cb; - __lws_sul_insert(&pt->pt_sul_owner, &pt->sul_cgi, - 3 * LWS_US_PER_SEC); + __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED], + &pt->sul_cgi, 3 * LWS_US_PER_SEC); } else lws_dll2_remove(&pt->sul_cgi.list); diff --git a/lib/roles/dbus/dbus.c b/lib/roles/dbus/dbus.c index 75b65aa62..3662c12ed 100644 --- a/lib/roles/dbus/dbus.c +++ b/lib/roles/dbus/dbus.c @@ -491,7 +491,7 @@ lws_dbus_sul_cb(lws_sorted_usec_list_t *sul) } } lws_end_foreach_dll_safe(rdt, nx); - __lws_sul_insert(&pt->pt_sul_owner, &pt->dbus.sul, + lws_sul_schedule(pt->context, pt->tid, &pt->dbus.sul, lws_dbus_sul_cb, 3 * LWS_US_PER_SEC); } @@ -501,13 +501,10 @@ rops_pt_init_destroy_dbus(struct lws_context *context, struct lws_context_per_thread *pt, int destroy) { if (!destroy) { - - pt->dbus.sul.cb = lws_dbus_sul_cb; - - __lws_sul_insert(&pt->pt_sul_owner, &pt->dbus.sul, + lws_sul_schedule(context, pt->tid, &pt->dbus.sul, lws_dbus_sul_cb, 3 * LWS_US_PER_SEC); } else - lws_dll2_remove(&pt->dbus.sul.list); + lws_sul_cancel(&pt->dbus.sul); return 0; } diff --git a/lib/roles/http/client/client-handshake.c b/lib/roles/http/client/client-handshake.c index 9983bb12f..73f0eaea0 100644 --- a/lib/roles/http/client/client-handshake.c +++ b/lib/roles/http/client/client-handshake.c @@ -756,8 +756,7 @@ ads_known: } conn_good: - lws_sul_schedule(wsi->context, 0, &wsi->sul_connect_timeout, NULL, - LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&wsi->sul_connect_timeout); lwsl_info("%s: Connection started %p\n", __func__, wsi->dns_results); /* the tcp connection has happend */ @@ -837,8 +836,7 @@ try_next_result_closesock: wsi->desc.sockfd = LWS_SOCK_INVALID; try_next_result: - lws_sul_schedule(wsi->context, 0, &wsi->sul_connect_timeout, - NULL, LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&wsi->sul_connect_timeout); if (wsi->dns_results_next) { wsi->dns_results_next = wsi->dns_results_next->ai_next; if (wsi->dns_results_next) diff --git a/lib/roles/mqtt/mqtt.c b/lib/roles/mqtt/mqtt.c index 8e2079de1..6eeae7cc0 100644 --- a/lib/roles/mqtt/mqtt.c +++ b/lib/roles/mqtt/mqtt.c @@ -1111,9 +1111,7 @@ bail1: * no need for ACK timeout wait * any more */ - lws_sul_schedule(lws_get_context(w), 0, - &w->mqtt->sul_qos1_puback_wait, NULL, - LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&w->mqtt->sul_qos1_puback_wait); if (requested_close) { __lws_close_free_wsi(w, @@ -1745,8 +1743,9 @@ do_write: /* For QoS1, if no PUBACK coming after 3s, we must RETRY the publish */ wsi->mqtt->sul_qos1_puback_wait.cb = lws_mqtt_publish_resend; - __lws_sul_insert(&pt->pt_sul_owner, &wsi->mqtt->sul_qos1_puback_wait, - 3 * LWS_USEC_PER_SEC); + __lws_sul_insert_us(&pt->pt_sul_owner[wsi->conn_validity_wakesuspend], + &wsi->mqtt->sul_qos1_puback_wait, + 3 * LWS_USEC_PER_SEC); return 0; } diff --git a/lib/roles/mqtt/ops-mqtt.c b/lib/roles/mqtt/ops-mqtt.c index ad4980217..22775ad38 100644 --- a/lib/roles/mqtt/ops-mqtt.c +++ b/lib/roles/mqtt/ops-mqtt.c @@ -422,8 +422,7 @@ rops_close_role_mqtt(struct lws_context_per_thread *pt, struct lws *wsi) c = &wsi->mqtt->client; - __lws_sul_insert(&pt->pt_sul_owner, &wsi->mqtt->sul_qos1_puback_wait, - LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&wsi->mqtt->sul_qos1_puback_wait); lws_mqtt_str_free(&c->username); lws_mqtt_str_free(&c->password); diff --git a/lib/roles/ws/server-ws.c b/lib/roles/ws/server-ws.c index 6fc4d1409..15e7d09bb 100644 --- a/lib/roles/ws/server-ws.c +++ b/lib/roles/ws/server-ws.c @@ -362,8 +362,7 @@ lws_process_ws_upgrade2(struct lws *wsi) * validity checking */ - __lws_sul_insert(&pt->pt_sul_owner, &wsi->sul_validity, - LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&wsi->sul_validity); } else #endif { diff --git a/lib/secure-streams/README.md b/lib/secure-streams/README.md index 730d6f8f4..98e96bef8 100644 --- a/lib/secure-streams/README.md +++ b/lib/secure-streams/README.md @@ -203,6 +203,14 @@ connection for retry + backoff The name of the trust store described in the `trust_stores` section to apply to validate the remote server cert. +### `swake_validity` + +Set to `true` if this streamtype is important enough for the functioning of the +device that its locally-initiated periodic connection validity checks of the +interval described in the associated retry / backoff selection, are important +enough to wake the whole system from low power suspend so they happen on +schedule. + ## http transport ### `http_method` diff --git a/lib/secure-streams/policy-json.c b/lib/secure-streams/policy-json.c index 891705330..253d36cab 100644 --- a/lib/secure-streams/policy-json.c +++ b/lib/secure-streams/policy-json.c @@ -90,6 +90,7 @@ static const char * const lejp_tokens_policy[] = { "s[].*.mqtt_will_message", "s[].*.mqtt_will_qos", "s[].*.mqtt_will_retain", + "s[].*.swake_validity", "s[].*", }; @@ -155,6 +156,7 @@ typedef enum { LSSPPT_MQTT_WILL_MESSAGE, LSSPPT_MQTT_WILL_QOS, LSSPPT_MQTT_WILL_RETAIN, + LSSPPT_SWAKE_VALIDITY, LSSPPT_STREAMTYPES } policy_token_t; @@ -498,6 +500,11 @@ lws_ss_policy_parser_cb(struct lejp_ctx *ctx, char reason) a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_HTTP_X_WWW_FORM_URLENCODED; break; + case LSSPPT_SWAKE_VALIDITY: + if (reason == LEJPCB_VAL_TRUE) + a->curr[LTY_POLICY].p->flags |= + LWSSSPOLF_WAKE_SUSPEND__VALIDITY; + break; case LSSPPT_RETRYPTR: bot = a->heads[LTY_BACKOFF].b; diff --git a/lib/secure-streams/protocols/ss-h1.c b/lib/secure-streams/protocols/ss-h1.c index b75c5b878..42124bc71 100644 --- a/lib/secure-streams/protocols/ss-h1.c +++ b/lib/secure-streams/protocols/ss-h1.c @@ -231,8 +231,10 @@ secstream_h1(struct lws *wsi, enum lws_callback_reasons reason, void *user, h->retry = 0; h->seqstate = SSSEQ_CONNECTED; - lws_ss_set_timeout_us(h, LWS_SET_TIMER_USEC_CANCEL); - lws_ss_event_helper(h, LWSSSCS_CONNECTED); + lws_sul_cancel(&h->sul); + if (lws_ss_event_helper(h, LWSSSCS_CONNECTED)) { + return -1; + } /* * Since it's an http transaction we initiated... this is diff --git a/lib/secure-streams/protocols/ss-mqtt.c b/lib/secure-streams/protocols/ss-mqtt.c index 1c6d506be..e00ab6798 100644 --- a/lib/secure-streams/protocols/ss-mqtt.c +++ b/lib/secure-streams/protocols/ss-mqtt.c @@ -72,7 +72,7 @@ secstream_mqtt(struct lws *wsi, enum lws_callback_reasons reason, void *user, h->wsi = wsi; h->retry = 0; h->seqstate = SSSEQ_CONNECTED; - lws_ss_set_timeout_us(h, LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&h->sul); lws_ss_event_helper(h, LWSSSCS_CONNECTED); if (h->policy->u.mqtt.topic) lws_callback_on_writable(wsi); diff --git a/lib/secure-streams/protocols/ss-raw.c b/lib/secure-streams/protocols/ss-raw.c index bad9c2575..e37b6710a 100644 --- a/lib/secure-streams/protocols/ss-raw.c +++ b/lib/secure-streams/protocols/ss-raw.c @@ -67,7 +67,7 @@ secstream_raw(struct lws *wsi, enum lws_callback_reasons reason, void *user, h->retry = 0; h->seqstate = SSSEQ_CONNECTED; - lws_ss_set_timeout_us(h, LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&h->sul); lws_ss_event_helper(h, LWSSSCS_CONNECTED); lws_validity_confirmed(wsi); diff --git a/lib/secure-streams/protocols/ss-ws.c b/lib/secure-streams/protocols/ss-ws.c index 086975cbd..cdd19f942 100644 --- a/lib/secure-streams/protocols/ss-ws.c +++ b/lib/secure-streams/protocols/ss-ws.c @@ -67,8 +67,9 @@ secstream_ws(struct lws *wsi, enum lws_callback_reasons reason, void *user, case LWS_CALLBACK_CLIENT_ESTABLISHED: h->retry = 0; h->seqstate = SSSEQ_CONNECTED; - lws_ss_set_timeout_us(h, LWS_SET_TIMER_USEC_CANCEL); - lws_ss_event_helper(h, LWSSSCS_CONNECTED); + lws_sul_cancel(&h->sul); + if (lws_ss_event_helper(h, LWSSSCS_CONNECTED)) + return -1; break; case LWS_CALLBACK_CLIENT_RECEIVE: diff --git a/lib/secure-streams/secure-streams-client.c b/lib/secure-streams/secure-streams-client.c index e9c849ec9..ce207757e 100644 --- a/lib/secure-streams/secure-streams-client.c +++ b/lib/secure-streams/secure-streams-client.c @@ -401,8 +401,7 @@ lws_sspc_destroy(lws_sspc_handle_t **ph) h->destroying = 1; - lws_sul_schedule(h->context, 0, &h->sul_retry, NULL, - LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&h->sul_retry); lws_dll2_remove(&h->client_list); if (h->dsh) diff --git a/lib/secure-streams/secure-streams.c b/lib/secure-streams/secure-streams.c index f9b5fc1d1..8424fe310 100644 --- a/lib/secure-streams/secure-streams.c +++ b/lib/secure-streams/secure-streams.c @@ -150,7 +150,9 @@ lws_ss_set_timeout_us(lws_ss_handle_t *h, lws_usec_t us) struct lws_context_per_thread *pt = &h->context->pt[h->tsi]; h->sul.cb = lws_ss_timeout_sul_check_cb; - __lws_sul_insert(&pt->pt_sul_owner, &h->sul, us); + __lws_sul_insert_us(&pt->pt_sul_owner[ + !!(h->policy->flags & LWSSSPOLF_WAKE_SUSPEND__VALIDITY)], + &h->sul, us); return 0; } @@ -273,6 +275,9 @@ lws_ss_client_connect(lws_ss_handle_t *h) } } + if (h->policy->flags & LWSSSPOLF_WAKE_SUSPEND__VALIDITY) + i.ssl_connection |= LCCSCF_WAKE_SUSPEND__VALIDITY; + i.address = ads; i.port = port; i.host = i.address; @@ -525,7 +530,7 @@ lws_ss_destroy(lws_ss_handle_t **ppss) pmd = pmd->next; } - lws_sul_schedule(h->context, 0, &h->sul, NULL, LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&h->sul); lws_free_set_NULL(h); } diff --git a/lib/system/dhcpclient/dhcpclient.c b/lib/system/dhcpclient/dhcpclient.c index cf58b5b4c..d10520a9f 100644 --- a/lib/system/dhcpclient/dhcpclient.c +++ b/lib/system/dhcpclient/dhcpclient.c @@ -334,8 +334,7 @@ callback_dhcpc(struct lws *wsi, enum lws_callback_reasons reason, void *user, if (!r) break; r->wsi_raw = NULL; - lws_sul_schedule(r->context, 0, &r->sul_write, NULL, - LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&r->sul_write); if (r->state != LDHC_BOUND) { r->state = LDHC_INIT; lws_retry_sul_schedule(r->context, 0, &r->sul_conn, &bo2, @@ -553,10 +552,8 @@ broken: /* clear timeouts related to the broadcast socket */ - lws_sul_schedule(r->context, 0, &r->sul_write, NULL, - LWS_SET_TIMER_USEC_CANCEL); - lws_sul_schedule(r->context, 0, &r->sul_conn, NULL, - LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&r->sul_write); + lws_sul_cancel(&r->sul_conn); lwsl_notice("%s: DHCP configured %s\n", __func__, (const char *)&r[1]); @@ -650,8 +647,7 @@ retry_conn: #if 0 cancel_conn_timer: - lws_sul_schedule(r->context, 0, &r->sul_conn, NULL, - LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&r->sul_conn); return 0; #endif @@ -665,10 +661,8 @@ lws_dhcpc_destroy(lws_dhcpc_req_t **pr) { lws_dhcpc_req_t *r = *pr; - lws_sul_schedule(r->context, 0, &r->sul_conn, NULL, - LWS_SET_TIMER_USEC_CANCEL); - lws_sul_schedule(r->context, 0, &r->sul_write, NULL, - LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&r->sul_conn); + lws_sul_cancel(&r->sul_write); if (r->wsi_raw) lws_set_timeout(r->wsi_raw, 1, LWS_TO_KILL_ASYNC); diff --git a/lib/system/ntpclient/ntpclient.c b/lib/system/ntpclient/ntpclient.c index 8499cd5e3..b56efe09d 100644 --- a/lib/system/ntpclient/ntpclient.c +++ b/lib/system/ntpclient/ntpclient.c @@ -195,8 +195,7 @@ do_close: v->wsi_udp = NULL; /* cancel any pending write retry */ - lws_sul_schedule(v->context, 0, &v->sul_write, NULL, - LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&v->sul_write); if (v->set_time) goto cancel_conn_timer; @@ -280,8 +279,7 @@ retry_conn: cancel_conn_timer: - lws_sul_schedule(v->context, 0, &v->sul_conn, NULL, - LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&v->sul_conn); return 0; } diff --git a/lib/tls/tls-server.c b/lib/tls/tls-server.c index 9d4ecc998..c18f56a4a 100644 --- a/lib/tls/tls-server.c +++ b/lib/tls/tls-server.c @@ -34,8 +34,9 @@ lws_sul_tls_cb(lws_sorted_usec_list_t *sul) lws_tls_check_all_cert_lifetimes(pt->context); - __lws_sul_insert(&pt->pt_sul_owner, &pt->sul_tls, - (lws_usec_t)24 * 3600 * LWS_US_PER_SEC); + __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED], + &pt->sul_tls, + (lws_usec_t)24 * 3600 * LWS_US_PER_SEC); } int @@ -115,8 +116,9 @@ lws_context_init_server_ssl(const struct lws_context_creation_info *info, /* check certs once a day */ context->pt[0].sul_tls.cb = lws_sul_tls_cb; - __lws_sul_insert(&context->pt[0].pt_sul_owner, &context->pt[0].sul_tls, - (lws_usec_t)24 * 3600 * LWS_US_PER_SEC); + __lws_sul_insert_us(&context->pt[0].pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED], + &context->pt[0].sul_tls, + (lws_usec_t)24 * 3600 * LWS_US_PER_SEC); return 0; } diff --git a/lwsws/main.c b/lwsws/main.c index 63a81983d..d280f8def 100644 --- a/lwsws/main.c +++ b/lwsws/main.c @@ -335,7 +335,7 @@ int main(int argc, char **argv) } /* cancel the per-minute sul */ - lws_sul_schedule(context, 0, &sul_lwsws, NULL, LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&sul_lwsws); lws_context_destroy(context); (void)budget; diff --git a/minimal-examples/client-server/minimal-ws-proxy/protocol_lws_minimal.c b/minimal-examples/client-server/minimal-ws-proxy/protocol_lws_minimal.c index 0e72c5443..10e525c3f 100644 --- a/minimal-examples/client-server/minimal-ws-proxy/protocol_lws_minimal.c +++ b/minimal-examples/client-server/minimal-ws-proxy/protocol_lws_minimal.c @@ -41,6 +41,8 @@ struct per_vhost_data__minimal { struct lws_vhost *vhost; const struct lws_protocols *protocol; + lws_sorted_usec_list_t sul; + struct per_session_data__minimal *pss_list; /* linked-list of live pss*/ struct lws_ring *ring; /* ringbuffer holding unsent messages */ @@ -60,9 +62,12 @@ __minimal_destroy_message(void *_msg) msg->len = 0; } -static int -connect_client(struct per_vhost_data__minimal *vhd) +static void +sul_connect_attempt(struct lws_sorted_usec_list *sul) { + struct per_vhost_data__minimal *vhd = + lws_container_of(sul, struct per_vhost_data__minimal, sul); + vhd->i.context = vhd->context; vhd->i.port = 443; vhd->i.address = "libwebsockets.org"; @@ -75,7 +80,9 @@ connect_client(struct per_vhost_data__minimal *vhd) vhd->i.local_protocol_name = "lws-minimal-proxy"; vhd->i.pwsi = &vhd->client_wsi; - return !lws_client_connect_via_info(&vhd->i); + if (!lws_client_connect_via_info(&vhd->i)) + lws_sul_schedule(vhd->context, 0, &vhd->sul, + sul_connect_attempt, 10 * LWS_US_PER_SEC); } static int @@ -109,14 +116,12 @@ callback_minimal(struct lws *wsi, enum lws_callback_reasons reason, if (!vhd->ring) return 1; - if (connect_client(vhd)) - lws_timed_callback_vh_protocol(vhd->vhost, - vhd->protocol, - LWS_CALLBACK_USER, 1); + sul_connect_attempt(&vhd->sul); break; case LWS_CALLBACK_PROTOCOL_DESTROY: lws_ring_destroy(vhd->ring); + lws_sul_cancel(&vhd->sul); break; /* --- serving callbacks --- */ @@ -169,8 +174,8 @@ callback_minimal(struct lws *wsi, enum lws_callback_reasons reason, lwsl_err("CLIENT_CONNECTION_ERROR: %s\n", in ? (char *)in : "(null)"); vhd->client_wsi = NULL; - lws_timed_callback_vh_protocol(vhd->vhost, vhd->protocol, - LWS_CALLBACK_USER, 1); + lws_sul_schedule(vhd->context, 0, &vhd->sul, + sul_connect_attempt, LWS_US_PER_SEC); break; case LWS_CALLBACK_CLIENT_ESTABLISHED: @@ -214,18 +219,8 @@ callback_minimal(struct lws *wsi, enum lws_callback_reasons reason, case LWS_CALLBACK_CLIENT_CLOSED: vhd->client_wsi = NULL; - lws_timed_callback_vh_protocol(vhd->vhost, vhd->protocol, - LWS_CALLBACK_USER, 1); - break; - - /* rate-limited client connect retries */ - - case LWS_CALLBACK_USER: - lwsl_notice("%s: LWS_CALLBACK_USER\n", __func__); - if (connect_client(vhd)) - lws_timed_callback_vh_protocol(vhd->vhost, - vhd->protocol, - LWS_CALLBACK_USER, 1); + lws_sul_schedule(vhd->context, 0, &vhd->sul, + sul_connect_attempt, LWS_US_PER_SEC); break; default: diff --git a/minimal-examples/dbus-client/minimal-dbus-ws-proxy-testclient/CMakeLists.txt b/minimal-examples/dbus-client/minimal-dbus-ws-proxy-testclient/CMakeLists.txt index c7443f5d4..7b1872fe8 100644 --- a/minimal-examples/dbus-client/minimal-dbus-ws-proxy-testclient/CMakeLists.txt +++ b/minimal-examples/dbus-client/minimal-dbus-ws-proxy-testclient/CMakeLists.txt @@ -1,4 +1,4 @@ -project(lws-minimal-dbus-ws-proxy-testclient) +project(lws-minimal-dbus-ws-proxy-testclient C) cmake_minimum_required(VERSION 2.8) find_package(libwebsockets CONFIG REQUIRED) list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR}) @@ -11,7 +11,7 @@ require_lws_config(LWS_ROLE_DBUS 1 requirements) require_lws_config(LWS_WITH_CLIENT 1 requirements) if (NOT MSVC AND NOT WIN32 AND requirements) - add_executable(${SAMP} ${SRCS}) + add_executable(${PROJECT_NAME} minimal-dbus-ws-proxy-testclient.c) if (NOT LWS_PLAT_FREERTOS) find_package(PkgConfig QUIET) @@ -21,11 +21,11 @@ if (NOT MSVC AND NOT WIN32 AND requirements) endif() include_directories("${LWS_DBUS_INCLUDE1}") - + message("project ${PROJECT_NAME}") if (websockets_shared) - target_link_libraries(${SAMP} websockets_shared) - add_dependencies(${SAMP} websockets_shared ${LWS_DBUS_LIB}) + target_link_libraries(${PROJECT_NAME} websockets_shared) + add_dependencies(${PROJECT_NAME} websockets_shared ${LWS_DBUS_LIB}) else() - target_link_libraries(${SAMP} websockets ${LWS_DBUS_LIB}) + target_link_libraries(${PROJECT_NAME} websockets ${LWS_DBUS_LIB}) endif() endif() diff --git a/minimal-examples/dbus-client/minimal-dbus-ws-proxy-testclient/minimal-dbus-ws-proxy-testclient.c b/minimal-examples/dbus-client/minimal-dbus-ws-proxy-testclient/minimal-dbus-ws-proxy-testclient.c index d2818fa77..c3d92ee0a 100644 --- a/minimal-examples/dbus-client/minimal-dbus-ws-proxy-testclient/minimal-dbus-ws-proxy-testclient.c +++ b/minimal-examples/dbus-client/minimal-dbus-ws-proxy-testclient/minimal-dbus-ws-proxy-testclient.c @@ -43,6 +43,8 @@ enum lws_dbus_client_state { struct lws_dbus_ctx_wsproxy_client { struct lws_dbus_ctx ctx; + lws_sorted_usec_list_t sul; + enum lws_dbus_client_state state; }; @@ -309,84 +311,57 @@ bail: return ret; } -/* - * Stub lws protocol, just so we can get synchronous timers conveniently. - * - * Set up a 1Hz timer and if our connection state is suitable, use that - * to write mirror protocol drawing packets to the proxied ws connection - */ - -static int -callback_just_timer(struct lws *wsi, enum lws_callback_reasons reason, - void *user, void *in, size_t len) +static void +sul_timer(struct lws_sorted_usec_list *sul) { char payload[64]; const char *ws_pkt = payload; DBusMessage *msg; - switch (reason) { - case LWS_CALLBACK_PROTOCOL_INIT: - case LWS_CALLBACK_USER: - lwsl_info("%s: LWS_CALLBACK_USER\n", __func__); + if (!dbus_ctx || dbus_ctx->state != LDCS_CONN_ONWARD) + goto again; - if (!dbus_ctx || dbus_ctx->state != LDCS_CONN_ONWARD) - goto again; - - if (autoexit_budget > 0) { - if (!--autoexit_budget) { - lwsl_notice("reached autoexit budget\n"); - interrupted = 1; - break; - } + if (autoexit_budget > 0) { + if (!--autoexit_budget) { + lwsl_notice("reached autoexit budget\n"); + interrupted = 1; + return; } - - msg = dbus_message_new_method_call(THIS_BUSNAME, THIS_OBJECT, - THIS_INTERFACE, "Send"); - if (!msg) - break; - - lws_snprintf(payload, sizeof(payload), "d #%06X %d %d %d %d;", - rand() & 0xffffff, rand() % 480, rand() % 300, - rand() % 480, rand() % 300); - - if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &ws_pkt, - DBUS_TYPE_INVALID)) { - dbus_message_unref(msg); - break; - } - - if (!dbus_connection_send_with_reply(dbus_ctx->ctx.conn, msg, - &dbus_ctx->ctx.pc, - DBUS_TIMEOUT_USE_DEFAULT)) { - lwsl_err("%s: unable to send\n", __func__); - dbus_message_unref(msg); - break; - } - - dbus_message_unref(msg); - dbus_pending_call_set_notify(dbus_ctx->ctx.pc, - pending_call_notify, - &dbus_ctx->ctx, NULL); - count_tx++; - -again: - lws_timed_callback_vh_protocol(lws_get_vhost(wsi), - lws_get_protocol(wsi), - LWS_CALLBACK_USER, 2); - break; - default: - break; } - return 0; + msg = dbus_message_new_method_call(THIS_BUSNAME, THIS_OBJECT, + THIS_INTERFACE, "Send"); + if (!msg) + goto again; + + lws_snprintf(payload, sizeof(payload), "d #%06X %d %d %d %d;", + rand() & 0xffffff, rand() % 480, rand() % 300, + rand() % 480, rand() % 300); + + if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &ws_pkt, + DBUS_TYPE_INVALID)) { + dbus_message_unref(msg); + goto again; + } + + if (!dbus_connection_send_with_reply(dbus_ctx->ctx.conn, msg, + &dbus_ctx->ctx.pc, + DBUS_TIMEOUT_USE_DEFAULT)) { + lwsl_err("%s: unable to send\n", __func__); + dbus_message_unref(msg); + goto again; + } + + dbus_message_unref(msg); + dbus_pending_call_set_notify(dbus_ctx->ctx.pc, + pending_call_notify, + &dbus_ctx->ctx, NULL); + count_tx++; + +again: + lws_sul_schedule(context, 0, &dbus_ctx->sul, sul_timer, 2 * LWS_US_PER_SEC); } -static struct lws_protocols protocols[] = { - { "_just_timer", callback_just_timer, 0, 10, 0, NULL, 0 }, - { } -}; - - int main(int argc, const char **argv) { struct lws_vhost *vh; @@ -413,7 +388,6 @@ int main(int argc, const char **argv) memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS; - info.protocols = protocols; context = lws_create_context(&info); if (!context) { lwsl_err("lws init failed\n"); @@ -431,6 +405,9 @@ int main(int argc, const char **argv) if (!dbus_ctx) goto bail1; + lws_sul_schedule(context, 0, &dbus_ctx->sul, sul_timer, LWS_US_PER_SEC); + + if (remote_method_call(dbus_ctx)) goto bail2; diff --git a/minimal-examples/http-client/minimal-http-client-h2-rxflow/minimal-http-client.c b/minimal-examples/http-client/minimal-http-client-h2-rxflow/minimal-http-client.c index b16a0ce4c..8e50610a9 100644 --- a/minimal-examples/http-client/minimal-http-client-h2-rxflow/minimal-http-client.c +++ b/minimal-examples/http-client/minimal-http-client-h2-rxflow/minimal-http-client.c @@ -115,8 +115,7 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason, case LWS_CALLBACK_CLOSED_CLIENT_HTTP: interrupted = 1; bad = status != 200; - lws_sul_schedule(lws_get_context(wsi), 0, &pss->sul, NULL, - LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&pss->sul); lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */ break; diff --git a/minimal-examples/http-server/minimal-http-server-h2-long-poll/minimal-http-server.c b/minimal-examples/http-server/minimal-http-server-h2-long-poll/minimal-http-server.c index b558dc968..148d4c78c 100644 --- a/minimal-examples/http-server/minimal-http-server-h2-long-poll/minimal-http-server.c +++ b/minimal-examples/http-server/minimal-http-server-h2-long-poll/minimal-http-server.c @@ -79,8 +79,7 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, case LWS_CALLBACK_CLOSED_HTTP: if (!pss) break; - lws_sul_schedule(lws_get_context(wsi), 0, &pss->sul, sul_cb, - LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&pss->sul); break; case LWS_CALLBACK_HTTP_WRITEABLE: diff --git a/minimal-examples/raw/minimal-raw-serial/minimal-raw-file.c b/minimal-examples/raw/minimal-raw-serial/minimal-raw-file.c index 1ee11a86a..f4e9d03df 100644 --- a/minimal-examples/raw/minimal-raw-serial/minimal-raw-file.c +++ b/minimal-examples/raw/minimal-raw-serial/minimal-raw-file.c @@ -153,7 +153,7 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason, case LWS_CALLBACK_RAW_CLOSE_FILE: lwsl_notice("LWS_CALLBACK_RAW_CLOSE_FILE\n"); - lws_sul_schedule(lws_get_context(wsi), 0, &vhd->sul, sul_cb, LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&vhd->sul); break; case LWS_CALLBACK_RAW_WRITEABLE_FILE: diff --git a/minimal-examples/secure-streams/minimal-secure-streams-alexa/alexa.c b/minimal-examples/secure-streams/minimal-secure-streams-alexa/alexa.c index ba1fa7e2f..fb70f27d2 100644 --- a/minimal-examples/secure-streams/minimal-secure-streams-alexa/alexa.c +++ b/minimal-examples/secure-streams/minimal-secure-streams-alexa/alexa.c @@ -234,8 +234,7 @@ drain_end_cb(void *v) /* * Put a hold on bringing in any more data */ - lws_sul_schedule(context, 0, &m->sul, NULL, - LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&m->sul); #endif /* destroy our copy of the handle */ m->mh = NULL; @@ -391,8 +390,7 @@ ss_avs_metadata_rx(void *userobj, const uint8_t *buf, size_t len, int flags) /* * Put a hold on bringing in any more data */ - lws_sul_schedule(context, 0, &m->sul, NULL, - LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&m->sul); #endif /* destroy our copy of the handle */ m->mh = NULL; @@ -549,8 +547,7 @@ ss_avs_metadata_state(void *userobj, void *sh, lws_ss_request_tx(m->ss); break; case LWSSSCS_DISCONNECTED: - lws_sul_schedule(context, 0, &m->sul, NULL, - LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&m->sul); //if (m->mh) { play_mp3(NULL, NULL, NULL); m->mh = NULL; diff --git a/minimal-examples/secure-streams/minimal-secure-streams-avs/avs.c b/minimal-examples/secure-streams/minimal-secure-streams-avs/avs.c index ea8f97e22..0121d6783 100644 --- a/minimal-examples/secure-streams/minimal-secure-streams-avs/avs.c +++ b/minimal-examples/secure-streams/minimal-secure-streams-avs/avs.c @@ -223,7 +223,7 @@ ss_avs_metadata_state(void *userobj, void *sh, { ss_avs_metadata_t *m = (ss_avs_metadata_t *)userobj; - struct lws_context *context = (struct lws_context *)m->opaque_data; + // struct lws_context *context = (struct lws_context *)m->opaque_data; lwsl_user("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name(state), (unsigned int)ack); @@ -243,13 +243,11 @@ ss_avs_metadata_state(void *userobj, void *sh, /* for this demo app, we want to exit on fail to connect */ case LWSSSCS_DISCONNECTED: /* for this demo app, we want to exit after complete flow */ - lws_sul_schedule(context, 0, &m->sul, use_buffer_50ms, - LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&m->sul); interrupted = 1; break; case LWSSSCS_DESTROYING: - lws_sul_schedule(context, 0, &m->sul, use_buffer_50ms, - LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&m->sul); break; default: break; diff --git a/minimal-examples/secure-streams/minimal-secure-streams-client-tx/minimal-secure-streams-client-tx.c b/minimal-examples/secure-streams/minimal-secure-streams-client-tx/minimal-secure-streams-client-tx.c index 0eee1e917..0e5e836a1 100644 --- a/minimal-examples/secure-streams/minimal-secure-streams-client-tx/minimal-secure-streams-client-tx.c +++ b/minimal-examples/secure-streams/minimal-secure-streams-client-tx/minimal-secure-streams-client-tx.c @@ -112,8 +112,7 @@ myss_state(void *userobj, void *sh, lws_ss_constate_t state, lws_sul_schedule(context, 0, &m->sul, txcb, RATE_US); break; case LWSSSCS_DISCONNECTED: - lws_sul_schedule(context, 0, &m->sul, txcb, - LWS_SET_TIMER_USEC_CANCEL); + lws_sul_cancel(&m->sul); break; case LWSSSCS_ALL_RETRIES_FAILED: /* if we're out of retries, we want to close the app and FAIL */ diff --git a/minimal-examples/ws-client/minimal-ws-client-echo/protocol_lws_minimal_client_echo.c b/minimal-examples/ws-client/minimal-ws-client-echo/protocol_lws_minimal_client_echo.c index 3e895902c..2e34b7782 100644 --- a/minimal-examples/ws-client/minimal-ws-client-echo/protocol_lws_minimal_client_echo.c +++ b/minimal-examples/ws-client/minimal-ws-client-echo/protocol_lws_minimal_client_echo.c @@ -43,6 +43,8 @@ struct vhd_minimal_client_echo { struct lws_vhost *vhost; struct lws *client_wsi; + lws_sorted_usec_list_t sul; + int *interrupted; int *options; const char **url; @@ -51,9 +53,11 @@ struct vhd_minimal_client_echo { int *port; }; -static int -connect_client(struct vhd_minimal_client_echo *vhd) +static void +sul_connect_attempt(struct lws_sorted_usec_list *sul) { + struct vhd_minimal_client_echo *vhd = + lws_container_of(sul, struct vhd_minimal_client_echo, sul); struct lws_client_connect_info i; char host[128]; @@ -77,7 +81,9 @@ connect_client(struct vhd_minimal_client_echo *vhd) lwsl_user("connecting to %s:%d/%s\n", i.address, i.port, i.path); - return !lws_client_connect_via_info(&i); + if (!lws_client_connect_via_info(&i)) + lws_sul_schedule(vhd->context, 0, &vhd->sul, + sul_connect_attempt, 10 * LWS_US_PER_SEC); } static void @@ -90,13 +96,6 @@ __minimal_destroy_message(void *_msg) msg->len = 0; } -static void -schedule_callback(struct lws *wsi, int reason, int secs) -{ - lws_timed_callback_vh_protocol(lws_get_vhost(wsi), - lws_get_protocol(wsi), reason, secs); -} - static int callback_minimal_client_echo(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) @@ -142,8 +141,11 @@ callback_minimal_client_echo(struct lws *wsi, enum lws_callback_reasons reason, (const struct lws_protocol_vhost_options *)in, "iface")->value; - if (connect_client(vhd)) - schedule_callback(wsi, LWS_CALLBACK_USER, 1); + sul_connect_attempt(&vhd->sul); + break; + + case LWS_CALLBACK_PROTOCOL_DESTROY: + lws_sul_cancel(&vhd->sul); break; case LWS_CALLBACK_CLIENT_ESTABLISHED: @@ -250,32 +252,18 @@ callback_minimal_client_echo(struct lws *wsi, enum lws_callback_reasons reason, lwsl_err("CLIENT_CONNECTION_ERROR: %s\n", in ? (char *)in : "(null)"); vhd->client_wsi = NULL; - //schedule_callback(wsi, LWS_CALLBACK_USER, 1); - //if (*vhd->options & 1) { - if (!*vhd->interrupted) - *vhd->interrupted = 3; - lws_cancel_service(lws_get_context(wsi)); - //} + if (!*vhd->interrupted) + *vhd->interrupted = 3; + lws_cancel_service(lws_get_context(wsi)); break; case LWS_CALLBACK_CLIENT_CLOSED: lwsl_user("LWS_CALLBACK_CLIENT_CLOSED\n"); lws_ring_destroy(pss->ring); vhd->client_wsi = NULL; - // schedule_callback(wsi, LWS_CALLBACK_USER, 1); - //if (*vhd->options & 1) { - if (!*vhd->interrupted) - *vhd->interrupted = 1 + pss->completed; - lws_cancel_service(lws_get_context(wsi)); - // } - break; - - /* rate-limited client connect retries */ - - case LWS_CALLBACK_USER: - lwsl_notice("%s: LWS_CALLBACK_USER\n", __func__); - if (connect_client(vhd)) - schedule_callback(wsi, LWS_CALLBACK_USER, 1); + if (!*vhd->interrupted) + *vhd->interrupted = 1 + pss->completed; + lws_cancel_service(lws_get_context(wsi)); break; default: diff --git a/minimal-examples/ws-client/minimal-ws-client-pmd-bulk/protocol_lws_minimal_pmd_bulk.c b/minimal-examples/ws-client/minimal-ws-client-pmd-bulk/protocol_lws_minimal_pmd_bulk.c index 33e224bbd..5212c0fd9 100644 --- a/minimal-examples/ws-client/minimal-ws-client-pmd-bulk/protocol_lws_minimal_pmd_bulk.c +++ b/minimal-examples/ws-client/minimal-ws-client-pmd-bulk/protocol_lws_minimal_pmd_bulk.c @@ -65,6 +65,8 @@ struct vhd_minimal_pmd_bulk { struct lws_vhost *vhost; struct lws *client_wsi; + lws_sorted_usec_list_t sul; + int *interrupted; int *options; }; @@ -78,9 +80,11 @@ static uint64_t rng(uint64_t *r) return *r; } -static int -connect_client(struct vhd_minimal_pmd_bulk *vhd) +static void +sul_connect_attempt(struct lws_sorted_usec_list *sul) { + struct vhd_minimal_pmd_bulk *vhd = + lws_container_of(sul, struct vhd_minimal_pmd_bulk, sul); struct lws_client_connect_info i; memset(&i, 0, sizeof(i)); @@ -96,14 +100,9 @@ connect_client(struct vhd_minimal_pmd_bulk *vhd) i.protocol = "lws-minimal-pmd-bulk"; i.pwsi = &vhd->client_wsi; - return !lws_client_connect_via_info(&i); -} - -static void -schedule_callback(struct lws *wsi, int reason, int secs) -{ - lws_timed_callback_vh_protocol(lws_get_vhost(wsi), - lws_get_protocol(wsi), reason, secs); + if (!lws_client_connect_via_info(&i)) + lws_sul_schedule(vhd->context, 0, &vhd->sul, + sul_connect_attempt, 10 * LWS_US_PER_SEC); } static int @@ -138,8 +137,11 @@ callback_minimal_pmd_bulk(struct lws *wsi, enum lws_callback_reasons reason, (const struct lws_protocol_vhost_options *)in, "options")->value; - if (connect_client(vhd)) - schedule_callback(wsi, LWS_CALLBACK_USER, 1); + sul_connect_attempt(&vhd->sul); + break; + + case LWS_CALLBACK_PROTOCOL_DESTROY: + lws_sul_cancel(&vhd->sul); break; case LWS_CALLBACK_CLIENT_ESTABLISHED: @@ -253,20 +255,14 @@ callback_minimal_pmd_bulk(struct lws *wsi, enum lws_callback_reasons reason, lwsl_err("CLIENT_CONNECTION_ERROR: %s\n", in ? (char *)in : "(null)"); vhd->client_wsi = NULL; - schedule_callback(wsi, LWS_CALLBACK_USER, 1); + lws_sul_schedule(vhd->context, 0, &vhd->sul, + sul_connect_attempt, LWS_US_PER_SEC); break; case LWS_CALLBACK_CLIENT_CLOSED: vhd->client_wsi = NULL; - schedule_callback(wsi, LWS_CALLBACK_USER, 1); - break; - - /* rate-limited client connect retries */ - - case LWS_CALLBACK_USER: - lwsl_notice("%s: LWS_CALLBACK_USER\n", __func__); - if (connect_client(vhd)) - schedule_callback(wsi, LWS_CALLBACK_USER, 1); + lws_sul_schedule(vhd->context, 0, &vhd->sul, + sul_connect_attempt, LWS_US_PER_SEC); break; default: diff --git a/minimal-examples/ws-client/minimal-ws-client-tx/minimal-ws-client.c b/minimal-examples/ws-client/minimal-ws-client-tx/minimal-ws-client.c index c83e23e96..2e78a19e6 100644 --- a/minimal-examples/ws-client/minimal-ws-client-tx/minimal-ws-client.c +++ b/minimal-examples/ws-client/minimal-ws-client-tx/minimal-ws-client.c @@ -44,6 +44,8 @@ struct per_vhost_data__minimal { const struct lws_protocols *protocol; pthread_t pthread_spam[2]; + lws_sorted_usec_list_t sul; + pthread_mutex_t lock_ring; /* serialize access to the ring buffer */ struct lws_ring *ring; /* ringbuffer holding unsent messages */ uint32_t tail; @@ -130,9 +132,12 @@ wait: return NULL; } -static int -connect_client(struct per_vhost_data__minimal *vhd) +static void +sul_connect_attempt(struct lws_sorted_usec_list *sul) { + struct per_vhost_data__minimal *vhd = + lws_container_of(sul, struct per_vhost_data__minimal, sul); + vhd->i.context = vhd->context; vhd->i.port = 7681; vhd->i.address = "localhost"; @@ -144,7 +149,9 @@ connect_client(struct per_vhost_data__minimal *vhd) vhd->i.protocol = "lws-minimal-broker"; vhd->i.pwsi = &vhd->client_wsi; - return !lws_client_connect_via_info(&vhd->i); + if (!lws_client_connect_via_info(&vhd->i)) + lws_sul_schedule(vhd->context, 0, &vhd->sul, + sul_connect_attempt, 10 * LWS_US_PER_SEC); } static int @@ -188,9 +195,7 @@ callback_minimal_broker(struct lws *wsi, enum lws_callback_reasons reason, goto init_fail; } - if (connect_client(vhd)) - lws_timed_callback_vh_protocol(vhd->vhost, - vhd->protocol, LWS_CALLBACK_USER, 1); + sul_connect_attempt(&vhd->sul); break; case LWS_CALLBACK_PROTOCOL_DESTROY: @@ -202,6 +207,7 @@ init_fail: if (vhd->ring) lws_ring_destroy(vhd->ring); + lws_sul_cancel(&vhd->sul); pthread_mutex_destroy(&vhd->lock_ring); return r; @@ -210,8 +216,8 @@ init_fail: lwsl_err("CLIENT_CONNECTION_ERROR: %s\n", in ? (char *)in : "(null)"); vhd->client_wsi = NULL; - lws_timed_callback_vh_protocol(vhd->vhost, - vhd->protocol, LWS_CALLBACK_USER, 1); + lws_sul_schedule(vhd->context, 0, &vhd->sul, + sul_connect_attempt, LWS_US_PER_SEC); break; /* --- client callbacks --- */ @@ -250,8 +256,8 @@ skip: case LWS_CALLBACK_CLIENT_CLOSED: vhd->client_wsi = NULL; vhd->established = 0; - lws_timed_callback_vh_protocol(vhd->vhost, vhd->protocol, - LWS_CALLBACK_USER, 1); + lws_sul_schedule(vhd->context, 0, &vhd->sul, + sul_connect_attempt, LWS_US_PER_SEC); break; case LWS_CALLBACK_EVENT_WAIT_CANCELLED: @@ -267,16 +273,6 @@ skip: lws_callback_on_writable(vhd->client_wsi); break; - /* rate-limited client connect retries */ - - case LWS_CALLBACK_USER: - lwsl_notice("%s: LWS_CALLBACK_USER\n", __func__); - if (connect_client(vhd)) - lws_timed_callback_vh_protocol(vhd->vhost, - vhd->protocol, - LWS_CALLBACK_USER, 1); - break; - default: break; } diff --git a/minimal-examples/ws-server/minimal-ws-server-threadpool/protocol_lws_minimal_threadpool.c b/minimal-examples/ws-server/minimal-ws-server-threadpool/protocol_lws_minimal_threadpool.c index 5fd7d8739..ba8c22781 100644 --- a/minimal-examples/ws-server/minimal-ws-server-threadpool/protocol_lws_minimal_threadpool.c +++ b/minimal-examples/ws-server/minimal-ws-server-threadpool/protocol_lws_minimal_threadpool.c @@ -34,6 +34,8 @@ struct per_vhost_data__minimal { struct lws_threadpool *tp; + struct lws_context *context; + lws_sorted_usec_list_t sul; const char *config; }; @@ -133,6 +135,22 @@ task_function(void *user, enum lws_threadpool_task_status s) return LWS_TP_RETURN_CHECKING_IN; } + +static void +sul_tp_dump(struct lws_sorted_usec_list *sul) +{ + struct per_vhost_data__minimal *vhd = + lws_container_of(sul, struct per_vhost_data__minimal, sul); + /* + * in debug mode, dump the threadpool stat to the logs once + * a second + */ + lws_threadpool_dump(vhd->tp); + lws_sul_schedule(vhd->context, 0, &vhd->sul, + sul_tp_dump, LWS_US_PER_SEC); +} + + static int callback_minimal(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) @@ -159,6 +177,8 @@ callback_minimal(struct lws *wsi, enum lws_callback_reasons reason, if (!vhd) return 1; + vhd->context = lws_get_context(wsi); + /* recover the pointer to the globals struct */ pvo = lws_pvo_search( (const struct lws_protocol_vhost_options *)in, @@ -179,27 +199,14 @@ callback_minimal(struct lws *wsi, enum lws_callback_reasons reason, if (!vhd->tp) return 1; - lws_timed_callback_vh_protocol(lws_get_vhost(wsi), - lws_get_protocol(wsi), - LWS_CALLBACK_USER, 1); - + lws_sul_schedule(vhd->context, 0, &vhd->sul, + sul_tp_dump, LWS_US_PER_SEC); break; case LWS_CALLBACK_PROTOCOL_DESTROY: lws_threadpool_finish(vhd->tp); lws_threadpool_destroy(vhd->tp); - break; - - case LWS_CALLBACK_USER: - - /* - * in debug mode, dump the threadpool stat to the logs once - * a second - */ - lws_threadpool_dump(vhd->tp); - lws_timed_callback_vh_protocol(lws_get_vhost(wsi), - lws_get_protocol(wsi), - LWS_CALLBACK_USER, 1); + lws_sul_cancel(&vhd->sul); break; case LWS_CALLBACK_ESTABLISHED: diff --git a/plugins/protocol_lws_server_status.c b/plugins/protocol_lws_server_status.c index d53e857a1..3bb57b004 100644 --- a/plugins/protocol_lws_server_status.c +++ b/plugins/protocol_lws_server_status.c @@ -47,6 +47,7 @@ struct vhd { struct lws_context *context; struct lws_vhost *vhost; const struct lws_protocols *protocol; + lws_sorted_usec_list_t sul; int hide_vhosts; int tow_flag; int period_s; @@ -58,8 +59,9 @@ struct vhd { static const struct lws_protocols protocols[1]; static void -update(struct vhd *v) +update(struct lws_sorted_usec_list *sul) { + struct vhd *v = lws_container_of(sul, struct vhd, sul); struct lws_ss_filepath *fp; char contents[256], pure[256], *p = v->d.buf + LWS_PRE, *end = v->d.buf + sizeof(v->d.buf) - LWS_PRE - 1; @@ -97,6 +99,8 @@ update(struct vhd *v) v->d.length = p - (v->d.buf + LWS_PRE); lws_callback_on_writable_all_protocol(v->context, &protocols[0]); + + lws_sul_schedule(v->context, 0, &v->sul, update, v->period_s * LWS_US_PER_SEC); } static int @@ -116,12 +120,9 @@ callback_lws_server_status(struct lws *wsi, enum lws_callback_reasons reason, case LWS_CALLBACK_ESTABLISHED: lwsl_info("%s: LWS_CALLBACK_ESTABLISHED\n", __func__); if (!v->clients++) { - lws_timed_callback_vh_protocol(v->vhost, v->protocol, - LWS_CALLBACK_USER, v->period_s); + lws_sul_schedule(lws_get_context(wsi), 0, &v->sul, update, 1); lwsl_info("%s: starting updates\n", __func__); } - update(v); - break; case LWS_CALLBACK_CLOSED: @@ -130,13 +131,6 @@ callback_lws_server_status(struct lws *wsi, enum lws_callback_reasons reason, break; - case LWS_CALLBACK_USER: - update(v); - if (v->clients) - lws_timed_callback_vh_protocol(v->vhost, v->protocol, - LWS_CALLBACK_USER, v->period_s); - break; - case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */ if (v) break; @@ -171,8 +165,7 @@ callback_lws_server_status(struct lws *wsi, enum lws_callback_reasons reason, v->vhost = lws_get_vhost(wsi); v->protocol = lws_get_protocol(wsi); - /* get the initial data */ - update(v); + lws_sul_schedule(lws_get_context(wsi), 0, &v->sul, update, 1); break; case LWS_CALLBACK_PROTOCOL_DESTROY: /* per vhost */