Skip to content

Commit 80c5dfe

Browse files
nanjekyejoannahvstinner
authored andcommitted
bpo-35537: Add setsid parameter to os.posix_spawn() and os.posix_spawnp() (GH-11608)
1 parent 05f1b93 commit 80c5dfe

File tree

5 files changed

+84
-33
lines changed

5 files changed

+84
-33
lines changed

Doc/library/os.rst

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3386,7 +3386,7 @@ written in Python, such as a mail server's external command delivery program.
33863386

33873387

33883388
.. function:: posix_spawn(path, argv, env, *, file_actions=None, \
3389-
setpgroup=None, resetids=False, setsigmask=(), \
3389+
setpgroup=None, resetids=False, setsid=False, setsigmask=(), \
33903390
setsigdef=(), scheduler=None)
33913391

33923392
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.
34443444
setting of the effective UID and GID. This argument corresponds to the C
34453445
library :c:data:`POSIX_SPAWN_RESETIDS` flag.
34463446

3447+
If the *setsid* argument is ``True``, it will create a new session ID
3448+
for `posix_spawn`. *setsid* requires :c:data:`POSIX_SPAWN_SETSID`
3449+
or :c:data:`POSIX_SPAWN_SETSID_NP` flag. Otherwise, :exc:`NotImplementedError`
3450+
is raised.
3451+
34473452
The *setsigmask* argument will set the signal mask to the signal set
34483453
specified. If the parameter is not used, then the child inherits the
34493454
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.
34623467

34633468
.. versionadded:: 3.7
34643469

3470+
.. availability:: Unix.
34653471

34663472
.. function:: posix_spawnp(path, argv, env, *, file_actions=None, \
3467-
setpgroup=None, resetids=False, setsigmask=(), \
3473+
setpgroup=None, resetids=False, setsid=False, setsigmask=(), \
34683474
setsigdef=(), scheduler=None)
34693475

34703476
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.
34753481

34763482
.. versionadded:: 3.8
34773483

3484+
.. availability:: See :func:`posix_spawn` documentation.
3485+
34783486

34793487
.. function:: register_at_fork(*, before=None, after_in_parent=None, \
34803488
after_in_child=None)

Lib/test/test_posix.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1624,6 +1624,22 @@ def test_setsigmask_wrong_type(self):
16241624
os.environ, setsigmask=[signal.NSIG,
16251625
signal.NSIG+1])
16261626

1627+
def test_start_new_session(self):
1628+
# For code coverage of calling setsid(). We don't care if we get an
1629+
# EPERM error from it depending on the test execution environment, that
1630+
# still indicates that it was called.
1631+
code = "import os; print(os.getpgid(os.getpid()))"
1632+
try:
1633+
self.spawn_func(sys.executable,
1634+
[sys.executable, "-c", code],
1635+
os.environ, setsid=True)
1636+
except NotImplementedError as exc:
1637+
self.skipTest("setsid is not supported: %s" % exc)
1638+
else:
1639+
parent_pgid = os.getpgid(os.getpid())
1640+
child_pgid = int(output)
1641+
self.assertNotEqual(parent_pgid, child_pgid)
1642+
16271643
@unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
16281644
'need signal.pthread_sigmask()')
16291645
def test_setsigdef(self):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
:func:`os.posix_spawn` and :func:`os.posix_spawnp` now have a *setsid* parameter.

Modules/clinic/posixmodule.c.h

Lines changed: 26 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/posixmodule.c

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5166,10 +5166,11 @@ convert_sched_param(PyObject *param, struct sched_param *res);
51665166
#endif
51675167

51685168
static int
5169-
parse_posix_spawn_flags(PyObject *setpgroup, int resetids, PyObject *setsigmask,
5169+
parse_posix_spawn_flags(PyObject *setpgroup, int resetids, int setsid, PyObject *setsigmask,
51705170
PyObject *setsigdef, PyObject *scheduler,
51715171
posix_spawnattr_t *attrp)
51725172
{
5173+
const char *func_name = "posix_spawnp";
51735174
long all_flags = 0;
51745175

51755176
errno = posix_spawnattr_init(attrp);
@@ -5195,6 +5196,17 @@ parse_posix_spawn_flags(PyObject *setpgroup, int resetids, PyObject *setsigmask,
51955196
all_flags |= POSIX_SPAWN_RESETIDS;
51965197
}
51975198

5199+
if (setsid) {
5200+
#ifdef POSIX_SPAWN_SETSID
5201+
all_flags |= POSIX_SPAWN_SETSID;
5202+
#elif defined(POSIX_SPAWN_SETSID_NP)
5203+
all_flags |= POSIX_SPAWN_SETSID_NP;
5204+
#else
5205+
argument_unavailable_error(func_name, "setsid");
5206+
return -1;
5207+
#endif
5208+
}
5209+
51985210
if (setsigmask) {
51995211
sigset_t set;
52005212
if (!_Py_Sigset_Converter(setsigmask, &set)) {
@@ -5385,7 +5397,7 @@ parse_file_actions(PyObject *file_actions,
53855397
static PyObject *
53865398
py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *argv,
53875399
PyObject *env, PyObject *file_actions,
5388-
PyObject *setpgroup, int resetids, PyObject *setsigmask,
5400+
PyObject *setpgroup, int resetids, int setsid, PyObject *setsigmask,
53895401
PyObject *setsigdef, PyObject *scheduler)
53905402
{
53915403
EXECV_CHAR **argvlist = NULL;
@@ -5400,7 +5412,7 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a
54005412
pid_t pid;
54015413
int err_code;
54025414

5403-
/* posix_spawn has three arguments: (path, argv, env), where
5415+
/* posix_spawn and posix_spawnp have three arguments: (path, argv, env), where
54045416
argv is a list or tuple of strings and env is a dictionary
54055417
like posix.environ. */
54065418

@@ -5455,7 +5467,7 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a
54555467
file_actionsp = &file_actions_buf;
54565468
}
54575469

5458-
if (parse_posix_spawn_flags(setpgroup, resetids, setsigmask,
5470+
if (parse_posix_spawn_flags(setpgroup, resetids, setsid, setsigmask,
54595471
setsigdef, scheduler, &attr)) {
54605472
goto exit;
54615473
}
@@ -5519,7 +5531,9 @@ os.posix_spawn
55195531
setpgroup: object = NULL
55205532
The pgroup to use with the POSIX_SPAWN_SETPGROUP flag.
55215533
resetids: bool(accept={int}) = False
5522-
If the value is `True` the POSIX_SPAWN_RESETIDS will be activated.
5534+
If the value is `true` the POSIX_SPAWN_RESETIDS will be activated.
5535+
setsid: bool(accept={int}) = False
5536+
If the value is `true` the POSIX_SPAWN_SETSID or POSIX_SPAWN_SETSID_NP will be activated.
55235537
setsigmask: object(c_default='NULL') = ()
55245538
The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag.
55255539
setsigdef: object(c_default='NULL') = ()
@@ -5533,12 +5547,13 @@ Execute the program specified by path in a new process.
55335547
static PyObject *
55345548
os_posix_spawn_impl(PyObject *module, path_t *path, PyObject *argv,
55355549
PyObject *env, PyObject *file_actions,
5536-
PyObject *setpgroup, int resetids, PyObject *setsigmask,
5537-
PyObject *setsigdef, PyObject *scheduler)
5538-
/*[clinic end generated code: output=45dfa4c515d09f2c input=2891c2f1d457e39b]*/
5550+
PyObject *setpgroup, int resetids, int setsid,
5551+
PyObject *setsigmask, PyObject *setsigdef,
5552+
PyObject *scheduler)
5553+
/*[clinic end generated code: output=14a1098c566bc675 input=8c6305619a00ad04]*/
55395554
{
55405555
return py_posix_spawn(0, module, path, argv, env, file_actions,
5541-
setpgroup, resetids, setsigmask, setsigdef,
5556+
setpgroup, resetids, setsid, setsigmask, setsigdef,
55425557
scheduler);
55435558
}
55445559
#endif /* HAVE_POSIX_SPAWN */
@@ -5563,6 +5578,8 @@ os.posix_spawnp
55635578
The pgroup to use with the POSIX_SPAWN_SETPGROUP flag.
55645579
resetids: bool(accept={int}) = False
55655580
If the value is `True` the POSIX_SPAWN_RESETIDS will be activated.
5581+
setsid: bool(accept={int}) = False
5582+
If the value is `True` the POSIX_SPAWN_SETSID or POSIX_SPAWN_SETSID_NP will be activated.
55665583
setsigmask: object(c_default='NULL') = ()
55675584
The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag.
55685585
setsigdef: object(c_default='NULL') = ()
@@ -5576,12 +5593,13 @@ Execute the program specified by path in a new process.
55765593
static PyObject *
55775594
os_posix_spawnp_impl(PyObject *module, path_t *path, PyObject *argv,
55785595
PyObject *env, PyObject *file_actions,
5579-
PyObject *setpgroup, int resetids, PyObject *setsigmask,
5580-
PyObject *setsigdef, PyObject *scheduler)
5581-
/*[clinic end generated code: output=7955dc0edc82b8c3 input=b7576eb25b1ed9eb]*/
5596+
PyObject *setpgroup, int resetids, int setsid,
5597+
PyObject *setsigmask, PyObject *setsigdef,
5598+
PyObject *scheduler)
5599+
/*[clinic end generated code: output=7b9aaefe3031238d input=c1911043a22028da]*/
55825600
{
55835601
return py_posix_spawn(1, module, path, argv, env, file_actions,
5584-
setpgroup, resetids, setsigmask, setsigdef,
5602+
setpgroup, resetids, setsid, setsigmask, setsigdef,
55855603
scheduler);
55865604
}
55875605
#endif /* HAVE_POSIX_SPAWNP */

0 commit comments

Comments
 (0)