Documentation
¶
Overview ¶
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
- 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 MemFD
- func (m *MemFD) Close() error
- func (m *MemFD) Fd() int
- func (m *MemFD) Name() string
- 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
- 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) Fd() int
- func (t *TimerFD) GetTime() (remaining, interval int64, err error)
- func (t *TimerFD) Read() (uint64, error)
- func (t *TimerFD) ReadInto(buf []byte) (int, error)
- type Writer
Constants ¶
const ( SYS_DUP = 32 SYS_DUP2 = 33 SYS_DUP3 = 292 SYS_FCNTL = 72 SYS_FTRUNCATE = 77 SYS_FSTAT = 5 )
Syscall numbers for Linux amd64.
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 ( 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
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") // ErrOverflow indicates a counter overflow (for eventfd). ErrOverflow = errors.New("fd: counter overflow") )
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 O_NONBLOCK and O_CLOEXEC by default.
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. In semaphore mode, reads decrement the counter by 1 instead of resetting it.
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.
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.
func (*EventFD) Value ¶
Value returns the current counter value without consuming it. This uses a non-standard approach via /proc and should be used sparingly. For most use cases, use Wait() instead.
type FD ¶
type FD int32
FD represents a file descriptor as a universal handle. It wraps an int32 and provides atomic operations for safe concurrent access.
Invariants:
- A valid FD holds a non-negative value.
- After Close(), the FD value becomes -1.
- FD is safe for concurrent use; Close() is idempotent.
const InvalidFD FD = -1
InvalidFD represents an invalid file descriptor.
func NewFD ¶
NewFD creates a new FD from a raw file descriptor value. The caller is responsible for ensuring fd is valid.
func (*FD) Close ¶
Close closes the file descriptor. It is safe to call Close multiple times; subsequent calls are no-ops. Returns nil if already closed.
Postcondition: fd.Raw() == -1
func (*FD) Fd ¶
Fd returns the file descriptor as an int for interface compatibility. Implements PollFd interface.
func (*FD) Raw ¶
Raw returns the underlying file descriptor as an int32. Returns -1 if the FD is invalid or closed.
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.
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 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.
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 flag.
The file is initially empty; call Truncate to set its size.
func NewMemFDHugeTLB ¶
NewMemFDHugeTLB creates a new memfd backed by huge pages. 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. 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) 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.
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 flag.
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.
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 FD in the current process that refers to the same open file description as targetFD in the target process.
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) 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.
// 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 valid only while the resource is open.
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. On Linux amd64, this is a 64-bit mask where bit N represents signal N+1.
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.
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 | 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) Read ¶
func (s *SignalFD) Read() (*SignalInfo, error)
Read reads signal information into the provided SignalInfo. Returns iox.ErrWouldBlock if no signal is pending.
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
// Read reads the number of expirations since the last read.
// Returns iox.ErrWouldBlock if no expirations have occurred.
Read() (uint64, 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.
func NewTimerFD ¶
NewTimerFD creates a new timerfd using CLOCK_MONOTONIC. The timer is initially disarmed.
func NewTimerFDBoottime ¶
NewTimerFDBoottime creates a new timerfd using CLOCK_BOOTTIME. This clock includes time spent in suspend.
func NewTimerFDRealtime ¶
NewTimerFDRealtime creates a new timerfd using CLOCK_REALTIME. 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)
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)
func (*TimerFD) ArmDuration ¶
ArmDuration is a convenience method that arms the timer using time.Duration.
func (*TimerFD) GetTime ¶
GetTime returns the current timer setting. Returns (remaining time until expiration, interval) in nanoseconds.
func (*TimerFD) Read ¶
Read 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.