mirror of
https://github.com/hathach/tinyusb.git
synced 2026-08-18 11:02:16 +00:00
A wedged USB device used to take the whole HIL run with it. Every worker that touched the poisoned node blocked uninterruptibly, the pool could not be joined, map_async discarded every board's result, and the job ran to the GitHub ceiling with no report at all -- while the self-hosted runner's single job slot stayed occupied and every queued job waited behind it. Bound the calls a worker makes itself. read_sysfs, bounded_open and run_cmd all answer within a wall clock; read_sysfs distinguishes "absent" from "unknown", because a blocked read is not evidence of absence, and caps stranded readers at four (each costs a thread and an fd for the life of the process) after which the worker declares itself blind. mtype, the gio unmount, the libmtp session and the arecord/iperf reaps go through those bounds; the MTP session runs in a disposable subprocess, since libmtp's ctypes calls block unkillably in D state. Bound the run. A pool guard (HIL_POOL_TIMEOUT, 60 min) fires before any job ceiling and still writes a report. When the pool will not shut down, the sweep kills what the workers spawned -- descendants, not just direct children, since flashers run in their own session -- confirms each kill actually landed, and exits early so the runner is freed. Whatever survived is named in the report. Deliberately shallow past that point. We do not re-scan process groups, prove pid ownership, or escalate through sudo: a root-owned survivor is reported, not force-killed, because signalling a pid we cannot prove is ours is the worse failure, and the job ceiling backstops whatever this misses. A D-state holder was never killable anyway. Recover instead of reporting a wedge. A HUNG usbtest case reflashes its own DUT through its roster flasher, but only where the flasher can reach its probe past a poisoned node -- openocd pinned to a validated vid_pid, or esptool. Where it cannot, the run says so rather than reserving budget for a path that cannot fire. Raise the CI ceilings above the pool guard so the guard fires first and still writes its report, and pin --retry 1 on every HIL leg: the guard is a flat constant and does not scale with max_retry, so argparse's default of 3 would triple the serialized usbtest tail against an unchanged guard. Split the module: execution in hil_test/hil_flash/usbtest, infrastructure in helper/ (locking, health, selection, shared bounded IO), and the two matrix generators into .github/scripts/ -- ci_set_matrix.py sat in workflows/, where GitHub treats every file as a workflow definition. 193 tests cover the bounded paths, the kill ladder, the guard and the selector against synthetic /proc trees and PATH-injected fakes; a real wedge cannot be manufactured on demand.
49 lines
1.2 KiB
YAML
49 lines
1.2 KiB
YAML
name: pre-commit
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
push:
|
|
pull_request:
|
|
branches: [ master ]
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
pre-commit:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Setup Ruby
|
|
uses: ruby/setup-ruby@v1
|
|
with:
|
|
ruby-version: '3.0'
|
|
|
|
- name: Checkout TinyUSB
|
|
uses: actions/checkout@v6
|
|
|
|
- name: Get Dependencies
|
|
run: |
|
|
# pinned: 1.1.0 breaks mock preprocessing on this project ("Failed to read
|
|
# _build/test/preprocess/.../raw/*.h for comment stripping"); revisit on next release
|
|
gem install ceedling -v 1.0.1
|
|
#cd test/unit-test
|
|
#ceedling test:all
|
|
|
|
# runs --all-files, so the hil-test hook fires here regardless of its `files:` scope
|
|
- name: Run pre-commit
|
|
uses: pre-commit/action@v3.0.1
|
|
|
|
- name: Build Fuzzer
|
|
run: |
|
|
sudo apt install libc++-dev libc++abi-dev
|
|
clang --version
|
|
export CC=clang
|
|
export CXX=clang++
|
|
fuzz_harness=$(ls -d test/fuzz/device/*/)
|
|
for h in $fuzz_harness
|
|
do
|
|
make -C $h get-deps
|
|
make -C $h all
|
|
done
|