Skip to content

Archive

Linux

231 articles
Linux 26 Sep 2026 4 min read

Batch Resize Images with Bash and ImageMagick Without Overwriting Originals

A resize command is straightforward. Keeping a batch recoverable takes more care. Writing results over the source images can leave a collection only partly processed if a conversion fails. Flattening every result into one folder also creates collisions: events/photo.jpg and products/photo.jpg would have the same destination name. A separate output tree avoids both problems. The script below accepts a source directory, a destination directory, and a maximum edge length. It processes JPEG, PNG, and WebP files recursively, retains their relative paths and formats, and leaves the originals alone.

Linux 26 Sep 2026 5 min read

Batch Convert JPEG and PNG to WebP with Bash and cwebp

Two files named photo.jpg and photo.png in the same directory would both become photo.webp. A batch converter that notices the collision only after it starts encoding may leave one image unconverted or replace an earlier result. It is better to check the entire input list first. The Bash script here uses cwebp for encoding and keeps a separate output tree. Its default auto mode encodes JPEG with lossy WebP and PNG with lossless WebP. The source images stay in place; existing destination files are skipped.

Linux 23 Sep 2026 4 min read

TFD_TIMER_CANCEL_ON_SET Turns Realtime Clock Jumps into ECANCELED

An absolute timer tied to CLOCK_REALTIME has a dependency that a monotonic deadline does not: an administrator, synchronization service, or privileged process can move the wall clock discontinuously while the timer is armed. Linux timerfd can expose that event explicitly. With TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, a qualifying clock jump causes a current or later read() on the timer descriptor to fail with ECANCELED. This behavior separates two events that would otherwise be easy to conflate: reaching a scheduled wall-clock instant and invalidating the clock basis used to schedule it.

Tech 23 Sep 2026 5 min read

TCP Keepalive Probes Detect Silent Dead Peers

An established TCP connection can remain quiet for a long time. Silence alone does not mean either endpoint has failed: an application may simply have no data to exchange. That property is useful for long-lived sessions, but it also creates an operational problem when a peer disappears without sending FIN or RST. A machine can lose power, a network path can fail, or state in an intermediate device can vanish. The surviving endpoint may retain a socket that still appears established because no packet has arrived to prove otherwise. TCP keepalive provides an optional mechanism for testing such idle connections.

Linux 23 Sep 2026 4 min read

signalfd Consumes Blocked Signals Through File Descriptor Reads

signalfd Consumes Blocked Signals Through File Descriptor Reads signalfd() turns selected signal notifications into records that can be consumed with read(). A matching pending signal makes the descriptor readable, which allows signal handling to share the same poll(), select(), or epoll path as sockets, timers, and other descriptors. The descriptor does not redirect signals merely because its mask names them. Normal signal-mask rules still apply. In the usual design, the selected signals are blocked before they can be delivered through their ordinary dispositions, then a signalfd reads the pending instances.

Linux 23 Sep 2026 4 min read

PR_SET_PDEATHSIG Binds a Child Notification to Parent Thread Exit

PR_SET_PDEATHSIG Binds a Child Notification to Parent Thread Exit PR_SET_PDEATHSIG lets a Linux process request a signal when the thread that created it terminates. The mechanism is narrow: it is a kernel-delivered notification tied to a parental relationship, not a general process-lifetime contract and not a guarantee that two processes terminate together. That distinction matters in supervisors, launchers, and helper processes. A child can react to loss of its creator without polling a PID, but the exact parent identity, setup timing, inheritance rules, and credential transitions define where the mechanism stops.

Linux 23 Sep 2026 4 min read

pidfd_getfd Duplicates a Target Descriptor into the Calling Process

pidfd_getfd Duplicates a Target Descriptor into the Calling Process pidfd_getfd() can place a duplicate of another process’s open file descriptor into the caller’s descriptor table. The returned descriptor is local to the caller, but it refers to the same open file description as the selected descriptor in the target process. That distinction matters. This operation does not reopen a pathname, reconstruct a socket, or create an independent file position. It duplicates an existing kernel reference across a process boundary.

Linux 23 Sep 2026 5 min read

membarrier Private Expedited Orders Userspace Memory Across Threads

Linux membarrier() can move part of a synchronization cost from a frequently executed path to a less frequent coordination path. With MEMBARRIER_CMD_PRIVATE_EXPEDITED, one thread asks the kernel to establish a memory-ordering point across the running threads in the same process. The caller pays for the system call when coordination is needed instead of requiring every fast-path execution to carry an explicit hardware memory barrier. This is narrower than a general thread rendezvous. membarrier() does not run an application callback on sibling threads, does not wait for application-level acknowledgements, and does not turn ordinary data races into valid synchronization. Its contract concerns ordering of userspace memory accesses around the barrier.

Linux 23 Sep 2026 3 min read

MADV_WIPEONFORK Replaces Inherited Private Memory with Zeroes

MADV_WIPEONFORK Replaces Inherited Private Memory with Zeroes A normal fork() gives the child mappings derived from the parent’s address space, with private writable pages commonly handled through copy-on-write. MADV_WIPEONFORK changes that inheritance rule for a selected private anonymous range: the mapping remains present in the child, but its contents are zero-filled there. The parent keeps its existing bytes. The operation therefore changes child-visible memory at the process-creation boundary rather than erasing the parent’s range.

Linux 23 Sep 2026 4 min read

MADV_DONTFORK Excludes Memory Ranges from Child Address Spaces

MADV_DONTFORK changes a specific part of Linux process creation: a mapping marked with this advice is not made available in the child created by fork(). The parent keeps the mapping. The child starts without that address range, so an address that was valid there in the parent is not automatically valid in the child. This is a semantic control over mapping inheritance, not a cache hint. It belongs to the Linux-specific madvise() operations whose effects can change memory behavior.

Tech 23 Sep 2026 5 min read

Linux RCU Grace Periods Separate Removal from Reclamation

Read-Copy Update, commonly called RCU, is a synchronization family used throughout the Linux kernel for data that is read frequently and changed less often. Its central move is to separate two events that ordinary locking often treats as one: removing an object from a shared structure and reclaiming the memory that stored it. A writer can publish a new state or unlink an old object while readers continue through read-side critical sections. The old storage remains valid until the kernel has established that every reader that could have observed the old reference has passed through a quiescent state. That interval is an RCU grace period.

Tech 23 Sep 2026 5 min read

Linux fork Uses Copy-on-Write to Delay Private Page Copies

fork() creates a new process with a virtual address space derived from the caller, but Linux does not need to duplicate every private physical page at the instant the syscall returns. For ordinary private writable mappings, the kernel can arrange parent and child page tables so both processes initially refer to the same physical memory while writes are constrained by copy-on-write state. This design makes process creation proportional to page-table and kernel bookkeeping rather than to the full amount of resident private data. Physical copying is deferred until a write requires the two address spaces to diverge.

Linux 23 Sep 2026 5 min read

fcntl OFD Locks Follow Open File Descriptions Instead of Processes

Traditional POSIX record locks have a property that can surprise code with several descriptors for the same file: lock ownership is associated with the process, and closing a descriptor for that file can release the process’s locks on it. Linux open file description locks move ownership to the kernel open file description referenced by a descriptor. The interface still uses fcntl() and struct flock, but the ownership boundary changes. F_OFD_SETLK, F_OFD_SETLKW, and F_OFD_GETLK make byte-range locking track the open file description rather than the process identity.

Linux 23 Sep 2026 5 min read

eventfd Semaphore Mode Turns Counter Values into Single-Unit Reads

Linux eventfd exposes a kernel-maintained 64-bit counter through a file descriptor. Its compact interface hides an important semantic choice: a normal read drains the current counter value, while an EFD_SEMAPHORE read consumes exactly one unit. The write path still adds values to the same counter. That distinction changes the object from an aggregate notification counter into a descriptor-backed source of individually consumable units. The readiness model remains compatible with poll, epoll, and related descriptor multiplexing, so the same object can connect producer accounting with an event loop without adding a separate pipe payload.

Linux 23 Sep 2026 4 min read

EPOLLEXCLUSIVE Limits Wakeups Across epoll Instances

EPOLLEXCLUSIVE Limits Wakeups Across epoll Instances EPOLLEXCLUSIVE changes event distribution when several epoll instances register the same target file description. Without the flag, a readiness event can wake waiters associated with every interested epoll instance. With exclusive registrations, Linux can restrict that fan-out and reduce redundant wakeups. The flag does not make delivery single-consumer, does not assign ownership of the target, and does not replace application-level coordination. Its contract is narrower: among epoll instances that registered a target with EPOLLEXCLUSIVE, one or more receive an event for a wakeup rather than requiring all of them to receive it.

Tech 23 Sep 2026 7 min read

epoll Readiness Modes Change How Event Loops Drain File Descriptors

Linux epoll lets one thread wait on readiness changes across many file descriptors without scanning every descriptor on each iteration. The interface is common in network servers, proxies, runtimes, and other programs that keep large sets of sockets active. The registration mode matters. Level-triggered operation keeps reporting a descriptor while the relevant condition remains ready. Edge-triggered operation reports transitions in readiness and expects the application to consume available work until the descriptor would block.

Linux 23 Sep 2026 5 min read

close_range with UNSHARE Separates File Descriptor Cleanup from Peer Threads

A multithreaded Linux process can share one file descriptor table across its threads. That arrangement is convenient during normal execution: a descriptor opened by one thread becomes available to its peers. It becomes less convenient when one thread is preparing a restricted execution context and wants to discard a broad descriptor range without racing with peers that can still allocate descriptors. close_range() provides a range operation for this boundary. With CLOSE_RANGE_UNSHARE, the kernel first separates the caller from the shared descriptor table and then applies the requested closure to the caller’s resulting table. The operation is close to combining unshare(CLONE_FILES) with a range close, but the kernel can perform less work in common cases.

Linux 22 Sep 2026 5 min read

TFD_TIMER_CANCEL_ON_SET Reports Realtime Clock Discontinuities

A timerfd armed against wall-clock time can cross a discontinuous clock adjustment before its deadline. With TFD_TIMER_CANCEL_ON_SET, Linux exposes that event through the descriptor: a subsequent read() fails with ECANCELED rather than presenting the clock jump as an ordinary timer expiration. The flag is deliberately narrow. It applies only when timerfd_settime() arms an absolute timer on CLOCK_REALTIME or CLOCK_REALTIME_ALARM, and it changes the handling of discontinuous changes to those clocks.

Tech 22 Sep 2026 6 min read

TCP TIME_WAIT Keeps Closed Connections Distinct from Delayed Segments

A TCP connection can finish exchanging application data and still leave a socket record behind. The familiar TIME_WAIT state is part of TCP’s close machinery, not evidence that a process forgot to close a descriptor. The endpoint that performs the active close commonly enters TIME_WAIT after the closing handshake. It keeps enough state for a bounded interval so late segments from the old connection cannot be confused with traffic from a later connection using the same endpoint identity.

Linux 22 Sep 2026 5 min read

SO_PEEK_OFF Gives UNIX Sockets a Stateful Peek Cursor

SO_PEEK_OFF Gives UNIX Sockets a Stateful Peek Cursor A normal recv(..., MSG_PEEK) examines data at the front of a socket receive queue without removing it. On Linux UNIX-domain sockets, SO_PEEK_OFF can replace that repeated front-of-queue view with a cursor that advances after each peek. The cursor is socket state. Peeking moves it forward, while consuming bytes from the front of the queue moves it backward by the amount removed. That interaction lets a process inspect successive queued regions without consuming them, while keeping the peek position tied to the remaining queue.

Linux 22 Sep 2026 6 min read

signalfd Turns Blocked Signals into Readable Events

Linux signals normally interrupt a thread through asynchronous delivery. signalfd() offers a different boundary for selected signals: keep them blocked in the relevant threads, then consume pending instances by reading a file descriptor. The signal mechanism itself does not become a byte stream. The kernel still maintains signal state and normal process- or thread-directed delivery rules. signalfd adds a file-descriptor interface for accepting signals from a configured set. Blocking and the descriptor mask are separate state A signalfd has a signal-set mask that selects which signals it can accept. That mask does not block those signals for a thread. Normal use therefore pairs descriptor creation with a signal mask operation.

Tech 22 Sep 2026 7 min read

NUMA First-Touch Placement Ties Physical Pages to the Faulting CPU

On a NUMA machine, reserving virtual address space does not necessarily choose the physical NUMA node that will supply every page. For anonymous memory, physical allocation commonly happens later, when a CPU first faults on a page. Under the default local allocation policy, that fault can make initialization order part of the memory-placement decision. This behavior is often called first-touch placement. The thread that first writes or otherwise faults a page can cause Linux to allocate backing memory near the NUMA node on which that thread is running, subject to the active memory policy, cpuset constraints, available memory, and kernel fallback behavior.

Tech 22 Sep 2026 6 min read

Linux TCP Receive Autotuning Expands Buffer Capacity with Flow Demand

A TCP receiver can accept data only while it has room to hold bytes that the application has not consumed. On Linux, that capacity does not have to remain fixed at the small amount available when a connection starts. Receive autotuning can enlarge the socket’s receive buffer as the connection develops, subject to system limits and the state of the flow. That behavior matters most when a connection carries sustained traffic across a path with a sizable bandwidth-delay product. A receiver with too little usable window can constrain the sender even when the network and sender could carry more data. Extra receive capacity gives TCP room to keep data in flight while the application drains the socket.

Tech 22 Sep 2026 5 min read

Linux Buffered Writes Separate Write Completion from Storage Persistence

A successful buffered write() does not generally mean that the new file data has already reached non-volatile storage. On Linux, the common buffered I/O path places file data in the page cache, marks the affected cache state dirty, and lets storage I/O occur later. That separation is central to normal filesystem I/O. Memory absorbs application writes at CPU-accessible speed, while the kernel can schedule backing-device traffic independently. The result improves flexibility and can reduce immediate storage stalls, but it also creates a boundary between syscall completion and persistence.