Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/fbuild-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub mod linker;
pub mod managed_zccache;
pub mod nrf52;
pub mod nxplpc;
pub mod package_override;
pub mod parallel;
pub mod perf_log;
pub mod pipeline;
Expand Down
35 changes: 32 additions & 3 deletions crates/fbuild-build/src/managed_zccache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,20 @@ mod tests {

#[test]
fn install_lock_blocks_second_caller_until_released() {
// What this test proves: holding the install lock makes a contending
// acquire wait until the first holder releases.
//
// Earlier shape — `std::thread::sleep(50ms); drop(first); assert waited >= 40ms` —
// was flaky under parallel-test contention: `std::thread::spawn` doesn't
// guarantee the spawned thread is scheduled before the main thread's sleep
// ends. If the waiter wasn't scheduled until after `drop(first)`, it would
// acquire instantly and report `waited ≈ 0ms`, failing the deadline.
//
// New shape: use `JoinHandle::is_finished` to prove the waiter is *still*
// blocked while we hold the lock — that's the actual invariant we care
// about. The wall-clock elapsed assertion becomes a much softer "waiter
// observed at least one polling sleep," which doesn't race with scheduler
// latency.
let tmp = tempfile::tempdir().unwrap();
let lock_dir = tmp.path().join("zccache.lock");
let first = acquire_install_lock_at(
Expand All @@ -700,13 +714,28 @@ mod tests {
started.elapsed()
});

std::thread::sleep(Duration::from_millis(50));
// Give the waiter a generous window to start polling. 100ms is far
// longer than any reasonable scheduler latency, so on a healthy run
// the waiter is definitely inside `acquire_install_lock_at` by now.
std::thread::sleep(Duration::from_millis(100));

// Load-bearing assertion: the waiter MUST still be blocked while we
// hold the lock. If it isn't, the lock isn't actually contended.
assert!(
!waiter.is_finished(),
"second lock acquire completed while the first lock was still held — \
the install lock is not blocking contended callers"
);

drop(first);

let waited = waiter.join().expect("waiter thread");
// Soft sanity check: at least some elapsed time. Don't pin a tight
// deadline — scheduler jitter on parallel test runs can hide between
// `Instant::now()` and the first `create_dir` call.
assert!(
waited >= Duration::from_millis(40),
"second lock should block behind the first, waited {waited:?}"
waited > Duration::from_millis(0),
"waiter should have measured a non-zero acquire duration, got {waited:?}"
);
}

Expand Down
6 changes: 5 additions & 1 deletion crates/fbuild-build/src/nxplpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@

pub mod mcu_config;
pub mod orchestrator;
pub mod platform_packages;
// `platform_packages` lookup is now shared at the workspace level
// (FastLED/fbuild#681) — see `crate::package_override`. The per-platform
// parser introduced in #663 has been folded into
// `fbuild_config::platform_packages` so every orchestrator gets the same
// parser without duplication.

use std::path::Path;

Expand Down
33 changes: 16 additions & 17 deletions crates/fbuild-build/src/nxplpc/orchestrator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,29 +119,28 @@ impl BuildOrchestrator for NxpLpcOrchestrator {
// framework owns `main()`, startup + vector table, wiring,
// HardwareSerial, SPI, and the device headers.
//
// Consumer override (FastLED/fbuild#663): when `platformio.ini`
// carries `platform_packages = framework-arduino-lpc8xx@<spec>`,
// fetch and use that commit instead of the const-pinned default
// — needed for bisection workflows like FastLED/FastLED#3325.
let env_config = ctx.config.get_env_config(&params.env_name)?;
let core_override =
super::platform_packages::lookup_override(env_config, "framework-arduino-lpc8xx");
let core = match &core_override {
// Honor `platform_packages = framework-arduino-lpc8xx@<URL>#<sha>`
// from the env section (FastLED/fbuild#663, #681): if set, the
// override URL replaces the const-pinned default and gets its own
// cache subdir via `PackageBase::with_override`. The parser
// + resolver are shared across every framework orchestrator so
// nxplpc carries no platform-specific platform_packages logic.
let core_override = ctx
.config
.get_env_config(&params.env_name)
.ok()
.and_then(|env| {
crate::package_override::resolve_override(env, "framework-arduino-lpc8xx")
});
let core = match core_override {
Some(ovr) => {
let short = &ovr.git_ref[..7.min(ovr.git_ref.len())];
let version = format!("override+g{}", short);
let banner = format!(
"ArduinoCore-LPC8xx OVERRIDE: {} (default pinned: {})",
ovr.archive_url,
ovr.url,
fbuild_packages::library::ArduinoCoreLpc8xx::commit()
);
tracing::info!("{}", banner);
ctx.build_log.push(banner);
fbuild_packages::library::ArduinoCoreLpc8xx::with_override(
&params.project_dir,
&ovr.archive_url,
&version,
)
fbuild_packages::library::ArduinoCoreLpc8xx::with_override(&params.project_dir, ovr)
}
None => fbuild_packages::library::ArduinoCoreLpc8xx::new(&params.project_dir),
};
Expand Down
259 changes: 0 additions & 259 deletions crates/fbuild-build/src/nxplpc/platform_packages.rs

This file was deleted.

Loading
Loading