iofd

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 25, 2025 License: MIT Imports: 7 Imported by: 0

README

iofd

Go Reference Go Report Card Codecov

Universal file descriptor abstractions for Unix systems in Go.

Language: English | 简体中文 | Español | 日本語 | Français

Overview

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.

Key Features
  • Zero Overhead: All kernel interactions via zcall assembly, bypassing Go's syscall hooks
  • Specialized Handles: Linux-specific EventFD, TimerFD, PidFD, MemFD, SignalFD
  • Cross-Platform Core: Base FD operations work on Linux, Darwin, and FreeBSD

Installation

go get code.hybscloud.com/iofd

Quick Start

efd, _ := iofd.NewEventFD(0)
efd.Signal(1)
val, _ := efd.Wait() // val == 1
efd.Close()

API

Core Types
Type Description
FD Universal file descriptor with atomic operations
EventFD Linux eventfd for inter-thread signaling
TimerFD Linux timerfd for high-resolution timers
PidFD Linux pidfd for race-free process management
MemFD Linux memfd for anonymous memory-backed files
SignalFD Linux signalfd for synchronous signal handling
Interfaces
Interface Methods Description
PollFd Fd() int Pollable file descriptor
PollCloser Fd(), Close() Closeable pollable descriptor
Handle Fd(), Close(), Read(), Write() Full I/O handle
Signaler Signal(), Wait() Signaling mechanism
Timer Arm(), Disarm(), Read() Timer handle
FD Operations
// Create FD from raw descriptor
fd := iofd.NewFD(rawFd)

// Atomic operations
fd.Raw()           // Get raw int32 value
fd.Valid()         // Check if valid (non-negative)
fd.Close()         // Idempotent close

// I/O operations
fd.Read(buf)       // Read bytes
fd.Write(buf)      // Write bytes

// Descriptor flags
fd.SetNonblock(true)   // Set O_NONBLOCK
fd.SetCloexec(true)    // Set FD_CLOEXEC
fd.Dup()               // Duplicate with CLOEXEC

Platform Support

Platform FD Core EventFD TimerFD PidFD MemFD SignalFD
Linux/amd64
Linux/arm64
Darwin/arm64
FreeBSD/amd64

Note: Specialized handles (EventFD, TimerFD, etc.) are Linux-specific kernel primitives. On Darwin and FreeBSD, only the core FD type is available.

License

MIT — see LICENSE.

©2025 Hayabusa Cloud Co., Ltd.

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

View Source
const (
	SYS_DUP       = 32
	SYS_DUP2      = 33
	SYS_DUP3      = 292
	SYS_FCNTL     = 72
	SYS_FTRUNCATE = 77
	SYS_FSTAT     = 5
)

Syscall numbers for Linux amd64.

View Source
const (
	O_NONBLOCK = 0x800
	O_CLOEXEC  = 0x80000
)

File status flags for fcntl F_GETFL/F_SETFL. These are consistent across all Linux architectures.

View Source
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.

View Source
const (
	EFD_SEMAPHORE = 0x1
	EFD_CLOEXEC   = 0x80000
	EFD_NONBLOCK  = 0x800
)

eventfd flags

View Source
const (
	MFD_CLOEXEC       = 0x1
	MFD_ALLOW_SEALING = 0x2
	MFD_HUGETLB       = 0x4
	MFD_NOEXEC_SEAL   = 0x8
	MFD_EXEC          = 0x10
)

memfd flags

View Source
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

View Source
const (
	F_ADD_SEALS = 1033
	F_GET_SEALS = 1034
)

fcntl commands for sealing

View Source
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.

View Source
const (
	SFD_CLOEXEC  = 0x80000
	SFD_NONBLOCK = 0x800
)

signalfd flags

View Source
const (
	CLOCK_REALTIME  = 0
	CLOCK_MONOTONIC = 1
	CLOCK_BOOTTIME  = 7
)

Clock IDs

View Source
const (
	TFD_CLOEXEC       = 0x80000
	TFD_NONBLOCK      = 0x800
	TFD_TIMER_ABSTIME = 0x1
)

timerfd flags

View Source
const (
	FD_CLOEXEC = 1
)

File descriptor flags for fcntl F_GETFD/F_SETFD. These are consistent across all Linux architectures.

View Source
const (
	PIDFD_NONBLOCK = 0x800
)

pidfd flags

Variables

View Source
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

func NewEventFD(initval uint) (*EventFD, error)

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

func NewEventFDSemaphore(initval uint) (*EventFD, error)

NewEventFDSemaphore creates a new eventfd in semaphore mode. In semaphore mode, reads decrement the counter by 1 instead of resetting it.

func (*EventFD) Close

func (e *EventFD) Close() error

Close closes the eventfd. Implements PollCloser interface.

func (*EventFD) Fd

func (e *EventFD) Fd() int

Fd returns the underlying file descriptor. Implements PollFd interface.

func (*EventFD) Read

func (e *EventFD) Read(p []byte) (int, error)

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

func (e *EventFD) Signal(val uint64) error

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

func (e *EventFD) Value() (uint64, error)

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.

func (*EventFD) Wait

func (e *EventFD) Wait() (uint64, error)

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).

func (*EventFD) Write

func (e *EventFD) Write(p []byte) (int, error)

Write writes a value to the eventfd from p. p must be at least 8 bytes containing a little-endian uint64. This is a lower-level interface; prefer Signal() for typical usage.

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

func NewFD(fd int) FD

NewFD creates a new FD from a raw file descriptor value. The caller is responsible for ensuring fd is valid.

func (*FD) Close

func (fd *FD) Close() error

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) Dup

func (fd *FD) Dup() (FD, error)

Dup duplicates the file descriptor. The new FD has FD_CLOEXEC set by default.

func (*FD) Fd

func (fd *FD) Fd() int

Fd returns the file descriptor as an int for interface compatibility. Implements PollFd interface.

func (*FD) Raw

func (fd *FD) Raw() int32

Raw returns the underlying file descriptor as an int32. Returns -1 if the FD is invalid or closed.

func (*FD) Read

func (fd *FD) Read(p []byte) (int, error)

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

func (fd *FD) SetCloexec(cloexec bool) error

SetCloexec sets or clears the FD_CLOEXEC flag on the file descriptor.

func (*FD) SetNonblock

func (fd *FD) SetNonblock(nonblock bool) error

SetNonblock sets or clears the O_NONBLOCK flag on the file descriptor.

func (*FD) Valid

func (fd *FD) Valid() bool

Valid reports whether the file descriptor is valid (non-negative).

func (*FD) Write

func (fd *FD) Write(p []byte) (int, error)

Write writes len(p) bytes to the file descriptor. Returns iox.ErrWouldBlock if the fd is non-blocking and cannot accept data.

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

func NewMemFD(name string) (*MemFD, error)

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

func NewMemFDHugeTLB(name string) (*MemFD, error)

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

func NewMemFDSealed(name string) (*MemFD, error)

NewMemFDSealed creates a new memfd that allows sealing operations. Use this when you need to apply seals to prevent modifications.

func (*MemFD) Close

func (m *MemFD) Close() error

Close closes the memfd. The memory is freed when all references (including mmaps) are released. Implements PollCloser interface.

func (*MemFD) Fd

func (m *MemFD) Fd() int

Fd returns the underlying file descriptor. Implements PollFd interface.

func (*MemFD) Name

func (m *MemFD) Name() string

Name returns the name given at creation.

func (*MemFD) Read

func (m *MemFD) Read(p []byte) (int, error)

Read reads from the memfd at the current file offset.

func (*MemFD) Seal

func (m *MemFD) Seal(seals uint) error

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.

func (*MemFD) Seals

func (m *MemFD) Seals() (uint, error)

Seals returns the current seal flags.

func (*MemFD) Size

func (m *MemFD) Size() (int64, error)

Size returns the current size of the memfd.

func (*MemFD) Truncate

func (m *MemFD) Truncate(size int64) error

Truncate sets the size of the memfd. If the new size is larger, the extended area is zero-filled. If smaller, data beyond the new size is discarded.

func (*MemFD) Valid

func (m *MemFD) Valid() bool

Valid reports whether the memfd is still valid.

func (*MemFD) Write

func (m *MemFD) Write(p []byte) (int, error)

Write writes to the memfd at the current file offset.

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

func NewPidFD(pid int) (*PidFD, error)

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

func NewPidFDBlocking(pid int) (*PidFD, error)

NewPidFDBlocking creates a new pidfd for the specified process ID without the PIDFD_NONBLOCK flag.

func (*PidFD) Close

func (p *PidFD) Close() error

Close closes the pidfd. Implements PollCloser interface.

func (*PidFD) Fd

func (p *PidFD) Fd() int

Fd returns the underlying file descriptor. Implements PollFd interface.

func (*PidFD) GetFD

func (p *PidFD) GetFD(targetFD int) (FD, error)

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

func (p *PidFD) PID() int

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

func (p *PidFD) SendSignal(sig int) error

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.

func (*PidFD) Valid

func (p *PidFD) Valid() bool

Valid reports whether the pidfd is still valid.

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

type ReadWriter interface {
	Reader
	Writer
}

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.

func (*SigSet) Add

func (s *SigSet) Add(sig int)

Add adds a signal to the set.

func (*SigSet) Del

func (s *SigSet) Del(sig int)

Del removes a signal from the set.

func (SigSet) Empty

func (s SigSet) Empty() bool

Empty reports whether the set is empty.

func (SigSet) Has

func (s SigSet) Has(sig int) bool

Has reports whether the signal is in the set.

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

func NewSignalFD(mask SigSet) (*SignalFD, error)

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) Close

func (s *SignalFD) Close() error

Close closes the signalfd. Implements PollCloser interface.

func (*SignalFD) Fd

func (s *SignalFD) Fd() int

Fd returns the underlying file descriptor. Implements PollFd interface.

func (*SignalFD) Mask

func (s *SignalFD) Mask() SigSet

Mask returns the current signal mask.

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.

func (*SignalFD) ReadInto

func (s *SignalFD) ReadInto(buf []byte) (int, error)

ReadInto reads signal information into the provided buffer. buf must be at least 128 bytes.

func (*SignalFD) SetMask

func (s *SignalFD) SetMask(mask SigSet) error

SetMask updates the signal mask monitored by this signalfd.

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

func NewTimerFD() (*TimerFD, error)

NewTimerFD creates a new timerfd using CLOCK_MONOTONIC. The timer is initially disarmed.

func NewTimerFDBoottime

func NewTimerFDBoottime() (*TimerFD, error)

NewTimerFDBoottime creates a new timerfd using CLOCK_BOOTTIME. This clock includes time spent in suspend.

func NewTimerFDRealtime

func NewTimerFDRealtime() (*TimerFD, error)

NewTimerFDRealtime creates a new timerfd using CLOCK_REALTIME. Use this for wall-clock time that adjusts with system time changes.

func (*TimerFD) Arm

func (t *TimerFD) Arm(initial, interval int64) error

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

func (t *TimerFD) ArmAt(deadline, interval int64) error

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

func (t *TimerFD) ArmDuration(initial, interval time.Duration) error

ArmDuration is a convenience method that arms the timer using time.Duration.

func (*TimerFD) Close

func (t *TimerFD) Close() error

Close closes the timerfd. Implements PollCloser interface.

func (*TimerFD) Disarm

func (t *TimerFD) Disarm() error

Disarm stops the timer.

func (*TimerFD) Fd

func (t *TimerFD) Fd() int

Fd returns the underlying file descriptor. Implements PollFd interface.

func (*TimerFD) GetTime

func (t *TimerFD) GetTime() (remaining, interval int64, err error)

GetTime returns the current timer setting. Returns (remaining time until expiration, interval) in nanoseconds.

func (*TimerFD) Read

func (t *TimerFD) Read() (uint64, error)

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.

func (*TimerFD) ReadInto

func (t *TimerFD) ReadInto(buf []byte) (int, error)

ReadInto reads expiration count into the provided buffer. buf must be at least 8 bytes.

type Writer

type Writer interface {
	// Write writes len(p) bytes from p.
	// Returns the number of bytes written and any error encountered.
	// Returns iox.ErrWouldBlock if the resource is not ready.
	Write(p []byte) (n int, err error)
}

Writer is an interface for writing to a file descriptor.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL