What’s new in Pigweed: April 2026#
Highlights:
Developer tools: pw_ide Bazel code intelligence and VS Code UI overhaul -
pw_ideoverhauled Bazel code intelligence for VS Code, shifting to preconfigured compile commands aspects and simplifying the UI for a zero-setup developer experience.Kernel: Userspace process control - Processes can now completely monitor and control each other.
Developer tools: pw_presubmit v2 - Introduced a new v2 presubmit system supporting automatic fixes and commit-by-commit execution.
Async and concurrency: Void future support in pw::async2::Select - The
Selectcombinator now supports mixtures of value-returning and void-returning futures.
Async and concurrency#
Void future support in pw::async2::Select#
pw::async2::Select can now handle mixtures of value-returning
and void futures. Example:
#include "pw_async2/dispatcher.h"
#include "pw_async2/select.h"
#include "pw_async2/value_future.h"
pw::async2::Poll<int> PollMixedTasks(pw::async2::Context& ctx,
pw::async2::ValueFuture<void>& task_void,
pw::async2::ValueFuture<int>& task_int) {
// Select over a mixture of void and value-returning futures
auto combined = pw::async2::Select(task_void, task_int);
auto poll_result = combined.Pend(ctx);
if (poll_result.IsReady()) {
if (poll_result->has_value<0>()) {
// task_void completed
return 0;
}
if (poll_result->has_value<1>()) {
// task_int completed
return poll_result->value<1>();
}
}
return pw::async2::Pending();
}
CLs: 1
Bluetooth#
Dynamic credit sharing mode in pw_bluetooth_proxy#
Instead of statically partitioning controller credits between the host and the proxy, both can now share a single credit pool. Packets are queued dynamically when credits are exhausted and drained using a fair round-robin strategy. This maximizes buffer utilization and throughput while mitigating memory exhaustion.
CLs: 1
Build systems#
New Python API for Bazel introspection and queries#
Introduced a Python API within pw_build for programmatically
interacting with Bazel. It provides common, structured utilities for executing
and parsing bazel info, bazel cquery (to track source and generated
dependencies), bazel mod (for canonical repo path and bzlmod discovery), and
standard label parsing (BazelLabel). Example:
from pw_build.bazel_mod import external_repo_path
from pw_build.bazel_label import BazelLabel
# Get the path to an external repository
repo_path = external_repo_path("@some_external_repo")
# Parse a label
label = BazelLabel.from_string("//pw_build:bazel_mod")
CLs: 1
C++ data structures and utilities#
pw_function config override header#
Added support for PW_FUNCTION_CONFIG_HEADER, allowing projects to provide a
header file to override pw_function configuration options. This is
especially useful in Bazel builds where propagating compiler defines like
-include is not supported. Example:
// my_project/pw_function_config.h
#pragma once
// Override the inline callable size.
#define PW_FUNCTION_INLINE_CALLABLE_SIZE_BYTES 32
CLs: 1
Non-owning callbacks via pw::FunctionRef#
pw::FunctionRef is a non-owning callable wrapper matching C++26
std::function_ref semantics. It supports passing arbitrary
callable types to functions, including capturing lambdas, with minimal
overhead. Example:
#include "pw_function/function_ref.h"
void ProcessItems(pw::FunctionRef<void(int)> callback) {
for (int i = 0; i < 5; ++i) {
callback(i);
}
}
void UseFunctionRef() {
int sum = 0;
// Pass a capturing lambda as a temporary.
ProcessItems([&sum](int value) { sum += value; });
}
Dynamic containers reset support#
Added a reset() method to dynamic containers (DynamicDeque,
DynamicHashMap, DynamicPtrVector, DynamicQueue, DynamicVector)
to clear elements and deallocate the underlying buffer, returning the container
to a zero-memory state. This is useful for ensuring allocators can be safely
destroyed before the containers go out of scope. Example:
#include "pw_allocator/simple_allocator.h"
#include "pw_containers/dynamic_vector.h"
// ...
pw::allocator::SimpleAllocator allocator(buffer);
pw::DynamicVector<int> vector(allocator);
vector.push_back(1);
vector.reset(); // Frees all allocated memory and elements
CLs: 1
std::variant support in pw::Hash#
Updated pw::Hash to support hashing std::variant types. Hashing mixes
the variant’s index with the hash of the currently active alternative to
reduce hash collisions.
CLs: 1
New pw_numeric arithmetic and rounding utilities#
The new pw_numeric:rounding library provides RoundUp and
RoundDown templated utility functions. Also added constexpr
implementations for pw::abs and related absolute value functions, and
updated IntegerDivisionRoundNearest to use modulo arithmetic for large types
to safely prevent overflows. Example of RoundUp:
#include "pw_numeric/rounding.h"
constexpr size_t kBufferSize = 100;
constexpr size_t kAlignment = 16;
// Rounds up to 112
constexpr size_t kAlignedSize = pw::numeric::RoundUp(kBufferSize, kAlignment);
Developer tools#
pw_ide Bazel code intelligence and VS Code UI overhaul#
Overhauled Bazel code intelligence in pw_ide to provide a reliable,
out-of-the-box experience in VS Code. By moving to preconfigured compile
commands aspects and simplifying the UI, developers no longer need manual
setup. This update also resolves header resolution issues in sandboxed
environments, adds a compile commands database verification tool, and
optimizes performance by caching path resolutions.
pw_presubmit v2#
v2 of pw_presubmit includes a new Step class that supports automatic
fixes via a fix() method, a new orchestrator that manages execution and
automatically applies fixes, and a streamlined command-line interface.
Embedded memory regions support in pw_snapshot diagnostics#
Enhanced pw_snapshot core diagnostics and its Python processing tools to
support capturing and dumping arbitrary embedded memory regions (such as
peripheral registers or isolated SRAM banks). The Snapshot proto definition
now includes a repeated MemoryRegion message that stores a region’s name,
base address, and a raw binary payload. The Python snapshot processor
automatically reports address-name descriptors and accepts a project-provided
memory_region_processor callback to programmatically dump or parse these
regions during crash audits.
CLs: 1
HALs#
pw_i2c mcuxpresso hardware timeouts support for deadlines#
Added I2C bus timeout support for pw_i2c_mcuxpresso.
Transaction deadlines are now mapped to MCUxpresso SDK hardware TIMEOUT
registers, preventing busy-wait spins. This improves I2C bus responsiveness
during peripheral failures, especially when paired with
auto_restart_interface controls.
CLs: 1
Kernel#
Userspace process control#
Processes can now completely monitor and control each other. A process
can wait on a group of other processes to finish, detect when other
processes have exited, and even forcibly restart other processes. All
process control is managed through the pw_kernel security model.
A process must have a handle, which is an unforgeable token provided by
the kernel, before it can monitor or control another process.
Userspace time support#
Most pw_kernel syscalls require userspace to specify a deadline by which
an operation must complete. The new userspace::time::SystemClock::now()
function provides the current time to userspace apps so that they can compute
deadlines. The new sleep_until function lets an app sleep until a deadline
has passed.
Out-of-band channel signaling#
In pw_kernel a channel is a unidirectional IPC connection between 2
asymmetric peers: an initiator and a handler. Only the initiator can initiate
IPC transactions. The new object_set_peer_user_signal provides out-of-band
signaling for the handler. E.g. when the handler has data that the initiator
needs, the handler can invoke object_set_peer_user_signal to notify the
initiator that it should start a new transaction to get the new data.
CLs: 1
System generation#
The new
rust_appBazel macro simplifies the end-to-end process of buildingpw_kernel-based systems.The system generator now validates that all names are valid Rust identifiers and that process names are unique across apps.
RAM size is now configured more granularly at the process level rather than the app level.
RPC#
pw_transfer server-side lifecycle callbacks#
Introduced StartCallback and EndCallback callbacks to
TransferService, allowing platforms to be notified when server-side
transfers begin and complete or fail. These callbacks are invoked from the
transfer thread and must be lightweight and non-reentrant. Example:
#include "pw_transfer/transfer.h"
auto on_start = [](uint32_t session_id, uint32_t resource_id) {
// …
};
auto on_end = [](uint32_t session_id, pw::Status status) {
// …
};
pw::transfer::TransferService transfer_service(transfer_thread,
max_window_size_bytes,
std::move(on_start),
std::move(on_end));
CLs: 1
Third-party hardware and software#
pw_allocator support for Zephyr#
The new pw_allocator_zephyr module enables standard pw_allocator
interfaces to be used with Zephyr kernel heaps. SystemHeapAllocator wraps
Zephyr’s shared system heap API, and SynchronizedHeapAllocator constructs
and manages local synchronized heaps using Zephyr’s k_heap object.
CLs: 1
Timing and clocks#
pw_clock_tree improvements#
Dependency requirements are now enforced at compile time, ensuring non-blocking
elements cannot depend on blocking ones. The may_block method was removed
in favor of a per-element locking scheme, and a runtime SetSource
method was introduced. The MCUXpresso backend was updated to use the new
SetSource feature to implement a clock mux
(ClockMcuxpressoSyncSelector) with runtime source selection.