Module rsyscall.sys.resource
#include <sys/resource.h>
Expand source code Browse git
"`#include <sys/resource.h>`"
from rsyscall._raw import ffi, lib # type: ignore
from rsyscall.struct import Struct
from dataclasses import dataclass
import enum
import typing as t
__all__ = [
"PRIO",
"RLIMIT",
"Rlimit",
"ResourceTask",
]
class PRIO(enum.IntFlag):
NONE = 0
PROCESS = lib.PRIO_PROCESS
PGRP = lib.PRIO_PGRP
USER = lib.PRIO_USER
class RLIMIT(enum.IntFlag):
NONE = 0
AS = lib.RLIMIT_AS
CORE = lib.RLIMIT_CORE
CPU = lib.RLIMIT_CPU
DATA = lib.RLIMIT_DATA
FSIZE = lib.RLIMIT_FSIZE
LOCKS = lib.RLIMIT_LOCKS
MEMLOCK = lib.RLIMIT_MEMLOCK
MSGQUEUE = lib.RLIMIT_MSGQUEUE
NICE = lib.RLIMIT_NICE
NOFILE = lib.RLIMIT_NOFILE
NPROC = lib.RLIMIT_NPROC
RSS = lib.RLIMIT_RSS
RTPRIO = lib.RLIMIT_RTPRIO
RTTIME = lib.RLIMIT_RTTIME
SIGPENDING = lib.RLIMIT_SIGPENDING
STACK = lib.RLIMIT_STACK
@dataclass
class Rlimit(Struct):
cur: int
max: int
def to_bytes(self) -> bytes:
struct = ffi.new('struct rlimit*', (self.cur, self.max))
return bytes(ffi.buffer(struct))
T = t.TypeVar('T', bound='Rlimit')
@classmethod
def from_bytes(cls: t.Type[T], data: bytes) -> T:
struct = ffi.cast('struct rlimit*', ffi.from_buffer(data))
return cls(struct.rlim_cur, struct.rlim_max)
@classmethod
def sizeof(cls) -> int:
return ffi.sizeof('struct rlimit')
#### Classes ####
import rsyscall.far
from rsyscall.handle.pointer import Pointer, WrittenPointer
class ResourceTask(rsyscall.far.Task):
async def setpriority(self, which: PRIO, prio: int) -> None:
"""set program scheduling priority
man: setpriority(2)
"""
return (await _setpriority(self.sysif, which, 0, prio))
async def getpriority(self, which: PRIO) -> int:
return (await _getpriority(self.sysif, which, 0))
# {get,set}rlimit have a different struct rlimit from prlimit on 32-bit architectures,
# so we annoyingly can't use the same Rlimit type for them.
# So we'll just implement them in terms of prlimit.
async def setrlimit(self, resource: RLIMIT, rlim: WrittenPointer[Rlimit]) -> None:
await self.prlimit(resource, rlim, None)
async def getrlimit(self, resource: RLIMIT, rlim: Pointer[Rlimit]) -> Pointer[Rlimit]:
await self.prlimit(resource, None, rlim)
return rlim
async def prlimit(self, resource: RLIMIT,
new_limit: t.Optional[Pointer[Rlimit]]=None,
old_limit: t.Optional[Pointer[Rlimit]]=None) -> None:
await _prlimit(self.sysif, None, resource,
new_limit.near if new_limit else None,
old_limit.near if old_limit else None)
#### Raw syscalls ####
from rsyscall.near.sysif import SyscallInterface
from rsyscall.sys.syscall import SYS
from rsyscall.near.types import (
Address,
Process,
)
async def _setpriority(
sysif: SyscallInterface,
which: PRIO,
who: int,
prio: int,
) -> None:
"""The raw setpriority syscall
This syscall is tricky to assign a type to. It's similar to waitid, but has the extra
complication that we can pass 0 for the "who" argument to operate on the current process/process
group/user, as determined by PRIO.
I considered making the type of "who", t.Union[Process, ProcessGroup, User, PRIO], and removing
the "which" argument; passing PRIO would cause setpriority to operate on the current
Process/ProcessGroup/User as determined by the PRIO value. That's the same as how our waitid
wrapper works, but that usage of PRIO seemed too weird.
"""
await sysif.syscall(SYS.setpriority, which, who, prio)
async def _getpriority(
sysif: SyscallInterface,
which: PRIO,
who: int,
) -> int:
return await sysif.syscall(SYS.getpriority, which, who)
async def _prlimit(
sysif: SyscallInterface,
pid: t.Optional[Process],
resource: RLIMIT,
new_limit: t.Optional[Address]=None,
old_limit: t.Optional[Address]=None,
) -> None:
await sysif.syscall(SYS.prlimit64, pid or 0, resource, new_limit or 0, old_limit or 0)
Classes
class PRIO (value, names=None, *, module=None, qualname=None, type=None, start=1)
-
An enumeration.
Expand source code Browse git
class PRIO(enum.IntFlag): NONE = 0 PROCESS = lib.PRIO_PROCESS PGRP = lib.PRIO_PGRP USER = lib.PRIO_USER
Ancestors
- enum.IntFlag
- builtins.int
- enum.Flag
- enum.Enum
Class variables
var NONE
var PROCESS
var PGRP
var USER
class RLIMIT (value, names=None, *, module=None, qualname=None, type=None, start=1)
-
An enumeration.
Expand source code Browse git
class RLIMIT(enum.IntFlag): NONE = 0 AS = lib.RLIMIT_AS CORE = lib.RLIMIT_CORE CPU = lib.RLIMIT_CPU DATA = lib.RLIMIT_DATA FSIZE = lib.RLIMIT_FSIZE LOCKS = lib.RLIMIT_LOCKS MEMLOCK = lib.RLIMIT_MEMLOCK MSGQUEUE = lib.RLIMIT_MSGQUEUE NICE = lib.RLIMIT_NICE NOFILE = lib.RLIMIT_NOFILE NPROC = lib.RLIMIT_NPROC RSS = lib.RLIMIT_RSS RTPRIO = lib.RLIMIT_RTPRIO RTTIME = lib.RLIMIT_RTTIME SIGPENDING = lib.RLIMIT_SIGPENDING STACK = lib.RLIMIT_STACK
Ancestors
- enum.IntFlag
- builtins.int
- enum.Flag
- enum.Enum
Class variables
var NONE
var AS
var CORE
var CPU
var DATA
var FSIZE
var LOCKS
var MEMLOCK
var MSGQUEUE
var NICE
var NOFILE
var NPROC
var RSS
var RTPRIO
var RTTIME
var SIGPENDING
var STACK
class Rlimit (cur: int, max: int)
-
Rlimit(cur: int, max: int)
Expand source code Browse git
@dataclass class Rlimit(Struct): cur: int max: int def to_bytes(self) -> bytes: struct = ffi.new('struct rlimit*', (self.cur, self.max)) return bytes(ffi.buffer(struct)) T = t.TypeVar('T', bound='Rlimit') @classmethod def from_bytes(cls: t.Type[T], data: bytes) -> T: struct = ffi.cast('struct rlimit*', ffi.from_buffer(data)) return cls(struct.rlim_cur, struct.rlim_max) @classmethod def sizeof(cls) -> int: return ffi.sizeof('struct rlimit')
Ancestors
Class variables
var cur : int
var max : int
var T
Inherited members
class ResourceTask (sysif: SyscallInterface, near_process: Process, fd_table: FDTable, address_space: AddressSpace, pidns: PidNamespace)
-
A wrapper around
SyscallInterface
which tracks the namespaces of the underlying processNote that this is a base class for the more fully featured
Task
.We store namespace objects to represent the namespaces that we believe that underlying processes is in. Since we have complete control over the process, we can make sure this belief is accurate, by updating our stored namespaces when the process changes namespace. That isn't done here; it's done in handle.Task.
Currently, we store only one
PidNamespace
. But each process actually has two pid namespaces:- the process's own pid namespace, which determines the pids returned from getpid, clone, and other syscalls.
- the pid namespace that new children will be in.
The two pid namespaces only differ if we call unshare(CLONE.NEWPID). Currently we don't do that because unshare(CLONE.NEWPID) makes monitoring children more complex, since they can be deleted without leaving a zombie at any time if the pid namespace shuts down. But if we did call unshare(CLONE.NEWPID), we'd need to handle this right.
In the analogy to near and far pointers, this is like a segment register, if a segment register was write-only. Then we'd need to maintain the knowledge of what the segment register was set to, outside the segment register itself. That's what we do here.
There actually were systems where segment registers were, if not quite write-only, at least expensive to set and expensive to read. For example, x86_64 - the FS and GS segment registers can only be set via syscall. If you wanted to use segmentation on such systems, you'd probably have a structure much like this one.
Expand source code Browse git
class ResourceTask(rsyscall.far.Task): async def setpriority(self, which: PRIO, prio: int) -> None: """set program scheduling priority man: setpriority(2) """ return (await _setpriority(self.sysif, which, 0, prio)) async def getpriority(self, which: PRIO) -> int: return (await _getpriority(self.sysif, which, 0)) # {get,set}rlimit have a different struct rlimit from prlimit on 32-bit architectures, # so we annoyingly can't use the same Rlimit type for them. # So we'll just implement them in terms of prlimit. async def setrlimit(self, resource: RLIMIT, rlim: WrittenPointer[Rlimit]) -> None: await self.prlimit(resource, rlim, None) async def getrlimit(self, resource: RLIMIT, rlim: Pointer[Rlimit]) -> Pointer[Rlimit]: await self.prlimit(resource, None, rlim) return rlim async def prlimit(self, resource: RLIMIT, new_limit: t.Optional[Pointer[Rlimit]]=None, old_limit: t.Optional[Pointer[Rlimit]]=None) -> None: await _prlimit(self.sysif, None, resource, new_limit.near if new_limit else None, old_limit.near if old_limit else None)
Ancestors
Subclasses
Class variables
var sysif : SyscallInterface
var near_process : Process
var fd_table : FDTable
var address_space : AddressSpace
var pidns : PidNamespace
Methods
async def setpriority(self, which: PRIO, prio: int) ‑> NoneType
-
set program scheduling priority
man: setpriority(2)
Expand source code Browse git
async def setpriority(self, which: PRIO, prio: int) -> None: """set program scheduling priority man: setpriority(2) """ return (await _setpriority(self.sysif, which, 0, prio))
async def getpriority(self, which: PRIO) ‑> int
-
Expand source code Browse git
async def getpriority(self, which: PRIO) -> int: return (await _getpriority(self.sysif, which, 0))
async def setrlimit(self, resource: RLIMIT, rlim: WrittenPointer[Rlimit]) ‑> NoneType
-
Expand source code Browse git
async def setrlimit(self, resource: RLIMIT, rlim: WrittenPointer[Rlimit]) -> None: await self.prlimit(resource, rlim, None)
async def getrlimit(self, resource: RLIMIT, rlim: Pointer[Rlimit]) ‑> Pointer[Rlimit]
-
Expand source code Browse git
async def getrlimit(self, resource: RLIMIT, rlim: Pointer[Rlimit]) -> Pointer[Rlimit]: await self.prlimit(resource, None, rlim) return rlim
async def prlimit(self, resource: RLIMIT, new_limit: Optional[Pointer[Rlimit]] = None, old_limit: Optional[Pointer[Rlimit]] = None) ‑> NoneType
-
Expand source code Browse git
async def prlimit(self, resource: RLIMIT, new_limit: t.Optional[Pointer[Rlimit]]=None, old_limit: t.Optional[Pointer[Rlimit]]=None) -> None: await _prlimit(self.sysif, None, resource, new_limit.near if new_limit else None, old_limit.near if old_limit else None)