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 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) Fd() int
- func (t *TimerFD) GetTime() (remaining, interval int64, 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 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) 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.
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.
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).
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.
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.
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.
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) 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.
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) 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.
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.
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.
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) 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.
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 is the zero-allocation variant for use in 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.
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) 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.
func (*TimerFD) GetTime ¶
GetTime returns the current timer setting. Returns (remaining time until expiration, interval) in nanoseconds.
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.