From e33788fcb8f1fb11b489623a839b8e41d0d9cf3b Mon Sep 17 00:00:00 2001 From: Florian Loitsch Date: Fri, 9 Feb 2024 12:22:58 +0400 Subject: [PATCH 1/5] Add hardware-watchdog abstraction. --- .github/dependabot.yml | 8 +++ .github/workflows/ci.yml | 50 ++++++++++++++++++ .github/workflows/publish.yml | 2 +- .gitignore | 1 + CMakeLists.txt | 10 ++++ Makefile | 27 ++++++++++ src/esp32.toit | 20 ++++++++ src/provider.toit | 88 +++++++++++++++++++++++--------- tests/CMakeLists.txt | 61 ++++++++++++++++++++++ tests/TESTS_LICENSE | 14 +++++ tests/correct-test.toit | 23 +++++++++ tests/many-one-failing-test.toit | 28 ++++++++++ tests/many-test.toit | 23 +++++++++ tests/package.lock | 5 ++ tests/package.yaml | 3 ++ tests/recover-test.toit | 30 +++++++++++ tests/timeout-test.toit | 19 +++++++ tests/util.toit | 56 ++++++++++++++++++++ 18 files changed, 444 insertions(+), 24 deletions(-) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/ci.yml create mode 100644 CMakeLists.txt create mode 100644 Makefile create mode 100644 src/esp32.toit create mode 100644 tests/CMakeLists.txt create mode 100644 tests/TESTS_LICENSE create mode 100644 tests/correct-test.toit create mode 100644 tests/many-one-failing-test.toit create mode 100644 tests/many-test.toit create mode 100644 tests/package.lock create mode 100644 tests/package.yaml create mode 100644 tests/recover-test.toit create mode 100644 tests/timeout-test.toit create mode 100644 tests/util.toit diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..5bacb9a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,8 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" # Necessary to update action hashs + directory: "/" + schedule: + interval: "weekly" + # Allow up to 3 opened pull requests for github-actions versions + open-pull-requests-limit: 3 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..a804619 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,50 @@ +# Zero-Clause BSD License + +# Copyright (C) 2024 Toitware ApS. + +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted. + +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +# FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +# PERFORMANCE OF THIS SOFTWARE. + +name: CI + +on: + push: + release: + types: [published] + +jobs: + build: + strategy: + matrix: + os: [ ubuntu-latest, windows-latest, macos-latest ] + # The versions should contain (at least) the lowest requirement + # and a version that is more up to date. + toit-version: [ v2.0.0-alpha.118, latest ] + include: + - toit-version: v2.0.0-alpha.118 + version-name: old + - toit-version: latest + version-name: new + + name: CI - ${{ matrix.os }} - ${{ matrix.version-name }} + + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v4 + + - uses: toitlang/action-setup@v1 + with: + toit-version: ${{ matrix.toit-version }} + + - name: Test + run: | + make test diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 740f21e..b137520 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -25,4 +25,4 @@ jobs: runs-on: ubuntu-latest steps: - name: Publish - uses: toitlang/pkg-publish@v1.3.0 + uses: toitlang/pkg-publish@v1.4.0 diff --git a/.gitignore b/.gitignore index 162e249..573186b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .packages/ +/build/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..2675392 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (C) 2024 Toitware ApS. +# Use of this source code is governed by a Zero-Clause BSD license that can +# be found in the tests/TESTS_LICENSE file. + +cmake_minimum_required(VERSION 3.23) + +project(watchdog NONE) + +enable_testing() +add_subdirectory(tests) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8ed1e02 --- /dev/null +++ b/Makefile @@ -0,0 +1,27 @@ +# Copyright (C) 2024 Toitware ApS. +# Use of this source code is governed by a Zero-Clause BSD license that can +# be found in the tests/LICENSE file. + +all: test + +.PHONY: build/CMakeCache.txt +build/CMakeCache.txt: + $(MAKE) rebuild-cmake + +install-pkgs: rebuild-cmake + cmake --build build --target install-pkgs + +test: install-pkgs rebuild-cmake + cmake --build build --target check + +# We rebuild the cmake file all the time. +# We use "glob" in the cmakefile, and wouldn't otherwise notice if a new +# file (for example a test) was added or removed. +# It takes <1s on Linux to run cmake, so it doesn't hurt to run it frequently. +rebuild-cmake: + mkdir -p build + # We need to set a build type, otherwise cmake won't run nicely on Windows. + # The build-type is otherwise unused. + cmake -B build -DCMAKE_BUILD_TYPE=Debug + +.PHONY: all test rebuild-cmake install-pkgs diff --git a/src/esp32.toit b/src/esp32.toit new file mode 100644 index 0000000..1a13b5f --- /dev/null +++ b/src/esp32.toit @@ -0,0 +1,20 @@ +// Copyright (C) 2024 Toitware ApS. All rights reserved. +// Use of this source code is governed by an MIT-style license that can be found +// in the LICENSE file. + +import esp32 + +import .provider show HardwareWatchdog + +class HardwareWatchdogEsp32 implements HardwareWatchdog: + start --ms/int: + esp32.watchdog-init --ms=ms + + feed -> none: + esp32.watchdog-reset + + stop -> none: + esp32.watchdog-deinit + + reboot -> none: + esp32.deep-sleep Duration.ZERO diff --git a/src/provider.toit b/src/provider.toit index 456a2a8..9b389d3 100644 --- a/src/provider.toit +++ b/src/provider.toit @@ -2,11 +2,42 @@ // Use of this source code is governed by an MIT-style license that can be found // in the LICENSE file. -import esp32 import log import monitor import system.services show ServiceProvider ServiceResource ServiceHandler import .api.service +import .esp32 show HardwareWatchdogEsp32 + +interface HardwareWatchdog: + /** + Starts the hardware watchdog timer. + + The watchdog will reset the system if it isn't fed within $ms milliseconds. + The hardware watchdog may have a coarser granularity than the given $ms. + */ + start --ms/int + + /** + Feeds the hardware watchdog. + + # Aliases + - `kick` + - `reset` + */ + feed -> none + + /** + Stops the hardware watchdog. + */ + stop -> none + + /** + Reboots the system. + + This is called if a watchdog isn't fed in time, but the system + watchdog still has time left. + */ + reboot -> none class WatchdogServiceProvider extends ServiceProvider implements ServiceHandler: @@ -14,12 +45,20 @@ class WatchdogServiceProvider extends ServiceProvider static GRANULARITY-MS ::= 2_000 dogs_/Map ::= {:} // From string to Watchdog. - system-watchdog-task_/Task? := null + hardware-watchdog_/HardwareWatchdog + hardware-watchdog-task_/Task? := null logger_/log.Logger mutex_/monitor.Mutex ::= monitor.Mutex + granularity-ms_/int - constructor --logger/log.Logger=((log.default.with-name "watchdog").with-level log.ERROR-LEVEL): + constructor + --logger/log.Logger=((log.default.with-name "watchdog").with-level log.ERROR-LEVEL) + --hardware-watchdog/HardwareWatchdog = HardwareWatchdogEsp32 + --granularity-ms/int = GRANULARITY-MS + : logger_ = logger + hardware-watchdog_ = hardware-watchdog + granularity-ms_ = granularity-ms super "watchdog" --major=1 --minor=0 provides WatchdogService.SELECTOR --handler=this @@ -43,7 +82,7 @@ class WatchdogServiceProvider extends ServiceProvider if index == WatchdogService.START-INDEX: dog := (this.resource client arguments[0]) as Watchdog dog.start (arguments[1] as int) - start-system-watchdog-if-necessary_ + start-hardware-watchdog-if-necessary_ logger_.info "started watchdog" --tags={ "id": dog.id } return null @@ -56,49 +95,52 @@ class WatchdogServiceProvider extends ServiceProvider if index == WatchdogService.STOP-INDEX: dog := (this.resource client arguments[0]) as Watchdog dog.stop - stop-system-watchdog-if-possible_ + stop-hardware-watchdog-if-possible_ logger_.info "stopped watchdog" --tags={ "id": dog.id } return null unreachable - start-system-watchdog-if-necessary_: - if system-watchdog-task_: return + start-hardware-watchdog-if-necessary_: + if hardware-watchdog-task_: return mutex_.do: - logger_.debug "starting system watchdog" - esp32.watchdog-init --ms=GRANULARITY-MS - system-watchdog-task_ = task:: + logger_.debug "starting hardware watchdog" + hardware-watchdog_.start --ms=granularity-ms_ + hardware-watchdog-task_ = task:: try: while true: too-late := false dogs_.do --values: | dog/Watchdog | if dog.is-too-late: - logger_.fatal "watchdog too late" --tags={ "id": dog.id } + logger_.error "watchdog too late" --tags={ "id": dog.id } too-late = true if too-late: - esp32.deep-sleep Duration.ZERO + // Feed the hardware watchdog one last time then request to reboot. + // This allows the system to clean up before rebooting. + mutex_.do: hardware-watchdog_.feed + hardware-watchdog_.reboot else: - // Feed the system watchdog. - logger_.debug "feeding system watchdog" - mutex_.do: esp32.watchdog-reset - sleep --ms=(GRANULARITY-MS / 2) + // Feed the hardware watchdog. + logger_.debug "feeding hardware watchdog" + mutex_.do: hardware-watchdog_.feed + sleep --ms=(granularity-ms_ / 2) finally: - system-watchdog-task_ = null + hardware-watchdog-task_ = null - stop-system-watchdog-if-possible_: - if not system-watchdog-task_: return + stop-hardware-watchdog-if-possible_: + if not hardware-watchdog-task_: return needs-watching := dogs_.any: | _ dog/Watchdog | not dog.is-stopped if needs-watching: return - // Shutdown the system watchdog. + // Shutdown the hardware watchdog. mutex_.do: - logger_.info "stopping system watchdog" - esp32.watchdog-deinit + logger_.info "stopping hardware watchdog" + hardware-watchdog_.stop - system-watchdog-task_.cancel + hardware-watchdog-task_.cancel remove-dog_ dog/Watchdog: logger_.info "removing watchdog" --tags={ "id": dog.id } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..25a0b8b --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,61 @@ +# Copyright (C) 2024 Toitware ApS. +# Use of this source code is governed by a Zero-Clause BSD license that can +# be found in the tests/LICENSE file. + +file(GLOB TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*_test.toit" "*-test.toit" "*_test_slow.toit" "*-test-slow.toit") + +# Add windows exe extension. +set(TOIT_EXEC "toit.run${CMAKE_EXECUTABLE_SUFFIX}" CACHE FILEPATH "The executable used to run the tests") +set(TPKG_EXEC "toit.pkg${CMAKE_EXECUTABLE_SUFFIX}" CACHE FILEPATH "The executable used to install the packages") +set(TEST_TIMEOUT 40 CACHE STRING "The maximal amount of time each test is allowed to run") +set(SLOW_TEST_TIMEOUT 200 CACHE STRING "The maximal amount of time each slow test is allowed to run") + +message("TPKG: ${TPKG_EXEC}") +add_custom_target( + "install-pkgs" + COMMAND "${TPKG_EXEC}" install + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" +) + +include(ProcessorCount) +ProcessorCount(NUM_CPU) + +# Add a custom target 'check' that runs our unit tests. +add_custom_target( + "check" + COMMAND "${CMAKE_CTEST_COMMAND}" -j${NUM_CPU} --output-on-failure -C Debug + USES_TERMINAL +) + +set(TEST_PREFIX "") +# Tests that fail locally and on toitlang/toit. +include(fail.cmake OPTIONAL) +# Tests that only fail when called with this test runner. +include(fail_pkg.cmake OPTIONAL) + +message("Failing tests: ${FAILING_TESTS}") +message("Skipped tests: ${SKIP_TESTS}") + +foreach(file ${TESTS}) + set(test_name "/tests/${file}") + if("${test_name}" IN_LIST SKIP_TESTS) + continue() + endif() + + add_test( + NAME "${test_name}" + COMMAND "${TOIT_EXEC}" "tests/${file}" + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) + + if ("${file}" MATCHES "slow.toit") + set_tests_properties(${test_name} PROPERTIES TIMEOUT ${SLOW_TEST_TIMEOUT}) + else() + set_tests_properties(${test_name} PROPERTIES TIMEOUT ${TEST_TIMEOUT}) + endif() + + if ("${test_name}" IN_LIST FAILING_TESTS) + set_tests_properties("${test_name}" PROPERTIES WILL_FAIL TRUE) + endif() + +endforeach() diff --git a/tests/TESTS_LICENSE b/tests/TESTS_LICENSE new file mode 100644 index 0000000..d049a4e --- /dev/null +++ b/tests/TESTS_LICENSE @@ -0,0 +1,14 @@ +Zero-Clause BSD License + +Copyright (C) 2024 Toitware ApS + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/tests/correct-test.toit b/tests/correct-test.toit new file mode 100644 index 0000000..401150e --- /dev/null +++ b/tests/correct-test.toit @@ -0,0 +1,23 @@ +// Copyright (C) 2024 Toitware ApS. +// Use of this source code is governed by a Zero-Clause BSD license that can +// be found in the tests/LICENSE file. + +import expect show * +import watchdog show WatchdogServiceClient + +import .util + +main: + run-test: |client ms hw-dog| test-correct-feeding client ms hw-dog + +test-correct-feeding client/WatchdogServiceClient ms/int hw-dog/FakeHardwareWatchdog: + dog := client.create "toit.io/test/correct" + dog.start --s=1 + 4.repeat: + dog.feed + sleep --ms=500 + dog.stop + dog.close + + expect-not hw-dog.failed + expect-not hw-dog.reboot-initiated diff --git a/tests/many-one-failing-test.toit b/tests/many-one-failing-test.toit new file mode 100644 index 0000000..deb97ab --- /dev/null +++ b/tests/many-one-failing-test.toit @@ -0,0 +1,28 @@ +// Copyright (C) 2024 Toitware ApS. +// Use of this source code is governed by a Zero-Clause BSD license that can +// be found in the tests/LICENSE file. + +import expect show * +import watchdog show WatchdogServiceClient + +import .util + +main: + run-test: |client ms hw-dog| test-many-one-timeout client ms hw-dog + +test-many-one-timeout client/WatchdogServiceClient ms/int hw-dog/FakeHardwareWatchdog: + dogs := List 20: client.create "toit.io/test/many-one-timeout/$it" + failing-dog := client.create "toit.io/test/many-one-timeout/failing" + dogs.do: it.start --s=1 + failing-dog.start --s=1 + 4.repeat: + dogs.do: it.feed + sleep --ms=500 + dogs.do: it.stop + dogs.do: it.close + failing-dog.stop + failing-dog.close + + expect hw-dog.failed + expect hw-dog.reboot-initiated + diff --git a/tests/many-test.toit b/tests/many-test.toit new file mode 100644 index 0000000..a83881b --- /dev/null +++ b/tests/many-test.toit @@ -0,0 +1,23 @@ +// Copyright (C) 2024 Toitware ApS. +// Use of this source code is governed by a Zero-Clause BSD license that can +// be found in the tests/LICENSE file. + +import expect show * +import watchdog show WatchdogServiceClient + +import .util + +main: + run-test: |client ms hw-dog| test-many client ms hw-dog + +test-many client/WatchdogServiceClient ms/int hw-dog/FakeHardwareWatchdog: + dogs := List 20: client.create "toit.io/test/many/$it" + dogs.do: it.start --s=1 + 4.repeat: + dogs.do: it.feed + sleep --ms=500 + dogs.do: it.stop + dogs.do: it.close + + expect-not hw-dog.failed + expect-not hw-dog.reboot-initiated diff --git a/tests/package.lock b/tests/package.lock new file mode 100644 index 0000000..2cc7f82 --- /dev/null +++ b/tests/package.lock @@ -0,0 +1,5 @@ +prefixes: + watchdog: .. +packages: + ..: + path: .. diff --git a/tests/package.yaml b/tests/package.yaml new file mode 100644 index 0000000..7a76c22 --- /dev/null +++ b/tests/package.yaml @@ -0,0 +1,3 @@ +dependencies: + watchdog: + path: .. diff --git a/tests/recover-test.toit b/tests/recover-test.toit new file mode 100644 index 0000000..8166851 --- /dev/null +++ b/tests/recover-test.toit @@ -0,0 +1,30 @@ +// Copyright (C) 2024 Toitware ApS. +// Use of this source code is governed by a Zero-Clause BSD license that can +// be found in the tests/LICENSE file. + +import expect show * +import watchdog show WatchdogServiceClient + +import .util + +main: + run-test: |client ms hw-dog| test-recover client ms hw-dog + +// If a watchdog gets lost/closed, another watchdog with the same name can take over. +test-recover client/WatchdogServiceClient ms/int hw-dog/FakeHardwareWatchdog: + dog := client.create "toit.io/test/recover" + dog.start --s=1 + // Simulate a crash/loss and just create a new dog with the same new name. + dog2 := client.create "toit.io/test/recover" + + 4.repeat: + dog2.feed + sleep --ms=500 + + dog2.stop + dog2.close + dog.stop + dog.close + + expect-not hw-dog.failed + expect-not hw-dog.reboot-initiated diff --git a/tests/timeout-test.toit b/tests/timeout-test.toit new file mode 100644 index 0000000..7fa2740 --- /dev/null +++ b/tests/timeout-test.toit @@ -0,0 +1,19 @@ +// Copyright (C) 2024 Toitware ApS. +// Use of this source code is governed by a Zero-Clause BSD license that can +// be found in the tests/LICENSE file. + +import expect show * +import watchdog show WatchdogServiceClient + +import .util + +main: + run-test: |client ms hw-dog| test-timeout client ms hw-dog + +test-timeout client/WatchdogServiceClient ms/int hw-dog/FakeHardwareWatchdog: + dog := client.create "toit.io/test/timeout" + dog.start --s=1 + hw-dog.signal.wait: hw-dog.failed + hw-dog.signal.wait: hw-dog.reboot-initiated + dog.stop + dog.close diff --git a/tests/util.toit b/tests/util.toit new file mode 100644 index 0000000..46c5d1c --- /dev/null +++ b/tests/util.toit @@ -0,0 +1,56 @@ +// Copyright (C) 2024 Toitware ApS. +// Use of this source code is governed by a Zero-Clause BSD license that can +// be found in the tests/LICENSE file. + +import monitor +import watchdog.provider +import watchdog show WatchdogServiceClient + +class FakeHardwareWatchdog implements provider.HardwareWatchdog: + // For simplicity we use the signal for internal and external + // notifications. + signal/monitor.Signal := monitor.Signal + task_/Task? := null + feed-count_/int := 0 + failed/bool := false + reboot-initiated/bool := false + + start --ms/int: + task_ = task:: + e := catch: + while true: + old-feed-count := feed-count_ + with-timeout --ms=ms: + signal.wait: old-feed-count != feed-count_ + // Timeout. + failed = true + signal.raise + + feed -> none: + feed-count_++ + signal.raise + + stop -> none: + task_.cancel + + reboot -> none: + failed = true + reboot-initiated = true + stop + signal.raise + +run-test [block]: + granularity-ms := 500 + fake-hardware-dog := FakeHardwareWatchdog + service-provider := provider.WatchdogServiceProvider + --granularity-ms=granularity-ms + --hardware-watchdog=fake-hardware-dog + service-provider.install + client := (WatchdogServiceClient).open + try: + with-timeout --ms=5_000: + block.call client granularity-ms fake-hardware-dog + finally: + client.close + service-provider.uninstall + From 89aa51a868e35e0eafee73367dcf182bf626dc6b Mon Sep 17 00:00:00 2001 From: Florian Loitsch Date: Fri, 9 Feb 2024 12:24:56 +0400 Subject: [PATCH 2/5] Don't use unintended ':' for functions. That's a feature that was introduced in a later SDK version. --- src/provider.toit | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/provider.toit b/src/provider.toit index 9b389d3..ad73de8 100644 --- a/src/provider.toit +++ b/src/provider.toit @@ -54,8 +54,7 @@ class WatchdogServiceProvider extends ServiceProvider constructor --logger/log.Logger=((log.default.with-name "watchdog").with-level log.ERROR-LEVEL) --hardware-watchdog/HardwareWatchdog = HardwareWatchdogEsp32 - --granularity-ms/int = GRANULARITY-MS - : + --granularity-ms/int = GRANULARITY-MS: logger_ = logger hardware-watchdog_ = hardware-watchdog granularity-ms_ = granularity-ms From 372674eb25cef398429524b61bf519aead1b52f6 Mon Sep 17 00:00:00 2001 From: Florian Loitsch Date: Fri, 9 Feb 2024 19:28:13 +0400 Subject: [PATCH 3/5] Feedback. --- src/esp32.toit | 4 ++-- src/provider.toit | 40 ++++++++++++++++---------------- tests/correct-test.toit | 8 +++---- tests/many-one-failing-test.toit | 8 +++---- tests/many-test.toit | 8 +++---- tests/recover-test.toit | 8 +++---- tests/timeout-test.toit | 8 +++---- tests/util.toit | 8 +++---- 8 files changed, 46 insertions(+), 46 deletions(-) diff --git a/src/esp32.toit b/src/esp32.toit index 1a13b5f..db8300f 100644 --- a/src/esp32.toit +++ b/src/esp32.toit @@ -4,9 +4,9 @@ import esp32 -import .provider show HardwareWatchdog +import .provider show SystemWatchdog -class HardwareWatchdogEsp32 implements HardwareWatchdog: +class SystemWatchdogEsp32 implements SystemWatchdog: start --ms/int: esp32.watchdog-init --ms=ms diff --git a/src/provider.toit b/src/provider.toit index ad73de8..4efe591 100644 --- a/src/provider.toit +++ b/src/provider.toit @@ -6,9 +6,9 @@ import log import monitor import system.services show ServiceProvider ServiceResource ServiceHandler import .api.service -import .esp32 show HardwareWatchdogEsp32 +import .esp32 show SystemWatchdogEsp32 -interface HardwareWatchdog: +interface SystemWatchdog: /** Starts the hardware watchdog timer. @@ -45,18 +45,18 @@ class WatchdogServiceProvider extends ServiceProvider static GRANULARITY-MS ::= 2_000 dogs_/Map ::= {:} // From string to Watchdog. - hardware-watchdog_/HardwareWatchdog - hardware-watchdog-task_/Task? := null + system-watchdog_/SystemWatchdog + system-watchdog-task_/Task? := null logger_/log.Logger mutex_/monitor.Mutex ::= monitor.Mutex granularity-ms_/int constructor --logger/log.Logger=((log.default.with-name "watchdog").with-level log.ERROR-LEVEL) - --hardware-watchdog/HardwareWatchdog = HardwareWatchdogEsp32 + --system-watchdog/SystemWatchdog = SystemWatchdogEsp32 --granularity-ms/int = GRANULARITY-MS: logger_ = logger - hardware-watchdog_ = hardware-watchdog + system-watchdog_ = system-watchdog granularity-ms_ = granularity-ms super "watchdog" --major=1 --minor=0 provides WatchdogService.SELECTOR --handler=this @@ -81,7 +81,7 @@ class WatchdogServiceProvider extends ServiceProvider if index == WatchdogService.START-INDEX: dog := (this.resource client arguments[0]) as Watchdog dog.start (arguments[1] as int) - start-hardware-watchdog-if-necessary_ + start-system-watchdog-if-necessary_ logger_.info "started watchdog" --tags={ "id": dog.id } return null @@ -94,19 +94,19 @@ class WatchdogServiceProvider extends ServiceProvider if index == WatchdogService.STOP-INDEX: dog := (this.resource client arguments[0]) as Watchdog dog.stop - stop-hardware-watchdog-if-possible_ + stop-system-watchdog-if-possible_ logger_.info "stopped watchdog" --tags={ "id": dog.id } return null unreachable - start-hardware-watchdog-if-necessary_: - if hardware-watchdog-task_: return + start-system-watchdog-if-necessary_: + if system-watchdog-task_: return mutex_.do: logger_.debug "starting hardware watchdog" - hardware-watchdog_.start --ms=granularity-ms_ - hardware-watchdog-task_ = task:: + system-watchdog_.start --ms=granularity-ms_ + system-watchdog-task_ = task:: try: while true: too-late := false @@ -118,18 +118,18 @@ class WatchdogServiceProvider extends ServiceProvider if too-late: // Feed the hardware watchdog one last time then request to reboot. // This allows the system to clean up before rebooting. - mutex_.do: hardware-watchdog_.feed - hardware-watchdog_.reboot + mutex_.do: system-watchdog_.feed + system-watchdog_.reboot else: // Feed the hardware watchdog. logger_.debug "feeding hardware watchdog" - mutex_.do: hardware-watchdog_.feed + mutex_.do: system-watchdog_.feed sleep --ms=(granularity-ms_ / 2) finally: - hardware-watchdog-task_ = null + system-watchdog-task_ = null - stop-hardware-watchdog-if-possible_: - if not hardware-watchdog-task_: return + stop-system-watchdog-if-possible_: + if not system-watchdog-task_: return needs-watching := dogs_.any: | _ dog/Watchdog | not dog.is-stopped if needs-watching: return @@ -137,9 +137,9 @@ class WatchdogServiceProvider extends ServiceProvider // Shutdown the hardware watchdog. mutex_.do: logger_.info "stopping hardware watchdog" - hardware-watchdog_.stop + system-watchdog_.stop - hardware-watchdog-task_.cancel + system-watchdog-task_.cancel remove-dog_ dog/Watchdog: logger_.info "removing watchdog" --tags={ "id": dog.id } diff --git a/tests/correct-test.toit b/tests/correct-test.toit index 401150e..15c1fb7 100644 --- a/tests/correct-test.toit +++ b/tests/correct-test.toit @@ -8,9 +8,9 @@ import watchdog show WatchdogServiceClient import .util main: - run-test: |client ms hw-dog| test-correct-feeding client ms hw-dog + run-test: |client ms system-dog| test-correct-feeding client ms system-dog -test-correct-feeding client/WatchdogServiceClient ms/int hw-dog/FakeHardwareWatchdog: +test-correct-feeding client/WatchdogServiceClient ms/int system-dog/FakeSystemWatchdog: dog := client.create "toit.io/test/correct" dog.start --s=1 4.repeat: @@ -19,5 +19,5 @@ test-correct-feeding client/WatchdogServiceClient ms/int hw-dog/FakeHardwareWatc dog.stop dog.close - expect-not hw-dog.failed - expect-not hw-dog.reboot-initiated + expect-not system-dog.failed + expect-not system-dog.reboot-initiated diff --git a/tests/many-one-failing-test.toit b/tests/many-one-failing-test.toit index deb97ab..86b3c8d 100644 --- a/tests/many-one-failing-test.toit +++ b/tests/many-one-failing-test.toit @@ -8,9 +8,9 @@ import watchdog show WatchdogServiceClient import .util main: - run-test: |client ms hw-dog| test-many-one-timeout client ms hw-dog + run-test: |client ms system-dog| test-many-one-timeout client ms system-dog -test-many-one-timeout client/WatchdogServiceClient ms/int hw-dog/FakeHardwareWatchdog: +test-many-one-timeout client/WatchdogServiceClient ms/int system-dog/FakeSystemWatchdog: dogs := List 20: client.create "toit.io/test/many-one-timeout/$it" failing-dog := client.create "toit.io/test/many-one-timeout/failing" dogs.do: it.start --s=1 @@ -23,6 +23,6 @@ test-many-one-timeout client/WatchdogServiceClient ms/int hw-dog/FakeHardwareWat failing-dog.stop failing-dog.close - expect hw-dog.failed - expect hw-dog.reboot-initiated + expect system-dog.failed + expect system-dog.reboot-initiated diff --git a/tests/many-test.toit b/tests/many-test.toit index a83881b..78447d3 100644 --- a/tests/many-test.toit +++ b/tests/many-test.toit @@ -8,9 +8,9 @@ import watchdog show WatchdogServiceClient import .util main: - run-test: |client ms hw-dog| test-many client ms hw-dog + run-test: |client ms system-dog| test-many client ms system-dog -test-many client/WatchdogServiceClient ms/int hw-dog/FakeHardwareWatchdog: +test-many client/WatchdogServiceClient ms/int system-dog/FakeSystemWatchdog: dogs := List 20: client.create "toit.io/test/many/$it" dogs.do: it.start --s=1 4.repeat: @@ -19,5 +19,5 @@ test-many client/WatchdogServiceClient ms/int hw-dog/FakeHardwareWatchdog: dogs.do: it.stop dogs.do: it.close - expect-not hw-dog.failed - expect-not hw-dog.reboot-initiated + expect-not system-dog.failed + expect-not system-dog.reboot-initiated diff --git a/tests/recover-test.toit b/tests/recover-test.toit index 8166851..0f16d95 100644 --- a/tests/recover-test.toit +++ b/tests/recover-test.toit @@ -8,10 +8,10 @@ import watchdog show WatchdogServiceClient import .util main: - run-test: |client ms hw-dog| test-recover client ms hw-dog + run-test: |client ms system-dog| test-recover client ms system-dog // If a watchdog gets lost/closed, another watchdog with the same name can take over. -test-recover client/WatchdogServiceClient ms/int hw-dog/FakeHardwareWatchdog: +test-recover client/WatchdogServiceClient ms/int system-dog/FakeSystemWatchdog: dog := client.create "toit.io/test/recover" dog.start --s=1 // Simulate a crash/loss and just create a new dog with the same new name. @@ -26,5 +26,5 @@ test-recover client/WatchdogServiceClient ms/int hw-dog/FakeHardwareWatchdog: dog.stop dog.close - expect-not hw-dog.failed - expect-not hw-dog.reboot-initiated + expect-not system-dog.failed + expect-not system-dog.reboot-initiated diff --git a/tests/timeout-test.toit b/tests/timeout-test.toit index 7fa2740..546ff7b 100644 --- a/tests/timeout-test.toit +++ b/tests/timeout-test.toit @@ -8,12 +8,12 @@ import watchdog show WatchdogServiceClient import .util main: - run-test: |client ms hw-dog| test-timeout client ms hw-dog + run-test: |client ms system-dog| test-timeout client ms system-dog -test-timeout client/WatchdogServiceClient ms/int hw-dog/FakeHardwareWatchdog: +test-timeout client/WatchdogServiceClient ms/int system-dog/FakeSystemWatchdog: dog := client.create "toit.io/test/timeout" dog.start --s=1 - hw-dog.signal.wait: hw-dog.failed - hw-dog.signal.wait: hw-dog.reboot-initiated + system-dog.signal.wait: system-dog.failed + system-dog.signal.wait: system-dog.reboot-initiated dog.stop dog.close diff --git a/tests/util.toit b/tests/util.toit index 46c5d1c..53d160b 100644 --- a/tests/util.toit +++ b/tests/util.toit @@ -6,7 +6,7 @@ import monitor import watchdog.provider import watchdog show WatchdogServiceClient -class FakeHardwareWatchdog implements provider.HardwareWatchdog: +class FakeSystemWatchdog implements provider.SystemWatchdog: // For simplicity we use the signal for internal and external // notifications. signal/monitor.Signal := monitor.Signal @@ -41,15 +41,15 @@ class FakeHardwareWatchdog implements provider.HardwareWatchdog: run-test [block]: granularity-ms := 500 - fake-hardware-dog := FakeHardwareWatchdog + fake-system-dog := FakeSystemWatchdog service-provider := provider.WatchdogServiceProvider --granularity-ms=granularity-ms - --hardware-watchdog=fake-hardware-dog + --system-watchdog=fake-system-dog service-provider.install client := (WatchdogServiceClient).open try: with-timeout --ms=5_000: - block.call client granularity-ms fake-hardware-dog + block.call client granularity-ms fake-system-dog finally: client.close service-provider.uninstall From ed585603ed4e5337f6b578d339a93b2a07104371 Mon Sep 17 00:00:00 2001 From: Florian Loitsch Date: Sat, 10 Feb 2024 11:30:48 +0100 Subject: [PATCH 4/5] Apply suggestions from code review Co-authored-by: Kasper Lund --- src/provider.toit | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/provider.toit b/src/provider.toit index 4efe591..8bfacbd 100644 --- a/src/provider.toit +++ b/src/provider.toit @@ -10,15 +10,15 @@ import .esp32 show SystemWatchdogEsp32 interface SystemWatchdog: /** - Starts the hardware watchdog timer. + Starts the system watchdog timer. The watchdog will reset the system if it isn't fed within $ms milliseconds. - The hardware watchdog may have a coarser granularity than the given $ms. + The system watchdog may have a coarser granularity than the given $ms. */ start --ms/int /** - Feeds the hardware watchdog. + Feeds the system watchdog. # Aliases - `kick` @@ -27,7 +27,7 @@ interface SystemWatchdog: feed -> none /** - Stops the hardware watchdog. + Stops the system watchdog. */ stop -> none @@ -104,7 +104,7 @@ class WatchdogServiceProvider extends ServiceProvider if system-watchdog-task_: return mutex_.do: - logger_.debug "starting hardware watchdog" + logger_.debug "starting system watchdog" system-watchdog_.start --ms=granularity-ms_ system-watchdog-task_ = task:: try: @@ -121,7 +121,7 @@ class WatchdogServiceProvider extends ServiceProvider mutex_.do: system-watchdog_.feed system-watchdog_.reboot else: - // Feed the hardware watchdog. + // Feed the system watchdog. logger_.debug "feeding hardware watchdog" mutex_.do: system-watchdog_.feed sleep --ms=(granularity-ms_ / 2) @@ -134,9 +134,9 @@ class WatchdogServiceProvider extends ServiceProvider needs-watching := dogs_.any: | _ dog/Watchdog | not dog.is-stopped if needs-watching: return - // Shutdown the hardware watchdog. + // Shutdown the system watchdog. mutex_.do: - logger_.info "stopping hardware watchdog" + logger_.info "stopping system watchdog" system-watchdog_.stop system-watchdog-task_.cancel From 0a8b21048986f46ad4e96d1d7ece47a2ad859976 Mon Sep 17 00:00:00 2001 From: Florian Loitsch Date: Sat, 10 Feb 2024 14:31:27 +0400 Subject: [PATCH 5/5] Rename hardware to system. Fix last reference. --- src/provider.toit | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/provider.toit b/src/provider.toit index 8bfacbd..a21e184 100644 --- a/src/provider.toit +++ b/src/provider.toit @@ -116,13 +116,13 @@ class WatchdogServiceProvider extends ServiceProvider too-late = true if too-late: - // Feed the hardware watchdog one last time then request to reboot. + // Feed the system watchdog one last time then request to reboot. // This allows the system to clean up before rebooting. mutex_.do: system-watchdog_.feed system-watchdog_.reboot else: // Feed the system watchdog. - logger_.debug "feeding hardware watchdog" + logger_.debug "feeding system watchdog" mutex_.do: system-watchdog_.feed sleep --ms=(granularity-ms_ / 2) finally: