mirror of
https://github.com/johndoe6345789/typthon.git
synced 2026-04-24 13:45:05 +00:00
Fixed additional patterns: - _PyOpcode_* → _TyOpcode_* (all opcode metadata) - _PyUOpName → _TyUOpName - _PyFunction_* → _TyFunction_* - _PyListIterObject → _TyListIterObject - _Py_T_OBJECT → _Ty_T_OBJECT - Py_BEGIN_ALLOW_THREADS, Py_END_ALLOW_THREADS → Ty_* - PyDoc_STRVAR, PyDoc_STR → TyDoc_* - PyInterpreterState, PyThread_*, PyTime_t → Ty* - PyStructSequence_* → TyStructSequence_* - PyLockStatus → TyLockStatus - PyVarObject_HEAD_INIT → TyVarObject_HEAD_INIT - PyBaseExceptionObject → TyBaseExceptionObject - Fixed _PyExc_ → _TyExc_ in exception macros Build is progressing further. Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
553 lines
14 KiB
C
553 lines
14 KiB
C
// Need limited C API version 3.13 for TySys_Audit()
|
|
#include "pyconfig.h" // Ty_GIL_DISABLED
|
|
#ifndef Ty_GIL_DISABLED
|
|
# define Ty_LIMITED_API 0x030d0000
|
|
#endif
|
|
|
|
#include "Python.h"
|
|
#include <errno.h> // errno
|
|
#include <string.h>
|
|
#include <sys/resource.h> // getrusage()
|
|
#include <unistd.h> // getpagesize()
|
|
|
|
/* On some systems, these aren't in any header file.
|
|
On others they are, with inconsistent prototypes.
|
|
We declare the (default) return type, to shut up gcc -Wall;
|
|
but we can't declare the prototype, to avoid errors
|
|
when the header files declare it different.
|
|
Worse, on some Linuxes, getpagesize() returns a size_t... */
|
|
|
|
#define doubletime(TV) ((double)(TV).tv_sec + (TV).tv_usec * 0.000001)
|
|
|
|
/*[clinic input]
|
|
module resource
|
|
[clinic start generated code]*/
|
|
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=e89d38ed52609d7c]*/
|
|
|
|
/*[python input]
|
|
class pid_t_converter(CConverter):
|
|
type = 'pid_t'
|
|
format_unit = '" _Ty_PARSE_PID "'
|
|
|
|
def parse_arg(self, argname, displayname, *, limited_capi):
|
|
return self.format_code("""
|
|
{paramname} = TyLong_AsPid({argname});
|
|
if ({paramname} == -1 && TyErr_Occurred()) {{{{
|
|
goto exit;
|
|
}}}}
|
|
""",
|
|
argname=argname)
|
|
[python start generated code]*/
|
|
/*[python end generated code: output=da39a3ee5e6b4b0d input=c94349aa1aad151d]*/
|
|
|
|
#include "clinic/resource.c.h"
|
|
|
|
TyDoc_STRVAR(struct_rusage__doc__,
|
|
"struct_rusage: Result from getrusage.\n\n"
|
|
"This object may be accessed either as a tuple of\n"
|
|
" (utime,stime,maxrss,ixrss,idrss,isrss,minflt,majflt,\n"
|
|
" nswap,inblock,oublock,msgsnd,msgrcv,nsignals,nvcsw,nivcsw)\n"
|
|
"or via the attributes ru_utime, ru_stime, ru_maxrss, and so on.");
|
|
|
|
static TyStructSequence_Field struct_rusage_fields[] = {
|
|
{"ru_utime", "user time used"},
|
|
{"ru_stime", "system time used"},
|
|
{"ru_maxrss", "max. resident set size"},
|
|
{"ru_ixrss", "shared memory size"},
|
|
{"ru_idrss", "unshared data size"},
|
|
{"ru_isrss", "unshared stack size"},
|
|
{"ru_minflt", "page faults not requiring I/O"},
|
|
{"ru_majflt", "page faults requiring I/O"},
|
|
{"ru_nswap", "number of swap outs"},
|
|
{"ru_inblock", "block input operations"},
|
|
{"ru_oublock", "block output operations"},
|
|
{"ru_msgsnd", "IPC messages sent"},
|
|
{"ru_msgrcv", "IPC messages received"},
|
|
{"ru_nsignals", "signals received"},
|
|
{"ru_nvcsw", "voluntary context switches"},
|
|
{"ru_nivcsw", "involuntary context switches"},
|
|
{0}
|
|
};
|
|
|
|
static TyStructSequence_Desc struct_rusage_desc = {
|
|
"resource.struct_rusage", /* name */
|
|
struct_rusage__doc__, /* doc */
|
|
struct_rusage_fields, /* fields */
|
|
16 /* n_in_sequence */
|
|
};
|
|
|
|
typedef struct {
|
|
TyTypeObject *StructRUsageType;
|
|
} resourcemodulestate;
|
|
|
|
|
|
static inline resourcemodulestate*
|
|
get_resource_state(TyObject *module)
|
|
{
|
|
void *state = TyModule_GetState(module);
|
|
assert(state != NULL);
|
|
return (resourcemodulestate *)state;
|
|
}
|
|
|
|
static struct TyModuleDef resourcemodule;
|
|
|
|
#ifdef HAVE_GETRUSAGE
|
|
/*[clinic input]
|
|
resource.getrusage
|
|
|
|
who: int
|
|
/
|
|
|
|
[clinic start generated code]*/
|
|
|
|
static TyObject *
|
|
resource_getrusage_impl(TyObject *module, int who)
|
|
/*[clinic end generated code: output=8fad2880ba6a9843 input=5c857bcc5b9ccb1b]*/
|
|
{
|
|
struct rusage ru;
|
|
TyObject *result;
|
|
|
|
if (getrusage(who, &ru) == -1) {
|
|
if (errno == EINVAL) {
|
|
TyErr_SetString(TyExc_ValueError,
|
|
"invalid who parameter");
|
|
return NULL;
|
|
}
|
|
TyErr_SetFromErrno(TyExc_OSError);
|
|
return NULL;
|
|
}
|
|
|
|
result = TyStructSequence_New(
|
|
get_resource_state(module)->StructRUsageType);
|
|
if (!result)
|
|
return NULL;
|
|
|
|
TyStructSequence_SetItem(result, 0,
|
|
TyFloat_FromDouble(doubletime(ru.ru_utime)));
|
|
TyStructSequence_SetItem(result, 1,
|
|
TyFloat_FromDouble(doubletime(ru.ru_stime)));
|
|
TyStructSequence_SetItem(result, 2, TyLong_FromLong(ru.ru_maxrss));
|
|
TyStructSequence_SetItem(result, 3, TyLong_FromLong(ru.ru_ixrss));
|
|
TyStructSequence_SetItem(result, 4, TyLong_FromLong(ru.ru_idrss));
|
|
TyStructSequence_SetItem(result, 5, TyLong_FromLong(ru.ru_isrss));
|
|
TyStructSequence_SetItem(result, 6, TyLong_FromLong(ru.ru_minflt));
|
|
TyStructSequence_SetItem(result, 7, TyLong_FromLong(ru.ru_majflt));
|
|
TyStructSequence_SetItem(result, 8, TyLong_FromLong(ru.ru_nswap));
|
|
TyStructSequence_SetItem(result, 9, TyLong_FromLong(ru.ru_inblock));
|
|
TyStructSequence_SetItem(result, 10, TyLong_FromLong(ru.ru_oublock));
|
|
TyStructSequence_SetItem(result, 11, TyLong_FromLong(ru.ru_msgsnd));
|
|
TyStructSequence_SetItem(result, 12, TyLong_FromLong(ru.ru_msgrcv));
|
|
TyStructSequence_SetItem(result, 13, TyLong_FromLong(ru.ru_nsignals));
|
|
TyStructSequence_SetItem(result, 14, TyLong_FromLong(ru.ru_nvcsw));
|
|
TyStructSequence_SetItem(result, 15, TyLong_FromLong(ru.ru_nivcsw));
|
|
|
|
if (TyErr_Occurred()) {
|
|
Ty_DECREF(result);
|
|
return NULL;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
static int
|
|
py2rlimit(TyObject *limits, struct rlimit *rl_out)
|
|
{
|
|
TyObject *curobj, *maxobj;
|
|
limits = PySequence_Tuple(limits);
|
|
if (!limits)
|
|
/* Here limits is a borrowed reference */
|
|
return -1;
|
|
|
|
if (TyTuple_Size(limits) != 2) {
|
|
TyErr_SetString(TyExc_ValueError,
|
|
"expected a tuple of 2 integers");
|
|
goto error;
|
|
}
|
|
curobj = TyTuple_GetItem(limits, 0); // borrowed
|
|
maxobj = TyTuple_GetItem(limits, 1); // borrowed
|
|
#if !defined(HAVE_LARGEFILE_SUPPORT)
|
|
rl_out->rlim_cur = TyLong_AsLong(curobj);
|
|
if (rl_out->rlim_cur == (rlim_t)-1 && TyErr_Occurred())
|
|
goto error;
|
|
rl_out->rlim_max = TyLong_AsLong(maxobj);
|
|
if (rl_out->rlim_max == (rlim_t)-1 && TyErr_Occurred())
|
|
goto error;
|
|
#else
|
|
/* The limits are probably bigger than a long */
|
|
rl_out->rlim_cur = TyLong_AsLongLong(curobj);
|
|
if (rl_out->rlim_cur == (rlim_t)-1 && TyErr_Occurred())
|
|
goto error;
|
|
rl_out->rlim_max = TyLong_AsLongLong(maxobj);
|
|
if (rl_out->rlim_max == (rlim_t)-1 && TyErr_Occurred())
|
|
goto error;
|
|
#endif
|
|
|
|
Ty_DECREF(limits);
|
|
rl_out->rlim_cur = rl_out->rlim_cur & RLIM_INFINITY;
|
|
rl_out->rlim_max = rl_out->rlim_max & RLIM_INFINITY;
|
|
return 0;
|
|
|
|
error:
|
|
Ty_DECREF(limits);
|
|
return -1;
|
|
}
|
|
|
|
static TyObject*
|
|
rlimit2py(struct rlimit rl)
|
|
{
|
|
if (sizeof(rl.rlim_cur) > sizeof(long)) {
|
|
return Ty_BuildValue("LL",
|
|
(long long) rl.rlim_cur,
|
|
(long long) rl.rlim_max);
|
|
}
|
|
return Ty_BuildValue("ll", (long) rl.rlim_cur, (long) rl.rlim_max);
|
|
}
|
|
|
|
/*[clinic input]
|
|
resource.getrlimit
|
|
|
|
resource: int
|
|
/
|
|
|
|
[clinic start generated code]*/
|
|
|
|
static TyObject *
|
|
resource_getrlimit_impl(TyObject *module, int resource)
|
|
/*[clinic end generated code: output=98327b25061ffe39 input=a697cb0004cb3c36]*/
|
|
{
|
|
struct rlimit rl;
|
|
|
|
if (resource < 0 || resource >= RLIM_NLIMITS) {
|
|
TyErr_SetString(TyExc_ValueError,
|
|
"invalid resource specified");
|
|
return NULL;
|
|
}
|
|
|
|
if (getrlimit(resource, &rl) == -1) {
|
|
TyErr_SetFromErrno(TyExc_OSError);
|
|
return NULL;
|
|
}
|
|
return rlimit2py(rl);
|
|
}
|
|
|
|
/*[clinic input]
|
|
resource.setrlimit
|
|
|
|
resource: int
|
|
limits: object
|
|
/
|
|
|
|
[clinic start generated code]*/
|
|
|
|
static TyObject *
|
|
resource_setrlimit_impl(TyObject *module, int resource, TyObject *limits)
|
|
/*[clinic end generated code: output=4e82ec3f34d013d1 input=6235a6ce23b4ca75]*/
|
|
{
|
|
struct rlimit rl;
|
|
|
|
if (resource < 0 || resource >= RLIM_NLIMITS) {
|
|
TyErr_SetString(TyExc_ValueError,
|
|
"invalid resource specified");
|
|
return NULL;
|
|
}
|
|
|
|
if (TySys_Audit("resource.setrlimit", "iO", resource,
|
|
limits ? limits : Ty_None) < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
if (py2rlimit(limits, &rl) < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
if (setrlimit(resource, &rl) == -1) {
|
|
if (errno == EINVAL)
|
|
TyErr_SetString(TyExc_ValueError,
|
|
"current limit exceeds maximum limit");
|
|
else if (errno == EPERM)
|
|
TyErr_SetString(TyExc_ValueError,
|
|
"not allowed to raise maximum limit");
|
|
else
|
|
TyErr_SetFromErrno(TyExc_OSError);
|
|
return NULL;
|
|
}
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
#ifdef HAVE_PRLIMIT
|
|
/*[clinic input]
|
|
resource.prlimit
|
|
|
|
pid: pid_t
|
|
resource: int
|
|
limits: object = None
|
|
/
|
|
|
|
[clinic start generated code]*/
|
|
|
|
static TyObject *
|
|
resource_prlimit_impl(TyObject *module, pid_t pid, int resource,
|
|
TyObject *limits)
|
|
/*[clinic end generated code: output=6ebc49ff8c3a816e input=54bb69c9585e33bf]*/
|
|
{
|
|
struct rlimit old_limit, new_limit;
|
|
int retval;
|
|
|
|
if (resource < 0 || resource >= RLIM_NLIMITS) {
|
|
TyErr_SetString(TyExc_ValueError,
|
|
"invalid resource specified");
|
|
return NULL;
|
|
}
|
|
|
|
if (TySys_Audit("resource.prlimit", "iiO", pid, resource,
|
|
limits ? limits : Ty_None) < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
if (limits != Ty_None) {
|
|
if (py2rlimit(limits, &new_limit) < 0) {
|
|
return NULL;
|
|
}
|
|
retval = prlimit(pid, resource, &new_limit, &old_limit);
|
|
}
|
|
else {
|
|
retval = prlimit(pid, resource, NULL, &old_limit);
|
|
}
|
|
|
|
if (retval == -1) {
|
|
if (errno == EINVAL) {
|
|
TyErr_SetString(TyExc_ValueError,
|
|
"current limit exceeds maximum limit");
|
|
} else {
|
|
TyErr_SetFromErrno(TyExc_OSError);
|
|
}
|
|
return NULL;
|
|
}
|
|
return rlimit2py(old_limit);
|
|
}
|
|
#endif /* HAVE_PRLIMIT */
|
|
|
|
/*[clinic input]
|
|
resource.getpagesize -> int
|
|
[clinic start generated code]*/
|
|
|
|
static int
|
|
resource_getpagesize_impl(TyObject *module)
|
|
/*[clinic end generated code: output=9ba93eb0f3d6c3a9 input=546545e8c1f42085]*/
|
|
{
|
|
long pagesize = 0;
|
|
#if defined(HAVE_GETPAGESIZE)
|
|
pagesize = getpagesize();
|
|
#elif defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
|
|
pagesize = sysconf(_SC_PAGE_SIZE);
|
|
#else
|
|
# error "unsupported platform: resource.getpagesize()"
|
|
#endif
|
|
return pagesize;
|
|
}
|
|
|
|
/* List of functions */
|
|
|
|
static struct TyMethodDef
|
|
resource_methods[] = {
|
|
RESOURCE_GETRUSAGE_METHODDEF
|
|
RESOURCE_GETRLIMIT_METHODDEF
|
|
RESOURCE_PRLIMIT_METHODDEF
|
|
RESOURCE_SETRLIMIT_METHODDEF
|
|
RESOURCE_GETPAGESIZE_METHODDEF
|
|
{NULL, NULL} /* sentinel */
|
|
};
|
|
|
|
|
|
/* Module initialization */
|
|
|
|
static int
|
|
resource_exec(TyObject *module)
|
|
{
|
|
resourcemodulestate *state = get_resource_state(module);
|
|
#define ADD_INT(module, value) \
|
|
do { \
|
|
if (TyModule_AddIntConstant(module, #value, value) < 0) { \
|
|
return -1; \
|
|
} \
|
|
} while (0)
|
|
|
|
/* Add some symbolic constants to the module */
|
|
if (TyModule_AddObjectRef(module, "error", TyExc_OSError) < 0) {
|
|
return -1;
|
|
}
|
|
|
|
state->StructRUsageType = TyStructSequence_NewType(&struct_rusage_desc);
|
|
if (state->StructRUsageType == NULL) {
|
|
return -1;
|
|
}
|
|
if (TyModule_AddType(module, state->StructRUsageType) < 0) {
|
|
return -1;
|
|
}
|
|
|
|
/* insert constants */
|
|
#ifdef RLIMIT_CPU
|
|
ADD_INT(module, RLIMIT_CPU);
|
|
#endif
|
|
|
|
#ifdef RLIMIT_FSIZE
|
|
ADD_INT(module, RLIMIT_FSIZE);
|
|
#endif
|
|
|
|
#ifdef RLIMIT_DATA
|
|
ADD_INT(module, RLIMIT_DATA);
|
|
#endif
|
|
|
|
#ifdef RLIMIT_STACK
|
|
ADD_INT(module, RLIMIT_STACK);
|
|
#endif
|
|
|
|
#ifdef RLIMIT_CORE
|
|
ADD_INT(module, RLIMIT_CORE);
|
|
#endif
|
|
|
|
#ifdef RLIMIT_NOFILE
|
|
ADD_INT(module, RLIMIT_NOFILE);
|
|
#endif
|
|
|
|
#ifdef RLIMIT_OFILE
|
|
ADD_INT(module, RLIMIT_OFILE);
|
|
#endif
|
|
|
|
#ifdef RLIMIT_VMEM
|
|
ADD_INT(module, RLIMIT_VMEM);
|
|
#endif
|
|
|
|
#ifdef RLIMIT_AS
|
|
ADD_INT(module, RLIMIT_AS);
|
|
#endif
|
|
|
|
#ifdef RLIMIT_RSS
|
|
ADD_INT(module, RLIMIT_RSS);
|
|
#endif
|
|
|
|
#ifdef RLIMIT_NPROC
|
|
ADD_INT(module, RLIMIT_NPROC);
|
|
#endif
|
|
|
|
#ifdef RLIMIT_MEMLOCK
|
|
ADD_INT(module, RLIMIT_MEMLOCK);
|
|
#endif
|
|
|
|
#ifdef RLIMIT_SBSIZE
|
|
ADD_INT(module, RLIMIT_SBSIZE);
|
|
#endif
|
|
|
|
/* Linux specific */
|
|
#ifdef RLIMIT_MSGQUEUE
|
|
ADD_INT(module, RLIMIT_MSGQUEUE);
|
|
#endif
|
|
|
|
#ifdef RLIMIT_NICE
|
|
ADD_INT(module, RLIMIT_NICE);
|
|
#endif
|
|
|
|
#ifdef RLIMIT_RTPRIO
|
|
ADD_INT(module, RLIMIT_RTPRIO);
|
|
#endif
|
|
|
|
#ifdef RLIMIT_RTTIME
|
|
ADD_INT(module, RLIMIT_RTTIME);
|
|
#endif
|
|
|
|
#ifdef RLIMIT_SIGPENDING
|
|
ADD_INT(module, RLIMIT_SIGPENDING);
|
|
#endif
|
|
|
|
/* target */
|
|
#ifdef RUSAGE_SELF
|
|
ADD_INT(module, RUSAGE_SELF);
|
|
#endif
|
|
|
|
#ifdef RUSAGE_CHILDREN
|
|
ADD_INT(module, RUSAGE_CHILDREN);
|
|
#endif
|
|
|
|
#ifdef RUSAGE_BOTH
|
|
ADD_INT(module, RUSAGE_BOTH);
|
|
#endif
|
|
|
|
#ifdef RUSAGE_THREAD
|
|
ADD_INT(module, RUSAGE_THREAD);
|
|
#endif
|
|
|
|
/* FreeBSD specific */
|
|
|
|
#ifdef RLIMIT_SWAP
|
|
ADD_INT(module, RLIMIT_SWAP);
|
|
#endif
|
|
|
|
#ifdef RLIMIT_SBSIZE
|
|
ADD_INT(module, RLIMIT_SBSIZE);
|
|
#endif
|
|
|
|
#ifdef RLIMIT_NPTS
|
|
ADD_INT(module, RLIMIT_NPTS);
|
|
#endif
|
|
|
|
#ifdef RLIMIT_KQUEUES
|
|
ADD_INT(module, RLIMIT_KQUEUES);
|
|
#endif
|
|
|
|
TyObject *v;
|
|
if (sizeof(RLIM_INFINITY) > sizeof(long)) {
|
|
v = TyLong_FromLongLong((long long) RLIM_INFINITY);
|
|
} else
|
|
{
|
|
v = TyLong_FromLong((long) RLIM_INFINITY);
|
|
}
|
|
if (TyModule_Add(module, "RLIM_INFINITY", v) < 0) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
|
|
#undef ADD_INT
|
|
}
|
|
|
|
static struct PyModuleDef_Slot resource_slots[] = {
|
|
{Ty_mod_exec, resource_exec},
|
|
{Ty_mod_multiple_interpreters, Ty_MOD_PER_INTERPRETER_GIL_SUPPORTED},
|
|
{Ty_mod_gil, Ty_MOD_GIL_NOT_USED},
|
|
{0, NULL}
|
|
};
|
|
|
|
static int
|
|
resourcemodule_traverse(TyObject *m, visitproc visit, void *arg) {
|
|
Ty_VISIT(get_resource_state(m)->StructRUsageType);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
resourcemodule_clear(TyObject *m) {
|
|
Ty_CLEAR(get_resource_state(m)->StructRUsageType);
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
resourcemodule_free(void *m) {
|
|
resourcemodule_clear((TyObject *)m);
|
|
}
|
|
|
|
static struct TyModuleDef resourcemodule = {
|
|
PyModuleDef_HEAD_INIT,
|
|
.m_name = "resource",
|
|
.m_size = sizeof(resourcemodulestate),
|
|
.m_methods = resource_methods,
|
|
.m_slots = resource_slots,
|
|
.m_traverse = resourcemodule_traverse,
|
|
.m_clear = resourcemodule_clear,
|
|
.m_free = resourcemodule_free,
|
|
};
|
|
|
|
PyMODINIT_FUNC
|
|
PyInit_resource(void)
|
|
{
|
|
return PyModuleDef_Init(&resourcemodule);
|
|
}
|