diff --git a/Doc/library/os.rst b/Doc/library/os.rst index bc8d5a8abbf31a..46d42d394016c8 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -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. @@ -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. @@ -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 diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index d402d4fb088ca2..6e9c2b7667a13c 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -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: diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-09-13-11-14-38.bpo-34663.BtJz-5.rst b/Misc/NEWS.d/next/Core and Builtins/2018-09-13-11-14-38.bpo-34663.BtJz-5.rst new file mode 100644 index 00000000000000..d5ccb0b881c208 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2018-09-13-11-14-38.bpo-34663.BtJz-5.rst @@ -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. diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index c3849a93c0c240..e35ef159632a51 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -1732,7 +1732,7 @@ os_execve(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *k 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" +" setsigdef=(), scheduler=None, use_vfork=False)\n" "--\n" "\n" "Execute the program specified by path in a new process.\n" @@ -1754,7 +1754,9 @@ PyDoc_STRVAR(os_posix_spawn__doc__, " setsigdef\n" " The sigmask to use with the POSIX_SPAWN_SETSIGDEF flag.\n" " scheduler\n" -" A tuple with the scheduler policy (optional) and parameters."); +" A tuple with the scheduler policy (optional) and parameters.\n" +" use_vfork\n" +" If the value is true the POSIX_SPAWN_USEVFORK will be activated."); #define OS_POSIX_SPAWN_METHODDEF \ {"posix_spawn", (PyCFunction)os_posix_spawn, METH_FASTCALL|METH_KEYWORDS, os_posix_spawn__doc__}, @@ -1763,14 +1765,14 @@ 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 *setsigdef, PyObject *scheduler, int use_vfork); 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", "setsigmask", "setsigdef", "scheduler", "use_vfork", NULL}; + static _PyArg_Parser _parser = {"O&OO|$OOiOOOi:posix_spawn", _keywords, 0}; path_t path = PATH_T_INITIALIZE("posix_spawn", "path", 0, 0); PyObject *argv; PyObject *env; @@ -1780,12 +1782,13 @@ os_posix_spawn(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje PyObject *setsigmask = NULL; PyObject *setsigdef = NULL; PyObject *scheduler = NULL; + int use_vfork = 0; 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, &setsigmask, &setsigdef, &scheduler, &use_vfork)) { 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, setsigmask, setsigdef, scheduler, use_vfork); exit: /* Cleanup for path */ @@ -6648,4 +6651,4 @@ os_getrandom(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject #ifndef OS_GETRANDOM_METHODDEF #define OS_GETRANDOM_METHODDEF #endif /* !defined(OS_GETRANDOM_METHODDEF) */ -/*[clinic end generated code: output=758ee0434fb03d90 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=d4d3d9754ff072e7 input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 7c02351a466130..587279cbe23937 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -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; @@ -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, + "The POSIX_SPAWN_USEVFORK flag is unavailable on this platform"); + goto fail; +#endif + } + errno = posix_spawnattr_setflags(attrp, all_flags); if (errno) { posix_error(); @@ -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]*/ @@ -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; @@ -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;