bpo-35537: Add setsid parameter to os.posix_spawn() and os.posix_spawnp() (GH-11608)
This commit is contained in:
parent
05f1b93f58
commit
80c5dfe74b
|
@ -3386,7 +3386,7 @@ written in Python, such as a mail server's external command delivery program.
|
|||
|
||||
|
||||
.. function:: posix_spawn(path, argv, env, *, file_actions=None, \
|
||||
setpgroup=None, resetids=False, setsigmask=(), \
|
||||
setpgroup=None, resetids=False, setsid=False, setsigmask=(), \
|
||||
setsigdef=(), scheduler=None)
|
||||
|
||||
Wraps the :c:func:`posix_spawn` C library API for use from Python.
|
||||
|
@ -3444,6 +3444,11 @@ written in Python, such as a mail server's external command delivery program.
|
|||
setting of the effective UID and GID. This argument corresponds to the C
|
||||
library :c:data:`POSIX_SPAWN_RESETIDS` flag.
|
||||
|
||||
If the *setsid* argument is ``True``, it will create a new session ID
|
||||
for `posix_spawn`. *setsid* requires :c:data:`POSIX_SPAWN_SETSID`
|
||||
or :c:data:`POSIX_SPAWN_SETSID_NP` flag. Otherwise, :exc:`NotImplementedError`
|
||||
is raised.
|
||||
|
||||
The *setsigmask* argument will set the signal mask to the signal set
|
||||
specified. If the parameter is not used, then the child inherits the
|
||||
parent's signal mask. This argument corresponds to the C library
|
||||
|
@ -3462,9 +3467,10 @@ written in Python, such as a mail server's external command delivery program.
|
|||
|
||||
.. versionadded:: 3.7
|
||||
|
||||
.. availability:: Unix.
|
||||
|
||||
.. function:: posix_spawnp(path, argv, env, *, file_actions=None, \
|
||||
setpgroup=None, resetids=False, setsigmask=(), \
|
||||
setpgroup=None, resetids=False, setsid=False, setsigmask=(), \
|
||||
setsigdef=(), scheduler=None)
|
||||
|
||||
Wraps the :c:func:`posix_spawnp` C library API for use from Python.
|
||||
|
@ -3475,6 +3481,8 @@ written in Python, such as a mail server's external command delivery program.
|
|||
|
||||
.. versionadded:: 3.8
|
||||
|
||||
.. availability:: See :func:`posix_spawn` documentation.
|
||||
|
||||
|
||||
.. function:: register_at_fork(*, before=None, after_in_parent=None, \
|
||||
after_in_child=None)
|
||||
|
|
|
@ -1624,6 +1624,22 @@ class _PosixSpawnMixin:
|
|||
os.environ, setsigmask=[signal.NSIG,
|
||||
signal.NSIG+1])
|
||||
|
||||
def test_start_new_session(self):
|
||||
# For code coverage of calling setsid(). We don't care if we get an
|
||||
# EPERM error from it depending on the test execution environment, that
|
||||
# still indicates that it was called.
|
||||
code = "import os; print(os.getpgid(os.getpid()))"
|
||||
try:
|
||||
self.spawn_func(sys.executable,
|
||||
[sys.executable, "-c", code],
|
||||
os.environ, setsid=True)
|
||||
except NotImplementedError as exc:
|
||||
self.skipTest("setsid is not supported: %s" % exc)
|
||||
else:
|
||||
parent_pgid = os.getpgid(os.getpid())
|
||||
child_pgid = int(output)
|
||||
self.assertNotEqual(parent_pgid, child_pgid)
|
||||
|
||||
@unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
|
||||
'need signal.pthread_sigmask()')
|
||||
def test_setsigdef(self):
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
:func:`os.posix_spawn` and :func:`os.posix_spawnp` now have a *setsid* parameter.
|
|
@ -1726,8 +1726,8 @@ exit:
|
|||
|
||||
PyDoc_STRVAR(os_posix_spawn__doc__,
|
||||
"posix_spawn($module, path, argv, env, /, *, file_actions=(),\n"
|
||||
" setpgroup=None, resetids=False, setsigmask=(),\n"
|
||||
" setsigdef=(), scheduler=None)\n"
|
||||
" setpgroup=None, resetids=False, setsid=False,\n"
|
||||
" setsigmask=(), setsigdef=(), scheduler=None)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Execute the program specified by path in a new process.\n"
|
||||
|
@ -1743,7 +1743,9 @@ PyDoc_STRVAR(os_posix_spawn__doc__,
|
|||
" setpgroup\n"
|
||||
" The pgroup to use with the POSIX_SPAWN_SETPGROUP flag.\n"
|
||||
" resetids\n"
|
||||
" If the value is `True` the POSIX_SPAWN_RESETIDS will be activated.\n"
|
||||
" If the value is `true` the POSIX_SPAWN_RESETIDS will be activated.\n"
|
||||
" setsid\n"
|
||||
" If the value is `true` the POSIX_SPAWN_SETSID or POSIX_SPAWN_SETSID_NP will be activated.\n"
|
||||
" setsigmask\n"
|
||||
" The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag.\n"
|
||||
" setsigdef\n"
|
||||
|
@ -1757,30 +1759,32 @@ PyDoc_STRVAR(os_posix_spawn__doc__,
|
|||
static PyObject *
|
||||
os_posix_spawn_impl(PyObject *module, path_t *path, PyObject *argv,
|
||||
PyObject *env, PyObject *file_actions,
|
||||
PyObject *setpgroup, int resetids, PyObject *setsigmask,
|
||||
PyObject *setsigdef, PyObject *scheduler);
|
||||
PyObject *setpgroup, int resetids, int setsid,
|
||||
PyObject *setsigmask, PyObject *setsigdef,
|
||||
PyObject *scheduler);
|
||||
|
||||
static PyObject *
|
||||
os_posix_spawn(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
static const char * const _keywords[] = {"", "", "", "file_actions", "setpgroup", "resetids", "setsigmask", "setsigdef", "scheduler", NULL};
|
||||
static _PyArg_Parser _parser = {"O&OO|$OOiOOO:posix_spawn", _keywords, 0};
|
||||
static const char * const _keywords[] = {"", "", "", "file_actions", "setpgroup", "resetids", "setsid", "setsigmask", "setsigdef", "scheduler", NULL};
|
||||
static _PyArg_Parser _parser = {"O&OO|$OOiiOOO:posix_spawn", _keywords, 0};
|
||||
path_t path = PATH_T_INITIALIZE("posix_spawn", "path", 0, 0);
|
||||
PyObject *argv;
|
||||
PyObject *env;
|
||||
PyObject *file_actions = NULL;
|
||||
PyObject *setpgroup = NULL;
|
||||
int resetids = 0;
|
||||
int setsid = 0;
|
||||
PyObject *setsigmask = NULL;
|
||||
PyObject *setsigdef = NULL;
|
||||
PyObject *scheduler = NULL;
|
||||
|
||||
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
|
||||
path_converter, &path, &argv, &env, &file_actions, &setpgroup, &resetids, &setsigmask, &setsigdef, &scheduler)) {
|
||||
path_converter, &path, &argv, &env, &file_actions, &setpgroup, &resetids, &setsid, &setsigmask, &setsigdef, &scheduler)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = os_posix_spawn_impl(module, &path, argv, env, file_actions, setpgroup, resetids, setsigmask, setsigdef, scheduler);
|
||||
return_value = os_posix_spawn_impl(module, &path, argv, env, file_actions, setpgroup, resetids, setsid, setsigmask, setsigdef, scheduler);
|
||||
|
||||
exit:
|
||||
/* Cleanup for path */
|
||||
|
@ -1795,8 +1799,8 @@ exit:
|
|||
|
||||
PyDoc_STRVAR(os_posix_spawnp__doc__,
|
||||
"posix_spawnp($module, path, argv, env, /, *, file_actions=(),\n"
|
||||
" setpgroup=None, resetids=False, setsigmask=(),\n"
|
||||
" setsigdef=(), scheduler=None)\n"
|
||||
" setpgroup=None, resetids=False, setsid=False,\n"
|
||||
" setsigmask=(), setsigdef=(), scheduler=None)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Execute the program specified by path in a new process.\n"
|
||||
|
@ -1813,6 +1817,8 @@ PyDoc_STRVAR(os_posix_spawnp__doc__,
|
|||
" The pgroup to use with the POSIX_SPAWN_SETPGROUP flag.\n"
|
||||
" resetids\n"
|
||||
" If the value is `True` the POSIX_SPAWN_RESETIDS will be activated.\n"
|
||||
" setsid\n"
|
||||
" If the value is `True` the POSIX_SPAWN_SETSID or POSIX_SPAWN_SETSID_NP will be activated.\n"
|
||||
" setsigmask\n"
|
||||
" The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag.\n"
|
||||
" setsigdef\n"
|
||||
|
@ -1826,30 +1832,32 @@ PyDoc_STRVAR(os_posix_spawnp__doc__,
|
|||
static PyObject *
|
||||
os_posix_spawnp_impl(PyObject *module, path_t *path, PyObject *argv,
|
||||
PyObject *env, PyObject *file_actions,
|
||||
PyObject *setpgroup, int resetids, PyObject *setsigmask,
|
||||
PyObject *setsigdef, PyObject *scheduler);
|
||||
PyObject *setpgroup, int resetids, int setsid,
|
||||
PyObject *setsigmask, PyObject *setsigdef,
|
||||
PyObject *scheduler);
|
||||
|
||||
static PyObject *
|
||||
os_posix_spawnp(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
static const char * const _keywords[] = {"", "", "", "file_actions", "setpgroup", "resetids", "setsigmask", "setsigdef", "scheduler", NULL};
|
||||
static _PyArg_Parser _parser = {"O&OO|$OOiOOO:posix_spawnp", _keywords, 0};
|
||||
static const char * const _keywords[] = {"", "", "", "file_actions", "setpgroup", "resetids", "setsid", "setsigmask", "setsigdef", "scheduler", NULL};
|
||||
static _PyArg_Parser _parser = {"O&OO|$OOiiOOO:posix_spawnp", _keywords, 0};
|
||||
path_t path = PATH_T_INITIALIZE("posix_spawnp", "path", 0, 0);
|
||||
PyObject *argv;
|
||||
PyObject *env;
|
||||
PyObject *file_actions = NULL;
|
||||
PyObject *setpgroup = NULL;
|
||||
int resetids = 0;
|
||||
int setsid = 0;
|
||||
PyObject *setsigmask = NULL;
|
||||
PyObject *setsigdef = NULL;
|
||||
PyObject *scheduler = NULL;
|
||||
|
||||
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
|
||||
path_converter, &path, &argv, &env, &file_actions, &setpgroup, &resetids, &setsigmask, &setsigdef, &scheduler)) {
|
||||
path_converter, &path, &argv, &env, &file_actions, &setpgroup, &resetids, &setsid, &setsigmask, &setsigdef, &scheduler)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = os_posix_spawnp_impl(module, &path, argv, env, file_actions, setpgroup, resetids, setsigmask, setsigdef, scheduler);
|
||||
return_value = os_posix_spawnp_impl(module, &path, argv, env, file_actions, setpgroup, resetids, setsid, setsigmask, setsigdef, scheduler);
|
||||
|
||||
exit:
|
||||
/* Cleanup for path */
|
||||
|
@ -7331,4 +7339,4 @@ exit:
|
|||
#ifndef OS_GETRANDOM_METHODDEF
|
||||
#define OS_GETRANDOM_METHODDEF
|
||||
#endif /* !defined(OS_GETRANDOM_METHODDEF) */
|
||||
/*[clinic end generated code: output=dabd0fa27bf87044 input=a9049054013a1b77]*/
|
||||
/*[clinic end generated code: output=d50ff73e5b5198b9 input=a9049054013a1b77]*/
|
||||
|
|
|
@ -5166,10 +5166,11 @@ convert_sched_param(PyObject *param, struct sched_param *res);
|
|||
#endif
|
||||
|
||||
static int
|
||||
parse_posix_spawn_flags(PyObject *setpgroup, int resetids, PyObject *setsigmask,
|
||||
parse_posix_spawn_flags(PyObject *setpgroup, int resetids, int setsid, PyObject *setsigmask,
|
||||
PyObject *setsigdef, PyObject *scheduler,
|
||||
posix_spawnattr_t *attrp)
|
||||
{
|
||||
const char *func_name = "posix_spawnp";
|
||||
long all_flags = 0;
|
||||
|
||||
errno = posix_spawnattr_init(attrp);
|
||||
|
@ -5195,6 +5196,17 @@ parse_posix_spawn_flags(PyObject *setpgroup, int resetids, PyObject *setsigmask,
|
|||
all_flags |= POSIX_SPAWN_RESETIDS;
|
||||
}
|
||||
|
||||
if (setsid) {
|
||||
#ifdef POSIX_SPAWN_SETSID
|
||||
all_flags |= POSIX_SPAWN_SETSID;
|
||||
#elif defined(POSIX_SPAWN_SETSID_NP)
|
||||
all_flags |= POSIX_SPAWN_SETSID_NP;
|
||||
#else
|
||||
argument_unavailable_error(func_name, "setsid");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (setsigmask) {
|
||||
sigset_t set;
|
||||
if (!_Py_Sigset_Converter(setsigmask, &set)) {
|
||||
|
@ -5385,7 +5397,7 @@ fail:
|
|||
static PyObject *
|
||||
py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *argv,
|
||||
PyObject *env, PyObject *file_actions,
|
||||
PyObject *setpgroup, int resetids, PyObject *setsigmask,
|
||||
PyObject *setpgroup, int resetids, int setsid, PyObject *setsigmask,
|
||||
PyObject *setsigdef, PyObject *scheduler)
|
||||
{
|
||||
EXECV_CHAR **argvlist = NULL;
|
||||
|
@ -5400,7 +5412,7 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a
|
|||
pid_t pid;
|
||||
int err_code;
|
||||
|
||||
/* posix_spawn has three arguments: (path, argv, env), where
|
||||
/* posix_spawn and posix_spawnp have three arguments: (path, argv, env), where
|
||||
argv is a list or tuple of strings and env is a dictionary
|
||||
like posix.environ. */
|
||||
|
||||
|
@ -5455,7 +5467,7 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a
|
|||
file_actionsp = &file_actions_buf;
|
||||
}
|
||||
|
||||
if (parse_posix_spawn_flags(setpgroup, resetids, setsigmask,
|
||||
if (parse_posix_spawn_flags(setpgroup, resetids, setsid, setsigmask,
|
||||
setsigdef, scheduler, &attr)) {
|
||||
goto exit;
|
||||
}
|
||||
|
@ -5519,7 +5531,9 @@ os.posix_spawn
|
|||
setpgroup: object = NULL
|
||||
The pgroup to use with the POSIX_SPAWN_SETPGROUP flag.
|
||||
resetids: bool(accept={int}) = False
|
||||
If the value is `True` the POSIX_SPAWN_RESETIDS will be activated.
|
||||
If the value is `true` the POSIX_SPAWN_RESETIDS will be activated.
|
||||
setsid: bool(accept={int}) = False
|
||||
If the value is `true` the POSIX_SPAWN_SETSID or POSIX_SPAWN_SETSID_NP will be activated.
|
||||
setsigmask: object(c_default='NULL') = ()
|
||||
The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag.
|
||||
setsigdef: object(c_default='NULL') = ()
|
||||
|
@ -5533,12 +5547,13 @@ Execute the program specified by path in a new process.
|
|||
static PyObject *
|
||||
os_posix_spawn_impl(PyObject *module, path_t *path, PyObject *argv,
|
||||
PyObject *env, PyObject *file_actions,
|
||||
PyObject *setpgroup, int resetids, PyObject *setsigmask,
|
||||
PyObject *setsigdef, PyObject *scheduler)
|
||||
/*[clinic end generated code: output=45dfa4c515d09f2c input=2891c2f1d457e39b]*/
|
||||
PyObject *setpgroup, int resetids, int setsid,
|
||||
PyObject *setsigmask, PyObject *setsigdef,
|
||||
PyObject *scheduler)
|
||||
/*[clinic end generated code: output=14a1098c566bc675 input=8c6305619a00ad04]*/
|
||||
{
|
||||
return py_posix_spawn(0, module, path, argv, env, file_actions,
|
||||
setpgroup, resetids, setsigmask, setsigdef,
|
||||
setpgroup, resetids, setsid, setsigmask, setsigdef,
|
||||
scheduler);
|
||||
}
|
||||
#endif /* HAVE_POSIX_SPAWN */
|
||||
|
@ -5563,6 +5578,8 @@ os.posix_spawnp
|
|||
The pgroup to use with the POSIX_SPAWN_SETPGROUP flag.
|
||||
resetids: bool(accept={int}) = False
|
||||
If the value is `True` the POSIX_SPAWN_RESETIDS will be activated.
|
||||
setsid: bool(accept={int}) = False
|
||||
If the value is `True` the POSIX_SPAWN_SETSID or POSIX_SPAWN_SETSID_NP will be activated.
|
||||
setsigmask: object(c_default='NULL') = ()
|
||||
The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag.
|
||||
setsigdef: object(c_default='NULL') = ()
|
||||
|
@ -5576,12 +5593,13 @@ Execute the program specified by path in a new process.
|
|||
static PyObject *
|
||||
os_posix_spawnp_impl(PyObject *module, path_t *path, PyObject *argv,
|
||||
PyObject *env, PyObject *file_actions,
|
||||
PyObject *setpgroup, int resetids, PyObject *setsigmask,
|
||||
PyObject *setsigdef, PyObject *scheduler)
|
||||
/*[clinic end generated code: output=7955dc0edc82b8c3 input=b7576eb25b1ed9eb]*/
|
||||
PyObject *setpgroup, int resetids, int setsid,
|
||||
PyObject *setsigmask, PyObject *setsigdef,
|
||||
PyObject *scheduler)
|
||||
/*[clinic end generated code: output=7b9aaefe3031238d input=c1911043a22028da]*/
|
||||
{
|
||||
return py_posix_spawn(1, module, path, argv, env, file_actions,
|
||||
setpgroup, resetids, setsigmask, setsigdef,
|
||||
setpgroup, resetids, setsid, setsigmask, setsigdef,
|
||||
scheduler);
|
||||
}
|
||||
#endif /* HAVE_POSIX_SPAWNP */
|
||||
|
|
Loading…
Reference in New Issue