Nov 2, 2026

[C++] ternary conditional operator

Reference:
[kernnel][C][C++] ternary conditional operator trick in action
Lightning Talk: ?: - Jonathan Müller - C++Now 2026

#include <iostream>
#include <type_traits>

int main() {
    bool cond = true;

    // 1. cond ? -1 : 1
    // Both operands are int, so the resulting type is int.
    auto r1 = cond ? -1 : 1;
    static_assert(std::is_same_v<decltype(r1), int>);

    // 2. cond ? -1 : 87654321
    // Both operands fit in int (decimal literal without suffix is int), resulting in int.
    auto r2 = cond ? -1 : 87654321;
    static_assert(std::is_same_v<decltype(r2), int>);

    // 3. cond ? -1 : 0x87654321
    // On systems with 32-bit int, 0x87654321 exceeds INT_MAX (2,147,483,647).
    // Hexadecimal integer literals without suffixes take the first type in:
    // int -> unsigned int -> long int -> unsigned long int ... that can represent the value.
    // Thus, 0x87654321 is typed as `unsigned int`.
    // By the usual arithmetic conversions for the ternary operator, 
    // int (-1) is converted to unsigned int, yielding an unsigned result.
    auto r3 = cond ? -1 : 0x87654321;
    static_assert(std::is_same_v<decltype(r3), unsigned int>);

    std::cout << "r1: " << r1 << " (type: int)\n";
    std::cout << "r2: " << r2 << " (type: int)\n";
    std::cout << "r3: " << r3 << " (type: unsigned int, value: " << r3 << ")\n";

    return 0;
}

#include <iostream>
#include <cstdint>
#include <type_traits>

int main() {
    bool cond = true;

    // 1. cond ? 'a' : 1
    // 'a' has type char, and 1 has type int.
    // By the usual arithmetic conversions, char is promoted to int.
    auto r1 = cond ? 'a' : 1;
    static_assert(std::is_same_v<decltype(r1), int>);

    // 2. cond ? 'a' : short(11)
    // Types smaller than int (here char and short) undergo integral promotion
    // to int before determining the common type, resulting in int.
    auto r2 = cond ? 'a' : short(11);
    static_assert(std::is_same_v<decltype(r2), int>);

    // 3. cond ? std::uint8_t(1) : std::int8_t(-1)
    // Both uint8_t and int8_t promote to int because int can represent 
    // all values of both types (0..255 and -128..127).
    auto r3 = cond ? std::uint8_t(1) : std::int8_t(-1);
    static_assert(std::is_same_v<decltype(r3), int>);

    std::cout << "r1: " << r1 << " (type: int)\n";
    std::cout << "r2: " << r2 << " (type: int)\n";
    std::cout << "r3: " << r3 << " (type: int)\n";

    return 0;
}

#include <iostream>
#include <type_traits>

enum A { a1, a2 };
enum B { b1, b2 };

int main() {
    bool cond = true;

    // 1. cond ? a1 : a2
    // Both operands are of the exact same unscoped enum type `A`,
    // so the resulting common type remains `A`.
    auto r1 = cond ? a1 : a2;
    static_assert(std::is_same_v<decltype(r1), A>);

    // 2. cond ? a1 : 11
    // One operand is enum `A` and the other is `int`.
    // Unscoped enums undergo integral promotion to their underlying type / `int`.
    // The common type resolves to `int`.
    auto r2 = cond ? a1 : 11;
    static_assert(std::is_same_v<decltype(r2), int>);

    // 3. cond ? a1 : b1
    // The operands are of distinct unscoped enum types `A` and `B`.
    // Both undergo integral promotions to `int` via the usual arithmetic conversions,
    // resulting in `int`.
    auto r3 = cond ? a1 : b1;
    static_assert(std::is_same_v<decltype(r3), int>);

    std::cout << "r1: " << r1 << " (type: A)\n";
    std::cout << "r2: " << r2 << " (type: int)\n";
    std::cout << "r3: " << r3 << " (type: int)\n";

    return 0;
}

#include <iostream>
#include <type_traits>

enum A { a1, a2 };

// "We have `std::constant_wrapper` at home"[cite: 4]
template <auto V>
using constant = std::integral_constant<decltype(V), V>;

int main() {
    bool cond = true;

    // 1. cond ? constant<0> : constant<0>
    // Both operands are the exact same type: constant<0>.
    auto r1 = cond ? constant<0>{} : constant<0>{};
    static_assert(std::is_same_v<decltype(r1), constant<0>>);

    // 2. cond ? constant<0> : constant<1>
    // Distinct types: std::integral_constant provides `constexpr operator value_type()`.
    // Both convert implicitly to int, so overload resolution selects int.
    auto r2 = cond ? constant<0>{} : constant<1>{};
    static_assert(std::is_same_v<decltype(r2), int>);

    // 3. cond ? constant<a1> : constant<a1>
    // Both operands are the exact same type: constant<a1>.
    auto r3 = cond ? constant<a1>{} : constant<a1>{};
    static_assert(std::is_same_v<decltype(r3), constant<a1>>);

    // 4. cond ? constant<a1> : constant<a2>
    // Both operands provide conversion operators to `A` (`operator A()`).
    // However, built-in conditional operator candidates [over.built] only exist 
    // for pointers, pointer-to-members, scoped enumerations, and promoted arithmetic types.
    // Because `A` is an unscoped enumeration, it undergoes integral promotion,
    // making `int operator?:(bool, int, int)` the candidate chosen, resulting in `int`.
    auto r4 = cond ? constant<a1>{} : constant<a2>{};
    static_assert(std::is_same_v<decltype(r4), int>);

    std::cout << "r1 type: constant<0>\n";
    std::cout << "r2 type: int\n";
    std::cout << "r3 type: constant<a1>\n";
    std::cout << "r4 type: int\n";

    return 0;
}

#include <iostream>
#include <cstdint>
#include <type_traits>

template <auto V>
using constant = std::integral_constant<decltype(V), V>;

int main() {
    bool cond = true;

    // 1. cond ? constant<'a'> : constant<short(11)>
    // Both operands are distinct types. Their implicit conversion operators
    // yield `char` and `short`, which both undergo integral promotion to `int`.
    // The built-in candidate `int operator?:(bool, int, int)` is selected.
    auto r1 = cond ? constant<'a'>{} : constant<short(11)>{};
    static_assert(std::is_same_v<decltype(r1), int>);

    // 2. cond ? constant<std::uint8_t(1)> : constant<std::int8_t(-1)>
    // Operands implicitly convert to `std::uint8_t` and `std::int8_t`.
    // Both types promote to `int` via the usual arithmetic conversions,
    // resulting in `int`.
    auto r2 = cond ? constant<std::uint8_t(1)>{} : constant<std::int8_t(-1)>{};
    static_assert(std::is_same_v<decltype(r2), int>);

    // 3. cond ? constant<std::uint8_t(1)> : constant<std::uint8_t(2)>
    // Even though both convert to the same underlying type (std::uint8_t),
    // they are distinct class template instantiations. Overload resolution for 
    // the conditional operator considers built-in candidate operators [over.built].
    // Built-in candidates exist only for promoted arithmetic types (at least `int`),
    // not for small types like `std::uint8_t`, so the common result type promotes to `int`.
    auto r3 = cond ? constant<std::uint8_t(1)>{} : constant<std::uint8_t(2)>{};
    static_assert(std::is_same_v<decltype(r3), int>);

    std::cout << "r1: " << r1 << " (type: int)\n";
    std::cout << "r2: " << r2 << " (type: int)\n";
    std::cout << "r3: " << r3 << " (type: int)\n";

    return 0;
}

#include <iostream>
#include <type_traits>
#include <utility>

int main() {
    bool cond = true;
    int i = 0;
    const int ci = 0;

    // 1. cond ? i : ci -> const int&
    // Both operands are lvalues differing only in cv-qualification.
    // The result is an lvalue of the cv-combined type (const int), yielding `const int&` under decltype.
    decltype(auto) r1 = cond ? i : ci; //[cite: 6]
    static_assert(std::is_same_v<decltype(cond ? i : ci), const int&>); //[cite: 6]

    // 2. cond ? std::move(i) : std::move(ci) -> const int&&
    // Both operands are xvalues (rvalue references) differing only in cv-qualification.
    // The result is an xvalue of the cv-combined type (const int), yielding `const int&&` under decltype.
    decltype(auto) r2 = cond ? std::move(i) : std::move(ci); //[cite: 6]
    static_assert(std::is_same_v<decltype(cond ? std::move(i) : std::move(ci)), const int&&>); //[cite: 6]

    // 3. cond ? i : std::move(ci) -> int
    // One operand is an lvalue (`int&`) and the other is an xvalue (`const int&&`).
    // Because value categories differ and cannot bind to a common reference category directly,
    // lvalue-to-rvalue conversion is applied to both, resulting in a prvalue of type `int`.
    decltype(auto) r3 = cond ? i : std::move(ci); //[cite: 6]
    static_assert(std::is_same_v<decltype(cond ? i : std::move(ci)), int>); //[cite: 6]

    std::cout << "r1: " << r1 << " (type: const int&)\n";
    std::cout << "r2: " << r2 << " (type: const int&&)\n";
    std::cout << "r3: " << r3 << " (type: int)\n";

    return 0;
}

Oct 31, 2026

Low-Latency Networking: Tuning NIC Ring Buffers and Kernel Socket Bypass

Reference:
https://docs.ebpf.io/


When building high-frequency trading systems, real-time audio pipelines, or distributed low-latency services, the Linux kernel's standard TCP/IP networking stack can become a major bottleneck. Every packet copy, interrupt moderation delay, and kernel-space traversal adds precious microseconds of jitter.

In this post, we explore how to optimize your network interface cards (NICs) by scaling ring buffers, disabling interrupt coalescing, and bypassing the kernel entirely using modern zero-copy primitives like AF_XDP.

1. Maximizing NIC Ring Buffers (ethtool)

Network interface cards use circular ring buffers (queues of buffer descriptors) to handle incoming (RX) and outgoing (TX) packets. Under heavy traffic bursts, default ring sizes (often 256 or 512 descriptors) fill up instantly, causing dropped packets and costly retransmissions.

Scaling Ring Sizes

Check your NIC's maximum supported ring limits and current settings:

ethtool -g eth0

Maximize the RX and TX ring sizes to their peak limits (e.g., 4096) to absorb traffic bursts:
sudo ethtool -G eth0 rx 4096 tx 4096


Eliminating Interrupt Coalescing

By default, NIC drivers use interrupt coalescing—delaying hardware interrupts for a few microseconds (rx-usecs) to batch packets and save CPU cycles. For low-latency systems, this delay is unacceptable. To force immediate interrupt delivery upon packet arrival:

sudo ethtool -C eth0 rx-usecs 0 rx-frames 1


2. Kernel Socket Bypass Technologies

Standard socket calls (recv(), send()) force packets to copy through the Linux kernel's networking stack, incurring context switches and memory allocation overhead. Kernel bypass technologies eliminate this by mapping NIC ring buffers directly into user space.

Native Zero-Copy with AF_XDP

AF_XDP is an address family built directly into the Linux kernel specifically optimized for high-performance packet processing.

  • How it works: An unprivileged application allocates an aligned memory region (UMEM), registers it with the kernel, and maps kernel ring descriptors (fill_ring, rx_ring) into user space using mmap.

  • The Result: The NIC driver performs DMA transfers directly into user-space buffers, allowing your application to poll and process packets instantly with zero syscall overhead or memory copying.

Alternative Enterprise Bypass (DPDK & Onload)

For sub-microsecond HFT environments, standard OS primitives are often replaced entirely:

  • DPDK (Data Plane Development Kit): Replaces the kernel network driver with a poll-mode driver (PMD) running in a tight user-space polling loop.

  • Solarflare OpenOnload: Transparently bypasses the OS kernel stack via user-space virtual interfaces (EF_VI) to accelerate standard TCP/UDP socket calls.

Summary Blueprint for Low-Latency Networking

  1. Enlarge Ring Buffers: Maximize RX/TX ring sizes with ethtool -G to prevent buffer overflows under burst loads.

  2. Disable Coalescing: Set rx-usecs 0 to fire hardware interrupts immediately.

  3. Deploy Kernel Bypass: Use AF_XDP or DPDK to map NIC queues directly into user space, eliminating kernel stack traversal and memory copying overhead.

C++ AF_XDP Polling Loop Example

#include <iostream>
#include <vector>
#include <cstring>
#include <unistd.h>
#include <poll.h>
#include <sys/socket.h>
#include <linux/if_xdp.h>

// Dummy structures representing your mapped ring buffers and context
// (Assumes socket, rings, and UMEM have already been initialized and mmap'd as shown previously)
struct XdpPollerContext {
    int xsk_fd = -1;
    
    // Ring pointers mapped from kernel via mmap()
    // In production, these point to the actual mmap regions for fill, rx, tx, and comp rings.
    void* umem_area = nullptr;
    
    // Tracking free frame indices for the UMEM buffer
    std::vector<__u64> free_frames;
};

// Helper to reserve and push free buffers into the Fill Ring
void replenish_fill_ring(int xsk_fd, struct xdp_ring* fill_ring, std::vector<__u64>& free_frames) {
    __u32 index;
    // Reserve slots in the fill ring
    unsigned int rcvd = xsk_ring_prod__reserve(fill_ring, free_frames.size(), &index);
    if (rcvd == 0) return;

    for (unsigned int i = 0; i < rcvd; ++i) {
        *xsk_ring_prod__fill_addr(fill_ring, index++) = free_frames.back();
        free_frames.pop_back();
    }

    // Submit the filled entries to the kernel
    xsk_ring_prod__submit(fill_ring, rcvd);
}

// Main packet processing loop
void poll_rx_packets(XdpPollerContext& ctx, struct xdp_ring* rx_ring, struct xdp_ring* fill_ring) {
    struct pollfd pfd = {};
    pfd.fd = ctx.xsk_fd;
    pfd.events = POLLIN;

    std::cout << "Starting AF_XDP packet polling loop...\n";

    bool running = true;
    while (running) {
        // 1. Ensure the Fill ring has available buffers for incoming packets
        if (!ctx.free_frames.empty()) {
            // (Assuming helper or direct ring producer macros are used)
            // replenish_fill_ring(ctx.xsk_fd, fill_ring, ctx.free_frames);
        }

        // 2. Poll the socket for incoming traffic (blocks until packets arrive or timeout)
        int ret = poll(&pfd, 1, 1000); // 1-second timeout
        if (ret < 0) {
            if (errno == EINTR) continue;
            std::cerr << "Poll error: " << std::strerror(errno) << "\n";
            break;
        } else if (ret == 0) {
            // Timeout - no packets received in this interval
            continue;
        }

        // 3. Check the RX ring for completed packet descriptors
        // unsigned int rcvd = xsk_ring_cons__peek(rx_ring, 32, &idx);
        // if (rcvd > 0) {
        //     for (unsigned int i = 0; i < rcvd; ++i) {
        //         const struct xdp_desc* desc = xsk_ring_cons__rx_desc(rx_ring, idx++);
        //         
        //         // Access packet data directly in user-space UMEM area!
        //         void* packet_data = (char*)ctx.umem_area + desc->addr;
        //         uint32_t packet_len = desc->len;
        //
        //         // Process packet here...
        //         std::cout << "Received packet of size: " << packet_len << " bytes\n";
        //
        //         // After processing, add desc->addr back to free_frames to recycle the UMEM chunk
        //         ctx.free_frames.push_back(desc->addr);
        //     }
        //     
        //     // Release consumed descriptors back to the RX ring
        //     xsk_ring_cons__release(rx_ring, rcvd);
        // }
    }
}


High-Performance Networking: Deep Dive into XDP and AF_XDP

When building ultra-low latency systems, high-throughput firewalls, or custom load balancers, the Linux kernel's standard TCP/IP networking stack can become a major bottleneck. Every packet copy, interrupt moderation delay, and kernel-space traversal adds precious microseconds of overhead.

Here is a focused, end-to-end breakdown of XDP and AF_XDP, covering how they work, when to use them, and how to implement zero-copy packet processing in C++.

1. What is XDP?

XDP stands for eXpress Data Path. It is a programmable, high-performance packet processing framework built directly into the Linux kernel network stack, operating via eBPF (Extended Berkeley Packet Filter) programs attached directly to the network interface card (NIC) driver.

  • Earliest Possible Hook: XDP runs eBPF code the exact moment a packet is received by the NIC driver—long before the kernel allocates an sk_buff memory structure or traverses the heavy TCP/IP stack.

  • Line-Rate Execution: Capable of processing millions of packets per second (PPS) for tasks like DDoS mitigation, packet filtering, and early routing.

2. What is AF_XDP and When Should You Choose It?

AF_XDP (Address Family XDP) is a specialized socket family designed for high-speed packet I/O that bridges the gap between raw kernel-bypass frameworks and standard Linux sockets.

When to Choose AF_XDP:

  1. Extreme Packet Rates: Your application needs to ingest or filter millions of packets per second where standard sockets (AF_INET / AF_PACKET) saturate the CPU.

  2. Coexistence with the Linux Kernel: Unlike legacy kernel-bypass frameworks (like DPDK) which completely take over the NIC driver, AF_XDP coexists with the Linux kernel. Regular management traffic, SSH, and standard tools (tcpdump, iptables) continue to run seamlessly on the same interface.

  3. Zero-Copy Performance: You want bare-metal DMA (Direct Memory Access) speeds—where the NIC writes incoming packets directly into your user-space memory buffers (UMEM) with zero copying.


3. Tight Busy-Polling Loop (xsk_ring_cons)

To process packets with absolute minimum latency without the context-switch overhead of poll(), use an unblocked while(true) busy-polling loop on your consumer ring (xsk_ring_cons), pinned to an isolated CPU core:


#include <linux/if_xdp.h>

void tight_busy_poll_loop(struct xsk_ring_cons* rx_ring, 
                           struct xsk_ring_prod* fill_ring, 
                           int xsk_fd, 
                           void* umem_area) {
    constexpr uint32_t BATCH_SIZE = 64;
    uint32_t rx_idx = 0;

    while (true) {
        // 1. Non-blocking peek: Check for new packet descriptors in the RX ring
        uint32_t rcvd = xsk_ring_cons__peek(rx_ring, BATCH_SIZE, &rx_idx);

        if (rcvd > 0) {
            for (uint32_t i = 0; i < rcvd; ++i) {
                const struct xdp_desc* desc = xsk_ring_cons__rx_desc(rx_ring, rx_idx++);
                
                // Zero-copy access to packet payload in registered UMEM
                void* packet_data = static_cast<char*>(umem_area) + desc->addr;
                uint32_t packet_len = desc->len;

                // Process packet instantly...
                (void)packet_data;
                (void)packet_len;
            }

            // 2. Release consumed descriptors back to the RX ring
            xsk_ring_cons__release(rx_ring, rcvd);
        } else {
            // 3. Handle kernel wakeup requirement if driver is sleeping
            if (xsk_ring_prod__needs_wakeup(fill_ring)) {
                char dummy;
                recvfrom(xsk_fd, &dummy, 0, MSG_DONTWAIT, nullptr, nullptr);
            }
        }
    }
}

Simplifying High-Performance AF_XDP Networking with libbpf Helpers

Writing raw AF_XDP code in C++ for ultra-low latency networking is powerful, but it traditionally comes with a steep learning curve and a mountain of boilerplate. Manually allocating page-aligned memory for UMEM, configuring multiple socket options via setsockopt, calculating ring offsets with mmap, and binding queues can quickly clutter your codebase.

Fortunately, libbpf provides clean, high-level helper functions—namely xsk_umem__create() and xsk_socket__create()—that drastically streamline AF_XDP setup.

The Power of libbpf XSK Helpers

Instead of manually wrestling with low-level kernel descriptors and memory mapping, libbpf wraps the entire initialization ritual into clean library APIs:

  1. xsk_umem__create(): Handles raw UMEM registration (XDP_UMEM_REG), memory allocation mapping offsets, and automatically sets up your Fill and Completion rings.

  2. xsk_socket__create(): Binds the AF_XDP socket to your target network interface and hardware queue while initializing your RX and TX consumer/producer rings.

Clean C++ Implementation

Here is how straightforward it is to initialize an AF_XDP session using libbpf helpers:



#include <iostream>
#include <vector>
#include <stdexcept>
#include <cstring>
#include <unistd.h>
#include <sys/mman.h>
#include <bpf/xsk.h>

struct XdpSession {
    struct xsk_umem* umem = nullptr;
    struct xsk_socket* xsk = nullptr;
    void* umem_buffer = nullptr;
    
    struct xsk_ring_prod fill_ring;
    struct xsk_ring_cons comp_ring;
    struct xsk_ring_cons rx_ring;
    struct xsk_ring_prod tx_ring;

    ~XdpSession() {
        if (xsk) xsk_socket__delete(xsk);
        if (umem) xsk_umem__delete(umem);
        if (umem_buffer) free(umem_buffer);
    }
};

XdpSession init_af_xdp(const char* ifname, int queue_id) {
    XdpSession session;

    // 1. Allocate page-aligned UMEM memory area (4096 frames of 4096 bytes)
    const size_t frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE; 
    const size_t num_frames = 4096;
    const size_t umem_size = frame_size * num_frames;

    if (posix_memalign(&session.umem_buffer, getpagesize(), umem_size) != 0) {
        throw std::runtime_error("Failed to allocate aligned memory for UMEM");
    }

    // 2. Create and register UMEM using libbpf
    struct xsk_umem_config umem_cfg = {
        .fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS,
        .comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS,
        .frame_size = (unsigned int)frame_size,
        .frame_headroom = 0,
        .flags = 0
    };

    int ret = xsk_umem__create(&session.umem, 
                               session.umem_buffer, 
                               umem_size, 
                               &session.fill_ring, 
                               &session.comp_ring, 
                               &umem_cfg);
    if (ret) {
        throw std::runtime_error("Failed to create xsk umem: " + std::string(std::strerror(-ret)));
    }

    // 3. Create the AF_XDP socket
    struct xsk_socket_config xsk_cfg = {
        .rx_size = XSK_RING_CONS__DEFAULT_NUM_DESCS,
        .tx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS,
        .libbpf_flags = XSK_SLIBBPF_FLAGS__INHIBIT_PROG_LOAD,
        .xdp_flags = 0,
        .bind_flags = XDP_USE_NEED_WAKEUP
    };

    ret = xsk_socket__create(&session.xsk, 
                             ifname, 
                             queue_id, 
                             session.umem, 
                             &session.rx_ring, 
                             &session.tx_ring, 
                             &xsk_cfg);
    if (ret) {
        throw std::runtime_error("Failed to create xsk socket: " + std::string(std::strerror(-ret)));
    }

    std::cout << "Successfully created libbpf AF_XDP socket on " << ifname << " queue " << queue_id << "\n";
    return session;
}


Summary

By leveraging libbpf's built-in XSK helpers, you eliminate dozens of lines of complex socket option and memory mapping code. This lets you jump straight into what matters most: writing high-performance, zero-copy packet processing loops for your low-latency systems.

Building Deterministic Low-Latency C++ Systems: From Kernel to Container

Achieving microsecond-level determinism in high-performance computing requires removing jitter at every layer of the software and hardware stack. Here is a concise, end-to-end blueprint covering data hazard resolution, cache optimization, Linux kernel isolation, C++ thread pinning, IRQ shielding, and container deployment.

1. Resolving Loop Data Hazards

Before optimizing execution, ensure your loops are free of loop-carried dependencies.

  • The Problem: Modifying arrays where subsequent iterations depend on cross-iteration indices prevents pipelining and parallel execution.

  • The Solution: Use loop peeling to isolate boundary conditions and reorder operations within the loop body so dependencies are resolved inside the same iteration.


2. Just-In-Time Cache Pre-Warming

Periodic background timer-based cache warming is an anti-pattern that causes cache pollution and gets disrupted by OS churn.

  • The Fix: Pre-warm caches just-in-time right before your critical section begins by synchronously touching memory addresses and invoking hot functions once.

// Data cache pre-warm
for (size_t i = 0; i < data.size(); i += cache_line_size / sizeof(int)) {
    dummy_sink += data[i]; 
}
// Instruction cache pre-warm
volatile int dummy_result = hot_function(0); 


3. Kernel-Level Core Isolation

To silence OS noise on performance-critical cores, configure a robust kernel isolation stack in /etc/default/grub:

  • isolcpus: Removes target cores from the OS scheduler's normal load-balancing domains.

  • nohz_full: Suppresses periodic OS timer ticks on those cores when running a single thread.

  • rcu_nocbs: Offloads Read-Copy Update callback processing to housekeeping cores.

(Example GRUB parameter: isolcpus=2,3 nohz_full=2,3 rcu_nocbs=2,3)

4. Strict Thread Pinning in C++

Once isolated at the kernel level, explicitly bind your application threads to designated cores using POSIX affinities:


cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(target_core, &cpuset);
pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);


5. Shielding Hardware Interrupts (IRQs)

Prevent network packets and hardware devices from dragging your isolated cores into kernel space:

  • irqbalance: Configure banned bitmasks in /etc/default/irqbalance to exclude your isolated cores.

  • smp_affinity: Manually pin device IRQs exclusively to housekeeping cores (e.g., echo 3 > /proc/irq/16/smp_affinity).


6. Containerizing for Bare-Metal Performance

To extend your low-latency guarantees inside a Docker container without introducing scheduler or memory jitter, launch with these essential flags:

  • --cpuset-cpus="2,3" (locks container to isolated cores)

  • --cap-add=SYS_NICE (permits real-time scheduling priority like SCHED_FIFO)

  • --ulimit rtprio=99 --ulimit nice=-20 (enables real-time thread priorities)

  • --ulimit memlock=-1 (prevents memory swapping)

  • --ipc=host (minimizes shared memory and IPC latency)

Oct 30, 2026

[clang] Thread Safety Analysis

https://clang.llvm.org/docs/ThreadSafetyAnalysis.html


The page documents Clang's compile-time race checker for C++. You annotate which lock protects which data, and the compiler warns when code touches that data without holding the lock. The check is static: no runtime cost, and it is not a runtime tool like TSan.

Enabling it
Compile with -Wthread-safety.
Google code uses the ABSL_* macros from absl/base/thread_annotations.h. The page itself defines its own macros in a sample mutex.h.

The core idea: capabilities
A capability is anything that acts as a lock (a mutex, for example). You mark the lock class with CAPABILITY("mutex"), whose older spelling is lockable.
A thread holds a capability either exclusively (writing allowed) or shared (reading only).
The analysis tracks, at every point in a function, which capabilities the thread holds.

Main annotations
Annotation Meaning
GUARDED_BY(mu) You must hold mu to read (shared) or write (exclusive) this member.
PT_GUARDED_BY(mu) Same rule, but for the data the pointer points to.
REQUIRES(mu) / REQUIRES_SHARED(mu) Callers must already hold mu when they call this function.
ACQUIRE(mu) / RELEASE(mu) The function locks or unlocks mu.
TRY_ACQUIRE(true, mu) The function locks mu only if it returns the given value.
EXCLUDES(mu) Callers must not hold mu (prevents deadlock on non-reentrant locks).
SCOPED_CAPABILITY Marks an RAII lock class (like MutexLock) that locks in its constructor and unlocks in its destructor.
ASSERT_CAPABILITY(mu) Tells the analysis that mu is held from here on (the function checks at runtime).
RETURN_CAPABILITY(mu) The function returns a reference to mu (for getters).
ACQUIRED_BEFORE / ACQUIRED_AFTER Declares the order locks must be taken in. Only checked under -Wthread-safety-beta.
NO_THREAD_SAFETY_ANALYSIS Turns the check off for one function.


Negative capabilities
With -Wthread-safety-negative, REQUIRES(!mu) states that the caller must not hold mu. This catches deadlocks more strictly than EXCLUDES.

Warning flags
-Wthread-safety is the umbrella flag. It turns on -attributes, -analysis, and -precise.
-Wthread-safety-reference and -Wthread-safety-beta add stricter or still-experimental checks.

Known limitations
  • Each function is checked on its own. The analysis does not look inside callees, so it relies on their annotations.
  • It does not track aliases. If two pointers refer to the same mutex, the analysis treats them as different locks.
  • Conditional locking (if (x) mu.Lock(); ... if (x) mu.Unlock();) produces warnings.
  • Constructors and destructors are not checked.
  • Lock ordering is only partly enforced.

Example
class Account {
  Mutex mu;
  int balance GUARDED_BY(mu);
  void Deposit(int x) {
    balance += x;      // warning: writing 'balance' requires holding 'mu' exclusively
  }
  void SafeDeposit(int x) {
    MutexLock l(&mu);  // SCOPED_CAPABILITY
    balance += x;      // OK
  }
};

[linker] link time GC

Reference:
https://vsdmars.blogspot.com/2022/09/elf-entry-function.html
https://vsdmars.blogspot.com/2024/12/ccpponsea-keep-c-binaries-small-summary.html


Link-time GC is the linker throwing away code and data that nothing uses. With 
  • -ffunction-sections 
  • -fdata-sections 
  • and --gc-sections
the compiler puts each function and global in its own section. The linker starts from a set of roots (the entry point main/_start, exported symbols, and every entry in .init_array, which holds the static initializers). It follows references from those roots and drops every section it never reaches.

That's why static initializers get in the way. Each one is a root, so everything it references stays in the binary, even if the program never uses it at runtime:cpp


// registry.cc
static Registrar r("foo", &FooHandler); // the static initializer is in .init_array, so it's a root
// FooHandler and everything it calls stay in the binary,
// even if nothing ever looks up "foo".


Without that global, nobody would reference FooHandler, and the linker would drop it.

Oct 12, 2026

Summary of Michael Nielsen's "Notes on writing well"

 Here is a summary of Michael Nielsen's "Notes on writing well" from the provided document:

  • Writing the truth is difficult: Early drafts are usually just rough approximations of what you actually mean. Capturing the "truth" requires rigorous, repeated revisions and constantly asking if each sentence can be sharper.

  • Good writing is applied psychology: Traditional writing rules (like "avoid adverbs") aren't just arbitrary laws. Good writing focuses on the relationship between the reader and the text. Understanding your reader's psychology makes you a better writer.

  • Use natural vocabulary: Avoid using words you wouldn't use in normal conversation just to sound authoritative. Using "expert" language you aren't familiar with usually serves your ego rather than the reader.

  • Maintain a single, overriding purpose: Every single part of a piece must serve one sharp purpose. Straying from this—what Nielsen calls "discursive disease"—confuses the reader and breaks their emotional bond with the text. Rewrite ruthlessly to cut anything that doesn't serve the core goal.

  • Apply Occam's razor: Given two passages with the same meaning, the shorter one is usually better. Cutting words makes writing clearer and more vivid.

  • Start with "one true sentence": When facing writer's block, Nielsen recommends Hemingway's method: strip away elaborate introductions and simply write the truest, simplest declarative sentence you know. Build from there.

  • Stop when you know what comes next: Another Hemingway tactic to avoid writer's block is to end your daily writing session when things are going well and you know exactly what happens next.

  • Be patient in finding the "new": Discovering new ideas or narratives requires patience. You have to seek out new stimuli and be willing to try things that won't work in order to learn.

  • Keep prefaces short and specific: Most prefaces drone on unnecessarily. A good preface is essentially "metadata"—it should concisely state what the book is about, who it is for, and what the reader will learn, and then get out of the way.

Oct 4, 2026

[c++23] coroutine with deducing this

C++23 Deducing this: 

A standard C++20 IILE (Immediately Invoked Lambda Expression) coroutine [=](){...}() captures the temporary closure by reference, causing an immediate dangling reference once the statement evaluates. Using the explicit object parameter (this auto) forces the closure and its captures to be passed by value into the coroutine frame, binding their lifetime to the coroutine state.

operator->* Overload: 

Replaces the easily missed trailing (); of an IILE. The operator evaluates left-to-right, perfectly forwarding and immediately invoking the callable. This shifts the execution trigger to the head of the block for immediate visual parsing.

ASYNC Macro: 

Fuses the invocation trick and deducing this into a zero-overhead DSL. It enforces explicit captures (__VA_ARGS__) and strictly defines the promise return type (Coro), completely hiding the C++23 boilerplate.

Execution Flow: 

pool_task always suspends initially. The thread pool queue stores this initial handle. The queue must never automatically repush the handle after resumption; continuation is strictly deferred to the awaited operation's await_suspend logic to prevent catastrophic spin-loops.

class thread_pool {
    queue<std::coroutine_handle<>> work;
    // ...
};

void thread_pool::submit(auto awaitable) {
    // Used after free bug due to capture in anonymous type instance.
    auto task = [=]() -> pool_task {
        // always suspends initially
        co_await awaitable;
        // destroys itself in final suspend
    }();
    work.push(task.handle());
}

Deduce this with copy by value; NOT capture by value.
void thread_pool::submit(auto awaitable) {
    auto task = lambda_invoker() ->* [=](this auto) -> pool_task {
        co_await awaitable;
    };
    work.push(task.handle());
}

struct lambda_invoker {
    auto operator->*(auto&& fn) {
        return std::forward<decltype(fn)>(fn)();
    }
};

Use ->* operator with macro.
void thread_pool::submit(auto awaitable) {
    auto task = ASYNC(pool_task, awaitable) {
        co_await awaitable;
    };
    work.push(task.handle());
}

struct lambda_invoker {
    auto operator->*(auto&& fn) {
        return std::forward<decltype(fn)>(fn)();
    }
};

#define ASYNC(Coro, ...) \
    lambda_invoker() ->* [__VA_ARGS__](this auto) -> Coro