Add U-mode task isolation and fix self-termination #265
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Linmo CI | |
| on: | |
| push: | |
| branches: | |
| - main | |
| pull_request: | |
| branches: | |
| - main | |
| # Cancel in-progress runs for the same PR/branch | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| # Least-privilege permissions | |
| permissions: | |
| contents: read | |
| jobs: | |
| # Fast-running lint job to catch formatting issues early | |
| lint: | |
| runs-on: ubuntu-24.04 | |
| name: Code Quality Checks | |
| timeout-minutes: 10 | |
| env: | |
| CLANG_FORMAT_VERSION: 18 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Install linting tools | |
| run: sudo apt-get update && sudo apt-get install -y --no-install-recommends clang-format-${{ env.CLANG_FORMAT_VERSION }} shfmt | |
| - name: Check code formatting | |
| run: .ci/check-format.sh | |
| - name: Check newline at end of files | |
| run: .ci/check-newline.sh | |
| # Build and test matrix - GNU and LLVM run in parallel after lint passes | |
| # GNU: Full test suite (build + app tests + functional tests) | |
| # LLVM: Build-only validation (verifies cross-toolchain compatibility) | |
| matrix-tests: | |
| runs-on: ubuntu-24.04 | |
| name: ${{ matrix.toolchain }} toolchain | |
| needs: lint | |
| timeout-minutes: 30 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| toolchain: [GNU, LLVM] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Install QEMU | |
| if: matrix.toolchain == 'GNU' | |
| run: sudo apt-get update && sudo apt-get install -y --no-install-recommends qemu-system-riscv32 | |
| - name: Set toolchain name | |
| id: toolchain | |
| run: echo "name=$(echo '${{ matrix.toolchain }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT | |
| - name: Cache toolchain | |
| uses: actions/cache@v5 | |
| id: cache-toolchain | |
| with: | |
| path: riscv | |
| key: riscv32-${{ steps.toolchain.outputs.name }}-${{ hashFiles('.ci/setup-toolchain.sh') }} | |
| - name: Setup ${{ matrix.toolchain }} toolchain | |
| if: steps.cache-toolchain.outputs.cache-hit != 'true' | |
| run: .ci/setup-toolchain.sh ${{ steps.toolchain.outputs.name }} | |
| - name: Configure toolchain environment | |
| run: | | |
| echo "$PWD/riscv/bin" >> "$GITHUB_PATH" | |
| echo "CROSS_COMPILE=riscv32-unknown-elf-" >> "$GITHUB_ENV" | |
| echo "TOOLCHAIN_TYPE=${{ steps.toolchain.outputs.name }}" >> "$GITHUB_ENV" | |
| - name: Verify toolchain | |
| run: | | |
| if [ "${{ matrix.toolchain }}" = "GNU" ]; then | |
| riscv32-unknown-elf-gcc --version | |
| qemu-system-riscv32 --version | |
| else | |
| riscv32-unknown-elf-clang --version | |
| fi | |
| - name: Build kernel | |
| run: make -j$(nproc) | |
| - name: Run app tests | |
| id: test | |
| continue-on-error: true | |
| if: matrix.toolchain == 'GNU' | |
| run: | | |
| output=$(.ci/run-app-tests.sh 2>&1) || true | |
| delimiter=$(openssl rand -hex 8) | |
| echo "TEST_OUTPUT<<$delimiter" >> $GITHUB_OUTPUT | |
| echo "$output" >> $GITHUB_OUTPUT | |
| echo "$delimiter" >> $GITHUB_OUTPUT | |
| - name: Run functional tests | |
| id: functional_test | |
| continue-on-error: true | |
| if: matrix.toolchain == 'GNU' | |
| run: | | |
| output=$(.ci/run-functional-tests.sh 2>&1) || true | |
| delimiter=$(openssl rand -hex 8) | |
| echo "FUNCTIONAL_TEST_OUTPUT<<$delimiter" >> $GITHUB_OUTPUT | |
| echo "$output" >> $GITHUB_OUTPUT | |
| echo "$delimiter" >> $GITHUB_OUTPUT | |
| - name: Collect test data | |
| if: always() | |
| run: | | |
| set -euo pipefail | |
| COMMIT_SHA="${{ github.sha }}" | |
| COMMIT_SHORT=$(git rev-parse --short HEAD 2>/dev/null || echo "${{ github.sha }}" | cut -c1-7) | |
| GITHUB_REPO="${{ github.repository }}" | |
| if [ "${{ matrix.toolchain }}" = "LLVM" ]; then | |
| # LLVM: Build-only validation, skip tests | |
| mkdir -p test-results | |
| echo "${{ steps.toolchain.outputs.name }}" > test-results/toolchain | |
| echo "$COMMIT_SHA" > test-results/commit_sha | |
| echo "$COMMIT_SHORT" > test-results/commit_short | |
| echo "$GITHUB_REPO" > test-results/github_repo | |
| echo "skipped" > test-results/crash_exit_code | |
| echo "skipped" > test-results/functional_exit_code | |
| # Generate skipped status for all apps | |
| for app in $(find app/ -name "*.c" -exec basename {} .c \; | sort); do | |
| echo "$app=skipped" >> test-results/apps_data | |
| done | |
| # Generate skipped status for functional tests | |
| echo "mutex=skipped" > test-results/functional_data | |
| echo "semaphore=skipped" >> test-results/functional_data | |
| # Generate skipped status for functional test criteria | |
| printf '%s\n' \ | |
| "mutex:fairness=skipped" \ | |
| "mutex:mutual_exclusion=skipped" \ | |
| "mutex:data_consistency=skipped" \ | |
| "mutex:overall=skipped" \ | |
| "semaphore:overall=skipped" \ | |
| > test-results/functional_criteria_data | |
| echo "LLVM: Build validation only (tests skipped)" | |
| else | |
| # GNU: Full test suite | |
| .ci/ci-tools.sh collect-data "${{ steps.toolchain.outputs.name }}" "$COMMIT_SHA" "$COMMIT_SHORT" "$GITHUB_REPO" "${{ steps.test.outputs.TEST_OUTPUT }}" "${{ steps.functional_test.outputs.FUNCTIONAL_TEST_OUTPUT }}" | |
| fi | |
| - name: Upload test results | |
| if: always() | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: test-results-${{ matrix.toolchain }} | |
| path: test-results/ | |
| retention-days: 7 | |
| if-no-files-found: warn | |
| # Aggregate results from all toolchain builds | |
| test-summary: | |
| runs-on: ubuntu-24.04 | |
| needs: matrix-tests | |
| if: always() | |
| timeout-minutes: 10 | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Download test results | |
| uses: actions/download-artifact@v7 | |
| with: | |
| pattern: test-results-* | |
| path: all-test-results/ | |
| - name: Generate test summary | |
| id: summary | |
| run: | | |
| .ci/ci-tools.sh aggregate all-test-results test-summary.toml | |
| if [ -f test-summary.toml ]; then | |
| echo "generated=true" >> $GITHUB_OUTPUT | |
| cat test-summary.toml | |
| else | |
| echo "generated=false" >> $GITHUB_OUTPUT | |
| echo "Warning: test-summary.toml not generated" | |
| fi | |
| - name: Upload test summary | |
| if: steps.summary.outputs.generated == 'true' | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: test-summary | |
| path: test-summary.toml | |
| retention-days: 30 | |
| - name: Post PR comment | |
| if: github.event_name == 'pull_request' && steps.summary.outputs.generated == 'true' | |
| continue-on-error: true | |
| run: .ci/ci-tools.sh post-comment test-summary.toml ${{ github.event.number }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Check final status | |
| run: | | |
| if [ ! -f test-summary.toml ]; then | |
| echo "Error: test-summary.toml not found" | |
| exit 1 | |
| fi | |
| status=$(grep -A1 '^\[summary\]' test-summary.toml | grep 'status =' | cut -d'"' -f2) | |
| echo "Overall status: $status" | |
| if [ "$status" = "passed" ]; then | |
| echo "All tests passed" | |
| else | |
| echo "Tests failed" | |
| grep -E '(failed|error)' test-summary.toml || true | |
| exit 1 | |
| fi |