Documentation
¶
Overview ¶
Package iofd provides minimal file descriptor abstractions and specialized Linux handles for the Go ecosystem. It serves as the canonical handle abstraction for high-performance I/O systems.
Design Principles ¶
Zero-Overhead: All kernel interactions use code.hybscloud.com/zcall exclusively, bypassing Go's standard library syscall hooks. This eliminates runtime scheduler overhead in hot paths.
Allocation Discipline: Fixed-size EventFD, TimerFD, and SignalFD success paths keep syscall argument storage stack-backed and do not allocate heap memory. Caller-provided Into methods keep result storage caller-owned.
Atomic Lifecycle: FD uses atomic operations through one addressable descriptor cell. Close() is idempotent for that same cell. Copying an open FD does not duplicate kernel ownership; use Dup() for an independent close-capable descriptor.
Non-Blocking Constructors: EventFD, TimerFD, SignalFD, and NewPidFD create non-blocking descriptors by default. MemFD is created close-on-exec but has no creation-time nonblocking flag, and NewPidFDBlocking intentionally creates a blocking pidfd. Non-blocking operations return iox.ErrWouldBlock when they would block.
Supported Architectures ¶
The core FD type works on all Unix platforms. Specialized handles (EventFD, TimerFD, PidFD, MemFD, SignalFD) require Linux.
Platform FD Core EventFD TimerFD PidFD MemFD SignalFD Linux/amd64 ✓ ✓ ✓ ✓ ✓ ✓ Linux/arm64 ✓ ✓ ✓ ✓ ✓ ✓ Darwin/arm64 ✓ - - - - - FreeBSD/amd64 ✓ - - - - -
Usage ¶
Basic EventFD usage:
efd, err := iofd.NewEventFD(0)
if err != nil {
return err
}
defer efd.Close()
// Signal from one goroutine
efd.Signal(1)
// Wait in another
val, err := efd.Wait()
Timer example:
tfd, err := iofd.NewTimerFD()
if err != nil {
return err
}
defer tfd.Close()
// Arm for 100ms one-shot
tfd.ArmDuration(100*time.Millisecond, 0)
// Poll or use with epoll/io_uring, then read expirations
count, err := tfd.Expirations()
Safety Considerations ¶
Atomic Operations: FD access uses atomic load/store through one addressable FD cell. Atomicity protects same-cell state transitions; it does not make descriptor-number reuse safe if Close races with in-flight operations.
Valid Check: Always check Valid() or handle ErrClosed before performing operations on potentially closed descriptors.
Close Idempotency: Close() can be called multiple times safely on the same FD cell. Do not close copied FD values; they are not independent owners. After Close(), Raw() returns -1 and operations return ErrClosed.
Close Ordering: Call Close only after all in-flight operations and borrowed raw descriptor users are drained. The package does not add hidden synchronization around kernel descriptor reuse.
MappedRegion Lifetime: When using MemFD.Mmap(), the returned MappedRegion's Bytes() slice is only valid while the region is mapped. Call Unmap() when done.
Dependencies ¶
This package depends on:
- code.hybscloud.com/zcall — Zero-overhead syscalls
- code.hybscloud.com/iox — Semantic errors (ErrWouldBlock)
Package iofd provides minimal file descriptor abstractions and specialized Linux handles for the Go ecosystem. It serves as the common denominator for kernel resource lifecycle management.
All kernel interactions use code.hybscloud.com/zcall exclusively, bypassing Go's standard library syscall hooks for zero-overhead operation.
Index ¶
- Constants
- Variables
- type EventFD
- func (e *EventFD) Close() error
- func (e *EventFD) Fd() int
- func (e *EventFD) Raw() int32
- func (e *EventFD) Read(p []byte) (int, error)
- func (e *EventFD) Signal(val uint64) error
- func (e *EventFD) Valid() bool
- func (e *EventFD) Wait() (uint64, error)
- func (e *EventFD) WaitInto(val *uint64) error
- func (e *EventFD) Write(p []byte) (int, error)
- type FD
- func (fd *FD) Close() error
- func (fd *FD) Dup() (FD, error)
- func (fd *FD) Fd() int
- func (fd *FD) Raw() int32
- func (fd *FD) Read(p []byte) (int, error)
- func (fd *FD) SetCloexec(cloexec bool) error
- func (fd *FD) SetNonblock(nonblock bool) error
- func (fd *FD) Valid() bool
- func (fd *FD) Write(p []byte) (int, error)
- type Handle
- type MappedRegion
- type MemFD
- func (m *MemFD) Close() error
- func (m *MemFD) Fd() int
- func (m *MemFD) Mmap(length int, prot int) (*MappedRegion, error)
- func (m *MemFD) MmapAt(length int, prot int, offset int64) (*MappedRegion, error)
- func (m *MemFD) Name() string
- func (m *MemFD) Pread(p []byte, offset int64) (int, error)
- func (m *MemFD) Pwrite(p []byte, offset int64) (int, error)
- func (m *MemFD) Raw() int32
- func (m *MemFD) Read(p []byte) (int, error)
- func (m *MemFD) Seal(seals uint) error
- func (m *MemFD) Seals() (uint, error)
- func (m *MemFD) Size() (int64, error)
- func (m *MemFD) Truncate(size int64) error
- func (m *MemFD) Valid() bool
- func (m *MemFD) Write(p []byte) (int, error)
- type PidFD
- type PollCloser
- type PollFd
- type ReadWriter
- type Reader
- type SigSet
- type SignalFD
- func (s *SignalFD) Close() error
- func (s *SignalFD) Fd() int
- func (s *SignalFD) Mask() SigSet
- func (s *SignalFD) Raw() int32
- func (s *SignalFD) Read(p []byte) (int, error)
- func (s *SignalFD) ReadInto(info *SignalInfo) error
- func (s *SignalFD) SetMask(mask SigSet) error
- func (s *SignalFD) Valid() bool
- type SignalInfo
- type Signaler
- type Timer
- type TimerFD
- func (t *TimerFD) Arm(initial, interval int64) error
- func (t *TimerFD) ArmAt(deadline, interval int64) error
- func (t *TimerFD) ArmDuration(initial, interval time.Duration) error
- func (t *TimerFD) Close() error
- func (t *TimerFD) Disarm() error
- func (t *TimerFD) Expirations() (uint64, error)
- func (t *TimerFD) ExpirationsInto(count *uint64) error
- func (t *TimerFD) Fd() int
- func (t *TimerFD) GetTime() (remaining, interval int64, err error)
- func (t *TimerFD) GetTimeDuration() (remaining, interval time.Duration, err error)
- func (t *TimerFD) Raw() int32
- func (t *TimerFD) Read(p []byte) (int, error)
- func (t *TimerFD) Valid() bool
- type Writer
Constants ¶
const ( O_NONBLOCK = 0x800 O_CLOEXEC = 0x80000 )
File status flags for fcntl F_GETFL/F_SETFL. These are consistent across all Linux architectures.
const ( F_DUPFD = 0 F_GETFD = 1 F_SETFD = 2 F_GETFL = 3 F_SETFL = 4 F_DUPFD_CLOEXEC = 1030 )
fcntl commands. These are consistent across all Linux architectures.
const ( EFD_SEMAPHORE = 0x1 EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x800 )
eventfd flags
const ( MFD_CLOEXEC = 0x1 MFD_ALLOW_SEALING = 0x2 MFD_HUGETLB = 0x4 MFD_NOEXEC_SEAL = 0x8 MFD_EXEC = 0x10 )
memfd flags
const ( F_SEAL_SEAL = 0x1 // Prevent further seals F_SEAL_SHRINK = 0x2 // Prevent shrinking F_SEAL_GROW = 0x4 // Prevent growing F_SEAL_WRITE = 0x8 // Prevent writes F_SEAL_FUTURE_WRITE = 0x10 // Prevent future writes (allows current mappings) )
Seal types for memfd
const ( F_ADD_SEALS = 1033 F_GET_SEALS = 1034 )
fcntl commands for sealing
const ( PROT_NONE = 0x0 PROT_READ = 0x1 PROT_WRITE = 0x2 PROT_EXEC = 0x4 )
Memory protection flags for Mmap.
const ( MAP_SHARED = 0x1 MAP_PRIVATE = 0x2 )
Memory mapping flags.
const ( SIGHUP = 1 SIGINT = 2 SIGQUIT = 3 SIGILL = 4 SIGTRAP = 5 SIGABRT = 6 SIGBUS = 7 SIGFPE = 8 SIGKILL = 9 SIGUSR1 = 10 SIGSEGV = 11 SIGUSR2 = 12 SIGPIPE = 13 SIGALRM = 14 SIGTERM = 15 SIGSTKFLT = 16 SIGCHLD = 17 SIGCONT = 18 SIGSTOP = 19 SIGTSTP = 20 SIGTTIN = 21 SIGTTOU = 22 SIGURG = 23 SIGXCPU = 24 SIGXFSZ = 25 SIGVTALRM = 26 SIGPROF = 27 SIGWINCH = 28 SIGIO = 29 SIGPWR = 30 SIGSYS = 31 )
Signal constants matching Linux signal numbers.
const ( SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x800 )
signalfd flags
const ( CLOCK_REALTIME = 0 CLOCK_MONOTONIC = 1 CLOCK_BOOTTIME = 7 )
Clock IDs
const ( TFD_CLOEXEC = 0x80000 TFD_NONBLOCK = 0x800 TFD_TIMER_ABSTIME = 0x1 )
timerfd flags
const (
FD_CLOEXEC = 1
)
File descriptor flags for fcntl F_GETFD/F_SETFD. These are consistent across all Linux architectures.
const (
PIDFD_NONBLOCK = 0x800
)
pidfd flags
const (
SYS_FCNTL = 72
)
Syscall numbers for Linux amd64.
Variables ¶
var ( // ErrClosed indicates the file descriptor has been closed. ErrClosed = errors.New("fd: file descriptor closed") // ErrInvalidParam indicates an invalid parameter was passed. ErrInvalidParam = errors.New("fd: invalid parameter") // ErrInterrupted indicates the operation was interrupted by a signal. ErrInterrupted = errors.New("fd: interrupted") // ErrNoMemory indicates insufficient memory for the operation. ErrNoMemory = errors.New("fd: no memory") // ErrPermission indicates permission denied. ErrPermission = errors.New("fd: permission denied") )
Error definitions for iofd operations. These errors provide semantic meaning for common file descriptor failures.
Functions ¶
This section is empty.
Types ¶
type EventFD ¶
type EventFD struct {
// contains filtered or unexported fields
}
EventFD represents a Linux eventfd file descriptor. It provides an efficient inter-thread/kernel signaling mechanism.
An eventfd maintains an unsigned 64-bit counter. Writing adds to the counter, reading returns and resets it (or decrements by 1 in semaphore mode).
EventFD is created with EFD_NONBLOCK and EFD_CLOEXEC by default. Do not copy EventFD after first use.
func NewEventFD ¶
NewEventFD creates a new eventfd with the given initial value. The eventfd is created with EFD_NONBLOCK | EFD_CLOEXEC flags.
Returns iox.ErrWouldBlock semantics are used for non-blocking operations.
func NewEventFDSemaphore ¶
NewEventFDSemaphore creates a new eventfd in semaphore mode. The eventfd is created with EFD_SEMAPHORE, EFD_NONBLOCK, and EFD_CLOEXEC. In semaphore mode, reads decrement the counter by 1 instead of resetting it.
func (*EventFD) Raw ¶ added in v0.2.0
Raw returns the raw file descriptor for use in tight loops. The caller must ensure the EventFD remains valid while using the raw fd. The returned descriptor number is borrowed and must not be closed directly.
func (*EventFD) Read ¶
Read reads the eventfd counter into p. p must be at least 8 bytes. Only the first 8 bytes are used. This is a lower-level interface; prefer Wait() for typical usage. Returns iox.ErrWouldBlock if the counter is zero.
func (*EventFD) Signal ¶
Signal increments the eventfd counter by val. Returns iox.ErrWouldBlock if the counter would overflow (non-blocking mode).
The maximum value is 0xFFFFFFFFFFFFFFFE (2^64 - 2). Writing would block/fail if adding val would exceed this limit. On the success path, Signal does not allocate heap memory.
func (*EventFD) Wait ¶
Wait reads and returns the eventfd counter value. In normal mode, this resets the counter to zero. In semaphore mode, this decrements the counter by 1.
Returns iox.ErrWouldBlock if the counter is zero (non-blocking mode). On the success path, Wait does not allocate heap memory.
func (*EventFD) WaitInto ¶ added in v0.3.1
WaitInto reads the eventfd counter value into a caller-provided pointer. Returns iox.ErrWouldBlock if the counter is zero (non-blocking mode). This stores the result in caller-owned memory for hot paths.
Postcondition: On success, *val contains the counter value.
type FD ¶
type FD int32
FD represents one close-capable file descriptor cell. It stores the raw descriptor number as an int32 and uses atomic operations for Raw, Valid, and same-cell Close access.
An FD value is small and copyable as a Go value, but copying an open FD does not duplicate kernel ownership. A copied FD contains the same descriptor number in a different Go cell; closing both cells can close an unrelated descriptor if the number is reused. Use Dup to create an independent close-capable descriptor.
FD does not serialize Close against in-flight operations or borrowed raw descriptor users. Callers must stop and drain descriptor users before closing.
Invariants:
- A valid FD holds a non-negative value.
- After Close(), the FD value becomes -1.
- FD access is atomic through one addressable cell.
- Close is idempotent for that same cell.
const InvalidFD FD = -1
InvalidFD represents an invalid file descriptor.
func NewFD ¶
NewFD creates an FD from a raw file descriptor value. The caller is responsible for ensuring fd is valid and for transferring close ownership to the returned FD. If the raw descriptor is only borrowed, do not call Close on the returned value.
func (*FD) Close ¶
Close closes the file descriptor owned by this FD cell. It is safe to call Close multiple times on the same FD cell; subsequent calls are no-ops.
Close idempotence does not extend across copied FD values. Copying an open FD copies the descriptor number, not ownership. Use Dup to create a second descriptor that may be closed independently.
Call Close only after all in-flight operations and borrowed raw descriptor users are drained. Returns nil if already closed.
Postcondition: fd.Raw() == -1
func (*FD) Dup ¶
Dup duplicates the file descriptor and returns a new close-capable FD. The returned FD refers to the same open file description through a distinct descriptor-table entry and has FD_CLOEXEC set by default.
func (*FD) Fd ¶
Fd returns the file descriptor number as an int for interface compatibility. Implements PollFd interface.
The returned descriptor number is borrowed and is valid only while the FD remains open.
func (*FD) Raw ¶
Raw returns the underlying file descriptor number as an int32. Returns -1 if the FD is invalid or closed.
Raw is a borrowed observation only. It does not transfer ownership and the returned descriptor number must not be closed independently. Callers must keep the FD open while using the returned number.
func (*FD) Read ¶
Read reads up to len(p) bytes from the file descriptor. Returns iox.ErrWouldBlock if the fd is non-blocking and no data is available.
On EOF (read returns 0 bytes with no error), this returns (0, nil) rather than (0, io.EOF). This is intentional for low-level I/O:
- For SOCK_STREAM: (0, nil) indicates peer closed the connection (EOF)
- For SOCK_DGRAM/SOCK_SEQPACKET: (0, nil) indicates an empty message was received, which is NOT EOF - the peer may send more messages
Higher-level stream abstractions should translate (0, nil) to io.EOF if needed.
func (*FD) SetCloexec ¶
SetCloexec sets or clears the FD_CLOEXEC flag on the file descriptor.
func (*FD) SetNonblock ¶
SetNonblock sets or clears the O_NONBLOCK flag on the file descriptor.
type Handle ¶
type Handle interface {
PollCloser
ReadWriter
}
Handle represents a generic kernel handle with full I/O capabilities.
type MappedRegion ¶ added in v0.3.0
type MappedRegion struct {
// contains filtered or unexported fields
}
MappedRegion represents a memory-mapped region of a MemFD. The region must be unmapped with Unmap when no longer needed.
func (*MappedRegion) Bytes ¶ added in v0.3.0
func (r *MappedRegion) Bytes() []byte
Bytes returns the mapped region as a byte slice. The returned slice is only valid while the region is mapped. After Unmap returns, all previously returned slices are invalid.
Concurrency: The caller must synchronize access to the returned slice. Concurrent reads are safe; concurrent writes require external locking.
func (*MappedRegion) Len ¶ added in v0.3.0
func (r *MappedRegion) Len() int
Len returns the length of the mapped region in bytes. On 32-bit systems, regions larger than 2GB are not supported.
func (*MappedRegion) Ptr ¶ added in v0.3.0
func (r *MappedRegion) Ptr() unsafe.Pointer
Ptr returns the base pointer of the mapped region.
func (*MappedRegion) Unmap ¶ added in v0.3.0
func (r *MappedRegion) Unmap() error
Unmap unmaps the memory region. After this call, the region must not be accessed.
type MemFD ¶
type MemFD struct {
// contains filtered or unexported fields
}
MemFD represents a Linux memfd file descriptor. It provides an anonymous memory-backed file that can be used for:
- Inter-process communication via file descriptor passing
- Memory mapping without filesystem overhead
- Sealing to prevent modifications
MemFD is created with MFD_CLOEXEC by default. memfd_create has no creation-time nonblocking flag. Do not copy MemFD after first use.
Invariants:
- The file exists only in memory; it has no filesystem presence.
- Size starts at 0; use Truncate to set the desired size before use.
- Content is zeroed on allocation.
func NewMemFD ¶
NewMemFD creates a new memfd with the given name. The name is used for debugging (visible in /proc/[pid]/fd/). The memfd is created with MFD_CLOEXEC. It is not created nonblocking because Linux memfd_create does not provide a nonblocking creation flag.
The file is initially empty; call Truncate to set its size.
func NewMemFDHugeTLB ¶
NewMemFDHugeTLB creates a new memfd backed by huge pages. The memfd is created with MFD_CLOEXEC and MFD_HUGETLB. This can improve performance for large memory mappings. The size must be a multiple of the huge page size.
func NewMemFDSealed ¶
NewMemFDSealed creates a new memfd that allows sealing operations. The memfd is created with MFD_CLOEXEC and MFD_ALLOW_SEALING. Use this when you need to apply seals to prevent modifications.
func (*MemFD) Close ¶
Close closes the memfd. The memory is freed when all references (including mmaps) are released. Implements PollCloser interface.
func (*MemFD) Mmap ¶ added in v0.3.0
func (m *MemFD) Mmap(length int, prot int) (*MappedRegion, error)
Mmap maps the memfd into memory for zero-copy access. The mapping starts at offset 0 and spans the specified length.
prot specifies the memory protection: PROT_READ, PROT_WRITE, or both. The memfd must be sized appropriately before mapping (see Truncate).
The returned MappedRegion must be unmapped with Unmap when done. The MemFD can be closed after mapping; the region remains valid.
func (*MemFD) MmapAt ¶ added in v0.3.0
MmapAt maps the memfd into memory starting at the given offset. offset must be page-aligned (typically 4096 bytes).
func (*MemFD) Pread ¶ added in v0.2.0
Pread reads from the memfd at the specified offset without changing the file position.
func (*MemFD) Pwrite ¶ added in v0.2.0
Pwrite writes to the memfd at the specified offset without changing the file position.
func (*MemFD) Raw ¶ added in v0.2.0
Raw returns the raw file descriptor for use in tight loops. The caller must ensure the MemFD remains valid while using the raw fd. The returned descriptor number is borrowed and must not be closed directly. Callers must synchronize Close with users of the borrowed descriptor number.
func (*MemFD) Seal ¶
Seal applies seals to prevent certain operations. This is only available if the memfd was created with MFD_ALLOW_SEALING.
Once a seal is applied, it cannot be removed.
type PidFD ¶
type PidFD struct {
// contains filtered or unexported fields
}
PidFD represents a Linux pidfd file descriptor. It provides a stable handle to a process that avoids PID reuse races.
A pidfd becomes readable when the process terminates, making it suitable for polling via epoll and io_uring. pidfd_open sets close-on-exec on returned pidfds. Do not copy PidFD after first use.
Invariants:
- The pidfd refers to a specific process instance, not just a PID.
- After the process exits, the pidfd remains valid for signal/wait operations.
func NewPidFD ¶
NewPidFD creates a new pidfd for the specified process ID. The pidfd is created with PIDFD_NONBLOCK. pidfd_open sets close-on-exec.
Returns an error if the process does not exist or if pidfd is not supported.
func NewPidFDBlocking ¶
NewPidFDBlocking creates a new pidfd for the specified process ID without the PIDFD_NONBLOCK flag. pidfd_open still sets close-on-exec.
func (*PidFD) GetFD ¶
GetFD duplicates a file descriptor from the target process. targetFD is the file descriptor number in the target process.
This operation requires appropriate privileges (CAP_SYS_PTRACE or being in the same user namespace with PTRACE_MODE_ATTACH_REALCREDS).
Returns a new close-capable FD in the current process that refers to the same open file description as targetFD in the target process. The returned FD has close-on-exec set by the kernel.
func (*PidFD) PID ¶
PID returns the process ID this pidfd refers to. Note: The PID value may be reused by a new process after the original exits, but the pidfd still refers to the original process instance.
func (*PidFD) Raw ¶ added in v0.2.0
Raw returns the raw file descriptor for use in tight loops. The caller must ensure the PidFD remains valid while using the raw fd. The returned descriptor number is borrowed and must not be closed directly. Callers must synchronize Close with users of the borrowed descriptor number.
func (*PidFD) SendSignal ¶
SendSignal sends a signal to the process. This is race-free with respect to PID reuse.
sig is the signal number to send (e.g., SIGTERM, SIGKILL). Returns nil on success.
type PollCloser ¶
type PollCloser interface {
PollFd
// Close releases the underlying file descriptor.
// Call Close only after in-flight users of the descriptor are drained.
// After Close returns, Fd() behavior is undefined.
Close() error
}
PollCloser extends PollFd with the ability to close the resource.
type PollFd ¶
type PollFd interface {
// Fd returns the underlying file descriptor as an integer.
// The returned value is borrowed and valid only while the resource is open.
// It must not be closed independently.
// Callers must keep the resource open while using the returned value.
Fd() int
}
PollFd represents a pollable file descriptor. Any resource that can be monitored for I/O readiness implements this interface.
type ReadWriter ¶
ReadWriter combines Reader and Writer interfaces.
type Reader ¶
type Reader interface {
// Read reads up to len(p) bytes into p.
// Returns the number of bytes read and any error encountered.
// Returns iox.ErrWouldBlock if the resource is not ready.
Read(p []byte) (n int, err error)
}
Reader is an interface for reading from a file descriptor.
type SigSet ¶
type SigSet uint64
SigSet represents a signal set for signalfd operations. This package represents it as a 64-bit mask where bit N represents signal N+1.
Limitation: This implementation supports signals 1-64 only. Real-time signals beyond SIGRTMIN+32 (signal 64) are not supported. For most applications, standard signals (1-31) are sufficient.
func (*SigSet) Add ¶
Add adds a signal to the set. If sig is outside the valid range (1-64), the call is a no-op.
func (*SigSet) Del ¶
Del removes a signal from the set. If sig is outside the valid range (1-64), the call is a no-op.
type SignalFD ¶
type SignalFD struct {
// contains filtered or unexported fields
}
SignalFD represents a Linux signalfd file descriptor. It provides a file descriptor for accepting signals synchronously, enabling signal handling via poll/epoll/io_uring.
SignalFD is created with SFD_NONBLOCK and SFD_CLOEXEC by default. Do not copy SignalFD after first use.
Invariants:
- The caller must block the signals with sigprocmask before using signalfd.
- Each Read returns exactly one SignalInfo structure (128 bytes).
func NewSignalFD ¶
NewSignalFD creates a new signalfd monitoring the given signal set. The signalfd is created with SFD_NONBLOCK and SFD_CLOEXEC flags.
The caller should block the signals in the set using sigprocmask before creating the signalfd to prevent default signal handling.
func (*SignalFD) Mask ¶
Mask returns the current signal mask. Concurrency: callers must synchronize with concurrent SetMask calls.
func (*SignalFD) Raw ¶ added in v0.2.0
Raw returns the raw file descriptor for use in tight loops. The caller must ensure the SignalFD remains valid while using the raw fd. The returned descriptor number is borrowed and must not be closed directly.
func (*SignalFD) Read ¶
Read reads signal information into the provided buffer. Implements io.Reader interface. p must be at least 128 bytes. Returns iox.ErrWouldBlock if no signal is pending.
func (*SignalFD) ReadInto ¶
func (s *SignalFD) ReadInto(info *SignalInfo) error
ReadInto reads signal information into a caller-provided SignalInfo. Returns iox.ErrWouldBlock if no signal is pending. This stores the result in caller-owned memory for hot paths.
Postcondition: On success, info contains the next pending signal.
type SignalInfo ¶
type SignalInfo struct {
Signo uint32 // Signal number
Errno int32 // Error number (unused)
Code int32 // Signal code
PID uint32 // PID of sender
UID uint32 // UID of sender
FD int32 // File descriptor (SIGIO)
TID uint32 // Kernel timer ID (POSIX timers)
Band uint32 // Band event (SIGIO)
Overrun uint32 // Overrun count (POSIX timers)
Trapno uint32 // Trap number
Status int32 // Exit status or signal (SIGCHLD)
Int int32 // Integer sent by sigqueue
Ptr uint64 // Pointer sent by sigqueue
Utime uint64 // User CPU time (SIGCHLD)
Stime uint64 // System CPU time (SIGCHLD)
Addr uint64 // Fault address (SIGILL, SIGFPE, SIGSEGV, SIGBUS)
AddrLsb uint16 // LSB of address (SIGBUS)
Syscall int32 // Syscall number (SIGSYS)
CallAddr uint64 // Syscall instruction address (SIGSYS)
Arch uint32 // Architecture (SIGSYS)
// contains filtered or unexported fields
}
SignalInfo contains information about a received signal. This structure matches struct signalfd_siginfo from the Linux kernel.
type Signaler ¶
type Signaler interface {
PollCloser
// Signal increments the eventfd counter by the given value.
// Returns iox.ErrWouldBlock if the counter would overflow.
Signal(val uint64) error
// Wait reads and resets the eventfd counter.
// Returns iox.ErrWouldBlock if the counter is zero.
Wait() (uint64, error)
}
Signaler is an interface for signaling mechanisms like eventfd.
type Timer ¶
type Timer interface {
PollCloser
// Arm sets the timer to expire after the given duration.
// If interval is non-zero, the timer repeats with that interval.
Arm(initial, interval int64) error
// Disarm stops the timer.
Disarm() error
}
Timer is an interface for timer handles like timerfd.
type TimerFD ¶
type TimerFD struct {
// contains filtered or unexported fields
}
TimerFD represents a Linux timerfd file descriptor. It provides a high-resolution timer that can be monitored via poll/epoll/io_uring.
TimerFD is created with TFD_NONBLOCK and TFD_CLOEXEC by default. Do not copy TimerFD after first use.
func NewTimerFD ¶
NewTimerFD creates a new timerfd using CLOCK_MONOTONIC. The timerfd is created with TFD_NONBLOCK and TFD_CLOEXEC. The timer is initially disarmed.
func NewTimerFDBoottime ¶
NewTimerFDBoottime creates a new timerfd using CLOCK_BOOTTIME. The timerfd is created with TFD_NONBLOCK and TFD_CLOEXEC. This clock includes time spent in suspend.
func NewTimerFDRealtime ¶
NewTimerFDRealtime creates a new timerfd using CLOCK_REALTIME. The timerfd is created with TFD_NONBLOCK and TFD_CLOEXEC. Use this for wall-clock time that adjusts with system time changes.
func (*TimerFD) Arm ¶
Arm sets the timer to expire after initial nanoseconds. If interval is non-zero, the timer repeats with that interval (in nanoseconds).
Parameters:
- initial: time until first expiration in nanoseconds (0 disarms)
- interval: interval for periodic timer in nanoseconds (0 for one-shot)
On the success path, Arm does not allocate heap memory.
func (*TimerFD) ArmAt ¶
ArmAt sets the timer to expire at an absolute time. If interval is non-zero, the timer repeats with that interval (in nanoseconds).
Parameters:
- deadline: absolute time for first expiration (Unix nanoseconds)
- interval: interval for periodic timer in nanoseconds (0 for one-shot)
On the success path, ArmAt does not allocate heap memory.
func (*TimerFD) ArmDuration ¶
ArmDuration is a convenience method that arms the timer using time.Duration.
func (*TimerFD) Expirations ¶ added in v0.2.0
Expirations reads the number of expirations since the last read. Returns iox.ErrWouldBlock if no expirations have occurred (non-blocking mode).
The returned value is the number of times the timer has expired since the last successful read. For periodic timers, this may be > 1 if multiple intervals elapsed before reading. On the success path, Expirations does not allocate heap memory.
func (*TimerFD) ExpirationsInto ¶ added in v0.3.2
ExpirationsInto reads expiration count into a caller-provided pointer. Returns iox.ErrWouldBlock if no expirations have occurred (non-blocking mode). This stores the result in caller-owned memory for hot paths.
Postcondition: On success, *count contains the expiration count.
func (*TimerFD) GetTime ¶
GetTime returns the current timer setting. Returns (remaining time until expiration, interval) in nanoseconds. On the success path, GetTime does not allocate heap memory.
func (*TimerFD) GetTimeDuration ¶ added in v0.3.1
GetTimeDuration is a convenience method that returns timer settings as time.Duration. Symmetric to ArmDuration().
func (*TimerFD) Raw ¶ added in v0.2.0
Raw returns the raw file descriptor for use in tight loops. The caller must ensure the TimerFD remains valid while using the raw fd. The returned descriptor number is borrowed and must not be closed directly.