diff --git a/lib/core-net/private-lib-core-net.h b/lib/core-net/private-lib-core-net.h index a688e03b5..c28a29642 100644 --- a/lib/core-net/private-lib-core-net.h +++ b/lib/core-net/private-lib-core-net.h @@ -1447,6 +1447,9 @@ lws_plat_mbedtls_net_send(void *ctx, const uint8_t *buf, size_t len); int lws_plat_mbedtls_net_recv(void *ctx, unsigned char *buf, size_t len); +lws_usec_t +lws_sul_nonmonotonic_adjust(struct lws_context *ctx, int64_t step_us); + enum { LW5CHS_RET_RET0, diff --git a/lib/core-net/sorted-usec-list.c b/lib/core-net/sorted-usec-list.c index 04de59168..895865c56 100644 --- a/lib/core-net/sorted-usec-list.c +++ b/lib/core-net/sorted-usec-list.c @@ -103,7 +103,7 @@ __lws_sul_service_ripe(lws_dll2_owner_t *own, int own_len, lws_usec_t usnow) lws_system_do_attach(pt); /* must be at least 1 */ - assert(own_len); + assert(own_len > 0); /* * Of the own_len sul owning lists, the earliest next sul could be on @@ -154,6 +154,72 @@ __lws_sul_service_ripe(lws_dll2_owner_t *own, int own_len, lws_usec_t usnow) return 0; } +/* + * Normally we use the OS monotonic time, which does not step when the + * gettimeofday() time is adjusted after, eg, ntpclient. But on some OSes, + * high resolution monotonic time doesn't exist; sul time is computed from and + * compared against gettimeofday() time and breaks when that steps. + * + * For those cases, this allows us to retrospectively adjust existing suls on + * all owning lists by the step amount, at the same time we adjust the + * nonmonotonic clock. Then nothing breaks so long as we do this when the + * gettimeofday() clock is stepped. + * + * Linux and so on offer Posix MONOTONIC, which lws uses. FreeRTOS doesn't + * have a high-resolution monotonic clock and has to use gettimeofday(), which + * requires this adjustment when it is stepped. + */ + +lws_usec_t +lws_sul_nonmonotonic_adjust(struct lws_context *ctx, int64_t step_us) +{ + struct lws_context_per_thread *pt = &ctx->pt[0]; + int n, m; + + /* + * for each pt + */ + + for (m = 0; m < ctx->count_threads; m++) { + + /* + * For each owning list... + */ + + lws_pt_lock(pt, __func__); + + for (n = 0; n < LWS_COUNT_PT_SUL_OWNERS; n++) { + + if (!pt->pt_sul_owner[n].count) + continue; + + /* ... and for every existing sul on a list... */ + + lws_start_foreach_dll(struct lws_dll2 *, p, + lws_dll2_get_head( + &pt->pt_sul_owner[n])) { + lws_sorted_usec_list_t *sul = lws_container_of( + p, lws_sorted_usec_list_t, list); + + /* + * ... retrospectively step its ripe time by the + * step we will adjust the gettimeofday() clock + * with + */ + + sul->us += step_us; + + } lws_end_foreach_dll(p); + } + + lws_pt_unlock(pt); + + pt++; + } + + return 0; +} + /* * Earliest wakeable event on any pt */ diff --git a/lib/system/ntpclient/ntpclient.c b/lib/system/ntpclient/ntpclient.c index 012c04196..04e2bad6c 100644 --- a/lib/system/ntpclient/ntpclient.c +++ b/lib/system/ntpclient/ntpclient.c @@ -127,6 +127,8 @@ callback_ntpc(struct lws *wsi, enum lws_callback_reasons reason, void *user, lws_protocol_vh_priv_get(lws_get_vhost(wsi), lws_get_protocol(wsi)); uint8_t pkt[LWS_PRE + 48]; + struct timeval t1; + int64_t delta_us; uint64_t ns; switch (reason) { @@ -224,16 +226,28 @@ do_close: ns = lws_ser_ru32be(((uint8_t *)in) + 40) - 2208988800; ns = (ns * 1000000000) + lws_ser_ru32be(((uint8_t *)in) + 44); - lwsl_notice("%s: Unix time: %llu\n", __func__, - (unsigned long long)ns / 1000000000); + /* + * Compute the step + */ -#if defined(LWS_ESP_PLATFORM) + gettimeofday(&t1, NULL); + + delta_us = (ns / 1000) - + ((t1.tv_sec * LWS_US_PER_SEC) + t1.tv_usec); + + lwsl_notice("%s: Unix time: %llu, step: %lldus\n", __func__, + (unsigned long long)ns / 1000000000, + delta_us); + +#if defined(LWS_PLAT_FREERTOS) { struct timeval t; t.tv_sec = (unsigned long long)ns / 1000000000; t.tv_usec = (ns % 1000000000) / 1000; + lws_sul_nonmonotonic_adjust(wsi->context, delta_us); + settimeofday(&t, NULL); } #endif