Skip to content

Commit

Permalink
pythongh-126303: Fix pickling and copying of os.sched_param objects (p…
Browse files Browse the repository at this point in the history
…ythonGH-126336)

(cherry picked from commit d384050)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
  • Loading branch information
serhiy-storchaka authored and miss-islington committed Nov 5, 2024
1 parent 05da4ee commit 0d00018
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 0 deletions.
1 change: 1 addition & 0 deletions Include/internal/pycore_typeobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ extern PyObject* _PyType_GetFullyQualifiedName(PyTypeObject *type, char sep);
// self->tp_flags = (self->tp_flags & ~mask) | flags;
extern void _PyType_SetFlags(PyTypeObject *self, unsigned long mask,
unsigned long flags);
extern int _PyType_AddMethod(PyTypeObject *, PyMethodDef *);

// Like _PyType_SetFlags(), but apply the operation to self and any of its
// subclasses without Py_TPFLAGS_IMMUTABLETYPE set.
Expand Down
21 changes: 21 additions & 0 deletions Lib/test/test_posix.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
from test.support import warnings_helper
from test.support.script_helper import assert_python_ok

import copy
import errno
import sys
import signal
import time
import os
import platform
import pickle
import stat
import tempfile
import unittest
Expand Down Expand Up @@ -1317,6 +1319,25 @@ def test_get_and_set_scheduler_and_param(self):
param = posix.sched_param(sched_priority=-large)
self.assertRaises(OverflowError, posix.sched_setparam, 0, param)

@requires_sched
def test_sched_param(self):
param = posix.sched_param(1)
for proto in range(pickle.HIGHEST_PROTOCOL+1):
newparam = pickle.loads(pickle.dumps(param, proto))
self.assertEqual(newparam, param)
newparam = copy.copy(param)
self.assertIsNot(newparam, param)
self.assertEqual(newparam, param)
newparam = copy.deepcopy(param)
self.assertIsNot(newparam, param)
self.assertEqual(newparam, param)
newparam = copy.replace(param)
self.assertIsNot(newparam, param)
self.assertEqual(newparam, param)
newparam = copy.replace(param, sched_priority=0)
self.assertNotEqual(newparam, param)
self.assertEqual(newparam.sched_priority, 0)

@unittest.skipUnless(hasattr(posix, "sched_rr_get_interval"), "no function")
def test_sched_rr_get_interval(self):
try:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix pickling and copying of :class:`os.sched_param` objects.
17 changes: 17 additions & 0 deletions Modules/posixmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include "pycore_signal.h" // Py_NSIG
#include "pycore_time.h" // _PyLong_FromTime_t()
#include "pycore_typeobject.h" // _PyType_AddMethod()

#ifdef HAVE_UNISTD_H
# include <unistd.h> // symlink()
Expand Down Expand Up @@ -8172,6 +8173,16 @@ os_sched_param_impl(PyTypeObject *type, PyObject *sched_priority)
return res;
}

static PyObject *
os_sched_param_reduce(PyObject *self, PyObject *Py_UNUSED(ignored))
{
return Py_BuildValue("(O(N))", Py_TYPE(self), PyStructSequence_GetItem(self, 0));
}

static PyMethodDef os_sched_param_reduce_method = {
"__reduce__", (PyCFunction)os_sched_param_reduce, METH_NOARGS|METH_COEXIST, NULL,
};

PyDoc_VAR(os_sched_param__doc__);

static PyStructSequence_Field sched_param_fields[] = {
Expand Down Expand Up @@ -17980,6 +17991,12 @@ posixmodule_exec(PyObject *m)
return -1;
}
((PyTypeObject *)state->SchedParamType)->tp_new = os_sched_param;
if (_PyType_AddMethod((PyTypeObject *)state->SchedParamType,
&os_sched_param_reduce_method) < 0)
{
return -1;
}
PyType_Modified((PyTypeObject *)state->SchedParamType);
#endif

/* initialize TerminalSize_info */
Expand Down
6 changes: 6 additions & 0 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -7332,6 +7332,12 @@ type_add_method(PyTypeObject *type, PyMethodDef *meth)
return 0;
}

int
_PyType_AddMethod(PyTypeObject *type, PyMethodDef *meth)
{
return type_add_method(type, meth);
}


/* Add the methods from tp_methods to the __dict__ in a type object */
static int
Expand Down

0 comments on commit 0d00018

Please sign in to comment.