From 4df7186945eee9236d59f4bc32e6053d4c686142 Mon Sep 17 00:00:00 2001
From: "Dirk O. Kaar" <dok@dok-net.net>
Date: Fri, 1 Jan 2021 18:51:38 +0100
Subject: [PATCH 01/21] delay0isyield squash commit.

---
 cores/esp8266/Esp.cpp                             |  2 --
 cores/esp8266/PolledTimeout.h                     |  3 ++-
 cores/esp8266/core_esp8266_main.cpp               |  9 +++++++++
 cores/esp8266/core_esp8266_postmortem.cpp         |  6 +++---
 cores/esp8266/core_esp8266_waveform_phase.cpp     |  2 +-
 cores/esp8266/core_esp8266_waveform_pwm.cpp       |  6 +++---
 cores/esp8266/core_esp8266_wiring.cpp             |  5 +----
 cores/esp8266/coredecls.h                         |  1 +
 cores/esp8266/uart.cpp                            | 15 ++++++++-------
 .../ESP8266HTTPClient/src/ESP8266HTTPClient.cpp   |  6 ++++--
 .../src/ESP8266HTTPUpdateServer-impl.h            |  3 ++-
 .../ESP8266WiFi/examples/WiFiScan/WiFiScan.ino    |  2 +-
 libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp  |  8 ++------
 libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp    |  7 ++++---
 libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp      |  5 ++---
 libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp     |  7 +++----
 .../ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp   |  1 -
 libraries/ESP8266WiFi/src/include/ClientContext.h |  7 +++----
 libraries/ESP8266WiFi/src/include/UdpContext.h    |  2 +-
 .../examples/SerialStress/SerialStress.ino        |  2 +-
 tests/host/common/Arduino.cpp                     |  7 +++++++
 tests/host/common/include/ClientContext.h         |  3 ---
 tests/host/common/user_interface.cpp              |  4 ----
 23 files changed, 58 insertions(+), 55 deletions(-)

diff --git a/cores/esp8266/Esp.cpp b/cores/esp8266/Esp.cpp
index 41d0592f31..dba0205164 100644
--- a/cores/esp8266/Esp.cpp
+++ b/cores/esp8266/Esp.cpp
@@ -115,8 +115,6 @@ void EspClass::wdtFeed(void)
     system_soft_wdt_feed();
 }
 
-extern "C" void esp_yield();
-
 void EspClass::deepSleep(uint64_t time_us, WakeMode mode)
 {
     system_deep_sleep_set_option(static_cast<int>(mode));
diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h
index 7eec547e48..a8da626ad5 100644
--- a/cores/esp8266/PolledTimeout.h
+++ b/cores/esp8266/PolledTimeout.h
@@ -27,6 +27,7 @@
 #include <limits>                  // std::numeric_limits
 #include <type_traits>             // std::is_unsigned
 #include <core_esp8266_features.h>
+#include <coredecls.h>
 
 namespace esp8266
 {
@@ -45,7 +46,7 @@ struct DoNothing
 
 struct YieldOrSkip
 {
-  static void execute() {delay(0);}
+  static void execute() {esp_break();}
 };
 
 template <unsigned long delayMs>
diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp
index ff95d08cfb..92472f7997 100644
--- a/cores/esp8266/core_esp8266_main.cpp
+++ b/cores/esp8266/core_esp8266_main.cpp
@@ -128,6 +128,15 @@ extern "C" IRAM_ATTR void esp_schedule() {
     ets_post(LOOP_TASK_PRIORITY, 0, 0);
 }
 
+// Replacement for delay(0). In CONT, same as yield(). Whereas yield() panics
+// in SYS, esp_break() is safe to call and only schedules CONT. Use yield()
+// whereever only called from CONT, use esp_break() if code is called from SYS
+// or both CONT and SYS.
+extern "C" void esp_break() {
+    esp_schedule();
+    esp_yield();
+}
+
 extern "C" void __yield() {
     if (can_yield()) {
         esp_schedule();
diff --git a/cores/esp8266/core_esp8266_postmortem.cpp b/cores/esp8266/core_esp8266_postmortem.cpp
index 3e75342d05..17ac3d7edd 100644
--- a/cores/esp8266/core_esp8266_postmortem.cpp
+++ b/cores/esp8266/core_esp8266_postmortem.cpp
@@ -245,12 +245,12 @@ static void print_stack(uint32_t start, uint32_t end) {
     }
 }
 
-static void uart_write_char_d(char c) {
+static void ICACHE_RAM_ATTR uart_write_char_d(char c) {
     uart0_write_char_d(c);
     uart1_write_char_d(c);
 }
 
-static void uart0_write_char_d(char c) {
+static void ICACHE_RAM_ATTR uart0_write_char_d(char c) {
     while (((USS(0) >> USTXC) & 0xff)) { }
 
     if (c == '\n') {
@@ -259,7 +259,7 @@ static void uart0_write_char_d(char c) {
     USF(0) = c;
 }
 
-static void uart1_write_char_d(char c) {
+static void ICACHE_RAM_ATTR uart1_write_char_d(char c) {
     while (((USS(1) >> USTXC) & 0xff) >= 0x7e) { }
 
     if (c == '\n') {
diff --git a/cores/esp8266/core_esp8266_waveform_phase.cpp b/cores/esp8266/core_esp8266_waveform_phase.cpp
index de2f914121..873dadede0 100644
--- a/cores/esp8266/core_esp8266_waveform_phase.cpp
+++ b/cores/esp8266/core_esp8266_waveform_phase.cpp
@@ -211,7 +211,7 @@ int startWaveformClockCycles_weak(uint8_t pin, uint32_t highCcys, uint32_t lowCc
   }
   std::atomic_thread_fence(std::memory_order_acq_rel);
   while (waveform.toSetBits) {
-    delay(0); // Wait for waveform to update
+    yield(); // Wait for waveform to update
     std::atomic_thread_fence(std::memory_order_acquire);
   }
   return true;
diff --git a/cores/esp8266/core_esp8266_waveform_pwm.cpp b/cores/esp8266/core_esp8266_waveform_pwm.cpp
index 916361e2ca..9ee80ffcc7 100644
--- a/cores/esp8266/core_esp8266_waveform_pwm.cpp
+++ b/cores/esp8266/core_esp8266_waveform_pwm.cpp
@@ -162,7 +162,7 @@ static IRAM_ATTR void _notifyPWM(PWMState *p, bool idle) {
   forceTimerInterrupt();
   while (pwmState.pwmUpdate) {
     if (idle) {
-      delay(0);
+      yield();
     }
     MEMBARRIER();
   }
@@ -372,7 +372,7 @@ int startWaveformClockCycles_weak(uint8_t pin, uint32_t timeHighCycles, uint32_t
   if (wvfState.waveformEnabled & mask) {
     // Make sure no waveform changes are waiting to be applied
     while (wvfState.waveformToChange) {
-      delay(0); // Wait for waveform to update
+      yield(); // Wait for waveform to update
       // No mem barrier here, the call to a global function implies global state updated
     }
     wvfState.waveformNewHigh = timeHighCycles;
@@ -392,7 +392,7 @@ int startWaveformClockCycles_weak(uint8_t pin, uint32_t timeHighCycles, uint32_t
     initTimer();
     forceTimerInterrupt();
     while (wvfState.waveformToEnable) {
-      delay(0); // Wait for waveform to update
+      yield(); // Wait for waveform to update
       // No mem barrier here, the call to a global function implies global state updated
     }
   }
diff --git a/cores/esp8266/core_esp8266_wiring.cpp b/cores/esp8266/core_esp8266_wiring.cpp
index b956cebe43..b11d14a1d8 100644
--- a/cores/esp8266/core_esp8266_wiring.cpp
+++ b/cores/esp8266/core_esp8266_wiring.cpp
@@ -24,13 +24,10 @@
 #include "osapi.h"
 #include "user_interface.h"
 #include "cont.h"
+#include "coredecls.h"
 
 extern "C" {
 
-extern void ets_delay_us(uint32_t us);
-extern void esp_schedule();
-extern void esp_yield();
-
 static os_timer_t delay_timer;
 static os_timer_t micros_overflow_timer;
 static uint32_t micros_at_last_overflow_tick = 0;
diff --git a/cores/esp8266/coredecls.h b/cores/esp8266/coredecls.h
index b9c771df77..9f7fff2d07 100644
--- a/cores/esp8266/coredecls.h
+++ b/cores/esp8266/coredecls.h
@@ -15,6 +15,7 @@ extern "C" {
 bool can_yield();
 void esp_yield();
 void esp_schedule();
+void esp_break();
 void tune_timeshift64 (uint64_t now_us);
 void disable_extra4k_at_link_time (void) __attribute__((noinline));
 bool sntp_set_timezone_in_seconds(int32_t timezone);
diff --git a/cores/esp8266/uart.cpp b/cores/esp8266/uart.cpp
index de574d0bee..80e0cbffd0 100644
--- a/cores/esp8266/uart.cpp
+++ b/cores/esp8266/uart.cpp
@@ -41,6 +41,7 @@
  *
  */
 #include "Arduino.h"
+#include "coredecls.h"
 #include <pgmspace.h>
 #include "gdb_hooks.h"
 #include "uart.h"
@@ -493,13 +494,13 @@ uart_stop_isr(uart_t* uart)
   -tools/sdk/uart_register.h
   -cores/esp8266/esp8266_peri.h
   */
-inline size_t
+inline __attribute__((always_inline)) size_t
 uart_tx_fifo_available(const int uart_nr)
 {
     return (USS(uart_nr) >> USTXC) & 0xff;
 }
 
-inline bool
+inline __attribute__((always_inline)) bool
 uart_tx_fifo_full(const int uart_nr)
 {
     return uart_tx_fifo_available(uart_nr) >= 0x7f;
@@ -566,7 +567,7 @@ uart_wait_tx_empty(uart_t* uart)
         return;
 
     while(uart_tx_fifo_available(uart->uart_nr) > 0)
-        delay(0);
+        esp_break();
 
 }
 
@@ -943,23 +944,23 @@ uart_ignore_char(char c)
     (void) c;
 }
 
-inline void
+inline __attribute__((always_inline)) void
 uart_write_char_delay(const int uart_nr, char c)
 {
     while(uart_tx_fifo_full(uart_nr))
-        delay(0);
+        esp_break();
 
     USF(uart_nr) = c;
 
 }
 
-static void
+static void ICACHE_RAM_ATTR
 uart0_write_char(char c)
 {
     uart_write_char_delay(0, c);
 }
 
-static void
+static void ICACHE_RAM_ATTR
 uart1_write_char(char c)
 {
     uart_write_char_delay(1, c);
diff --git a/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.cpp b/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.cpp
index b98edcccc0..7be96030da 100644
--- a/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.cpp
+++ b/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.cpp
@@ -22,6 +22,7 @@
  *
  */
 #include <Arduino.h>
+#include <coredecls.h>
 
 #include "ESP8266HTTPClient.h"
 #include <ESP8266WiFi.h>
@@ -567,6 +568,7 @@ int HTTPClient::sendRequest(const char * type, Stream * stream, size_t size)
     if (transferred != size)
     {
         DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] short write, asked for %d but got %d failed.\n", size, transferred);
+        esp_break();
         return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
     }
 
@@ -709,7 +711,7 @@ int HTTPClient::writeToPrint(Print * print)
                 return returnError(HTTPC_ERROR_READ_TIMEOUT);
             }
 
-            delay(0);
+            esp_break();
         }
     } else {
         return returnError(HTTPC_ERROR_ENCODING);
@@ -1074,7 +1076,7 @@ int HTTPClient::handleHeaderResponse()
             if((millis() - lastDataTime) > _tcpTimeout) {
                 return HTTPC_ERROR_READ_TIMEOUT;
             }
-            delay(0);
+            esp_break();
         }
     }
 
diff --git a/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer-impl.h b/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer-impl.h
index 3357f2ac63..303e5963d9 100644
--- a/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer-impl.h
+++ b/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer-impl.h
@@ -1,4 +1,5 @@
 #include <Arduino.h>
+#include <coredecls.h>
 #include <WiFiClient.h>
 #include <WiFiServer.h>
 #include <ESP8266WebServer.h>
@@ -119,7 +120,7 @@ void ESP8266HTTPUpdateServerTemplate<ServerType>::setup(ESP8266WebServerTemplate
         Update.end();
         if (_serial_output) Serial.println("Update was aborted");
       }
-      delay(0);
+      esp_break();
     });
 }
 
diff --git a/libraries/ESP8266WiFi/examples/WiFiScan/WiFiScan.ino b/libraries/ESP8266WiFi/examples/WiFiScan/WiFiScan.ino
index 84a9befcf2..b546df4a7d 100644
--- a/libraries/ESP8266WiFi/examples/WiFiScan/WiFiScan.ino
+++ b/libraries/ESP8266WiFi/examples/WiFiScan/WiFiScan.ino
@@ -49,7 +49,7 @@ void loop() {
                     (encryptionType == ENC_TYPE_NONE) ? ' ' : '*',
                     hidden ? 'H' : 'V',
                     ssid.c_str());
-      delay(0);
+      yield();
     }
   } else {
     Serial.printf(PSTR("WiFi scan error %d"), scanResult);
diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp
index 19da592c76..37f80e56b6 100644
--- a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp
+++ b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp
@@ -49,10 +49,6 @@ extern "C" {
 #include "debug.h"
 #include "include/WiFiState.h"
 
-extern "C" void esp_schedule();
-extern "C" void esp_yield();
-
-
 // -----------------------------------------------------------------------------------------------------------------------
 // ------------------------------------------------- Generic WiFi function -----------------------------------------------
 // -----------------------------------------------------------------------------------------------------------------------
@@ -518,9 +514,9 @@ bool ESP8266WiFiGenericClass::forceSleepBegin(uint32 sleepUs) {
     }
 
     wifi_fpm_set_sleep_type(MODEM_SLEEP_T);
-    delay(0);
+    esp_break();
     wifi_fpm_open();
-    delay(0);
+    esp_break();
     auto ret = wifi_fpm_do_sleep(sleepUs);
     if (ret != 0)
     {
diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp
index 8d74f687cb..788c8eee1b 100644
--- a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp
+++ b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp
@@ -25,6 +25,7 @@
 
 #include "PolledTimeout.h"
 #include "ESP8266WiFiMulti.h"
+#include <coredecls.h>
 #include <limits.h>
 #include <string.h>
 
@@ -91,7 +92,7 @@ static wl_status_t waitWiFiConnect(uint32_t connectTimeoutMs)
     // Wait for WiFi status change or timeout
     do {
         // Refresh watchdog
-        delay(0);
+        esp_break();
 
         // Get WiFi status
         status = WiFi.status();
@@ -249,7 +250,7 @@ int8_t ESP8266WiFiMulti::startScan()
     // Wait for WiFi scan change or timeout
     do {
         // Refresh watchdog
-        delay(0);
+        esp_break();
 
         // Check scan timeout which may occur when scan does not report completion
         if (scanTimeout) {
@@ -535,7 +536,7 @@ void ESP8266WiFiMulti::printWiFiScan()
                          rssi,
                          (encryptionType == ENC_TYPE_NONE) ? ' ' : '*',
                          ssid.c_str());
-        delay(0);
+        esp_break();
     }
 #endif
 }
diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp
index 618dbfcc86..c1c63996aa 100644
--- a/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp
+++ b/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp
@@ -28,6 +28,8 @@
 #include "PolledTimeout.h"
 #include "LwipIntf.h"
 
+#include <coredecls.h>
+
 #include "c_types.h"
 #include "ets_sys.h"
 #include "os_type.h"
@@ -44,9 +46,6 @@ extern "C" {
 
 #include "debug.h"
 
-extern "C" void esp_schedule();
-extern "C" void esp_yield();
-
 // -----------------------------------------------------------------------------------------------------------------------
 // ---------------------------------------------------- Private functions ------------------------------------------------
 // -----------------------------------------------------------------------------------------------------------------------
diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp
index 65878a3d5b..ae9b8e3c66 100644
--- a/libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp
+++ b/libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp
@@ -26,6 +26,8 @@
 #include "ESP8266WiFiGeneric.h"
 #include "ESP8266WiFiScan.h"
 
+#include <coredecls.h>
+
 extern "C" {
 #include "c_types.h"
 #include "ets_sys.h"
@@ -37,9 +39,6 @@ extern "C" {
 
 #include "debug.h"
 
-extern "C" void esp_schedule();
-extern "C" void esp_yield();
-
 // -----------------------------------------------------------------------------------------------------------------------
 // ---------------------------------------------------- Private functions ------------------------------------------------
 // -----------------------------------------------------------------------------------------------------------------------
@@ -94,7 +93,7 @@ int8_t ESP8266WiFiScanClass::scanNetworks(bool async, bool show_hidden, uint8 ch
         ESP8266WiFiScanClass::_scanStarted = true;
 
         if(ESP8266WiFiScanClass::_scanAsync) {
-            delay(0); // time for the OS to trigger the scan
+            esp_break(); // time for the OS to trigger the scan
             return WIFI_SCAN_RUNNING;
         }
 
diff --git a/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp b/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp
index 6a82ff3b96..9ad357c33a 100644
--- a/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp
+++ b/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp
@@ -44,7 +44,6 @@ extern "C" {
 #include "lwip/netif.h"
 #include <include/ClientContext.h>
 #include "c_types.h"
-#include "coredecls.h"
 #include <mmu_iram.h>
 #include <umm_malloc/umm_malloc.h>
 #include <umm_malloc/umm_heap_select.h>
diff --git a/libraries/ESP8266WiFi/src/include/ClientContext.h b/libraries/ESP8266WiFi/src/include/ClientContext.h
index a994b5cb1d..4fb557456f 100644
--- a/libraries/ESP8266WiFi/src/include/ClientContext.h
+++ b/libraries/ESP8266WiFi/src/include/ClientContext.h
@@ -26,12 +26,11 @@ class WiFiClient;
 
 typedef void (*discard_cb_t)(void*, ClientContext*);
 
-extern "C" void esp_yield();
-extern "C" void esp_schedule();
-
 #include <assert.h>
 #include <esp_priv.h>
 
+#include <coredecls.h>
+
 bool getDefaultPrivateGlobalSyncValue ();
 
 class ClientContext
@@ -352,7 +351,7 @@ class ClientContext
                 last_sent = millis();
             }
 
-            delay(0); // from sys or os context
+            esp_break(); // from sys or os context
 
             if ((state() != ESTABLISHED) || (sndbuf == TCP_SND_BUF)) {
                 // peer has closed or all bytes are sent and acked
diff --git a/libraries/ESP8266WiFi/src/include/UdpContext.h b/libraries/ESP8266WiFi/src/include/UdpContext.h
index 1d3c6e418c..b444de3551 100644
--- a/libraries/ESP8266WiFi/src/include/UdpContext.h
+++ b/libraries/ESP8266WiFi/src/include/UdpContext.h
@@ -411,7 +411,7 @@ class UdpContext
         err_t err;
         esp8266::polledTimeout::oneShotFastMs timeout(timeoutMs);
         while (((err = trySend(addr, port, /* keep buffer on error */true)) != ERR_OK) && !timeout)
-            delay(0);
+            esp_break();
         if (err != ERR_OK)
             cancelBuffer(); // get rid of buffer kept on error after timeout
         return err == ERR_OK;
diff --git a/libraries/esp8266/examples/SerialStress/SerialStress.ino b/libraries/esp8266/examples/SerialStress/SerialStress.ino
index b06b38e307..a19eb9f270 100644
--- a/libraries/esp8266/examples/SerialStress/SerialStress.ino
+++ b/libraries/esp8266/examples/SerialStress/SerialStress.ino
@@ -122,7 +122,7 @@ void loop() {
   if ((out_idx += local_written_size) == BUFFER_SIZE) {
     out_idx = 0;
   }
-  delay(0);
+  yield();
 
   DEBUG(logger->printf("----------\n"));
 
diff --git a/tests/host/common/Arduino.cpp b/tests/host/common/Arduino.cpp
index 780c4adc14..c80d9bb34b 100644
--- a/tests/host/common/Arduino.cpp
+++ b/tests/host/common/Arduino.cpp
@@ -57,6 +57,13 @@ extern "C" void esp_yield()
 {
 }
 
+extern "C" void esp_schedule ()
+{
+}
+
+extern "C" void esp_break ()
+{
+}
 
 extern "C" void __panic_func(const char* file, int line, const char* func) {
     (void)file;
diff --git a/tests/host/common/include/ClientContext.h b/tests/host/common/include/ClientContext.h
index 744d7872d4..bd9c9b80a5 100644
--- a/tests/host/common/include/ClientContext.h
+++ b/tests/host/common/include/ClientContext.h
@@ -24,9 +24,6 @@
 class ClientContext;
 class WiFiClient;
 
-extern "C" void esp_yield();
-extern "C" void esp_schedule();
-
 #include <assert.h>
 
 bool getDefaultPrivateGlobalSyncValue ();
diff --git a/tests/host/common/user_interface.cpp b/tests/host/common/user_interface.cpp
index b3a302df18..4e03d77786 100644
--- a/tests/host/common/user_interface.cpp
+++ b/tests/host/common/user_interface.cpp
@@ -498,10 +498,6 @@ extern "C"
         (void)intr;
     }
 
-    void esp_schedule(void)
-    {
-    }
-
     void dns_setserver(u8_t numdns, ip_addr_t *dnsserver)
     {
         (void)numdns;

From b64622d303d10261c20fbb494cbcf095d2225946 Mon Sep 17 00:00:00 2001
From: "Dirk O. Kaar" <dok@dok-net.net>
Date: Sun, 10 Jan 2021 13:21:47 +0100
Subject: [PATCH 02/21] _notifyPWM may be called indirectly from ISR, cannot
 yield() from ISR, must not panic.

---
 cores/esp8266/core_esp8266_waveform_pwm.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/cores/esp8266/core_esp8266_waveform_pwm.cpp b/cores/esp8266/core_esp8266_waveform_pwm.cpp
index 9ee80ffcc7..0ba024e334 100644
--- a/cores/esp8266/core_esp8266_waveform_pwm.cpp
+++ b/cores/esp8266/core_esp8266_waveform_pwm.cpp
@@ -40,6 +40,7 @@
 
 
 #include <Arduino.h>
+#include <coredecls.h>
 #include "ets_sys.h"
 #include "core_esp8266_waveform.h"
 #include "user_interface.h"
@@ -162,7 +163,7 @@ static IRAM_ATTR void _notifyPWM(PWMState *p, bool idle) {
   forceTimerInterrupt();
   while (pwmState.pwmUpdate) {
     if (idle) {
-      yield();
+      esp_break();
     }
     MEMBARRIER();
   }

From 9bb489466e83c3b24fb219549379b4f704759622 Mon Sep 17 00:00:00 2001
From: "Dirk O. Kaar" <dok@dok-net.net>
Date: Mon, 15 Mar 2021 10:33:20 +0100
Subject: [PATCH 03/21] Fix for 656a33e6f8

---
 cores/esp8266/core_esp8266_postmortem.cpp | 6 +++---
 cores/esp8266/uart.cpp                    | 4 ++--
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/cores/esp8266/core_esp8266_postmortem.cpp b/cores/esp8266/core_esp8266_postmortem.cpp
index 17ac3d7edd..2279401b54 100644
--- a/cores/esp8266/core_esp8266_postmortem.cpp
+++ b/cores/esp8266/core_esp8266_postmortem.cpp
@@ -245,12 +245,12 @@ static void print_stack(uint32_t start, uint32_t end) {
     }
 }
 
-static void ICACHE_RAM_ATTR uart_write_char_d(char c) {
+static void IRAM_ATTR uart_write_char_d(char c) {
     uart0_write_char_d(c);
     uart1_write_char_d(c);
 }
 
-static void ICACHE_RAM_ATTR uart0_write_char_d(char c) {
+static void IRAM_ATTR uart0_write_char_d(char c) {
     while (((USS(0) >> USTXC) & 0xff)) { }
 
     if (c == '\n') {
@@ -259,7 +259,7 @@ static void ICACHE_RAM_ATTR uart0_write_char_d(char c) {
     USF(0) = c;
 }
 
-static void ICACHE_RAM_ATTR uart1_write_char_d(char c) {
+static void IRAM_ATTR uart1_write_char_d(char c) {
     while (((USS(1) >> USTXC) & 0xff) >= 0x7e) { }
 
     if (c == '\n') {
diff --git a/cores/esp8266/uart.cpp b/cores/esp8266/uart.cpp
index 80e0cbffd0..2e7251c841 100644
--- a/cores/esp8266/uart.cpp
+++ b/cores/esp8266/uart.cpp
@@ -954,13 +954,13 @@ uart_write_char_delay(const int uart_nr, char c)
 
 }
 
-static void ICACHE_RAM_ATTR
+static void IRAM_ATTR
 uart0_write_char(char c)
 {
     uart_write_char_delay(0, c);
 }
 
-static void ICACHE_RAM_ATTR
+static void IRAM_ATTR
 uart1_write_char(char c)
 {
     uart_write_char_delay(1, c);

From 97d59aea115410b4f23731fb88c1b2efbb3e5dd2 Mon Sep 17 00:00:00 2001
From: "Dirk O. Kaar" <dok@dok-net.net>
Date: Thu, 8 Apr 2021 12:14:20 +0200
Subject: [PATCH 04/21] Consolidate renaming of identifiers to clarify strict
 meaning of suspend vs. yield

---
 cores/esp8266/Esp.cpp                         |  6 ++--
 cores/esp8266/PolledTimeout.h                 |  2 +-
 cores/esp8266/Schedule.cpp                    | 10 +++---
 cores/esp8266/cont.S                          | 20 +++++------
 cores/esp8266/cont.h                          | 12 +++----
 cores/esp8266/cont_util.cpp                   |  4 +--
 cores/esp8266/core_esp8266_main.cpp           | 36 +++++++++----------
 cores/esp8266/core_esp8266_waveform_pwm.cpp   |  2 +-
 cores/esp8266/core_esp8266_wiring.cpp         |  2 +-
 cores/esp8266/coredecls.h                     |  4 +--
 cores/esp8266/hwdt_app_entry.cpp              |  8 ++---
 cores/esp8266/uart.cpp                        |  4 +--
 .../src/ESP8266HTTPClient.cpp                 |  6 ++--
 .../src/ESP8266HTTPUpdateServer-impl.h        |  2 +-
 .../ESP8266WiFi/src/ESP8266WiFiGeneric.cpp    |  4 +--
 .../ESP8266WiFi/src/ESP8266WiFiMulti.cpp      |  6 ++--
 .../ESP8266WiFi/src/ESP8266WiFiSTA-WPS.cpp    |  2 +-
 libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp |  4 +--
 .../ESP8266WiFi/src/include/ClientContext.h   |  2 +-
 .../ESP8266WiFi/src/include/UdpContext.h      |  6 ++--
 libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp |  4 +--
 tests/host/common/Arduino.cpp                 |  8 ++---
 22 files changed, 78 insertions(+), 76 deletions(-)

diff --git a/cores/esp8266/Esp.cpp b/cores/esp8266/Esp.cpp
index dba0205164..2ee4a65b5e 100644
--- a/cores/esp8266/Esp.cpp
+++ b/cores/esp8266/Esp.cpp
@@ -119,14 +119,14 @@ void EspClass::deepSleep(uint64_t time_us, WakeMode mode)
 {
     system_deep_sleep_set_option(static_cast<int>(mode));
     system_deep_sleep(time_us);
-    esp_yield();
+    esp_suspend();
 }
 
 void EspClass::deepSleepInstant(uint64_t time_us, WakeMode mode)
 {
     system_deep_sleep_set_option(static_cast<int>(mode));
     system_deep_sleep_instant(time_us);
-    esp_yield();
+    esp_suspend();
 }
 
 //this calculation was taken verbatim from the SDK api reference for SDK 2.1.0.
@@ -198,7 +198,7 @@ void EspClass::reset(void)
 void EspClass::restart(void)
 {
     system_restart();
-    esp_yield();
+    esp_suspend();
 }
 
 [[noreturn]] void EspClass::rebootIntoUartDownloadMode()
diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h
index a8da626ad5..1252ce6c29 100644
--- a/cores/esp8266/PolledTimeout.h
+++ b/cores/esp8266/PolledTimeout.h
@@ -46,7 +46,7 @@ struct DoNothing
 
 struct YieldOrSkip
 {
-  static void execute() {esp_break();}
+  static void execute() {esp_yield();}
 };
 
 template <unsigned long delayMs>
diff --git a/cores/esp8266/Schedule.cpp b/cores/esp8266/Schedule.cpp
index b1230ed675..baef3e9601 100644
--- a/cores/esp8266/Schedule.cpp
+++ b/cores/esp8266/Schedule.cpp
@@ -164,9 +164,10 @@ void run_scheduled_functions()
         if (yieldNow)
         {
             // because scheduled functions might last too long for watchdog etc,
-            // this is yield() in cont stack:
+            // this is yield() in cont stack, but need to call cont_suspend directly
+            // to prevent recursion into run_scheduled_recurrent_functions()
             esp_schedule();
-            cont_yield(g_pcont);
+            cont_suspend(g_pcont);
         }
     }
 }
@@ -241,9 +242,10 @@ void run_scheduled_recurrent_functions()
         if (yieldNow)
         {
             // because scheduled functions might last too long for watchdog etc,
-            // this is yield() in cont stack:
+            // this is yield() in cont stack, but need to call cont_suspend directly
+            // to prevent recursion into run_scheduled_recurrent_functions()
             esp_schedule();
-            cont_yield(g_pcont);
+            cont_suspend(g_pcont);
         }
     } while (current && !done);
 
diff --git a/cores/esp8266/cont.S b/cores/esp8266/cont.S
index 00ca017785..4832b39170 100644
--- a/cores/esp8266/cont.S
+++ b/cores/esp8266/cont.S
@@ -21,9 +21,9 @@
     .section .irom0.text
     .align    4
     .literal_position
-    .global   cont_yield
-    .type     cont_yield, @function
-cont_yield:
+    .global   cont_suspend
+    .type     cont_suspend, @function
+cont_suspend:
     /* a1: sp */
     /* a2: void* cont_ctx */
     /* adjust stack and save registers */
@@ -35,10 +35,10 @@ cont_yield:
     s32i    a0,  a1, 16
     s32i    a2,  a1, 20
 
-    /* &cont_continue -> cont_ctx.pc_yield */
+    /* &cont_continue -> cont_ctx.pc_suspend */
     movi    a3, cont_continue
     s32i    a3, a2, 8
-    /* sp -> cont_ctx.sp_yield */
+    /* sp -> cont_ctx.sp_suspend */
     s32i    a1, a2, 12
 
     /* a0 <- cont_ctx.pc_ret */
@@ -56,7 +56,7 @@ cont_continue:
     l32i    a2,  a1, 20
     addi    a1,  a1, 24
     ret
-    .size    cont_yield, . - cont_yield
+    .size    cont_suspend, . - cont_suspend
 
 ////////////////////////////////////////////////////
 
@@ -108,7 +108,7 @@ cont_run:
     /* sp -> cont_ctx.sp_ret */
     s32i    a1, a2, 4
 
-    /* if cont_ctx.pc_yield != 0, goto cont_resume */
+    /* if cont_ctx.pc_suspend != 0, goto cont_resume */
     l32i    a4, a2, 8
     bnez    a4, cont_resume
     /* else */
@@ -119,12 +119,12 @@ cont_run:
     jx      a2
 
 cont_resume:
-    /* a1 <- cont_ctx.sp_yield */
+    /* a1 <- cont_ctx.sp_suspend */
     l32i    a1, a2, 12
-    /* reset yield flag, 0 -> cont_ctx.pc_yield */
+    /* reset yield flag, 0 -> cont_ctx.pc_suspend */
     movi    a3, 0
     s32i    a3, a2, 8
-    /* jump to saved cont_ctx.pc_yield */
+    /* jump to saved cont_ctx.pc_suspend */
     movi    a0, cont_ret
     jx       a4
 
diff --git a/cores/esp8266/cont.h b/cores/esp8266/cont.h
index 21ecad2806..6932416b68 100644
--- a/cores/esp8266/cont.h
+++ b/cores/esp8266/cont.h
@@ -35,8 +35,8 @@ typedef struct cont_ {
         void (*pc_ret)(void);
         unsigned* sp_ret;
 
-        void (*pc_yield)(void);
-        unsigned* sp_yield;
+        void (*pc_suspend)(void);
+        unsigned* sp_suspend;
 
         unsigned* stack_end;
         unsigned unused1;
@@ -55,12 +55,12 @@ extern cont_t* g_pcont;
 void cont_init(cont_t*);
 
 // Run function pfn in a separate stack, or continue execution
-// at the point where cont_yield was called
+// at the point where cont_suspend was called
 void cont_run(cont_t*, void (*pfn)(void));
 
 // Return to the point where cont_run was called, saving the
 // execution state (registers and stack)
-void cont_yield(cont_t*);
+void cont_suspend(cont_t*);
 
 // Check guard bytes around the stack. Return 0 in case everything is ok,
 // return 1 if guard bytes were overwritten.
@@ -70,9 +70,9 @@ int cont_check(cont_t* cont);
 // and thus weren't used by the user code. i.e. that stack space is free. (high water mark)
 int cont_get_free_stack(cont_t* cont);
 
-// Check if yield() may be called. Returns true if we are running inside
+// Check if cont_suspend() may be called. Returns true if we are running inside
 // continuation stack
-bool cont_can_yield(cont_t* cont);
+bool cont_can_suspend(cont_t* cont);
 
 // Repaint the stack from the current SP to the end, to allow individual
 // routines' stack usages to be calculated by re-painting, checking current
diff --git a/cores/esp8266/cont_util.cpp b/cores/esp8266/cont_util.cpp
index 8fa4421802..fd72ee5d18 100644
--- a/cores/esp8266/cont_util.cpp
+++ b/cores/esp8266/cont_util.cpp
@@ -62,9 +62,9 @@ int cont_get_free_stack(cont_t* cont) {
     return freeWords * 4;
 }
 
-bool IRAM_ATTR cont_can_yield(cont_t* cont) {
+bool IRAM_ATTR cont_can_suspend(cont_t* cont) {
     return !ETS_INTR_WITHINISR() &&
-           cont->pc_ret != 0 && cont->pc_yield == 0;
+           cont->pc_ret != 0 && cont->pc_suspend == 0;
 }
 
 // No need for this to be in IRAM, not expected to be IRQ called
diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp
index 92472f7997..5a471c79be 100644
--- a/cores/esp8266/core_esp8266_main.cpp
+++ b/cores/esp8266/core_esp8266_main.cpp
@@ -62,7 +62,7 @@ cont_t* g_pcont __attribute__((section(".noinit")));
 static os_event_t s_loop_queue[LOOP_QUEUE_SIZE];
 
 /* Used to implement optimistic_yield */
-static uint32_t s_cycles_at_yield_start;
+static uint32_t s_cycles_at_resume;
 
 /* For ets_intr_lock_nest / ets_intr_unlock_nest
  * Max nesting seen by SDK so far is 2.
@@ -106,41 +106,41 @@ extern "C" void __preloop_update_frequency() {
 extern "C" void preloop_update_frequency() __attribute__((weak, alias("__preloop_update_frequency")));
 
 extern "C" bool can_yield() {
-  return cont_can_yield(g_pcont);
+  return cont_can_suspend(g_pcont);
 }
 
-static inline void esp_yield_within_cont() __attribute__((always_inline));
-static void esp_yield_within_cont() {
-        cont_yield(g_pcont);
-        s_cycles_at_yield_start = ESP.getCycleCount();
+static inline void esp_suspend_within_cont() __attribute__((always_inline));
+static void esp_suspend_within_cont() {
+        cont_suspend(g_pcont);
+        s_cycles_at_resume = ESP.getCycleCount();
         run_scheduled_recurrent_functions();
 }
 
-extern "C" void __esp_yield() {
-    if (can_yield()) {
-        esp_yield_within_cont();
+extern "C" void __esp_suspend() {
+    if (cont_can_suspend(g_pcont)) {
+        esp_suspend_within_cont();
     }
 }
 
-extern "C" void esp_yield() __attribute__ ((weak, alias("__esp_yield")));
+extern "C" void esp_suspend() __attribute__ ((weak, alias("__esp_suspend")));
 
 extern "C" IRAM_ATTR void esp_schedule() {
     ets_post(LOOP_TASK_PRIORITY, 0, 0);
 }
 
 // Replacement for delay(0). In CONT, same as yield(). Whereas yield() panics
-// in SYS, esp_break() is safe to call and only schedules CONT. Use yield()
-// whereever only called from CONT, use esp_break() if code is called from SYS
+// in SYS, esp_yield() is safe to call and only schedules CONT. Use yield()
+// whereever only called from CONT, use esp_yield() if code is called from SYS
 // or both CONT and SYS.
-extern "C" void esp_break() {
+extern "C" void esp_yield() {
     esp_schedule();
-    esp_yield();
+    esp_suspend();
 }
 
 extern "C" void __yield() {
-    if (can_yield()) {
+    if (cont_can_suspend(g_pcont)) {
         esp_schedule();
-        esp_yield_within_cont();
+        esp_suspend_within_cont();
     }
     else {
         panic();
@@ -156,7 +156,7 @@ extern "C" void optimistic_yield(uint32_t interval_us) {
 #else
         ESP.getCpuFreqMHz();
 #endif
-    if ((ESP.getCycleCount() - s_cycles_at_yield_start) > intvl_cycles &&
+    if ((ESP.getCycleCount() - s_cycles_at_resume) > intvl_cycles &&
         can_yield())
     {
         yield();
@@ -216,7 +216,7 @@ static void loop_wrapper() {
 
 static void loop_task(os_event_t *events) {
     (void) events;
-    s_cycles_at_yield_start = ESP.getCycleCount();
+    s_cycles_at_resume = ESP.getCycleCount();
     ESP.resetHeap();
     cont_run(g_pcont, &loop_wrapper);
     ESP.setDramHeap();
diff --git a/cores/esp8266/core_esp8266_waveform_pwm.cpp b/cores/esp8266/core_esp8266_waveform_pwm.cpp
index 0ba024e334..65e75a0c71 100644
--- a/cores/esp8266/core_esp8266_waveform_pwm.cpp
+++ b/cores/esp8266/core_esp8266_waveform_pwm.cpp
@@ -163,7 +163,7 @@ static IRAM_ATTR void _notifyPWM(PWMState *p, bool idle) {
   forceTimerInterrupt();
   while (pwmState.pwmUpdate) {
     if (idle) {
-      esp_break();
+      esp_yield();
     }
     MEMBARRIER();
   }
diff --git a/cores/esp8266/core_esp8266_wiring.cpp b/cores/esp8266/core_esp8266_wiring.cpp
index b11d14a1d8..65a9a6aecc 100644
--- a/cores/esp8266/core_esp8266_wiring.cpp
+++ b/cores/esp8266/core_esp8266_wiring.cpp
@@ -47,7 +47,7 @@ void __delay(unsigned long ms) {
     } else {
         esp_schedule();
     }
-    esp_yield();
+    esp_suspend();
     if(ms) {
         os_timer_disarm(&delay_timer);
     }
diff --git a/cores/esp8266/coredecls.h b/cores/esp8266/coredecls.h
index 9f7fff2d07..7268016a9f 100644
--- a/cores/esp8266/coredecls.h
+++ b/cores/esp8266/coredecls.h
@@ -13,9 +13,9 @@ extern "C" {
 #include <cont.h> // g_pcont declaration
 
 bool can_yield();
-void esp_yield();
+void esp_suspend();
 void esp_schedule();
-void esp_break();
+void esp_yield();
 void tune_timeshift64 (uint64_t now_us);
 void disable_extra4k_at_link_time (void) __attribute__((noinline));
 bool sntp_set_timezone_in_seconds(int32_t timezone);
diff --git a/cores/esp8266/hwdt_app_entry.cpp b/cores/esp8266/hwdt_app_entry.cpp
index 3a657cfcd9..22a91a6bee 100644
--- a/cores/esp8266/hwdt_app_entry.cpp
+++ b/cores/esp8266/hwdt_app_entry.cpp
@@ -952,13 +952,13 @@ STATIC void IRAM_MAYBE handle_hwdt(void) {
                 /* Print separate ctx: cont stack */
 
                 /* Check if cont stack is yielding to SYS */
-                if (0 == hwdt_info.cont_integrity && 0 != g_pcont->pc_yield) {
-                    ctx_cont_ptr = (const uint32_t *)((uintptr_t)g_pcont->sp_yield - 8u);
+                if (0 == hwdt_info.cont_integrity && 0 != g_pcont->pc_suspend) {
+                    ctx_cont_ptr = (const uint32_t *)((uintptr_t)g_pcont->sp_suspend - 8u);
                 }
                 print_stack((uintptr_t)ctx_cont_ptr, (uintptr_t)g_pcont->stack_end, PRINT_STACK::CONT);
             } else {
-                if (0 == hwdt_info.cont_integrity && 0 != g_pcont->pc_yield) {
-                    ETS_PRINTF("\nCont stack is yielding. Active stack starts at 0x%08X.\n", (uint32_t)g_pcont->sp_yield - 8u);
+                if (0 == hwdt_info.cont_integrity && 0 != g_pcont->pc_suspend) {
+                    ETS_PRINTF("\nCont stack is yielding. Active stack starts at 0x%08X.\n", (uint32_t)g_pcont->sp_suspend - 8u);
                 }
             }
 
diff --git a/cores/esp8266/uart.cpp b/cores/esp8266/uart.cpp
index 2e7251c841..1f657c9403 100644
--- a/cores/esp8266/uart.cpp
+++ b/cores/esp8266/uart.cpp
@@ -567,7 +567,7 @@ uart_wait_tx_empty(uart_t* uart)
         return;
 
     while(uart_tx_fifo_available(uart->uart_nr) > 0)
-        esp_break();
+        esp_yield();
 
 }
 
@@ -948,7 +948,7 @@ inline __attribute__((always_inline)) void
 uart_write_char_delay(const int uart_nr, char c)
 {
     while(uart_tx_fifo_full(uart_nr))
-        esp_break();
+        esp_yield();
 
     USF(uart_nr) = c;
 
diff --git a/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.cpp b/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.cpp
index 7be96030da..195ade0274 100644
--- a/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.cpp
+++ b/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.cpp
@@ -568,7 +568,7 @@ int HTTPClient::sendRequest(const char * type, Stream * stream, size_t size)
     if (transferred != size)
     {
         DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] short write, asked for %d but got %d failed.\n", size, transferred);
-        esp_break();
+        esp_yield();
         return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
     }
 
@@ -711,7 +711,7 @@ int HTTPClient::writeToPrint(Print * print)
                 return returnError(HTTPC_ERROR_READ_TIMEOUT);
             }
 
-            esp_break();
+            esp_yield();
         }
     } else {
         return returnError(HTTPC_ERROR_ENCODING);
@@ -1076,7 +1076,7 @@ int HTTPClient::handleHeaderResponse()
             if((millis() - lastDataTime) > _tcpTimeout) {
                 return HTTPC_ERROR_READ_TIMEOUT;
             }
-            esp_break();
+            esp_yield();
         }
     }
 
diff --git a/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer-impl.h b/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer-impl.h
index 303e5963d9..39608934cd 100644
--- a/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer-impl.h
+++ b/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer-impl.h
@@ -120,7 +120,7 @@ void ESP8266HTTPUpdateServerTemplate<ServerType>::setup(ESP8266WebServerTemplate
         Update.end();
         if (_serial_output) Serial.println("Update was aborted");
       }
-      esp_break();
+      esp_yield();
     });
 }
 
diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp
index 37f80e56b6..5c1dba65db 100644
--- a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp
+++ b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp
@@ -514,9 +514,9 @@ bool ESP8266WiFiGenericClass::forceSleepBegin(uint32 sleepUs) {
     }
 
     wifi_fpm_set_sleep_type(MODEM_SLEEP_T);
-    esp_break();
+    esp_yield();
     wifi_fpm_open();
-    esp_break();
+    esp_yield();
     auto ret = wifi_fpm_do_sleep(sleepUs);
     if (ret != 0)
     {
diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp
index 788c8eee1b..847a5ae969 100644
--- a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp
+++ b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp
@@ -92,7 +92,7 @@ static wl_status_t waitWiFiConnect(uint32_t connectTimeoutMs)
     // Wait for WiFi status change or timeout
     do {
         // Refresh watchdog
-        esp_break();
+        esp_yield();
 
         // Get WiFi status
         status = WiFi.status();
@@ -250,7 +250,7 @@ int8_t ESP8266WiFiMulti::startScan()
     // Wait for WiFi scan change or timeout
     do {
         // Refresh watchdog
-        esp_break();
+        esp_yield();
 
         // Check scan timeout which may occur when scan does not report completion
         if (scanTimeout) {
@@ -536,7 +536,7 @@ void ESP8266WiFiMulti::printWiFiScan()
                          rssi,
                          (encryptionType == ENC_TYPE_NONE) ? ' ' : '*',
                          ssid.c_str());
-        esp_break();
+        esp_yield();
     }
 #endif
 }
diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiSTA-WPS.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiSTA-WPS.cpp
index 99d27ba7a3..f6c639fdb7 100644
--- a/libraries/ESP8266WiFi/src/ESP8266WiFiSTA-WPS.cpp
+++ b/libraries/ESP8266WiFi/src/ESP8266WiFiSTA-WPS.cpp
@@ -70,7 +70,7 @@ bool ESP8266WiFiSTAClass::beginWPSConfig(void) {
         return false;
     }
 
-    esp_yield();
+    esp_suspend();
     // will resume when wifi_wps_status_cb fires
 
     return true;
diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp
index ae9b8e3c66..94bd12ee96 100644
--- a/libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp
+++ b/libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp
@@ -93,11 +93,11 @@ int8_t ESP8266WiFiScanClass::scanNetworks(bool async, bool show_hidden, uint8 ch
         ESP8266WiFiScanClass::_scanStarted = true;
 
         if(ESP8266WiFiScanClass::_scanAsync) {
-            esp_break(); // time for the OS to trigger the scan
+            esp_yield(); // time for the OS to trigger the scan
             return WIFI_SCAN_RUNNING;
         }
 
-        esp_yield(); // will resume when _scanDone fires
+        esp_suspend(); // will resume when _scanDone fires
         return ESP8266WiFiScanClass::_scanCount;
     } else {
         return WIFI_SCAN_FAILED;
diff --git a/libraries/ESP8266WiFi/src/include/ClientContext.h b/libraries/ESP8266WiFi/src/include/ClientContext.h
index 4fb557456f..416a666a60 100644
--- a/libraries/ESP8266WiFi/src/include/ClientContext.h
+++ b/libraries/ESP8266WiFi/src/include/ClientContext.h
@@ -351,7 +351,7 @@ class ClientContext
                 last_sent = millis();
             }
 
-            esp_break(); // from sys or os context
+            esp_yield(); // from sys or os context
 
             if ((state() != ESTABLISHED) || (sndbuf == TCP_SND_BUF)) {
                 // peer has closed or all bytes are sent and acked
diff --git a/libraries/ESP8266WiFi/src/include/UdpContext.h b/libraries/ESP8266WiFi/src/include/UdpContext.h
index b444de3551..1e7f639e34 100644
--- a/libraries/ESP8266WiFi/src/include/UdpContext.h
+++ b/libraries/ESP8266WiFi/src/include/UdpContext.h
@@ -24,7 +24,7 @@
 class UdpContext;
 
 extern "C" {
-void esp_yield();
+void esp_suspend();
 void esp_schedule();
 #include <assert.h>
 }
@@ -177,7 +177,7 @@ class UdpContext
     }
 
     // warning: handler is called from tcp stack context
-    // esp_yield and non-reentrant functions which depend on it will fail
+    // esp_suspend and non-reentrant functions which depend on it will fail
     void onRx(rxhandler_t handler) {
         _on_rx = handler;
     }
@@ -411,7 +411,7 @@ class UdpContext
         err_t err;
         esp8266::polledTimeout::oneShotFastMs timeout(timeoutMs);
         while (((err = trySend(addr, port, /* keep buffer on error */true)) != ERR_OK) && !timeout)
-            esp_break();
+            esp_yield();
         if (err != ERR_OK)
             cancelBuffer(); // get rid of buffer kept on error after timeout
         return err == ERR_OK;
diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp b/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp
index 6fc4e3cd01..bf1b1cde26 100644
--- a/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp
+++ b/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp
@@ -702,7 +702,7 @@ bool MDNSResponder::_parseResponse(const MDNSResponder::stcMDNS_MsgHeader& p_Msg
                 for (uint16_t qd=0; ((bDumpResult) && (qd<p_MsgHeader.m_u16QDCount)); ++qd) {
                     stcMDNS_RRQuestion  questionRR;
                     bDumpResult = _readRRQuestion(questionRR);
-                    esp_yield();
+                    esp_suspend();
                 }   // for questions
                 // Handle known answers
                 uint32_t    u32Answers = (p_MsgHeader.m_u16ANCount + p_MsgHeader.m_u16NSCount + p_MsgHeader.m_u16ARCount);
@@ -713,7 +713,7 @@ bool MDNSResponder::_parseResponse(const MDNSResponder::stcMDNS_MsgHeader& p_Msg
                         delete pRRAnswer;
                         pRRAnswer = 0;
                     }
-                    esp_yield();
+                    esp_suspend();
                 }
             );*/
         m_pUDPContext->flush();
diff --git a/tests/host/common/Arduino.cpp b/tests/host/common/Arduino.cpp
index c80d9bb34b..ff5c43835d 100644
--- a/tests/host/common/Arduino.cpp
+++ b/tests/host/common/Arduino.cpp
@@ -53,15 +53,15 @@ extern "C" void optimistic_yield (uint32_t interval_us)
     (void)interval_us;
 }
 
-extern "C" void esp_yield()
+extern "C" void esp_suspend()
 {
 }
 
-extern "C" void esp_schedule ()
+extern "C" void esp_schedule()
 {
 }
 
-extern "C" void esp_break ()
+extern "C" void esp_yield()
 {
 }
 
@@ -84,6 +84,6 @@ extern "C" void delayMicroseconds(unsigned int us)
 
 #include "cont.h"
 cont_t* g_pcont = NULL;
-extern "C" void cont_yield(cont_t*)
+extern "C" void cont_suspend(cont_t*)
 {
 }

From 08ed7d0b2828bab3e55ca8951c5cae1e2123f7cb Mon Sep 17 00:00:00 2001
From: "Dirk O. Kaar" <dok@dok-net.net>
Date: Sat, 10 Apr 2021 10:05:24 +0200
Subject: [PATCH 05/21] Non-recurring scheduled functions may yield, therefore
 run_scheduled_functions can use

optimistic_yield()
---
 cores/esp8266/Schedule.cpp | 14 ++++----------
 1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/cores/esp8266/Schedule.cpp b/cores/esp8266/Schedule.cpp
index baef3e9601..279e78ff6c 100644
--- a/cores/esp8266/Schedule.cpp
+++ b/cores/esp8266/Schedule.cpp
@@ -135,8 +135,6 @@ bool schedule_recurrent_function_us(const std::function<bool(void)>& fn,
 
 void run_scheduled_functions()
 {
-    esp8266::polledTimeout::periodicFastMs yieldNow(100); // yield every 100ms
-
     // prevent scheduling of new functions during this run
     auto stop = sLast;
     bool done = false;
@@ -161,14 +159,10 @@ void run_scheduled_functions()
             recycle_fn_unsafe(to_recycle);
         }
 
-        if (yieldNow)
-        {
-            // because scheduled functions might last too long for watchdog etc,
-            // this is yield() in cont stack, but need to call cont_suspend directly
-            // to prevent recursion into run_scheduled_recurrent_functions()
-            esp_schedule();
-            cont_suspend(g_pcont);
-        }
+        // scheduled functions might last too long for watchdog etc.
+        // yield() is allowed in scheduled functions, therefore
+        // recursion into run_scheduled_recurrent_functions() is permitted
+        optimistic_yield(100000);
     }
 }
 

From 397408fc5a64eb4e1dde3626127a787a034c6e00 Mon Sep 17 00:00:00 2001
From: "Dirk O. Kaar" <dok@dok-net.net>
Date: Thu, 8 Apr 2021 12:42:38 +0200
Subject: [PATCH 06/21] Add HAVE_ESP_SUSPEND define to allow 3rd party
 libraries to detect API changes

---
 cores/esp8266/coredecls.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/cores/esp8266/coredecls.h b/cores/esp8266/coredecls.h
index 7268016a9f..474f77c5df 100644
--- a/cores/esp8266/coredecls.h
+++ b/cores/esp8266/coredecls.h
@@ -2,6 +2,8 @@
 #ifndef __COREDECLS_H
 #define __COREDECLS_H
 
+#define HAVE_ESP_SUSPEND 1
+
 #ifdef __cplusplus
 extern "C" {
 #endif

From 0bb470cd588a1b4fa69b90f7b167de517d920683 Mon Sep 17 00:00:00 2001
From: "Dirk O. Kaar" <dok@dok-net.net>
Date: Fri, 9 Apr 2021 12:14:08 +0200
Subject: [PATCH 07/21] Merge branch 'esp_yield_mt' into delay0isyield

---
 cores/esp8266/core_esp8266_main.cpp           | 39 ++++++++++-
 cores/esp8266/core_esp8266_wiring.cpp         | 18 +----
 cores/esp8266/coredecls.h                     | 16 +++++
 cores/esp8266/time.cpp                        |  5 ++
 .../ESP8266WiFi/src/ESP8266WiFiGeneric.cpp    | 14 ++--
 .../ESP8266WiFi/src/ESP8266WiFiMulti.cpp      | 69 +++++++------------
 .../ESP8266WiFi/src/ESP8266WiFiSTA-WPS.cpp    |  8 ++-
 libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp |  9 +--
 .../ESP8266WiFi/src/include/ClientContext.h   | 26 ++++---
 tests/host/common/Arduino.cpp                 | 17 ++++-
 10 files changed, 130 insertions(+), 91 deletions(-)

diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp
index 5a471c79be..e6b110783a 100644
--- a/cores/esp8266/core_esp8266_main.cpp
+++ b/cores/esp8266/core_esp8266_main.cpp
@@ -80,6 +80,10 @@ const char* core_release =
 #else
     NULL;
 #endif
+
+static os_timer_t delay_timer;
+#define ONCE 0
+#define REPEAT 1
 } // extern "C"
 
 void initVariant() __attribute__((weak));
@@ -137,6 +141,38 @@ extern "C" void esp_yield() {
     esp_suspend();
 }
 
+void delay_end(void* arg) {
+    (void)arg;
+    esp_schedule();
+}
+
+extern "C" void __esp_delay(unsigned long ms) {
+    if (ms) {
+        os_timer_setfn(&delay_timer, (os_timer_func_t*)&delay_end, 0);
+        os_timer_arm(&delay_timer, ms, ONCE);
+    }
+    else {
+        esp_schedule();
+    }
+    esp_suspend();
+    if (ms) {
+        os_timer_disarm(&delay_timer);
+    }
+}
+
+extern "C" void esp_delay(unsigned long ms) __attribute__((weak, alias("__esp_delay")));
+
+using IsBlockedCB = std::function<bool()>;
+
+void esp_delay(const uint32_t timeout_ms, const IsBlockedCB& blocked, const uint32_t intvl_ms) {
+    const auto start = millis();
+    decltype(millis()) expired;
+    while ((expired = millis() - start) < timeout_ms && blocked()) {
+        auto remaining = timeout_ms - expired;
+        esp_delay(remaining <= intvl_ms ? remaining : intvl_ms);
+    }
+}
+
 extern "C" void __yield() {
     if (cont_can_suspend(g_pcont)) {
         esp_schedule();
@@ -224,8 +260,8 @@ static void loop_task(os_event_t *events) {
         panic();
     }
 }
-extern "C" {
 
+extern "C" {
 struct object { long placeholder[ 10 ]; };
 void __register_frame_info (const void *begin, struct object *ob);
 extern char __eh_frame[];
@@ -262,7 +298,6 @@ static void  __unhandled_exception_cpp()
     }
 #endif
 }
-
 }
 
 void init_done() {
diff --git a/cores/esp8266/core_esp8266_wiring.cpp b/cores/esp8266/core_esp8266_wiring.cpp
index 65a9a6aecc..40a996d560 100644
--- a/cores/esp8266/core_esp8266_wiring.cpp
+++ b/cores/esp8266/core_esp8266_wiring.cpp
@@ -23,34 +23,18 @@
 #include "ets_sys.h"
 #include "osapi.h"
 #include "user_interface.h"
-#include "cont.h"
 #include "coredecls.h"
 
 extern "C" {
 
-static os_timer_t delay_timer;
 static os_timer_t micros_overflow_timer;
 static uint32_t micros_at_last_overflow_tick = 0;
 static uint32_t micros_overflow_count = 0;
 #define ONCE 0
 #define REPEAT 1
 
-void delay_end(void* arg) {
-    (void) arg;
-    esp_schedule();
-}
-
 void __delay(unsigned long ms) {
-    if(ms) {
-        os_timer_setfn(&delay_timer, (os_timer_func_t*) &delay_end, 0);
-        os_timer_arm(&delay_timer, ms, ONCE);
-    } else {
-        esp_schedule();
-    }
-    esp_suspend();
-    if(ms) {
-        os_timer_disarm(&delay_timer);
-    }
+    esp_delay(ms);
 }
 
 void delay(unsigned long ms) __attribute__ ((weak, alias("__delay"))); 
diff --git a/cores/esp8266/coredecls.h b/cores/esp8266/coredecls.h
index 474f77c5df..e7baf26c62 100644
--- a/cores/esp8266/coredecls.h
+++ b/cores/esp8266/coredecls.h
@@ -16,6 +16,7 @@ extern "C" {
 
 bool can_yield();
 void esp_suspend();
+void esp_delay(unsigned long ms);
 void esp_schedule();
 void esp_yield();
 void tune_timeshift64 (uint64_t now_us);
@@ -35,9 +36,24 @@ uint32_t crc32 (const void* data, size_t length, uint32_t crc = 0xffffffff);
 using BoolCB = std::function<void(bool)>;
 using TrivialCB = std::function<void()>;
 
+void settimeofday_cb (BoolCB&& cb);
 void settimeofday_cb (const BoolCB& cb);
 void settimeofday_cb (const TrivialCB& cb);
 
+using IsBlockedCB = std::function<bool()>;
+
+inline void esp_suspend(const IsBlockedCB& blocked) {
+    do {
+        esp_suspend();
+    } while (blocked());
+}
+
+void esp_delay(const uint32_t timeout_ms, const IsBlockedCB& blocked, const uint32_t intvl_ms);
+
+inline void esp_delay(const uint32_t timeout_ms, const IsBlockedCB& blocked) {
+    esp_delay(timeout_ms, blocked, timeout_ms);
+}
+
 #endif // __cplusplus
 
 #endif // __COREDECLS_H
diff --git a/cores/esp8266/time.cpp b/cores/esp8266/time.cpp
index b9489c330f..8e997c72d5 100644
--- a/cores/esp8266/time.cpp
+++ b/cores/esp8266/time.cpp
@@ -214,6 +214,11 @@ void settimeofday_cb (const TrivialCB& cb)
     _settimeofday_cb = [cb](bool sntp) { (void)sntp; cb(); };
 }
 
+void settimeofday_cb (BoolCB&& cb)
+{
+    _settimeofday_cb = std::move(cb);
+}
+
 void settimeofday_cb (const BoolCB& cb)
 {
     _settimeofday_cb = cb;
diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp
index 5c1dba65db..a7d323cd57 100644
--- a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp
+++ b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp
@@ -434,10 +434,9 @@ bool ESP8266WiFiGenericClass::mode(WiFiMode_t m) {
     //tasks to wait correctly.
     constexpr unsigned int timeoutValue = 1000; //1 second
     if(can_yield()) {
-        using oneShot = esp8266::polledTimeout::oneShotFastMs;
-        oneShot timeout(timeoutValue);
-        while(wifi_get_opmode() != (uint8) m && !timeout)
-            delay(5);
+        // The final argument, intvl_ms, to esp_delay influences how frequently
+        // the scheduled recurrent functions (Schedule.h) are probed.
+        esp_delay(timeoutValue, [m]() { return wifi_get_opmode() != m; }, 5);
 
         //if at this point mode still hasn't been reached, give up
         if(wifi_get_opmode() != (uint8) m) {
@@ -617,7 +616,7 @@ int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResul
         aResult = IPAddress(&addr);
     } else if(err == ERR_INPROGRESS) {
         _dns_lookup_pending = true;
-        delay(timeout_ms);
+        esp_delay(timeout_ms, []() { return _dns_lookup_pending; });
         // will resume on timeout or when wifi_dns_found_callback fires
         _dns_lookup_pending = false;
         // will return here when dns_found_callback fires
@@ -667,8 +666,8 @@ int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResul
         aResult = IPAddress(&addr);
     } else if(err == ERR_INPROGRESS) {
         _dns_lookup_pending = true;
-        delay(timeout_ms);
         // will resume on timeout or when wifi_dns_found_callback fires
+        esp_delay(timeout_ms, []() { return _dns_lookup_pending; });
         _dns_lookup_pending = false;
         // will return here when dns_found_callback fires
         if(aResult.isSet()) {
@@ -701,7 +700,8 @@ void wifi_dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *ca
     if(ipaddr) {
         (*reinterpret_cast<IPAddress*>(callback_arg)) = IPAddress(ipaddr);
     }
-    esp_schedule(); // break delay in hostByName
+    _dns_lookup_pending = false; // resume hostByName
+    esp_schedule();
 }
 
 uint32_t ESP8266WiFiGenericClass::shutdownCRC (const WiFiState& state)
diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp
index 847a5ae969..992beb23cb 100644
--- a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp
+++ b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp
@@ -84,36 +84,25 @@ static void printWiFiStatus(wl_status_t status)
 static wl_status_t waitWiFiConnect(uint32_t connectTimeoutMs)
 {
     wl_status_t status;
+    // The final argument, intvl_ms, to esp_delay influences how frequently
+    // the scheduled recurrent functions (Schedule.h) are probed.
+    esp_delay(connectTimeoutMs,
+        [&status]() { status = WiFi.status(); return status != WL_CONNECTED && status != WL_CONNECT_FAILED; }, 0);
 
-    // Set WiFi connect timeout
-    using esp8266::polledTimeout::oneShotMs;
-    oneShotMs connectTimeout(connectTimeoutMs);
-
-    // Wait for WiFi status change or timeout
-    do {
-        // Refresh watchdog
-        esp_yield();
-
-        // Get WiFi status
-        status = WiFi.status();
-
-        // Check status
-        if (status == WL_CONNECTED) {
-            // Connected, print WiFi status
-            printWiFiStatus(status);
-
-            // Return WiFi status
-            return status;
-        } else if (status == WL_CONNECT_FAILED) {
-            DEBUG_WIFI_MULTI("[WIFIM] Connect failed\n");
-
-            // Return WiFi connect failed
-            return WL_CONNECT_FAILED;
-        }
-    } while (!connectTimeout);
+    // Check status
+    if (status == WL_CONNECTED) {
+        // Connected, print WiFi status
+        printWiFiStatus(status);
 
-    DEBUG_WIFI_MULTI("[WIFIM] Connect timeout\n");
+        // Return WiFi status
+        return status;
+    } else if (status == WL_CONNECT_FAILED) {
+        DEBUG_WIFI_MULTI("[WIFIM] Connect failed\n");
+    } else {
+        DEBUG_WIFI_MULTI("[WIFIM] Connect timeout\n");
+    }
 
+    // Return WiFi connect failed
     return WL_CONNECT_FAILED;
 }
 
@@ -243,24 +232,16 @@ int8_t ESP8266WiFiMulti::startScan()
     // Start wifi scan in async mode
     WiFi.scanNetworks(true);
 
-    // Set WiFi scan timeout
-    using esp8266::polledTimeout::oneShotMs;
-    oneShotMs scanTimeout(WIFI_SCAN_TIMEOUT_MS);
-
     // Wait for WiFi scan change or timeout
-    do {
-        // Refresh watchdog
-        esp_yield();
-
-        // Check scan timeout which may occur when scan does not report completion
-        if (scanTimeout) {
-            DEBUG_WIFI_MULTI("[WIFIM] Scan timeout\n");
-            return WIFI_SCAN_FAILED;
-        }
-
-        // Get scan result
-        scanResult = WiFi.scanComplete();
-    } while (scanResult < 0);
+    // The final argument, intvl_ms, to esp_delay influences how frequently
+    // the scheduled recurrent functions (Schedule.h) are probed.
+    esp_delay(WIFI_SCAN_TIMEOUT_MS,
+        [&scanResult]() { scanResult = WiFi.scanComplete(); return scanResult < 0; }, 0);
+    // Check for scan timeout which may occur when scan does not report completion
+    if (scanResult < 0) {
+        DEBUG_WIFI_MULTI("[WIFIM] Scan timeout\n");
+        return WIFI_SCAN_FAILED;
+    }
 
     // Print WiFi scan result
     printWiFiScan();
diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiSTA-WPS.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiSTA-WPS.cpp
index f6c639fdb7..b93c77da9c 100644
--- a/libraries/ESP8266WiFi/src/ESP8266WiFiSTA-WPS.cpp
+++ b/libraries/ESP8266WiFi/src/ESP8266WiFiSTA-WPS.cpp
@@ -30,6 +30,8 @@
 
 static void wifi_wps_status_cb(wps_cb_status status);
 
+static bool _wps_config_pending = false;
+
 /**
  * WPS config
  * so far only WPS_TYPE_PBC is supported (SDK 1.2.0)
@@ -70,8 +72,9 @@ bool ESP8266WiFiSTAClass::beginWPSConfig(void) {
         return false;
     }
 
-    esp_suspend();
+    _wps_config_pending = true;
     // will resume when wifi_wps_status_cb fires
+    esp_suspend([]() { return _wps_config_pending; });
 
     return true;
 }
@@ -107,5 +110,6 @@ void wifi_wps_status_cb(wps_cb_status status) {
     }
     // TODO user function to get status
 
-    esp_schedule(); // resume beginWPSConfig
+    _wps_config_pending = false; // resume beginWPSConfig
+    esp_schedule();
 }
diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp
index 94bd12ee96..6aaf432e2d 100644
--- a/libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp
+++ b/libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp
@@ -26,8 +26,6 @@
 #include "ESP8266WiFiGeneric.h"
 #include "ESP8266WiFiScan.h"
 
-#include <coredecls.h>
-
 extern "C" {
 #include "c_types.h"
 #include "ets_sys.h"
@@ -38,6 +36,7 @@ extern "C" {
 }
 
 #include "debug.h"
+#include <coredecls.h>
 
 // -----------------------------------------------------------------------------------------------------------------------
 // ---------------------------------------------------- Private functions ------------------------------------------------
@@ -97,7 +96,9 @@ int8_t ESP8266WiFiScanClass::scanNetworks(bool async, bool show_hidden, uint8 ch
             return WIFI_SCAN_RUNNING;
         }
 
-        esp_suspend(); // will resume when _scanDone fires
+        // will resume when _scanDone fires
+        esp_suspend([]() { return !ESP8266WiFiScanClass::_scanComplete && ESP8266WiFiScanClass::_scanStarted; });
+
         return ESP8266WiFiScanClass::_scanCount;
     } else {
         return WIFI_SCAN_FAILED;
@@ -321,7 +322,7 @@ void ESP8266WiFiScanClass::_scanDone(void* result, int status) {
     ESP8266WiFiScanClass::_scanStarted = false;
     ESP8266WiFiScanClass::_scanComplete = true;
 
-    if(!ESP8266WiFiScanClass::_scanAsync) {
+    if (!ESP8266WiFiScanClass::_scanAsync) {
         esp_schedule(); // resume scanNetworks
     } else if (ESP8266WiFiScanClass::_onComplete) {
         ESP8266WiFiScanClass::_onComplete(ESP8266WiFiScanClass::_scanCount);
diff --git a/libraries/ESP8266WiFi/src/include/ClientContext.h b/libraries/ESP8266WiFi/src/include/ClientContext.h
index 416a666a60..7fcad3678a 100644
--- a/libraries/ESP8266WiFi/src/include/ClientContext.h
+++ b/libraries/ESP8266WiFi/src/include/ClientContext.h
@@ -28,7 +28,6 @@ typedef void (*discard_cb_t)(void*, ClientContext*);
 
 #include <assert.h>
 #include <esp_priv.h>
-
 #include <coredecls.h>
 
 bool getDefaultPrivateGlobalSyncValue ();
@@ -144,11 +143,9 @@ class ClientContext
         }
         _connect_pending = true;
         _op_start_time = millis();
-        for (decltype(_timeout_ms) i = 0; _connect_pending && i < _timeout_ms; i++) {
-               // Give scheduled functions a chance to run (e.g. Ethernet uses recurrent)
-               delay(1);
-               // will resume on timeout or when _connected or _notify_error fires
-        }
+        // will resume on timeout or when _connected or _notify_error fires
+        // give scheduled functions a chance to run (e.g. Ethernet uses recurrent)
+        esp_delay(_timeout_ms, [this]() { return this->_connect_pending; }, 1);
         _connect_pending = false;
         if (!_pcb) {
             DEBUGV(":cabrt\r\n");
@@ -457,9 +454,10 @@ class ClientContext
     void _notify_error()
     {
         if (_connect_pending || _send_waiting) {
+            // resume connect or _write_from_source
             _send_waiting = false;
             _connect_pending = false;
-            esp_schedule(); // break delay in connect or _write_from_source
+            esp_schedule();
         }
     }
 
@@ -486,11 +484,9 @@ class ClientContext
             }
 
             _send_waiting = true;
-            for (decltype(_timeout_ms) i = 0; _send_waiting && i < _timeout_ms; i++) {
-               // Give scheduled functions a chance to run (e.g. Ethernet uses recurrent)
-               delay(1);
-               // will resume on timeout or when _write_some_from_cb or _notify_error fires
-            }
+            // will resume on timeout or when _write_some_from_cb or _notify_error fires
+            // give scheduled functions a chance to run (e.g. Ethernet uses recurrent)
+            esp_delay(_timeout_ms, [this]() { return this->_send_waiting; }, 1);
             _send_waiting = false;
         } while(true);
 
@@ -560,8 +556,9 @@ class ClientContext
     void _write_some_from_cb()
     {
         if (_send_waiting) {
+            // resume _write_from_source
             _send_waiting = false;
-            esp_schedule(); // break delay in _write_from_source
+            esp_schedule();
         }
     }
 
@@ -648,8 +645,9 @@ class ClientContext
         (void) pcb;
         assert(pcb == _pcb);
         if (_connect_pending) {
+            // resume connect
             _connect_pending = false;
-            esp_schedule(); // break delay in connect
+            esp_schedule();
         }
         return ERR_OK;
     }
diff --git a/tests/host/common/Arduino.cpp b/tests/host/common/Arduino.cpp
index ff5c43835d..eed0ebebdc 100644
--- a/tests/host/common/Arduino.cpp
+++ b/tests/host/common/Arduino.cpp
@@ -15,6 +15,7 @@
 
 #include <sys/time.h>
 #include "Arduino.h"
+#include <functional>
 
 #include <unistd.h>
 
@@ -65,6 +66,20 @@ extern "C" void esp_yield()
 {
 }
 
+extern "C" void esp_delay (unsigned long ms)
+{
+    usleep(ms * 1000);
+}
+
+using IsBlockedCB = std::function<bool()>;
+
+void esp_delay(const uint32_t timeout_ms, const IsBlockedCB& blocked, const uint32_t intvl_ms)
+{
+    (void)blocked;
+    (void)intvl_ms;
+    usleep(timeout_ms * 1000);
+}
+
 extern "C" void __panic_func(const char* file, int line, const char* func) {
     (void)file;
     (void)line;
@@ -74,7 +89,7 @@ extern "C" void __panic_func(const char* file, int line, const char* func) {
 
 extern "C" void delay(unsigned long ms)
 {
-    usleep(ms * 1000);
+    esp_delay(ms);
 }
 
 extern "C" void delayMicroseconds(unsigned int us)

From 971ad28dad73327ab2d8ac878e4f5bed09a1925d Mon Sep 17 00:00:00 2001
From: "Dirk O. Kaar" <dok@dok-net.net>
Date: Mon, 19 Apr 2021 18:10:39 +0200
Subject: [PATCH 08/21] Make detectBaudrate safe from SYS context, for what
 it's worth.

---
 cores/esp8266/HardwareSerial.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/cores/esp8266/HardwareSerial.cpp b/cores/esp8266/HardwareSerial.cpp
index 88b47b33f3..4896e27758 100644
--- a/cores/esp8266/HardwareSerial.cpp
+++ b/cores/esp8266/HardwareSerial.cpp
@@ -143,7 +143,7 @@ unsigned long HardwareSerial::detectBaudrate(time_t timeoutMillis)
         if ((detectedBaudrate = testBaudrate())) {
           break;
         }
-        delay(100);
+        esp_delay(100);
     }
     return detectedBaudrate;
 }

From 99ed6fcca3212752972144206d2b853146edca4f Mon Sep 17 00:00:00 2001
From: "Dirk O. Kaar" <dok@dok-net.net>
Date: Mon, 19 Apr 2021 21:46:16 +0200
Subject: [PATCH 09/21] Add comment about how optimistic_yield() is safe for
 SYS, like in callbacks.

---
 cores/esp8266/core_esp8266_main.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp
index e6b110783a..00e3cc9f19 100644
--- a/cores/esp8266/core_esp8266_main.cpp
+++ b/cores/esp8266/core_esp8266_main.cpp
@@ -185,6 +185,9 @@ extern "C" void __yield() {
 
 extern "C" void yield(void) __attribute__ ((weak, alias("__yield")));
 
+// In CONT, actually performs yield() only once the given time interval
+// has elapsed since the last time yield() occured. Whereas yield() panics
+// in SYS, optimistic_yield() additionally is safe to call and does nothing.
 extern "C" void optimistic_yield(uint32_t interval_us) {
     const uint32_t intvl_cycles = interval_us *
 #if defined(F_CPU)

From cd8d2d311f3953a36467d4edb866b8e1e3189c5b Mon Sep 17 00:00:00 2001
From: "Dirk O. Kaar" <dok@dok-net.net>
Date: Tue, 20 Jul 2021 18:39:25 +0200
Subject: [PATCH 10/21] Adapt logic to feed scheduled recurrent functions in
 hostByName from PR #6212

---
 libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp
index a7d323cd57..bd784b48e7 100644
--- a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp
+++ b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp
@@ -616,10 +616,12 @@ int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResul
         aResult = IPAddress(&addr);
     } else if(err == ERR_INPROGRESS) {
         _dns_lookup_pending = true;
-        esp_delay(timeout_ms, []() { return _dns_lookup_pending; });
-        // will resume on timeout or when wifi_dns_found_callback fires
+        // Will resume on timeout or when wifi_dns_found_callback fires.
+        // The final argument, intvl_ms, to esp_delay influences how frequently
+        // the scheduled recurrent functions (Schedule.h) are probed; here, to allow
+        // the ethernet driver perform work.
+        esp_delay(timeout_ms, []() { return _dns_lookup_pending; }, 1);
         _dns_lookup_pending = false;
-        // will return here when dns_found_callback fires
         if(aResult.isSet()) {
             err = ERR_OK;
         }

From 070eb482748386274cf63b21d8db613054959664 Mon Sep 17 00:00:00 2001
From: "Dirk O. Kaar" <dok@dok-net.net>
Date: Wed, 6 Oct 2021 23:09:18 +0200
Subject: [PATCH 11/21] Add clarifying comments to esp_suspend and esp_delay
 overloads.

---
 cores/esp8266/coredecls.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/cores/esp8266/coredecls.h b/cores/esp8266/coredecls.h
index e7baf26c62..7a7be8b31a 100644
--- a/cores/esp8266/coredecls.h
+++ b/cores/esp8266/coredecls.h
@@ -42,14 +42,23 @@ void settimeofday_cb (const TrivialCB& cb);
 
 using IsBlockedCB = std::function<bool()>;
 
+// This overload of esp_suspend() performs the blocked callback whenever it is resumed,
+// and if that returns true, it immediately suspends again.
 inline void esp_suspend(const IsBlockedCB& blocked) {
     do {
         esp_suspend();
     } while (blocked());
 }
 
+// This overload of esp_delay() delays for a duration of at most timeout_ms milliseconds.
+// Whenever it is resumed, as well as every intvl_ms millisconds, it performs
+// the blocked callback, and if that returns true, it keeps delaying for the remainder
+// of the original timeout_ms period.
 void esp_delay(const uint32_t timeout_ms, const IsBlockedCB& blocked, const uint32_t intvl_ms);
 
+// This overload of esp_delay() delays for a duration of at most timeout_ms milliseconds.
+// Whenever it is resumed, it performs the blocked callback, and if that returns true,
+// it keeps delaying for the remainder of the original timeout_ms period.
 inline void esp_delay(const uint32_t timeout_ms, const IsBlockedCB& blocked) {
     esp_delay(timeout_ms, blocked, timeout_ms);
 }

From d11be8b360914010a5b0c140d09cd930b2bfca57 Mon Sep 17 00:00:00 2001
From: "Dirk O. Kaar" <dok@dok-net.net>
Date: Wed, 6 Oct 2021 23:35:52 +0200
Subject: [PATCH 12/21] Refactoring as seen in PR #8317

---
 .../ESP8266WiFi/src/ESP8266WiFiGeneric.cpp    | 20 +++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp
index bd784b48e7..c66f7ad48b 100644
--- a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp
+++ b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp
@@ -627,13 +627,13 @@ int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResul
         }
     }
 
-    if(err != 0) {
-        DEBUG_WIFI_GENERIC("[hostByName] Host: %s lookup error: %d!\n", aHostname, (int)err);
-    } else {
+    if(err == ERR_OK) {
         DEBUG_WIFI_GENERIC("[hostByName] Host: %s IP: %s\n", aHostname, aResult.toString().c_str());
+        return 1;
+    } else {
+        DEBUG_WIFI_GENERIC("[hostByName] Host: %s lookup error: %d!\n", aHostname, (int)err);
+        return 0;
     }
-
-    return (err == ERR_OK) ? 1 : 0;
 }
 
 #if LWIP_IPV4 && LWIP_IPV6
@@ -677,13 +677,13 @@ int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResul
         }
     }
 
-    if(err != 0) {
-        DEBUG_WIFI_GENERIC("[hostByName] Host: %s lookup error: %d!\n", aHostname, (int)err);
-    } else {
+    if(err == ERR_OK) {
         DEBUG_WIFI_GENERIC("[hostByName] Host: %s IP: %s\n", aHostname, aResult.toString().c_str());
+        return 1;
+    } else {
+        DEBUG_WIFI_GENERIC("[hostByName] Host: %s lookup error: %d!\n", aHostname, (int)err);
+        return 0;
     }
-
-    return (err == ERR_OK) ? 1 : 0;
 }
 #endif
 

From 4b92d287c075dfc4062234b0816674aceffdde1c Mon Sep 17 00:00:00 2001
From: "Dirk O. Kaar" <dok@dok-net.net>
Date: Thu, 7 Oct 2021 23:09:55 +0200
Subject: [PATCH 13/21] Removed redundant duplicate type definition.

---
 cores/esp8266/core_esp8266_main.cpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp
index 00e3cc9f19..5545a0e30f 100644
--- a/cores/esp8266/core_esp8266_main.cpp
+++ b/cores/esp8266/core_esp8266_main.cpp
@@ -162,8 +162,6 @@ extern "C" void __esp_delay(unsigned long ms) {
 
 extern "C" void esp_delay(unsigned long ms) __attribute__((weak, alias("__esp_delay")));
 
-using IsBlockedCB = std::function<bool()>;
-
 void esp_delay(const uint32_t timeout_ms, const IsBlockedCB& blocked, const uint32_t intvl_ms) {
     const auto start = millis();
     decltype(millis()) expired;

From 208c4a3f41af444f448ec47dc5c0e9bccbcaac03 Mon Sep 17 00:00:00 2001
From: "Dirk O. Kaar" <dok@dok-net.net>
Date: Sat, 9 Oct 2021 02:33:19 +0200
Subject: [PATCH 14/21] Use function template syntax to save using
 std::function objects.

---
 cores/esp8266/core_esp8266_main.cpp | 12 +++++++-----
 cores/esp8266/coredecls.h           | 21 +++++++++++++++------
 tests/host/common/Arduino.cpp       | 16 +++++++++-------
 3 files changed, 31 insertions(+), 18 deletions(-)

diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp
index 5545a0e30f..a4be973191 100644
--- a/cores/esp8266/core_esp8266_main.cpp
+++ b/cores/esp8266/core_esp8266_main.cpp
@@ -162,13 +162,15 @@ extern "C" void __esp_delay(unsigned long ms) {
 
 extern "C" void esp_delay(unsigned long ms) __attribute__((weak, alias("__esp_delay")));
 
-void esp_delay(const uint32_t timeout_ms, const IsBlockedCB& blocked, const uint32_t intvl_ms) {
-    const auto start = millis();
+bool try_esp_delay(const uint32_t start_ms, const uint32_t timeout_ms, const uint32_t intvl_ms) {
     decltype(millis()) expired;
-    while ((expired = millis() - start) < timeout_ms && blocked()) {
-        auto remaining = timeout_ms - expired;
-        esp_delay(remaining <= intvl_ms ? remaining : intvl_ms);
+
+    if ((expired = millis() - start_ms) >= timeout_ms) {
+        return true;
     }
+    const auto remaining = timeout_ms - expired;
+    esp_delay(remaining <= intvl_ms ? remaining : intvl_ms);
+    return false;
 }
 
 extern "C" void __yield() {
diff --git a/cores/esp8266/coredecls.h b/cores/esp8266/coredecls.h
index 7a7be8b31a..d5da1cfade 100644
--- a/cores/esp8266/coredecls.h
+++ b/cores/esp8266/coredecls.h
@@ -4,6 +4,8 @@
 
 #define HAVE_ESP_SUSPEND 1
 
+#include "core_esp8266_features.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -40,27 +42,34 @@ void settimeofday_cb (BoolCB&& cb);
 void settimeofday_cb (const BoolCB& cb);
 void settimeofday_cb (const TrivialCB& cb);
 
-using IsBlockedCB = std::function<bool()>;
-
 // This overload of esp_suspend() performs the blocked callback whenever it is resumed,
 // and if that returns true, it immediately suspends again.
-inline void esp_suspend(const IsBlockedCB& blocked) {
+template <typename T>
+inline void esp_suspend(T&& blocked) {
     do {
         esp_suspend();
     } while (blocked());
 }
 
+bool try_esp_delay(const uint32_t start_ms, const uint32_t timeout_ms, const uint32_t intvl_ms);
+
 // This overload of esp_delay() delays for a duration of at most timeout_ms milliseconds.
 // Whenever it is resumed, as well as every intvl_ms millisconds, it performs
 // the blocked callback, and if that returns true, it keeps delaying for the remainder
 // of the original timeout_ms period.
-void esp_delay(const uint32_t timeout_ms, const IsBlockedCB& blocked, const uint32_t intvl_ms);
+template <typename T>
+inline void esp_delay(const uint32_t timeout_ms, T&& blocked, const uint32_t intvl_ms) {
+    const auto start_ms = millis();
+    while (!try_esp_delay(start_ms, timeout_ms, intvl_ms) && blocked()) {
+    }
+}
 
 // This overload of esp_delay() delays for a duration of at most timeout_ms milliseconds.
 // Whenever it is resumed, it performs the blocked callback, and if that returns true,
 // it keeps delaying for the remainder of the original timeout_ms period.
-inline void esp_delay(const uint32_t timeout_ms, const IsBlockedCB& blocked) {
-    esp_delay(timeout_ms, blocked, timeout_ms);
+template <typename T>
+inline void esp_delay(const uint32_t timeout_ms, T&& blocked) {
+    esp_delay(timeout_ms, std::forward<T>(blocked), timeout_ms);
 }
 
 #endif // __cplusplus
diff --git a/tests/host/common/Arduino.cpp b/tests/host/common/Arduino.cpp
index eed0ebebdc..e934f8acba 100644
--- a/tests/host/common/Arduino.cpp
+++ b/tests/host/common/Arduino.cpp
@@ -71,13 +71,15 @@ extern "C" void esp_delay (unsigned long ms)
     usleep(ms * 1000);
 }
 
-using IsBlockedCB = std::function<bool()>;
-
-void esp_delay(const uint32_t timeout_ms, const IsBlockedCB& blocked, const uint32_t intvl_ms)
-{
-    (void)blocked;
-    (void)intvl_ms;
-    usleep(timeout_ms * 1000);
+bool try_esp_delay(const uint32_t start_ms, const uint32_t timeout_ms, const uint32_t intvl_ms) {
+    decltype(millis()) expired;
+
+    if ((expired = millis() - start_ms) >= timeout_ms) {
+        return true;
+    }
+    const auto remaining = timeout_ms - expired;
+    esp_delay(remaining <= intvl_ms ? remaining : intvl_ms);
+    return false;
 }
 
 extern "C" void __panic_func(const char* file, int line, const char* func) {

From 3720ac0a86e09f638e46cc7a6f7275d0d8ab85b9 Mon Sep 17 00:00:00 2001
From: "Dirk O. Kaar" <dok@dok-net.net>
Date: Sat, 9 Oct 2021 02:59:51 +0200
Subject: [PATCH 15/21] Fix uninitialized status for immediately expired
 timeout.

---
 libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp
index 992beb23cb..a4d95383e5 100644
--- a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp
+++ b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp
@@ -83,7 +83,7 @@ static void printWiFiStatus(wl_status_t status)
  */
 static wl_status_t waitWiFiConnect(uint32_t connectTimeoutMs)
 {
-    wl_status_t status;
+    wl_status_t status = WL_CONNECT_FAILED;
     // The final argument, intvl_ms, to esp_delay influences how frequently
     // the scheduled recurrent functions (Schedule.h) are probed.
     esp_delay(connectTimeoutMs,

From 3be70a45ed7b73810170ec0e434a93b1cb396a1c Mon Sep 17 00:00:00 2001
From: "Dirk O. Kaar" <dok@dok-net.net>
Date: Sat, 9 Oct 2021 09:53:31 +0200
Subject: [PATCH 16/21] Specification for try_esp_delay added as code comment.

---
 cores/esp8266/coredecls.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/cores/esp8266/coredecls.h b/cores/esp8266/coredecls.h
index d5da1cfade..e1edf8b927 100644
--- a/cores/esp8266/coredecls.h
+++ b/cores/esp8266/coredecls.h
@@ -51,6 +51,10 @@ inline void esp_suspend(T&& blocked) {
     } while (blocked());
 }
 
+// Try to delay for timeout_ms relative to start_ms. Returns false if the delayed task
+// is asynchronously resumed before the timeout is reached.
+// Also returns false if intvl_ms have expired during the active call.
+// Otherwise return true to indicate the timeout_ms have completely expired.
 bool try_esp_delay(const uint32_t start_ms, const uint32_t timeout_ms, const uint32_t intvl_ms);
 
 // This overload of esp_delay() delays for a duration of at most timeout_ms milliseconds.

From 67ced120cf35d779e38b09fe2ceb0c5cbc9e8ced Mon Sep 17 00:00:00 2001
From: "Dirk O. Kaar" <19971886+dok-net@users.noreply.github.com>
Date: Wed, 13 Oct 2021 07:53:09 +0200
Subject: [PATCH 17/21] Apply suggestions from code review

Co-authored-by: Max Prokhorov <prokhorov.max@outlook.com>
---
 cores/esp8266/core_esp8266_main.cpp              |  8 +++-----
 libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp | 12 ++++++------
 2 files changed, 9 insertions(+), 11 deletions(-)

diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp
index a4be973191..9cd262de26 100644
--- a/cores/esp8266/core_esp8266_main.cpp
+++ b/cores/esp8266/core_esp8266_main.cpp
@@ -163,13 +163,11 @@ extern "C" void __esp_delay(unsigned long ms) {
 extern "C" void esp_delay(unsigned long ms) __attribute__((weak, alias("__esp_delay")));
 
 bool try_esp_delay(const uint32_t start_ms, const uint32_t timeout_ms, const uint32_t intvl_ms) {
-    decltype(millis()) expired;
-
-    if ((expired = millis() - start_ms) >= timeout_ms) {
+    uint32_t expired = millis() - start_ms;
+    if (expired >= timeout_ms) {
         return true;
     }
-    const auto remaining = timeout_ms - expired;
-    esp_delay(remaining <= intvl_ms ? remaining : intvl_ms);
+    esp_delay(std::min((timeout_ms - expired), intvl_ms));
     return false;
 }
 
diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp
index c66f7ad48b..822f861a91 100644
--- a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp
+++ b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp
@@ -630,10 +630,10 @@ int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResul
     if(err == ERR_OK) {
         DEBUG_WIFI_GENERIC("[hostByName] Host: %s IP: %s\n", aHostname, aResult.toString().c_str());
         return 1;
-    } else {
-        DEBUG_WIFI_GENERIC("[hostByName] Host: %s lookup error: %d!\n", aHostname, (int)err);
-        return 0;
     }
+    
+    DEBUG_WIFI_GENERIC("[hostByName] Host: %s lookup error: %s (%d)!\n", aHostname, lwip_strerr(err), (int)err);
+    return 0;
 }
 
 #if LWIP_IPV4 && LWIP_IPV6
@@ -680,10 +680,10 @@ int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResul
     if(err == ERR_OK) {
         DEBUG_WIFI_GENERIC("[hostByName] Host: %s IP: %s\n", aHostname, aResult.toString().c_str());
         return 1;
-    } else {
-        DEBUG_WIFI_GENERIC("[hostByName] Host: %s lookup error: %d!\n", aHostname, (int)err);
-        return 0;
     }
+
+    DEBUG_WIFI_GENERIC("[hostByName] Host: %s lookup error: %d!\n", aHostname, (int)err);
+    return 0;
 }
 #endif
 

From 62af9406a9030a0aa71754c46bc403a866053254 Mon Sep 17 00:00:00 2001
From: "Dirk O. Kaar" <dok@dok-net.net>
Date: Wed, 13 Oct 2021 08:01:30 +0200
Subject: [PATCH 18/21] By review feedback, maintain esp_ as prefix.

---
 cores/esp8266/core_esp8266_main.cpp | 2 +-
 cores/esp8266/coredecls.h           | 4 ++--
 tests/host/common/Arduino.cpp       | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp
index 9cd262de26..bd784bc7c8 100644
--- a/cores/esp8266/core_esp8266_main.cpp
+++ b/cores/esp8266/core_esp8266_main.cpp
@@ -162,7 +162,7 @@ extern "C" void __esp_delay(unsigned long ms) {
 
 extern "C" void esp_delay(unsigned long ms) __attribute__((weak, alias("__esp_delay")));
 
-bool try_esp_delay(const uint32_t start_ms, const uint32_t timeout_ms, const uint32_t intvl_ms) {
+bool esp_try_delay(const uint32_t start_ms, const uint32_t timeout_ms, const uint32_t intvl_ms) {
     uint32_t expired = millis() - start_ms;
     if (expired >= timeout_ms) {
         return true;
diff --git a/cores/esp8266/coredecls.h b/cores/esp8266/coredecls.h
index e1edf8b927..8b176fa0b3 100644
--- a/cores/esp8266/coredecls.h
+++ b/cores/esp8266/coredecls.h
@@ -55,7 +55,7 @@ inline void esp_suspend(T&& blocked) {
 // is asynchronously resumed before the timeout is reached.
 // Also returns false if intvl_ms have expired during the active call.
 // Otherwise return true to indicate the timeout_ms have completely expired.
-bool try_esp_delay(const uint32_t start_ms, const uint32_t timeout_ms, const uint32_t intvl_ms);
+bool esp_try_delay(const uint32_t start_ms, const uint32_t timeout_ms, const uint32_t intvl_ms);
 
 // This overload of esp_delay() delays for a duration of at most timeout_ms milliseconds.
 // Whenever it is resumed, as well as every intvl_ms millisconds, it performs
@@ -64,7 +64,7 @@ bool try_esp_delay(const uint32_t start_ms, const uint32_t timeout_ms, const uin
 template <typename T>
 inline void esp_delay(const uint32_t timeout_ms, T&& blocked, const uint32_t intvl_ms) {
     const auto start_ms = millis();
-    while (!try_esp_delay(start_ms, timeout_ms, intvl_ms) && blocked()) {
+    while (!esp_try_delay(start_ms, timeout_ms, intvl_ms) && blocked()) {
     }
 }
 
diff --git a/tests/host/common/Arduino.cpp b/tests/host/common/Arduino.cpp
index e934f8acba..293b812bc9 100644
--- a/tests/host/common/Arduino.cpp
+++ b/tests/host/common/Arduino.cpp
@@ -71,7 +71,7 @@ extern "C" void esp_delay (unsigned long ms)
     usleep(ms * 1000);
 }
 
-bool try_esp_delay(const uint32_t start_ms, const uint32_t timeout_ms, const uint32_t intvl_ms) {
+bool esp_try_delay(const uint32_t start_ms, const uint32_t timeout_ms, const uint32_t intvl_ms) {
     decltype(millis()) expired;
 
     if ((expired = millis() - start_ms) >= timeout_ms) {

From 863c4825e022be7bb76f9ae396b1ef71915f1d12 Mon Sep 17 00:00:00 2001
From: "Dirk O. Kaar" <dok@dok-net.net>
Date: Wed, 13 Oct 2021 08:10:32 +0200
Subject: [PATCH 19/21] Code cleanup as per review feedback.

---
 libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp
index a4d95383e5..0f6cb72abe 100644
--- a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp
+++ b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp
@@ -87,7 +87,10 @@ static wl_status_t waitWiFiConnect(uint32_t connectTimeoutMs)
     // The final argument, intvl_ms, to esp_delay influences how frequently
     // the scheduled recurrent functions (Schedule.h) are probed.
     esp_delay(connectTimeoutMs,
-        [&status]() { status = WiFi.status(); return status != WL_CONNECTED && status != WL_CONNECT_FAILED; }, 0);
+        [&status]() {
+            status = WiFi.status();
+            return status != WL_CONNECTED && status != WL_CONNECT_FAILED;
+        }, 0);
 
     // Check status
     if (status == WL_CONNECTED) {
@@ -236,7 +239,10 @@ int8_t ESP8266WiFiMulti::startScan()
     // The final argument, intvl_ms, to esp_delay influences how frequently
     // the scheduled recurrent functions (Schedule.h) are probed.
     esp_delay(WIFI_SCAN_TIMEOUT_MS,
-        [&scanResult]() { scanResult = WiFi.scanComplete(); return scanResult < 0; }, 0);
+        [&scanResult]() {
+            scanResult = WiFi.scanComplete();
+            return scanResult < 0;
+        }, 0);
     // Check for scan timeout which may occur when scan does not report completion
     if (scanResult < 0) {
         DEBUG_WIFI_MULTI("[WIFIM] Scan timeout\n");

From 679ecb16cb49a1e8831787db44e540e38cb2bb19 Mon Sep 17 00:00:00 2001
From: "Dirk O. Kaar" <dok@dok-net.net>
Date: Thu, 14 Oct 2021 08:12:28 +0200
Subject: [PATCH 20/21] Enable the startWaveform functions for calling from SYS
 context. Remove microoptimization that

could break on inlining.
---
 cores/esp8266/core_esp8266_waveform_phase.cpp | 2 +-
 cores/esp8266/core_esp8266_waveform_pwm.cpp   | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/cores/esp8266/core_esp8266_waveform_phase.cpp b/cores/esp8266/core_esp8266_waveform_phase.cpp
index 873dadede0..4240ccb3c1 100644
--- a/cores/esp8266/core_esp8266_waveform_phase.cpp
+++ b/cores/esp8266/core_esp8266_waveform_phase.cpp
@@ -211,7 +211,7 @@ int startWaveformClockCycles_weak(uint8_t pin, uint32_t highCcys, uint32_t lowCc
   }
   std::atomic_thread_fence(std::memory_order_acq_rel);
   while (waveform.toSetBits) {
-    yield(); // Wait for waveform to update
+    esp_yield(); // Wait for waveform to update
     std::atomic_thread_fence(std::memory_order_acquire);
   }
   return true;
diff --git a/cores/esp8266/core_esp8266_waveform_pwm.cpp b/cores/esp8266/core_esp8266_waveform_pwm.cpp
index 65e75a0c71..f85ccb76aa 100644
--- a/cores/esp8266/core_esp8266_waveform_pwm.cpp
+++ b/cores/esp8266/core_esp8266_waveform_pwm.cpp
@@ -373,8 +373,8 @@ int startWaveformClockCycles_weak(uint8_t pin, uint32_t timeHighCycles, uint32_t
   if (wvfState.waveformEnabled & mask) {
     // Make sure no waveform changes are waiting to be applied
     while (wvfState.waveformToChange) {
-      yield(); // Wait for waveform to update
-      // No mem barrier here, the call to a global function implies global state updated
+      esp_yield(); // Wait for waveform to update
+      MEMBARRIER();
     }
     wvfState.waveformNewHigh = timeHighCycles;
     wvfState.waveformNewLow = timeLowCycles;
@@ -393,8 +393,8 @@ int startWaveformClockCycles_weak(uint8_t pin, uint32_t timeHighCycles, uint32_t
     initTimer();
     forceTimerInterrupt();
     while (wvfState.waveformToEnable) {
-      yield(); // Wait for waveform to update
-      // No mem barrier here, the call to a global function implies global state updated
+      esp_yield(); // Wait for waveform to update
+      MEMBARRIER();
     }
   }
 

From 6199eb922c5265666a6ab108fe0bffc47dece0a0 Mon Sep 17 00:00:00 2001
From: "Dirk O. Kaar" <dok@dok-net.net>
Date: Fri, 15 Oct 2021 01:46:37 +0200
Subject: [PATCH 21/21] Adopt same code for host-test version of
 `esp_try_delay`.

Fix in-source specification for the main `esp_try_delay`.
---
 cores/esp8266/coredecls.h     | 9 +++++----
 tests/host/common/Arduino.cpp | 8 +++-----
 2 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/cores/esp8266/coredecls.h b/cores/esp8266/coredecls.h
index 8b176fa0b3..e5573792bb 100644
--- a/cores/esp8266/coredecls.h
+++ b/cores/esp8266/coredecls.h
@@ -51,10 +51,11 @@ inline void esp_suspend(T&& blocked) {
     } while (blocked());
 }
 
-// Try to delay for timeout_ms relative to start_ms. Returns false if the delayed task
-// is asynchronously resumed before the timeout is reached.
-// Also returns false if intvl_ms have expired during the active call.
-// Otherwise return true to indicate the timeout_ms have completely expired.
+// Try to delay until timeout_ms has expired since start_ms.
+// Returns true if timeout_ms has completely expired on entry.
+// Otherwise returns false after delaying for the relative
+// remainder of timeout_ms, or an absolute intvl_ms, whichever is shorter.
+// The delay may be asynchronously cancelled, before that timeout is reached.
 bool esp_try_delay(const uint32_t start_ms, const uint32_t timeout_ms, const uint32_t intvl_ms);
 
 // This overload of esp_delay() delays for a duration of at most timeout_ms milliseconds.
diff --git a/tests/host/common/Arduino.cpp b/tests/host/common/Arduino.cpp
index 293b812bc9..c2c1fa10a2 100644
--- a/tests/host/common/Arduino.cpp
+++ b/tests/host/common/Arduino.cpp
@@ -72,13 +72,11 @@ extern "C" void esp_delay (unsigned long ms)
 }
 
 bool esp_try_delay(const uint32_t start_ms, const uint32_t timeout_ms, const uint32_t intvl_ms) {
-    decltype(millis()) expired;
-
-    if ((expired = millis() - start_ms) >= timeout_ms) {
+    uint32_t expired = millis() - start_ms;
+    if (expired >= timeout_ms) {
         return true;
     }
-    const auto remaining = timeout_ms - expired;
-    esp_delay(remaining <= intvl_ms ? remaining : intvl_ms);
+    esp_delay(std::min((timeout_ms - expired), intvl_ms));
     return false;
 }