expose sched.h functions (closes #12655)
This commit is contained in:
parent
4e4d5d2a73
commit
94b580d423
|
@ -2744,6 +2744,155 @@ used to determine the disposition of a process.
|
|||
Availability: Unix.
|
||||
|
||||
|
||||
Interface to the scheduler
|
||||
--------------------------
|
||||
|
||||
These functions control how a process is allocated CPU time by the operating
|
||||
system. They are only available on some Unix platforms. For more detailed
|
||||
information, consult your Unix manpages.
|
||||
|
||||
.. versionadded:: 3.3
|
||||
|
||||
The following scheduling policies are exposed if they are a supported by the
|
||||
operating system.
|
||||
|
||||
.. data:: SCHED_OTHER
|
||||
|
||||
The default scheduling policy.
|
||||
|
||||
.. data:: SCHED_BATCH
|
||||
|
||||
Scheduling policy for CPU-intensive processes that tries to preserve
|
||||
interactivity on the rest of the computer.
|
||||
|
||||
.. data:: SCHED_IDLE
|
||||
|
||||
Scheduling policy for extremely low priority background tasks.
|
||||
|
||||
.. data:: SCHED_SPORADIC
|
||||
|
||||
Scheduling policy for sporadic server programs.
|
||||
|
||||
.. data:: SCHED_FIFO
|
||||
|
||||
A First In First Out scheduling policy.
|
||||
|
||||
.. data:: SCHED_RR
|
||||
|
||||
A round-robin scheduling policy.
|
||||
|
||||
.. data:: SCHED_RESET_ON_FORK
|
||||
|
||||
This flag can OR'ed with any other scheduling policy. When a process with
|
||||
this flag set forks, its child's scheduling policy and priority are reset to
|
||||
the default.
|
||||
|
||||
|
||||
.. class:: sched_param(sched_priority)
|
||||
|
||||
This class represents tunable scheduling parameters used in
|
||||
:func:`sched_setparam`, :func:`sched_setscheduler`, and
|
||||
:func:`sched_getparam`. It is immutable.
|
||||
|
||||
At the moment, there is only one possible parameter:
|
||||
|
||||
.. attribute:: sched_priority
|
||||
|
||||
The scheduling priority for a scheduling policy.
|
||||
|
||||
|
||||
.. function:: sched_get_priority_min(policy)
|
||||
|
||||
Get the minimum priority value for *policy*. *policy* is one of the
|
||||
scheduling policy constants above.
|
||||
|
||||
|
||||
.. function:: sched_get_priority_max(policy)
|
||||
|
||||
Get the maximum priority value for *policy*. *policy* is one of the
|
||||
scheduling policy constants above.
|
||||
|
||||
|
||||
.. function:: sched_setscheduler(pid, policy, param)
|
||||
|
||||
Set the scheduling policy for the process with PID *pid*. A *pid* of 0 means
|
||||
the calling process. *policy* is one of the scheduling policy constants
|
||||
above. *param* is a :class:`sched_param` instance.
|
||||
|
||||
|
||||
.. function:: sched_getscheduler(pid)
|
||||
|
||||
Return the scheduling policy for the process with PID *pid*. A *pid* of 0
|
||||
means the calling process. The result is one of the scheduling policy
|
||||
constants above.
|
||||
|
||||
|
||||
.. function:: sched_setparam(pid, param)
|
||||
|
||||
Set a scheduling parameters for the process with PID *pid*. A *pid* of 0 means
|
||||
the calling process. *param* is a :class:`sched_param` instance.
|
||||
|
||||
|
||||
.. function:: sched_getparam(pid)
|
||||
|
||||
Return the scheduling parameters as a :class:`sched_param` instance for the
|
||||
process with PID *pid*. A *pid* of 0 means the calling process.
|
||||
|
||||
|
||||
.. function:: sched_rr_get_interval(pid)
|
||||
|
||||
Return the round-robin quantum in seconds for the process with PID *pid*. A
|
||||
*pid* of 0 means the calling process.
|
||||
|
||||
|
||||
.. function:: sched_yield()
|
||||
|
||||
Voluntarily relinquish the CPU.
|
||||
|
||||
|
||||
.. class:: cpu_set(ncpus)
|
||||
|
||||
:class:`cpu_set` represents a set of CPUs on which a process is eligible to
|
||||
run. *ncpus* is the number of CPUs the set should describe. Methods on
|
||||
:class:`cpu_set` allow CPUs to be add or removed.
|
||||
|
||||
:class:`cpu_set` supports the AND, OR, and XOR bitwise operations. For
|
||||
example, given two cpu_sets, ``one`` and ``two``, ``one | two`` returns a
|
||||
:class:`cpu_set` containing the cpus enabled both in ``one`` and ``two``.
|
||||
|
||||
.. method:: set(i)
|
||||
|
||||
Enable CPU *i*.
|
||||
|
||||
.. method:: clear(i)
|
||||
|
||||
Remove CPU *i*.
|
||||
|
||||
.. method:: isset(i)
|
||||
|
||||
Return ``True`` if CPU *i* is enabled in the set.
|
||||
|
||||
.. method:: count()
|
||||
|
||||
Return the number of enabled CPUs in the set.
|
||||
|
||||
.. method:: zero()
|
||||
|
||||
Clear the set completely.
|
||||
|
||||
|
||||
.. function:: sched_setaffinity(pid, mask)
|
||||
|
||||
Restrict the process with PID *pid* to a set of CPUs. *mask* is a
|
||||
:class:`cpu_set` instance.
|
||||
|
||||
|
||||
.. function:: sched_getaffinity(pid, size)
|
||||
|
||||
Return the :class:`cpu_set` the process with PID *pid* is restricted to. The
|
||||
result will contain *size* CPUs.
|
||||
|
||||
|
||||
.. _os-path:
|
||||
|
||||
Miscellaneous System Information
|
||||
|
|
|
@ -829,6 +829,138 @@ class PosixTester(unittest.TestCase):
|
|||
finally:
|
||||
posix.close(f)
|
||||
|
||||
requires_sched_h = unittest.skipUnless(hasattr(posix, 'sched_yield'),
|
||||
"don't have scheduling support")
|
||||
|
||||
@requires_sched_h
|
||||
def test_sched_yield(self):
|
||||
# This has no error conditions (at least on Linux).
|
||||
posix.sched_yield()
|
||||
|
||||
@requires_sched_h
|
||||
def test_sched_priority(self):
|
||||
# Round-robin usually has interesting priorities.
|
||||
pol = posix.SCHED_RR
|
||||
lo = posix.sched_get_priority_min(pol)
|
||||
hi = posix.sched_get_priority_max(pol)
|
||||
self.assertIsInstance(lo, int)
|
||||
self.assertIsInstance(hi, int)
|
||||
self.assertGreaterEqual(hi, lo)
|
||||
self.assertRaises(OSError, posix.sched_get_priority_min, -23)
|
||||
self.assertRaises(OSError, posix.sched_get_priority_max, -23)
|
||||
|
||||
@requires_sched_h
|
||||
def test_get_and_set_scheduler_and_param(self):
|
||||
possible_schedulers = [sched for name, sched in posix.__dict__.items()
|
||||
if name.startswith("SCHED_")]
|
||||
mine = posix.sched_getscheduler(0)
|
||||
self.assertIn(mine, possible_schedulers)
|
||||
try:
|
||||
init = posix.sched_getscheduler(1)
|
||||
except OSError as e:
|
||||
if e.errno != errno.EPERM:
|
||||
raise
|
||||
else:
|
||||
self.assertIn(init, possible_schedulers)
|
||||
self.assertRaises(OSError, posix.sched_getscheduler, -1)
|
||||
self.assertRaises(OSError, posix.sched_getparam, -1)
|
||||
param = posix.sched_getparam(0)
|
||||
self.assertIsInstance(param.sched_priority, int)
|
||||
posix.sched_setscheduler(0, mine, param)
|
||||
posix.sched_setparam(0, param)
|
||||
self.assertRaises(OSError, posix.sched_setparam, -1, param)
|
||||
self.assertRaises(OSError, posix.sched_setscheduler, -1, mine, param)
|
||||
self.assertRaises(TypeError, posix.sched_setscheduler, 0, mine, None)
|
||||
self.assertRaises(TypeError, posix.sched_setparam, 0, 43)
|
||||
param = posix.sched_param(None)
|
||||
self.assertRaises(TypeError, posix.sched_setparam, 0, param)
|
||||
large = 214748364700
|
||||
param = posix.sched_param(large)
|
||||
self.assertRaises(OverflowError, posix.sched_setparam, 0, param)
|
||||
param = posix.sched_param(sched_priority=-large)
|
||||
self.assertRaises(OverflowError, posix.sched_setparam, 0, param)
|
||||
|
||||
@requires_sched_h
|
||||
def test_sched_rr_get_interval(self):
|
||||
interval = posix.sched_rr_get_interval(0)
|
||||
self.assertIsInstance(interval, float)
|
||||
# Reasonable constraints, I think.
|
||||
self.assertGreaterEqual(interval, 0.)
|
||||
self.assertLess(interval, 1.)
|
||||
|
||||
@requires_sched_h
|
||||
def test_sched_affinity(self):
|
||||
mask = posix.sched_getaffinity(0, 1024)
|
||||
self.assertGreaterEqual(mask.count(), 1)
|
||||
self.assertIsInstance(mask, posix.cpu_set)
|
||||
self.assertRaises(OSError, posix.sched_getaffinity, -1, 1024)
|
||||
empty = posix.cpu_set(10)
|
||||
posix.sched_setaffinity(0, mask)
|
||||
self.assertRaises(OSError, posix.sched_setaffinity, 0, empty)
|
||||
self.assertRaises(OSError, posix.sched_setaffinity, -1, mask)
|
||||
|
||||
@requires_sched_h
|
||||
def test_cpu_set_basic(self):
|
||||
s = posix.cpu_set(10)
|
||||
self.assertEqual(len(s), 10)
|
||||
self.assertEqual(s.count(), 0)
|
||||
s.set(0)
|
||||
s.set(9)
|
||||
self.assertTrue(s.isset(0))
|
||||
self.assertTrue(s.isset(9))
|
||||
self.assertFalse(s.isset(5))
|
||||
self.assertEqual(s.count(), 2)
|
||||
s.clear(0)
|
||||
self.assertFalse(s.isset(0))
|
||||
self.assertEqual(s.count(), 1)
|
||||
s.zero()
|
||||
self.assertFalse(s.isset(0))
|
||||
self.assertFalse(s.isset(9))
|
||||
self.assertEqual(s.count(), 0)
|
||||
self.assertRaises(ValueError, s.set, -1)
|
||||
self.assertRaises(ValueError, s.set, 10)
|
||||
self.assertRaises(ValueError, s.clear, -1)
|
||||
self.assertRaises(ValueError, s.clear, 10)
|
||||
self.assertRaises(ValueError, s.isset, -1)
|
||||
self.assertRaises(ValueError, s.isset, 10)
|
||||
|
||||
@requires_sched_h
|
||||
def test_cpu_set_cmp(self):
|
||||
self.assertNotEqual(posix.cpu_set(11), posix.cpu_set(12))
|
||||
l = posix.cpu_set(10)
|
||||
r = posix.cpu_set(10)
|
||||
self.assertEqual(l, r)
|
||||
l.set(1)
|
||||
self.assertNotEqual(l, r)
|
||||
r.set(1)
|
||||
self.assertEqual(l, r)
|
||||
|
||||
@requires_sched_h
|
||||
def test_cpu_set_bitwise(self):
|
||||
l = posix.cpu_set(5)
|
||||
l.set(0)
|
||||
l.set(1)
|
||||
r = posix.cpu_set(5)
|
||||
r.set(1)
|
||||
r.set(2)
|
||||
b = l & r
|
||||
self.assertEqual(b.count(), 1)
|
||||
self.assertTrue(b.isset(1))
|
||||
b = l | r
|
||||
self.assertEqual(b.count(), 3)
|
||||
self.assertTrue(b.isset(0))
|
||||
self.assertTrue(b.isset(1))
|
||||
self.assertTrue(b.isset(2))
|
||||
b = l ^ r
|
||||
self.assertEqual(b.count(), 2)
|
||||
self.assertTrue(b.isset(0))
|
||||
self.assertFalse(b.isset(1))
|
||||
self.assertTrue(b.isset(2))
|
||||
b = l
|
||||
b |= r
|
||||
self.assertIs(b, l)
|
||||
self.assertEqual(l.count(), 3)
|
||||
|
||||
class PosixGroupsTester(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
@ -864,7 +996,6 @@ class PosixGroupsTester(unittest.TestCase):
|
|||
posix.setgroups(groups)
|
||||
self.assertListEqual(groups, posix.getgroups())
|
||||
|
||||
|
||||
def test_main():
|
||||
try:
|
||||
support.run_unittest(PosixTester, PosixGroupsTester)
|
||||
|
|
|
@ -251,6 +251,11 @@ Core and Builtins
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue #12655: Expose functions from sched.h in the os module: sched_yield(),
|
||||
sched_setscheduler(), sched_getscheduler(), sched_setparam(),
|
||||
sched_get_min_priority(), sched_get_max_priority(), sched_rr_get_interval(),
|
||||
sched_getaffinity(), sched_setaffinity().
|
||||
|
||||
- Issues #11104, #8688: Fix the behavior of distutils' sdist command with
|
||||
manually-maintained MANIFEST files.
|
||||
|
||||
|
|
|
@ -105,6 +105,10 @@ corresponding Unix manual entries for more information on calls.");
|
|||
#include <sys/sendfile.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SCHED_H
|
||||
#include <sched.h>
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__APPLE__)
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
|
@ -1605,6 +1609,7 @@ static PyTypeObject WaitidResultType;
|
|||
static int initialized;
|
||||
static PyTypeObject StatResultType;
|
||||
static PyTypeObject StatVFSResultType;
|
||||
static PyTypeObject SchedParamType;
|
||||
static newfunc structseq_new;
|
||||
|
||||
static PyObject *
|
||||
|
@ -4544,6 +4549,542 @@ posix_fork(PyObject *self, PyObject *noargs)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SCHED_H
|
||||
|
||||
PyDoc_STRVAR(posix_sched_get_priority_max__doc__,
|
||||
"sched_get_priority_max(policy)\n\n\
|
||||
Get the maximum scheduling priority for *policy*.");
|
||||
|
||||
static PyObject *
|
||||
posix_sched_get_priority_max(PyObject *self, PyObject *args)
|
||||
{
|
||||
int policy, max;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i:sched_get_priority_max", &policy))
|
||||
return NULL;
|
||||
max = sched_get_priority_max(policy);
|
||||
if (max < 0)
|
||||
return posix_error();
|
||||
return PyLong_FromLong(max);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(posix_sched_get_priority_min__doc__,
|
||||
"sched_get_priority_min(policy)\n\n\
|
||||
Get the minimum scheduling priority for *policy*.");
|
||||
|
||||
static PyObject *
|
||||
posix_sched_get_priority_min(PyObject *self, PyObject *args)
|
||||
{
|
||||
int policy, min;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i:sched_get_priority_min", &policy))
|
||||
return NULL;
|
||||
min = sched_get_priority_min(policy);
|
||||
if (min < 0)
|
||||
return posix_error();
|
||||
return PyLong_FromLong(min);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(posix_sched_getscheduler__doc__,
|
||||
"sched_getscheduler(pid)\n\n\
|
||||
Get the scheduling policy for the process with a PID of *pid*.\n\
|
||||
Passing a PID of 0 returns the scheduling policy for the calling process.");
|
||||
|
||||
static PyObject *
|
||||
posix_sched_getscheduler(PyObject *self, PyObject *args)
|
||||
{
|
||||
pid_t pid;
|
||||
int policy;
|
||||
|
||||
if (!PyArg_ParseTuple(args, _Py_PARSE_PID ":sched_getscheduler", &pid))
|
||||
return NULL;
|
||||
policy = sched_getscheduler(pid);
|
||||
if (policy < 0)
|
||||
return posix_error();
|
||||
return PyLong_FromLong(policy);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
sched_param_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
PyObject *res, *priority;
|
||||
static char *kwlist[] = {"sched_priority"};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:sched_param", kwlist, &priority))
|
||||
return NULL;
|
||||
res = PyStructSequence_New(type);
|
||||
if (!res)
|
||||
return NULL;
|
||||
Py_INCREF(priority);
|
||||
PyStructSequence_SET_ITEM(res, 0, priority);
|
||||
return res;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(sched_param__doc__,
|
||||
"sched_param(sched_priority): A scheduling parameter.\n\n\
|
||||
Current has only one field: sched_priority");
|
||||
|
||||
static PyStructSequence_Field sched_param_fields[] = {
|
||||
{"sched_priority", "the scheduling priority"},
|
||||
{0}
|
||||
};
|
||||
|
||||
static PyStructSequence_Desc sched_param_desc = {
|
||||
"sched_param", /* name */
|
||||
sched_param__doc__, /* doc */
|
||||
sched_param_fields,
|
||||
1
|
||||
};
|
||||
|
||||
static int
|
||||
convert_sched_param(PyObject *param, struct sched_param *res)
|
||||
{
|
||||
long priority;
|
||||
|
||||
if (Py_TYPE(param) != &SchedParamType) {
|
||||
PyErr_SetString(PyExc_TypeError, "must have a sched_param object");
|
||||
return 0;
|
||||
}
|
||||
priority = PyLong_AsLong(PyStructSequence_GET_ITEM(param, 0));
|
||||
if (priority == -1 && PyErr_Occurred())
|
||||
return 0;
|
||||
if (priority > INT_MAX || priority < INT_MIN) {
|
||||
PyErr_SetString(PyExc_OverflowError, "sched_priority out of range");
|
||||
return 0;
|
||||
}
|
||||
res->sched_priority = Py_SAFE_DOWNCAST(priority, long, int);
|
||||
return 1;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(posix_sched_setscheduler__doc__,
|
||||
"sched_setscheduler(pid, policy, param)\n\n\
|
||||
Set the scheduling policy, *policy*, for *pid*.\n\
|
||||
If *pid* is 0, the calling process is changed.\n\
|
||||
*param* is an instance of sched_param.");
|
||||
|
||||
static PyObject *
|
||||
posix_sched_setscheduler(PyObject *self, PyObject *args)
|
||||
{
|
||||
pid_t pid;
|
||||
int policy;
|
||||
struct sched_param param;
|
||||
|
||||
if (!PyArg_ParseTuple(args, _Py_PARSE_PID "iO&:sched_setscheduler",
|
||||
&pid, &policy, &convert_sched_param, ¶m))
|
||||
return NULL;
|
||||
if (sched_setscheduler(pid, policy, ¶m))
|
||||
return posix_error();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(posix_sched_getparam__doc__,
|
||||
"sched_getparam(pid) -> sched_param\n\n\
|
||||
Returns scheduling parameters for the process with *pid* as an instance of the\n\
|
||||
sched_param class. A PID of 0 means the calling process.");
|
||||
|
||||
static PyObject *
|
||||
posix_sched_getparam(PyObject *self, PyObject *args)
|
||||
{
|
||||
pid_t pid;
|
||||
struct sched_param param;
|
||||
PyObject *res, *priority;
|
||||
|
||||
if (!PyArg_ParseTuple(args, _Py_PARSE_PID ":sched_getparam", &pid))
|
||||
return NULL;
|
||||
if (sched_getparam(pid, ¶m))
|
||||
return posix_error();
|
||||
res = PyStructSequence_New(&SchedParamType);
|
||||
if (!res)
|
||||
return NULL;
|
||||
priority = PyLong_FromLong(param.sched_priority);
|
||||
if (!priority) {
|
||||
Py_DECREF(res);
|
||||
return NULL;
|
||||
}
|
||||
PyStructSequence_SET_ITEM(res, 0, priority);
|
||||
return res;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(posix_sched_setparam__doc__,
|
||||
"sched_setparam(pid, param)\n\n\
|
||||
Set scheduling parameters for a process with PID *pid*.\n\
|
||||
A PID of 0 means the calling process.");
|
||||
|
||||
static PyObject *
|
||||
posix_sched_setparam(PyObject *self, PyObject *args)
|
||||
{
|
||||
pid_t pid;
|
||||
struct sched_param param;
|
||||
|
||||
if (!PyArg_ParseTuple(args, _Py_PARSE_PID "O&:sched_setparam",
|
||||
&pid, &convert_sched_param, ¶m))
|
||||
return NULL;
|
||||
if (sched_setparam(pid, ¶m))
|
||||
return posix_error();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(posix_sched_rr_get_interval__doc__,
|
||||
"sched_rr_get_interval(pid) -> float\n\n\
|
||||
Return the round-robin quantum for the process with PID *pid* in seconds.");
|
||||
|
||||
static PyObject *
|
||||
posix_sched_rr_get_interval(PyObject *self, PyObject *args)
|
||||
{
|
||||
pid_t pid;
|
||||
struct timespec interval;
|
||||
|
||||
if (!PyArg_ParseTuple(args, _Py_PARSE_PID ":sched_rr_get_interval", &pid))
|
||||
return NULL;
|
||||
if (sched_rr_get_interval(pid, &interval))
|
||||
return posix_error();
|
||||
return PyFloat_FromDouble((double)interval.tv_sec + 1e-9*interval.tv_nsec);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(posix_sched_yield__doc__,
|
||||
"sched_yield()\n\n\
|
||||
Voluntarily relinquish the CPU.");
|
||||
|
||||
static PyObject *
|
||||
posix_sched_yield(PyObject *self, PyObject *noargs)
|
||||
{
|
||||
if (sched_yield())
|
||||
return posix_error();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD;
|
||||
Py_ssize_t size;
|
||||
int ncpus;
|
||||
cpu_set_t *set;
|
||||
} Py_cpu_set;
|
||||
|
||||
static PyTypeObject cpu_set_type;
|
||||
|
||||
static void
|
||||
cpu_set_dealloc(Py_cpu_set *set)
|
||||
{
|
||||
assert(set->set);
|
||||
CPU_FREE(set->set);
|
||||
Py_TYPE(set)->tp_free(set);
|
||||
}
|
||||
|
||||
static Py_cpu_set *
|
||||
make_new_cpu_set(PyTypeObject *type, Py_ssize_t size)
|
||||
{
|
||||
Py_cpu_set *set;
|
||||
|
||||
if (size < 0) {
|
||||
PyErr_SetString(PyExc_ValueError, "negative size");
|
||||
return NULL;
|
||||
}
|
||||
set = (Py_cpu_set *)type->tp_alloc(type, 0);
|
||||
if (!set)
|
||||
return NULL;
|
||||
set->ncpus = size;
|
||||
set->size = CPU_ALLOC_SIZE(size);
|
||||
set->set = CPU_ALLOC(size);
|
||||
if (!set->set) {
|
||||
type->tp_free(set);
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
CPU_ZERO_S(set->size, set->set);
|
||||
return set;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cpu_set_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
int size;
|
||||
|
||||
if (!_PyArg_NoKeywords("cpu_set()", kwargs) ||
|
||||
!PyArg_ParseTuple(args, "i:cpu_set", &size))
|
||||
return NULL;
|
||||
return (PyObject *)make_new_cpu_set(type, size);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cpu_set_repr(Py_cpu_set *set)
|
||||
{
|
||||
return PyUnicode_FromFormat("<cpu_set with %li entries>", set->ncpus);
|
||||
}
|
||||
|
||||
static Py_ssize_t
|
||||
cpu_set_len(Py_cpu_set *set)
|
||||
{
|
||||
return set->ncpus;
|
||||
}
|
||||
|
||||
static int
|
||||
_get_cpu(Py_cpu_set *set, const char *requester, PyObject *args)
|
||||
{
|
||||
int cpu;
|
||||
if (!PyArg_ParseTuple(args, requester, &cpu))
|
||||
return -1;
|
||||
if (cpu < 0) {
|
||||
PyErr_SetString(PyExc_ValueError, "cpu < 0 not valid");
|
||||
return -1;
|
||||
}
|
||||
if (cpu >= set->ncpus) {
|
||||
PyErr_SetString(PyExc_ValueError, "cpu too large for set");
|
||||
return -1;
|
||||
}
|
||||
return cpu;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(cpu_set_set_doc,
|
||||
"cpu_set.set(i)\n\n\
|
||||
Add CPU *i* to the set.");
|
||||
|
||||
static PyObject *
|
||||
cpu_set_set(Py_cpu_set *set, PyObject *args)
|
||||
{
|
||||
int cpu = _get_cpu(set, "i|set", args);
|
||||
if (cpu == -1)
|
||||
return NULL;
|
||||
CPU_SET_S(cpu, set->size, set->set);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(cpu_set_count_doc,
|
||||
"cpu_set.count() -> int\n\n\
|
||||
Return the number of CPUs active in the set.");
|
||||
|
||||
static PyObject *
|
||||
cpu_set_count(Py_cpu_set *set, PyObject *noargs)
|
||||
{
|
||||
return PyLong_FromLong(CPU_COUNT_S(set->size, set->set));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(cpu_set_clear_doc,
|
||||
"cpu_set.clear(i)\n\n\
|
||||
Remove CPU *i* from the set.");
|
||||
|
||||
static PyObject *
|
||||
cpu_set_clear(Py_cpu_set *set, PyObject *args)
|
||||
{
|
||||
int cpu = _get_cpu(set, "i|clear", args);
|
||||
if (cpu == -1)
|
||||
return NULL;
|
||||
CPU_CLR_S(cpu, set->size, set->set);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(cpu_set_isset_doc,
|
||||
"cpu_set.isset(i) -> bool\n\n\
|
||||
Test if CPU *i* is in the set.");
|
||||
|
||||
static PyObject *
|
||||
cpu_set_isset(Py_cpu_set *set, PyObject *args)
|
||||
{
|
||||
int cpu = _get_cpu(set, "i|isset", args);
|
||||
if (cpu == -1)
|
||||
return NULL;
|
||||
if (CPU_ISSET_S(cpu, set->size, set->set))
|
||||
Py_RETURN_TRUE;
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(cpu_set_zero_doc,
|
||||
"cpu_set.zero()\n\n\
|
||||
Clear the cpu_set.");
|
||||
|
||||
static PyObject *
|
||||
cpu_set_zero(Py_cpu_set *set, PyObject *noargs)
|
||||
{
|
||||
CPU_ZERO_S(set->size, set->set);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cpu_set_richcompare(Py_cpu_set *set, Py_cpu_set *other, int op)
|
||||
{
|
||||
int eq;
|
||||
|
||||
if ((op != Py_EQ && op != Py_NE) || Py_TYPE(other) != &cpu_set_type) {
|
||||
Py_INCREF(Py_NotImplemented);
|
||||
return Py_NotImplemented;
|
||||
}
|
||||
eq = set->ncpus == other->ncpus && CPU_EQUAL_S(set->size, set->set, other->set);
|
||||
if ((op == Py_EQ) ? eq : !eq)
|
||||
Py_RETURN_TRUE;
|
||||
else
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
#define CPU_SET_BINOP(name, op) \
|
||||
static PyObject * \
|
||||
do_cpu_set_##name(Py_cpu_set *left, Py_cpu_set *right, Py_cpu_set *res) { \
|
||||
if (res) { \
|
||||
Py_INCREF(res); \
|
||||
} \
|
||||
else { \
|
||||
res = make_new_cpu_set(&cpu_set_type, left->size); \
|
||||
if (!res) \
|
||||
return NULL; \
|
||||
} \
|
||||
if (Py_TYPE(right) != &cpu_set_type || left->size != right->size) { \
|
||||
Py_DECREF(res); \
|
||||
Py_INCREF(Py_NotImplemented); \
|
||||
return Py_NotImplemented; \
|
||||
} \
|
||||
assert(left->size == right->size == res->size); \
|
||||
op(res->size, res->set, left->set, right->set); \
|
||||
return (PyObject *)res; \
|
||||
} \
|
||||
static PyObject * \
|
||||
cpu_set_##name(Py_cpu_set *left, Py_cpu_set *right) { \
|
||||
return do_cpu_set_##name(left, right, NULL); \
|
||||
} \
|
||||
static PyObject * \
|
||||
cpu_set_i##name(Py_cpu_set *left, Py_cpu_set *right) { \
|
||||
return do_cpu_set_##name(left, right, left); \
|
||||
} \
|
||||
|
||||
CPU_SET_BINOP(and, CPU_AND_S)
|
||||
CPU_SET_BINOP(or, CPU_OR_S)
|
||||
CPU_SET_BINOP(xor, CPU_XOR_S)
|
||||
#undef CPU_SET_BINOP
|
||||
|
||||
PyDoc_STRVAR(cpu_set_doc,
|
||||
"cpu_set(size)\n\n\
|
||||
Create an empty mask of CPUs.");
|
||||
|
||||
static PyNumberMethods cpu_set_as_number = {
|
||||
0, /*nb_add*/
|
||||
0, /*nb_subtract*/
|
||||
0, /*nb_multiply*/
|
||||
0, /*nb_remainder*/
|
||||
0, /*nb_divmod*/
|
||||
0, /*nb_power*/
|
||||
0, /*nb_negative*/
|
||||
0, /*nb_positive*/
|
||||
0, /*nb_absolute*/
|
||||
0, /*nb_bool*/
|
||||
0, /*nb_invert*/
|
||||
0, /*nb_lshift*/
|
||||
0, /*nb_rshift*/
|
||||
(binaryfunc)cpu_set_and, /*nb_and*/
|
||||
(binaryfunc)cpu_set_xor, /*nb_xor*/
|
||||
(binaryfunc)cpu_set_or, /*nb_or*/
|
||||
0, /*nb_int*/
|
||||
0, /*nb_reserved*/
|
||||
0, /*nb_float*/
|
||||
0, /*nb_inplace_add*/
|
||||
0, /*nb_inplace_subtract*/
|
||||
0, /*nb_inplace_multiply*/
|
||||
0, /*nb_inplace_remainder*/
|
||||
0, /*nb_inplace_power*/
|
||||
0, /*nb_inplace_lshift*/
|
||||
0, /*nb_inplace_rshift*/
|
||||
(binaryfunc)cpu_set_iand, /*nb_inplace_and*/
|
||||
(binaryfunc)cpu_set_ixor, /*nb_inplace_xor*/
|
||||
(binaryfunc)cpu_set_ior, /*nb_inplace_or*/
|
||||
};
|
||||
|
||||
static PySequenceMethods cpu_set_as_sequence = {
|
||||
(lenfunc)cpu_set_len, /* sq_length */
|
||||
};
|
||||
|
||||
static PyMethodDef cpu_set_methods[] = {
|
||||
{"clear", (PyCFunction)cpu_set_clear, METH_VARARGS, cpu_set_clear_doc},
|
||||
{"count", (PyCFunction)cpu_set_count, METH_NOARGS, cpu_set_count_doc},
|
||||
{"isset", (PyCFunction)cpu_set_isset, METH_VARARGS, cpu_set_isset_doc},
|
||||
{"set", (PyCFunction)cpu_set_set, METH_VARARGS, cpu_set_set_doc},
|
||||
{"zero", (PyCFunction)cpu_set_zero, METH_NOARGS, cpu_set_zero_doc},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static PyTypeObject cpu_set_type = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"posix.cpu_set", /* tp_name */
|
||||
sizeof(Py_cpu_set), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
/* methods */
|
||||
(destructor)cpu_set_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_reserved */
|
||||
(reprfunc)cpu_set_repr, /* tp_repr */
|
||||
&cpu_set_as_number, /* tp_as_number */
|
||||
&cpu_set_as_sequence, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
PyObject_HashNotImplemented, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
cpu_set_doc, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
(richcmpfunc)cpu_set_richcompare, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
cpu_set_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
PyType_GenericAlloc, /* tp_alloc */
|
||||
cpu_set_new, /* tp_new */
|
||||
PyObject_Del, /* tp_free */
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(posix_sched_setaffinity__doc__,
|
||||
"sched_setaffinity(pid, cpu_set)\n\n\
|
||||
Set the affinity of the process with PID *pid* to *cpu_set*.");
|
||||
|
||||
static PyObject *
|
||||
posix_sched_setaffinity(PyObject *self, PyObject *args)
|
||||
{
|
||||
pid_t pid;
|
||||
Py_cpu_set *cpu_set;
|
||||
|
||||
if (!PyArg_ParseTuple(args, _Py_PARSE_PID "O!|sched_setaffinity",
|
||||
&pid, &cpu_set_type, &cpu_set))
|
||||
return NULL;
|
||||
if (sched_setaffinity(pid, cpu_set->size, cpu_set->set))
|
||||
return posix_error();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(posix_sched_getaffinity__doc__,
|
||||
"sched_getaffinity(pid, ncpus) -> cpu_set\n\n\
|
||||
Return the affinity of the process with PID *pid*.\n\
|
||||
The returned cpu_set will be of size *ncpus*.");
|
||||
|
||||
static PyObject *
|
||||
posix_sched_getaffinity(PyObject *self, PyObject *args)
|
||||
{
|
||||
pid_t pid;
|
||||
int ncpus;
|
||||
Py_cpu_set *res;
|
||||
|
||||
if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i|sched_getaffinity",
|
||||
&pid, &ncpus))
|
||||
return NULL;
|
||||
res = make_new_cpu_set(&cpu_set_type, ncpus);
|
||||
if (!res)
|
||||
return NULL;
|
||||
if (sched_getaffinity(pid, res->size, res->set)) {
|
||||
Py_DECREF(res);
|
||||
return posix_error();
|
||||
}
|
||||
return (PyObject *)res;
|
||||
}
|
||||
|
||||
#endif /* HAVE_SCHED_H */
|
||||
|
||||
/* AIX uses /dev/ptc but is otherwise the same as /dev/ptmx */
|
||||
/* IRIX has both /dev/ptc and /dev/ptmx, use ptmx */
|
||||
#if defined(HAVE_DEV_PTC) && !defined(HAVE_DEV_PTMX)
|
||||
|
@ -9506,6 +10047,18 @@ static PyMethodDef posix_methods[] = {
|
|||
#ifdef HAVE_FORK
|
||||
{"fork", posix_fork, METH_NOARGS, posix_fork__doc__},
|
||||
#endif /* HAVE_FORK */
|
||||
#ifdef HAVE_SCHED_H
|
||||
{"sched_get_priority_max", posix_sched_get_priority_max, METH_VARARGS, posix_sched_get_priority_max__doc__},
|
||||
{"sched_get_priority_min", posix_sched_get_priority_min, METH_VARARGS, posix_sched_get_priority_min__doc__},
|
||||
{"sched_getparam", posix_sched_getparam, METH_VARARGS, posix_sched_getparam__doc__},
|
||||
{"sched_getscheduler", posix_sched_getscheduler, METH_VARARGS, posix_sched_getscheduler__doc__},
|
||||
{"sched_rr_get_interval", posix_sched_rr_get_interval, METH_VARARGS, posix_sched_rr_get_interval__doc__},
|
||||
{"sched_setparam", posix_sched_setparam, METH_VARARGS, posix_sched_setparam__doc__},
|
||||
{"sched_setscheduler", posix_sched_setscheduler, METH_VARARGS, posix_sched_setscheduler__doc__},
|
||||
{"sched_yield", posix_sched_yield, METH_NOARGS, posix_sched_yield__doc__},
|
||||
{"sched_setaffinity", posix_sched_setaffinity, METH_VARARGS, posix_sched_setaffinity__doc__},
|
||||
{"sched_getaffinity", posix_sched_getaffinity, METH_VARARGS, posix_sched_getaffinity__doc__},
|
||||
#endif
|
||||
#if defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX)
|
||||
{"openpty", posix_openpty, METH_NOARGS, posix_openpty__doc__},
|
||||
#endif /* HAVE_OPENPTY || HAVE__GETPTY || HAVE_DEV_PTMX */
|
||||
|
@ -10243,6 +10796,24 @@ all_ins(PyObject *d)
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SCHED_H
|
||||
if (ins(d, "SCHED_FIFO", (long)SCHED_FIFO)) return -1;
|
||||
if (ins(d, "SCHED_RR", (long)SCHED_RR)) return -1;
|
||||
#ifdef SCHED_SPORADIC
|
||||
if (ins(d, "SCHED_SPORADIC", (long)SCHED_SPORADIC) return -1;
|
||||
#endif
|
||||
if (ins(d, "SCHED_OTHER", (long)SCHED_OTHER)) return -1;
|
||||
#ifdef SCHED_BATCH
|
||||
if (ins(d, "SCHED_BATCH", (long)SCHED_BATCH)) return -1;
|
||||
#endif
|
||||
#ifdef SCHED_IDLE
|
||||
if (ins(d, "SCHED_IDLE", (long)SCHED_IDLE)) return -1;
|
||||
#endif
|
||||
#ifdef SCHED_RESET_ON_FORK
|
||||
if (ins(d, "SCHED_RESET_ON_FORK", (long)SCHED_RESET_ON_FORK)) return -1;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(PYOS_OS2)
|
||||
if (insertvalues(d)) return -1;
|
||||
#endif
|
||||
|
@ -10305,6 +10876,11 @@ INITFUNC(void)
|
|||
Py_INCREF(PyExc_OSError);
|
||||
PyModule_AddObject(m, "error", PyExc_OSError);
|
||||
|
||||
if (PyType_Ready(&cpu_set_type) < 0)
|
||||
return NULL;
|
||||
Py_INCREF(&cpu_set_type);
|
||||
PyModule_AddObject(m, "cpu_set", (PyObject *)&cpu_set_type);
|
||||
|
||||
#ifdef HAVE_PUTENV
|
||||
if (posix_putenv_garbage == NULL)
|
||||
posix_putenv_garbage = PyDict_New();
|
||||
|
@ -10334,6 +10910,12 @@ INITFUNC(void)
|
|||
# else
|
||||
ticks_per_second = 60; /* magic fallback value; may be bogus */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SCHED_H
|
||||
sched_param_desc.name = MODNAME ".sched_param";
|
||||
PyStructSequence_InitType(&SchedParamType, &sched_param_desc);
|
||||
SchedParamType.tp_new = sched_param_new;
|
||||
#endif
|
||||
}
|
||||
#if defined(HAVE_WAITID) && !defined(__APPLE__)
|
||||
|
@ -10345,6 +10927,8 @@ INITFUNC(void)
|
|||
Py_INCREF((PyObject*) &StatVFSResultType);
|
||||
PyModule_AddObject(m, "statvfs_result",
|
||||
(PyObject*) &StatVFSResultType);
|
||||
Py_INCREF(&SchedParamType);
|
||||
PyModule_AddObject(m, "sched_param", (PyObject *)&SchedParamType);
|
||||
initialized = 1;
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
|
|
@ -6092,7 +6092,7 @@ fi
|
|||
for ac_header in asm/types.h conio.h curses.h direct.h dlfcn.h errno.h \
|
||||
fcntl.h grp.h \
|
||||
ieeefp.h io.h langinfo.h libintl.h ncurses.h poll.h process.h pthread.h \
|
||||
shadow.h signal.h stdint.h stropts.h termios.h \
|
||||
sched.h shadow.h signal.h stdint.h stropts.h termios.h \
|
||||
unistd.h utime.h \
|
||||
sys/audioio.h sys/bsdtty.h sys/epoll.h sys/event.h sys/file.h sys/loadavg.h \
|
||||
sys/lock.h sys/mkdev.h sys/modem.h \
|
||||
|
@ -14418,8 +14418,8 @@ esac
|
|||
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
# Files that config.status was made for.
|
||||
config_files="`echo $ac_config_files`"
|
||||
config_headers="`echo $ac_config_headers`"
|
||||
config_files="$ac_config_files"
|
||||
config_headers="$ac_config_headers"
|
||||
|
||||
_ACEOF
|
||||
|
||||
|
|
|
@ -1301,7 +1301,7 @@ AC_HEADER_STDC
|
|||
AC_CHECK_HEADERS(asm/types.h conio.h curses.h direct.h dlfcn.h errno.h \
|
||||
fcntl.h grp.h \
|
||||
ieeefp.h io.h langinfo.h libintl.h ncurses.h poll.h process.h pthread.h \
|
||||
shadow.h signal.h stdint.h stropts.h termios.h \
|
||||
sched.h shadow.h signal.h stdint.h stropts.h termios.h \
|
||||
unistd.h utime.h \
|
||||
sys/audioio.h sys/bsdtty.h sys/epoll.h sys/event.h sys/file.h sys/loadavg.h \
|
||||
sys/lock.h sys/mkdev.h sys/modem.h \
|
||||
|
|
|
@ -650,6 +650,9 @@
|
|||
/* Define to 1 if you have the `round' function. */
|
||||
#undef HAVE_ROUND
|
||||
|
||||
/* Define to 1 if you have the <sched.h> header file. */
|
||||
#undef HAVE_SCHED_H
|
||||
|
||||
/* Define to 1 if you have the `select' function. */
|
||||
#undef HAVE_SELECT
|
||||
|
||||
|
|
Loading…
Reference in New Issue