Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 20 additions & 13 deletions Doc/library/os.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3396,7 +3396,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=(), \
setsigdef=(), scheduler=None)
setsigdef=(), scheduler=None, use_vfork=False)

Wraps the :c:func:`posix_spawn` C library API for use from Python.

Expand Down Expand Up @@ -3435,22 +3435,22 @@ written in Python, such as a mail server's external command delivery program.
:c:func:`posix_spawn_file_actions_adddup2` API calls used to prepare
for the :c:func:`posix_spawn` call itself.

The *setpgroup* argument will set the process group of the child to the value
specified. If the value specified is 0, the child's process group ID will be
made the same as its process ID. If the value of *setpgroup* is not set, the
child will inherit the parent's process group ID. This argument corresponds
to the C library :c:data:`POSIX_SPAWN_SETPGROUP` flag.
The *setpgroup* argument will set the process group of the child process to
the value specified. If the value specified is 0, the child's process group
ID will be made the same as its process ID. If the value of *setpgroup* is
not set, the child process will inherit the parent's process group ID. This
argument corresponds to the C library :c:data:`POSIX_SPAWN_SETPGROUP` flag.

If the *resetids* argument is ``True`` it will reset the effective UID and
GID of the child to the real UID and GID of the parent process. If the
argument is ``False``, then the child retains the effective UID and GID of
the parent. In either case, if the set-user-ID and set-group-ID permission
bits are enabled on the executable file, their effect will override the
setting of the effective UID and GID. This argument corresponds to the C
library :c:data:`POSIX_SPAWN_RESETIDS` flag.
GID of the child process to the real UID and GID of the parent process. If
the argument is ``False``, then the child process retains the effective UID
and GID of the parent. In either case, if the set-user-ID and set-group-ID
permission bits are enabled on the executable file, their effect will
override the setting of the effective UID and GID. This argument corresponds
to the C library :c:data:`POSIX_SPAWN_RESETIDS` flag.

The *setsigmask* argument will set the signal mask to the signal set
specified. If the parameter is not used, then the child inherits the
specified. If the parameter is not used, then the child process inherits the
parent's signal mask. This argument corresponds to the C library
:c:data:`POSIX_SPAWN_SETSIGMASK` flag.

Expand All @@ -3465,6 +3465,13 @@ written in Python, such as a mail server's external command delivery program.
:c:data:`POSIX_SPAWN_SETSCHEDPARAM` and :c:data:`POSIX_SPAWN_SETSCHEDULER`
flags.

If the value of *use_vfork* is true, the child process will be created using
:c:func:`vfork` instead of :c:func:`fork`. This corresponds to the GNU
specific flag :c:data:`POSIX_SPAWN_USEVFORK`. If the flag is not available on
the platform, :exc:`NotImplementedError` will be raised.

Availability: Unix. Using *use_vfork* is only available on Linux.

.. versionadded:: 3.7


Expand Down
14 changes: 14 additions & 0 deletions Lib/test/test_posix.py
Original file line number Diff line number Diff line change
Expand Up @@ -1790,6 +1790,20 @@ def test_dup2(self):
with open(dupfile) as f:
self.assertEqual(f.read(), 'hello')

def test_use_vfork(self):
args = self.python_args('-c', 'pass')
try:
pid = posix.posix_spawn(
args[0],
args,
os.environ,
use_vfork=True
)
except NotImplementedError as exc:
raise self.skipTest(str(exc))
else:
self.assertEqual(os.waitpid(pid, 0), (pid, 0))


def test_main():
try:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Added support for `use_vfork` parameter of :func:`os.posix_spawn`, which
allows to use ``POSIX_SPAWN_USEVFORK`` constant when the flag is available
in the system.
19 changes: 11 additions & 8 deletions Modules/clinic/posixmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 16 additions & 4 deletions Modules/posixmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -5188,7 +5188,7 @@ convert_sched_param(PyObject *param, struct sched_param *res);

static int
parse_posix_spawn_flags(PyObject *setpgroup, int resetids, PyObject *setsigmask,
PyObject *setsigdef, PyObject *scheduler,
PyObject *setsigdef, PyObject *scheduler, int use_vfork,
posix_spawnattr_t *attrp)
{
long all_flags = 0;
Expand Down Expand Up @@ -5278,6 +5278,16 @@ parse_posix_spawn_flags(PyObject *setpgroup, int resetids, PyObject *setsigmask,
#endif
}

if (use_vfork) {
#ifdef POSIX_SPAWN_USEVFORK
all_flags |= POSIX_SPAWN_SETSCHEDULER;
#else
PyErr_SetString(PyExc_NotImplementedError,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use argument_unavailable_error() here.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I discussed with Pablo and using "posix_spawn()" function name is less useless than mentioning the "POSIX_SPAWN_USEVFORK flag".

"The POSIX_SPAWN_USEVFORK flag is unavailable on this platform");
goto fail;
#endif
}

errno = posix_spawnattr_setflags(attrp, all_flags);
if (errno) {
posix_error();
Expand Down Expand Up @@ -5425,6 +5435,8 @@ os.posix_spawn
The sigmask to use with the POSIX_SPAWN_SETSIGDEF flag.
scheduler: object = NULL
A tuple with the scheduler policy (optional) and parameters.
use_vfork: bool(accept={int}) = False
If the value is true the POSIX_SPAWN_USEVFORK will be activated.

Execute the program specified by path in a new process.
[clinic start generated code]*/
Expand All @@ -5433,8 +5445,8 @@ 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 *setsigdef, PyObject *scheduler, int use_vfork)
/*[clinic end generated code: output=ed9323af139a50f7 input=9ca9c905ec19bf04]*/
{
EXECV_CHAR **argvlist = NULL;
EXECV_CHAR **envlist = NULL;
Expand Down Expand Up @@ -5504,7 +5516,7 @@ os_posix_spawn_impl(PyObject *module, path_t *path, PyObject *argv,
}

if (parse_posix_spawn_flags(setpgroup, resetids, setsigmask,
setsigdef, scheduler, &attr)) {
setsigdef, scheduler, use_vfork, &attr)) {
goto exit;
}
attrp = &attr;
Expand Down