Module rsyscall.sys.uio

#include <sys/uio.h>

Expand source code Browse git
"`#include <sys/uio.h>`"
from __future__ import annotations
from rsyscall._raw import lib, ffi # type: ignore
import enum
import typing as t
from rsyscall.handle.pointer import Pointer, WrittenPointer
from rsyscall.struct import Serializable

class RWF(enum.IntFlag):
    NONE = 0
    DSYNC = lib.RWF_DSYNC
    HIPRI = lib.RWF_HIPRI
    SYNC = lib.RWF_SYNC

class IovecList(t.List[Pointer], Serializable):
    def split(self, n: int) -> t.Tuple[IovecList, IovecList]:
        first, middle, second = self.split_with_middle(n)
        if middle is None:
            return first, second
        else:
            first_mid, second_mid = middle
            return IovecList(first + [first_mid]), IovecList([second_mid] + second)

    def split_with_middle(self, n: int) -> t.Tuple[IovecList, t.Optional[t.Tuple[Pointer, Pointer]], IovecList]:
        valid: t.List[Pointer] = []
        middle: t.Optional[t.Tuple[Pointer, Pointer]] = None
        invalid: t.List[Pointer] = []
        for ptr in self:
            size = ptr.size()
            if n >= size:
                valid.append(ptr)
                n -= size
            elif n > 0:
                middle = ptr.split(n)
                n = 0
            else:
                invalid.append(ptr)
        return IovecList(valid), middle, IovecList(invalid)

    def to_bytes(self) -> bytes:
        ret = b""
        for ptr in self:
            ret += bytes(ffi.buffer(ffi.new('struct iovec const*', {
                "iov_base": ffi.cast('void*', int(ptr.near)),
                "iov_len": ptr.size(),
            })))
        return ret

    T = t.TypeVar('T', bound='IovecList')
    @classmethod
    def from_bytes(cls: t.Type[T], data: bytes) -> T:
        raise Exception("can't get pointer handles from raw bytes")

def split_iovec(iov: WrittenPointer[IovecList], ret: int
) -> t.Tuple[WrittenPointer[IovecList], t.Optional[t.Tuple[Pointer, Pointer]], WrittenPointer[IovecList]]:
    first, middle, last = iov.value.split_with_middle(ret)
    if middle is None:
        first_count = len(first)
    else:
        # we include the partially-consumed middle pointer in the first WP[IovecList] returned;
        # I think this is the most ergonomic choice, since in the normal case, I'll want to
        # operate on middle separately, then on second.
        first_count = len(first) + 1
    # TODO this is fairly ad-hoc, splitting on a WrittenPointer should really call into the
    # Serializer to determine validity. (And then I suppose we would have .degrade to degrade a
    # WrittenPointer back into a Pointer so we can split it??? Hmm, seems awkward...)
    first_ptr, last_ptr = iov.split(first_count * ffi.sizeof('struct iovec'))
    return first_ptr._wrote(first), middle, last_ptr._wrote(last)

#### Classes ####
from rsyscall.handle.fd import BaseFileDescriptor
import contextlib

class UioFileDescriptor(BaseFileDescriptor):
    async def readv(self, iov: WrittenPointer[IovecList], flags: RWF=RWF.NONE
    ) -> t.Tuple[WrittenPointer[IovecList], t.Optional[t.Tuple[Pointer, Pointer]], WrittenPointer[IovecList]]:
        # TODO should check that the WrittenPointer's value and size correspond...
        # maybe we should check that at construction time?
        # otherwise one could make a WrittenPointer that is short, but has a long iovec, and we'd read off the end.
        with contextlib.ExitStack() as stack:
            stack.enter_context(iov.borrow(self.task))
            ret = await _preadv2(self.task.sysif, self.near, iov.near, len(iov.value), -1, flags)
        return split_iovec(iov, ret)

    async def writev(self, iov: WrittenPointer[IovecList], flags: RWF=RWF.NONE
    ) -> t.Tuple[WrittenPointer[IovecList], t.Optional[t.Tuple[Pointer, Pointer]], WrittenPointer[IovecList]]:
        with contextlib.ExitStack() as stack:
            stack.enter_context(iov.borrow(self.task))
            ret = await _pwritev2(self.task.sysif, self.near, iov.near, len(iov.value), -1, flags)
        return split_iovec(iov, ret)

#### Raw syscalls ####
import rsyscall.near.types as near
from rsyscall.near.sysif import SyscallInterface
from rsyscall.sys.syscall import SYS

async def _preadv2(sysif: SyscallInterface, fd: near.FileDescriptor,
                   iov: near.Address, iovcnt: int, offset: int, flags: RWF) -> int:
    return (await sysif.syscall(SYS.preadv2, fd, iov, iovcnt, offset, flags))

async def _pwritev2(sysif: SyscallInterface, fd: near.FileDescriptor,
                    iov: near.Address, iovcnt: int, offset: int, flags: RWF) -> int:
    return (await sysif.syscall(SYS.pwritev2, fd, iov, iovcnt, offset, flags))

Functions

def split_iovec(iov: WrittenPointer[IovecList], ret: int) ‑> Tuple[WrittenPointer[IovecList], Optional[Tuple[PointerPointer]], WrittenPointer[IovecList]]
Expand source code Browse git
def split_iovec(iov: WrittenPointer[IovecList], ret: int
) -> t.Tuple[WrittenPointer[IovecList], t.Optional[t.Tuple[Pointer, Pointer]], WrittenPointer[IovecList]]:
    first, middle, last = iov.value.split_with_middle(ret)
    if middle is None:
        first_count = len(first)
    else:
        # we include the partially-consumed middle pointer in the first WP[IovecList] returned;
        # I think this is the most ergonomic choice, since in the normal case, I'll want to
        # operate on middle separately, then on second.
        first_count = len(first) + 1
    # TODO this is fairly ad-hoc, splitting on a WrittenPointer should really call into the
    # Serializer to determine validity. (And then I suppose we would have .degrade to degrade a
    # WrittenPointer back into a Pointer so we can split it??? Hmm, seems awkward...)
    first_ptr, last_ptr = iov.split(first_count * ffi.sizeof('struct iovec'))
    return first_ptr._wrote(first), middle, last_ptr._wrote(last)

Classes

class RWF (value, names=None, *, module=None, qualname=None, type=None, start=1)

An enumeration.

Expand source code Browse git
class RWF(enum.IntFlag):
    NONE = 0
    DSYNC = lib.RWF_DSYNC
    HIPRI = lib.RWF_HIPRI
    SYNC = lib.RWF_SYNC

Ancestors

  • enum.IntFlag
  • builtins.int
  • enum.Flag
  • enum.Enum

Class variables

var NONE
var DSYNC
var HIPRI
var SYNC
class IovecList (*args, **kwargs)

Built-in mutable sequence.

If no argument is given, the constructor creates a new empty list. The argument must be an iterable if specified.

Expand source code Browse git
class IovecList(t.List[Pointer], Serializable):
    def split(self, n: int) -> t.Tuple[IovecList, IovecList]:
        first, middle, second = self.split_with_middle(n)
        if middle is None:
            return first, second
        else:
            first_mid, second_mid = middle
            return IovecList(first + [first_mid]), IovecList([second_mid] + second)

    def split_with_middle(self, n: int) -> t.Tuple[IovecList, t.Optional[t.Tuple[Pointer, Pointer]], IovecList]:
        valid: t.List[Pointer] = []
        middle: t.Optional[t.Tuple[Pointer, Pointer]] = None
        invalid: t.List[Pointer] = []
        for ptr in self:
            size = ptr.size()
            if n >= size:
                valid.append(ptr)
                n -= size
            elif n > 0:
                middle = ptr.split(n)
                n = 0
            else:
                invalid.append(ptr)
        return IovecList(valid), middle, IovecList(invalid)

    def to_bytes(self) -> bytes:
        ret = b""
        for ptr in self:
            ret += bytes(ffi.buffer(ffi.new('struct iovec const*', {
                "iov_base": ffi.cast('void*', int(ptr.near)),
                "iov_len": ptr.size(),
            })))
        return ret

    T = t.TypeVar('T', bound='IovecList')
    @classmethod
    def from_bytes(cls: t.Type[T], data: bytes) -> T:
        raise Exception("can't get pointer handles from raw bytes")

Ancestors

Class variables

var T

Methods

def split(self, n: int) ‑> Tuple[IovecListIovecList]
Expand source code Browse git
def split(self, n: int) -> t.Tuple[IovecList, IovecList]:
    first, middle, second = self.split_with_middle(n)
    if middle is None:
        return first, second
    else:
        first_mid, second_mid = middle
        return IovecList(first + [first_mid]), IovecList([second_mid] + second)
def split_with_middle(self, n: int) ‑> Tuple[IovecList, Optional[Tuple[PointerPointer]], IovecList]
Expand source code Browse git
def split_with_middle(self, n: int) -> t.Tuple[IovecList, t.Optional[t.Tuple[Pointer, Pointer]], IovecList]:
    valid: t.List[Pointer] = []
    middle: t.Optional[t.Tuple[Pointer, Pointer]] = None
    invalid: t.List[Pointer] = []
    for ptr in self:
        size = ptr.size()
        if n >= size:
            valid.append(ptr)
            n -= size
        elif n > 0:
            middle = ptr.split(n)
            n = 0
        else:
            invalid.append(ptr)
    return IovecList(valid), middle, IovecList(invalid)

Inherited members

class UioFileDescriptor (task: FileDescriptorTask, near: FileDescriptor, valid: bool)

A file descriptor accessed through some Task

This is an rsyscall-internal base class, which other FileDescriptor objects inherit from for core lifecycle methods. See FileDescriptor for more information.

Expand source code Browse git
class UioFileDescriptor(BaseFileDescriptor):
    async def readv(self, iov: WrittenPointer[IovecList], flags: RWF=RWF.NONE
    ) -> t.Tuple[WrittenPointer[IovecList], t.Optional[t.Tuple[Pointer, Pointer]], WrittenPointer[IovecList]]:
        # TODO should check that the WrittenPointer's value and size correspond...
        # maybe we should check that at construction time?
        # otherwise one could make a WrittenPointer that is short, but has a long iovec, and we'd read off the end.
        with contextlib.ExitStack() as stack:
            stack.enter_context(iov.borrow(self.task))
            ret = await _preadv2(self.task.sysif, self.near, iov.near, len(iov.value), -1, flags)
        return split_iovec(iov, ret)

    async def writev(self, iov: WrittenPointer[IovecList], flags: RWF=RWF.NONE
    ) -> t.Tuple[WrittenPointer[IovecList], t.Optional[t.Tuple[Pointer, Pointer]], WrittenPointer[IovecList]]:
        with contextlib.ExitStack() as stack:
            stack.enter_context(iov.borrow(self.task))
            ret = await _pwritev2(self.task.sysif, self.near, iov.near, len(iov.value), -1, flags)
        return split_iovec(iov, ret)

Ancestors

Subclasses

Methods

async def readv(self, iov: WrittenPointer[IovecList], flags: RWF = RWF.NONE) ‑> Tuple[WrittenPointer[IovecList], Optional[Tuple[PointerPointer]], WrittenPointer[IovecList]]
Expand source code Browse git
async def readv(self, iov: WrittenPointer[IovecList], flags: RWF=RWF.NONE
) -> t.Tuple[WrittenPointer[IovecList], t.Optional[t.Tuple[Pointer, Pointer]], WrittenPointer[IovecList]]:
    # TODO should check that the WrittenPointer's value and size correspond...
    # maybe we should check that at construction time?
    # otherwise one could make a WrittenPointer that is short, but has a long iovec, and we'd read off the end.
    with contextlib.ExitStack() as stack:
        stack.enter_context(iov.borrow(self.task))
        ret = await _preadv2(self.task.sysif, self.near, iov.near, len(iov.value), -1, flags)
    return split_iovec(iov, ret)
async def writev(self, iov: WrittenPointer[IovecList], flags: RWF = RWF.NONE) ‑> Tuple[WrittenPointer[IovecList], Optional[Tuple[PointerPointer]], WrittenPointer[IovecList]]
Expand source code Browse git
async def writev(self, iov: WrittenPointer[IovecList], flags: RWF=RWF.NONE
) -> t.Tuple[WrittenPointer[IovecList], t.Optional[t.Tuple[Pointer, Pointer]], WrittenPointer[IovecList]]:
    with contextlib.ExitStack() as stack:
        stack.enter_context(iov.borrow(self.task))
        ret = await _pwritev2(self.task.sysif, self.near, iov.near, len(iov.value), -1, flags)
    return split_iovec(iov, ret)

Inherited members