bpo-35674: Add os.posix_spawnp() (GH-11554)

Add a new os.posix_spawnp() function.
This commit is contained in:
Joannah Nanjekye 2019-01-16 16:29:26 +03:00 committed by Victor Stinner
parent 9daecf37a5
commit 92b8322e7e
9 changed files with 322 additions and 112 deletions

View File

@ -3396,6 +3396,10 @@ written in Python, such as a mail server's external command delivery program.
The positional-only arguments *path*, *args*, and *env* are similar to The positional-only arguments *path*, *args*, and *env* are similar to
:func:`execve`. :func:`execve`.
The *path* parameter is the path to the executable file.The *path* should
contain a directory.Use :func:`posix_spawnp` to pass an executable file
without directory.
The *file_actions* argument may be a sequence of tuples describing actions The *file_actions* argument may be a sequence of tuples describing actions
to take on specific file descriptors in the child process between the C to take on specific file descriptors in the child process between the C
library implementation's :c:func:`fork` and :c:func:`exec` steps. library implementation's :c:func:`fork` and :c:func:`exec` steps.
@ -3459,6 +3463,19 @@ written in Python, such as a mail server's external command delivery program.
.. versionadded:: 3.7 .. versionadded:: 3.7
.. function:: posix_spawnp(path, argv, env, *, file_actions=None, \
setpgroup=None, resetids=False, setsigmask=(), \
setsigdef=(), scheduler=None)
Wraps the :c:func:`posix_spawnp` C library API for use from Python.
Similar to :func:`posix_spawn` except that the system searches
for the *executable* file in the list of directories specified by the
:envvar:`PATH` environment variable (in the same way as for ``execvp(3)``).
.. versionadded:: 3.8
.. function:: register_at_fork(*, before=None, after_in_parent=None, \ .. function:: register_at_fork(*, before=None, after_in_parent=None, \
after_in_child=None) after_in_child=None)

View File

@ -1489,10 +1489,10 @@ class PosixGroupsTester(unittest.TestCase):
self.assertListEqual(groups, posix.getgroups()) self.assertListEqual(groups, posix.getgroups())
@unittest.skipUnless(hasattr(os, 'posix_spawn'), "test needs os.posix_spawn") class _PosixSpawnMixin:
class TestPosixSpawn(unittest.TestCase): # Program which does nothing and exits with status 0 (success)
# Program which does nothing and exit with status 0 (success)
NOOP_PROGRAM = (sys.executable, '-I', '-S', '-c', 'pass') NOOP_PROGRAM = (sys.executable, '-I', '-S', '-c', 'pass')
spawn_func = None
def python_args(self, *args): def python_args(self, *args):
# Disable site module to avoid side effects. For example, # Disable site module to avoid side effects. For example,
@ -1511,7 +1511,7 @@ class TestPosixSpawn(unittest.TestCase):
pidfile.write(str(os.getpid())) pidfile.write(str(os.getpid()))
""" """
args = self.python_args('-c', script) args = self.python_args('-c', script)
pid = posix.posix_spawn(args[0], args, os.environ) pid = self.spawn_func(args[0], args, os.environ)
self.assertEqual(os.waitpid(pid, 0), (pid, 0)) self.assertEqual(os.waitpid(pid, 0), (pid, 0))
with open(pidfile) as f: with open(pidfile) as f:
self.assertEqual(f.read(), str(pid)) self.assertEqual(f.read(), str(pid))
@ -1519,9 +1519,9 @@ class TestPosixSpawn(unittest.TestCase):
def test_no_such_executable(self): def test_no_such_executable(self):
no_such_executable = 'no_such_executable' no_such_executable = 'no_such_executable'
try: try:
pid = posix.posix_spawn(no_such_executable, pid = self.spawn_func(no_such_executable,
[no_such_executable], [no_such_executable],
os.environ) os.environ)
except FileNotFoundError as exc: except FileNotFoundError as exc:
self.assertEqual(exc.filename, no_such_executable) self.assertEqual(exc.filename, no_such_executable)
else: else:
@ -1538,14 +1538,14 @@ class TestPosixSpawn(unittest.TestCase):
envfile.write(os.environ['foo']) envfile.write(os.environ['foo'])
""" """
args = self.python_args('-c', script) args = self.python_args('-c', script)
pid = posix.posix_spawn(args[0], args, pid = self.spawn_func(args[0], args,
{**os.environ, 'foo': 'bar'}) {**os.environ, 'foo': 'bar'})
self.assertEqual(os.waitpid(pid, 0), (pid, 0)) self.assertEqual(os.waitpid(pid, 0), (pid, 0))
with open(envfile) as f: with open(envfile) as f:
self.assertEqual(f.read(), 'bar') self.assertEqual(f.read(), 'bar')
def test_empty_file_actions(self): def test_empty_file_actions(self):
pid = posix.posix_spawn( pid = self.spawn_func(
self.NOOP_PROGRAM[0], self.NOOP_PROGRAM[0],
self.NOOP_PROGRAM, self.NOOP_PROGRAM,
os.environ, os.environ,
@ -1554,7 +1554,7 @@ class TestPosixSpawn(unittest.TestCase):
self.assertEqual(os.waitpid(pid, 0), (pid, 0)) self.assertEqual(os.waitpid(pid, 0), (pid, 0))
def test_resetids_explicit_default(self): def test_resetids_explicit_default(self):
pid = posix.posix_spawn( pid = self.spawn_func(
sys.executable, sys.executable,
[sys.executable, '-c', 'pass'], [sys.executable, '-c', 'pass'],
os.environ, os.environ,
@ -1563,7 +1563,7 @@ class TestPosixSpawn(unittest.TestCase):
self.assertEqual(os.waitpid(pid, 0), (pid, 0)) self.assertEqual(os.waitpid(pid, 0), (pid, 0))
def test_resetids(self): def test_resetids(self):
pid = posix.posix_spawn( pid = self.spawn_func(
sys.executable, sys.executable,
[sys.executable, '-c', 'pass'], [sys.executable, '-c', 'pass'],
os.environ, os.environ,
@ -1573,12 +1573,12 @@ class TestPosixSpawn(unittest.TestCase):
def test_resetids_wrong_type(self): def test_resetids_wrong_type(self):
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
posix.posix_spawn(sys.executable, self.spawn_func(sys.executable,
[sys.executable, "-c", "pass"], [sys.executable, "-c", "pass"],
os.environ, resetids=None) os.environ, resetids=None)
def test_setpgroup(self): def test_setpgroup(self):
pid = posix.posix_spawn( pid = self.spawn_func(
sys.executable, sys.executable,
[sys.executable, '-c', 'pass'], [sys.executable, '-c', 'pass'],
os.environ, os.environ,
@ -1588,9 +1588,9 @@ class TestPosixSpawn(unittest.TestCase):
def test_setpgroup_wrong_type(self): def test_setpgroup_wrong_type(self):
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
posix.posix_spawn(sys.executable, self.spawn_func(sys.executable,
[sys.executable, "-c", "pass"], [sys.executable, "-c", "pass"],
os.environ, setpgroup="023") os.environ, setpgroup="023")
@unittest.skipUnless(hasattr(signal, 'pthread_sigmask'), @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
'need signal.pthread_sigmask()') 'need signal.pthread_sigmask()')
@ -1599,7 +1599,7 @@ class TestPosixSpawn(unittest.TestCase):
import signal import signal
signal.raise_signal(signal.SIGUSR1)""") signal.raise_signal(signal.SIGUSR1)""")
pid = posix.posix_spawn( pid = self.spawn_func(
sys.executable, sys.executable,
[sys.executable, '-c', code], [sys.executable, '-c', code],
os.environ, os.environ,
@ -1609,18 +1609,18 @@ class TestPosixSpawn(unittest.TestCase):
def test_setsigmask_wrong_type(self): def test_setsigmask_wrong_type(self):
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
posix.posix_spawn(sys.executable, self.spawn_func(sys.executable,
[sys.executable, "-c", "pass"], [sys.executable, "-c", "pass"],
os.environ, setsigmask=34) os.environ, setsigmask=34)
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
posix.posix_spawn(sys.executable, self.spawn_func(sys.executable,
[sys.executable, "-c", "pass"], [sys.executable, "-c", "pass"],
os.environ, setsigmask=["j"]) os.environ, setsigmask=["j"])
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
posix.posix_spawn(sys.executable, self.spawn_func(sys.executable,
[sys.executable, "-c", "pass"], [sys.executable, "-c", "pass"],
os.environ, setsigmask=[signal.NSIG, os.environ, setsigmask=[signal.NSIG,
signal.NSIG+1]) signal.NSIG+1])
@unittest.skipUnless(hasattr(signal, 'pthread_sigmask'), @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
'need signal.pthread_sigmask()') 'need signal.pthread_sigmask()')
@ -1630,7 +1630,7 @@ class TestPosixSpawn(unittest.TestCase):
import signal import signal
signal.raise_signal(signal.SIGUSR1)""") signal.raise_signal(signal.SIGUSR1)""")
try: try:
pid = posix.posix_spawn( pid = self.spawn_func(
sys.executable, sys.executable,
[sys.executable, '-c', code], [sys.executable, '-c', code],
os.environ, os.environ,
@ -1646,17 +1646,17 @@ class TestPosixSpawn(unittest.TestCase):
def test_setsigdef_wrong_type(self): def test_setsigdef_wrong_type(self):
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
posix.posix_spawn(sys.executable, self.spawn_func(sys.executable,
[sys.executable, "-c", "pass"], [sys.executable, "-c", "pass"],
os.environ, setsigdef=34) os.environ, setsigdef=34)
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
posix.posix_spawn(sys.executable, self.spawn_func(sys.executable,
[sys.executable, "-c", "pass"], [sys.executable, "-c", "pass"],
os.environ, setsigdef=["j"]) os.environ, setsigdef=["j"])
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
posix.posix_spawn(sys.executable, self.spawn_func(sys.executable,
[sys.executable, "-c", "pass"], [sys.executable, "-c", "pass"],
os.environ, setsigdef=[signal.NSIG, signal.NSIG+1]) os.environ, setsigdef=[signal.NSIG, signal.NSIG+1])
@requires_sched @requires_sched
@unittest.skipIf(sys.platform.startswith(('freebsd', 'netbsd')), @unittest.skipIf(sys.platform.startswith(('freebsd', 'netbsd')),
@ -1670,7 +1670,7 @@ class TestPosixSpawn(unittest.TestCase):
sys.exit(101) sys.exit(101)
if os.sched_getparam(0).sched_priority != {priority}: if os.sched_getparam(0).sched_priority != {priority}:
sys.exit(102)""") sys.exit(102)""")
pid = posix.posix_spawn( pid = self.spawn_func(
sys.executable, sys.executable,
[sys.executable, '-c', code], [sys.executable, '-c', code],
os.environ, os.environ,
@ -1690,7 +1690,7 @@ class TestPosixSpawn(unittest.TestCase):
sys.exit(101) sys.exit(101)
if os.sched_getparam(0).sched_priority != {priority}: if os.sched_getparam(0).sched_priority != {priority}:
sys.exit(102)""") sys.exit(102)""")
pid = posix.posix_spawn( pid = self.spawn_func(
sys.executable, sys.executable,
[sys.executable, '-c', code], [sys.executable, '-c', code],
os.environ, os.environ,
@ -1704,40 +1704,40 @@ class TestPosixSpawn(unittest.TestCase):
(os.POSIX_SPAWN_CLOSE, 0), (os.POSIX_SPAWN_CLOSE, 0),
(os.POSIX_SPAWN_DUP2, 1, 4), (os.POSIX_SPAWN_DUP2, 1, 4),
] ]
pid = posix.posix_spawn(self.NOOP_PROGRAM[0], pid = self.spawn_func(self.NOOP_PROGRAM[0],
self.NOOP_PROGRAM, self.NOOP_PROGRAM,
os.environ, os.environ,
file_actions=file_actions) file_actions=file_actions)
self.assertEqual(os.waitpid(pid, 0), (pid, 0)) self.assertEqual(os.waitpid(pid, 0), (pid, 0))
def test_bad_file_actions(self): def test_bad_file_actions(self):
args = self.NOOP_PROGRAM args = self.NOOP_PROGRAM
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
posix.posix_spawn(args[0], args, os.environ, self.spawn_func(args[0], args, os.environ,
file_actions=[None]) file_actions=[None])
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
posix.posix_spawn(args[0], args, os.environ, self.spawn_func(args[0], args, os.environ,
file_actions=[()]) file_actions=[()])
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
posix.posix_spawn(args[0], args, os.environ, self.spawn_func(args[0], args, os.environ,
file_actions=[(None,)]) file_actions=[(None,)])
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
posix.posix_spawn(args[0], args, os.environ, self.spawn_func(args[0], args, os.environ,
file_actions=[(12345,)]) file_actions=[(12345,)])
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
posix.posix_spawn(args[0], args, os.environ, self.spawn_func(args[0], args, os.environ,
file_actions=[(os.POSIX_SPAWN_CLOSE,)]) file_actions=[(os.POSIX_SPAWN_CLOSE,)])
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
posix.posix_spawn(args[0], args, os.environ, self.spawn_func(args[0], args, os.environ,
file_actions=[(os.POSIX_SPAWN_CLOSE, 1, 2)]) file_actions=[(os.POSIX_SPAWN_CLOSE, 1, 2)])
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
posix.posix_spawn(args[0], args, os.environ, self.spawn_func(args[0], args, os.environ,
file_actions=[(os.POSIX_SPAWN_CLOSE, None)]) file_actions=[(os.POSIX_SPAWN_CLOSE, None)])
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
posix.posix_spawn(args[0], args, os.environ, self.spawn_func(args[0], args, os.environ,
file_actions=[(os.POSIX_SPAWN_OPEN, file_actions=[(os.POSIX_SPAWN_OPEN,
3, __file__ + '\0', 3, __file__ + '\0',
os.O_RDONLY, 0)]) os.O_RDONLY, 0)])
def test_open_file(self): def test_open_file(self):
outfile = support.TESTFN outfile = support.TESTFN
@ -1752,8 +1752,8 @@ class TestPosixSpawn(unittest.TestCase):
stat.S_IRUSR | stat.S_IWUSR), stat.S_IRUSR | stat.S_IWUSR),
] ]
args = self.python_args('-c', script) args = self.python_args('-c', script)
pid = posix.posix_spawn(args[0], args, os.environ, pid = self.spawn_func(args[0], args, os.environ,
file_actions=file_actions) file_actions=file_actions)
self.assertEqual(os.waitpid(pid, 0), (pid, 0)) self.assertEqual(os.waitpid(pid, 0), (pid, 0))
with open(outfile) as f: with open(outfile) as f:
self.assertEqual(f.read(), 'hello') self.assertEqual(f.read(), 'hello')
@ -1770,8 +1770,8 @@ class TestPosixSpawn(unittest.TestCase):
closefile.write('is closed %d' % e.errno) closefile.write('is closed %d' % e.errno)
""" """
args = self.python_args('-c', script) args = self.python_args('-c', script)
pid = posix.posix_spawn(args[0], args, os.environ, pid = self.spawn_func(args[0], args, os.environ,
file_actions=[(os.POSIX_SPAWN_CLOSE, 0),]) file_actions=[(os.POSIX_SPAWN_CLOSE, 0)])
self.assertEqual(os.waitpid(pid, 0), (pid, 0)) self.assertEqual(os.waitpid(pid, 0), (pid, 0))
with open(closefile) as f: with open(closefile) as f:
self.assertEqual(f.read(), 'is closed %d' % errno.EBADF) self.assertEqual(f.read(), 'is closed %d' % errno.EBADF)
@ -1788,16 +1788,64 @@ class TestPosixSpawn(unittest.TestCase):
(os.POSIX_SPAWN_DUP2, childfile.fileno(), 1), (os.POSIX_SPAWN_DUP2, childfile.fileno(), 1),
] ]
args = self.python_args('-c', script) args = self.python_args('-c', script)
pid = posix.posix_spawn(args[0], args, os.environ, pid = self.spawn_func(args[0], args, os.environ,
file_actions=file_actions) file_actions=file_actions)
self.assertEqual(os.waitpid(pid, 0), (pid, 0)) self.assertEqual(os.waitpid(pid, 0), (pid, 0))
with open(dupfile) as f: with open(dupfile) as f:
self.assertEqual(f.read(), 'hello') self.assertEqual(f.read(), 'hello')
@unittest.skipUnless(hasattr(os, 'posix_spawn'), "test needs os.posix_spawn")
class TestPosixSpawn(unittest.TestCase, _PosixSpawnMixin):
spawn_func = getattr(posix, 'posix_spawn', None)
@unittest.skipUnless(hasattr(os, 'posix_spawnp'), "test needs os.posix_spawnp")
class TestPosixSpawnP(unittest.TestCase, _PosixSpawnMixin):
spawn_func = getattr(posix, 'posix_spawnp', None)
@support.skip_unless_symlink
def test_posix_spawnp(self):
# Use a symlink to create a program in its own temporary directory
temp_dir = tempfile.mkdtemp()
self.addCleanup(support.rmtree, temp_dir)
program = 'posix_spawnp_test_program.exe'
program_fullpath = os.path.join(temp_dir, program)
os.symlink(sys.executable, program_fullpath)
try:
path = os.pathsep.join((temp_dir, os.environ['PATH']))
except KeyError:
path = temp_dir # PATH is not set
spawn_args = (program, '-I', '-S', '-c', 'pass')
code = textwrap.dedent("""
import os
args = %a
pid = os.posix_spawnp(args[0], args, os.environ)
pid2, status = os.waitpid(pid, 0)
if pid2 != pid:
raise Exception(f"pid {pid2} != {pid}")
if status != 0:
raise Exception(f"status {status} != 0")
""" % (spawn_args,))
# Use a subprocess to test os.posix_spawnp() with a modified PATH
# environment variable: posix_spawnp() uses the current environment
# to locate the program, not its environment argument.
args = ('-c', code)
assert_python_ok(*args, PATH=path)
def test_main(): def test_main():
try: try:
support.run_unittest(PosixTester, PosixGroupsTester, TestPosixSpawn) support.run_unittest(
PosixTester,
PosixGroupsTester,
TestPosixSpawn,
TestPosixSpawnP,
)
finally: finally:
support.reap_children() support.reap_children()

View File

@ -0,0 +1,2 @@
Add a new :func:`os.posix_spawnp` function.
Patch by Joannah Nanjekye.

View File

@ -1791,6 +1791,75 @@ exit:
#endif /* defined(HAVE_POSIX_SPAWN) */ #endif /* defined(HAVE_POSIX_SPAWN) */
#if defined(HAVE_POSIX_SPAWNP)
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"
"--\n"
"\n"
"Execute the program specified by path in a new process.\n"
"\n"
" path\n"
" Path of executable file.\n"
" argv\n"
" Tuple or list of strings.\n"
" env\n"
" Dictionary of strings mapping to strings.\n"
" file_actions\n"
" A sequence of file action tuples.\n"
" 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"
" setsigmask\n"
" The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag.\n"
" setsigdef\n"
" The sigmask to use with the POSIX_SPAWN_SETSIGDEF flag.\n"
" scheduler\n"
" A tuple with the scheduler policy (optional) and parameters.");
#define OS_POSIX_SPAWNP_METHODDEF \
{"posix_spawnp", (PyCFunction)(void(*)(void))os_posix_spawnp, METH_FASTCALL|METH_KEYWORDS, 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);
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};
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;
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)) {
goto exit;
}
return_value = os_posix_spawnp_impl(module, &path, argv, env, file_actions, setpgroup, resetids, setsigmask, setsigdef, scheduler);
exit:
/* Cleanup for path */
path_cleanup(&path);
return return_value;
}
#endif /* defined(HAVE_POSIX_SPAWNP) */
#if (defined(HAVE_SPAWNV) || defined(HAVE_WSPAWNV)) #if (defined(HAVE_SPAWNV) || defined(HAVE_WSPAWNV))
PyDoc_STRVAR(os_spawnv__doc__, PyDoc_STRVAR(os_spawnv__doc__,
@ -6851,6 +6920,10 @@ exit:
#define OS_POSIX_SPAWN_METHODDEF #define OS_POSIX_SPAWN_METHODDEF
#endif /* !defined(OS_POSIX_SPAWN_METHODDEF) */ #endif /* !defined(OS_POSIX_SPAWN_METHODDEF) */
#ifndef OS_POSIX_SPAWNP_METHODDEF
#define OS_POSIX_SPAWNP_METHODDEF
#endif /* !defined(OS_POSIX_SPAWNP_METHODDEF) */
#ifndef OS_SPAWNV_METHODDEF #ifndef OS_SPAWNV_METHODDEF
#define OS_SPAWNV_METHODDEF #define OS_SPAWNV_METHODDEF
#endif /* !defined(OS_SPAWNV_METHODDEF) */ #endif /* !defined(OS_SPAWNV_METHODDEF) */
@ -7258,4 +7331,4 @@ exit:
#ifndef OS_GETRANDOM_METHODDEF #ifndef OS_GETRANDOM_METHODDEF
#define OS_GETRANDOM_METHODDEF #define OS_GETRANDOM_METHODDEF
#endif /* !defined(OS_GETRANDOM_METHODDEF) */ #endif /* !defined(OS_GETRANDOM_METHODDEF) */
/*[clinic end generated code: output=febc1e16c9024e40 input=a9049054013a1b77]*/ /*[clinic end generated code: output=dabd0fa27bf87044 input=a9049054013a1b77]*/

View File

@ -5381,39 +5381,12 @@ fail:
return -1; return -1;
} }
/*[clinic input]
os.posix_spawn
path: path_t
Path of executable file.
argv: object
Tuple or list of strings.
env: object
Dictionary of strings mapping to strings.
/
*
file_actions: object(c_default='NULL') = ()
A sequence of file action tuples.
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.
setsigmask: object(c_default='NULL') = ()
The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag.
setsigdef: object(c_default='NULL') = ()
The sigmask to use with the POSIX_SPAWN_SETSIGDEF flag.
scheduler: object = NULL
A tuple with the scheduler policy (optional) and parameters.
Execute the program specified by path in a new process.
[clinic start generated code]*/
static PyObject * static PyObject *
os_posix_spawn_impl(PyObject *module, path_t *path, PyObject *argv, py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *argv,
PyObject *env, PyObject *file_actions, PyObject *env, PyObject *file_actions,
PyObject *setpgroup, int resetids, PyObject *setsigmask, PyObject *setpgroup, int resetids, PyObject *setsigmask,
PyObject *setsigdef, PyObject *scheduler) PyObject *setsigdef, PyObject *scheduler)
/*[clinic end generated code: output=45dfa4c515d09f2c input=2891c2f1d457e39b]*/
{ {
EXECV_CHAR **argvlist = NULL; EXECV_CHAR **argvlist = NULL;
EXECV_CHAR **envlist = NULL; EXECV_CHAR **envlist = NULL;
@ -5489,9 +5462,19 @@ os_posix_spawn_impl(PyObject *module, path_t *path, PyObject *argv,
attrp = &attr; attrp = &attr;
_Py_BEGIN_SUPPRESS_IPH _Py_BEGIN_SUPPRESS_IPH
err_code = posix_spawn(&pid, path->narrow, #ifdef HAVE_POSIX_SPAWNP
file_actionsp, attrp, argvlist, envlist); if (use_posix_spawnp) {
err_code = posix_spawnp(&pid, path->narrow,
file_actionsp, attrp, argvlist, envlist);
}
else
#endif /* HAVE_POSIX_SPAWNP */
{
err_code = posix_spawn(&pid, path->narrow,
file_actionsp, attrp, argvlist, envlist);
}
_Py_END_SUPPRESS_IPH _Py_END_SUPPRESS_IPH
if (err_code) { if (err_code) {
errno = err_code; errno = err_code;
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path->object); PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path->object);
@ -5518,7 +5501,90 @@ exit:
Py_XDECREF(temp_buffer); Py_XDECREF(temp_buffer);
return result; return result;
} }
#endif /* HAVE_POSIX_SPAWN */
/*[clinic input]
os.posix_spawn
path: path_t
Path of executable file.
argv: object
Tuple or list of strings.
env: object
Dictionary of strings mapping to strings.
/
*
file_actions: object(c_default='NULL') = ()
A sequence of file action tuples.
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.
setsigmask: object(c_default='NULL') = ()
The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag.
setsigdef: object(c_default='NULL') = ()
The sigmask to use with the POSIX_SPAWN_SETSIGDEF flag.
scheduler: object = NULL
A tuple with the scheduler policy (optional) and parameters.
Execute the program specified by path in a new process.
[clinic start generated code]*/
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]*/
{
return py_posix_spawn(0, module, path, argv, env, file_actions,
setpgroup, resetids, setsigmask, setsigdef,
scheduler);
}
#endif /* HAVE_POSIX_SPAWN */
#ifdef HAVE_POSIX_SPAWNP
/*[clinic input]
os.posix_spawnp
path: path_t
Path of executable file.
argv: object
Tuple or list of strings.
env: object
Dictionary of strings mapping to strings.
/
*
file_actions: object(c_default='NULL') = ()
A sequence of file action tuples.
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.
setsigmask: object(c_default='NULL') = ()
The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag.
setsigdef: object(c_default='NULL') = ()
The sigmask to use with the POSIX_SPAWN_SETSIGDEF flag.
scheduler: object = NULL
A tuple with the scheduler policy (optional) and parameters.
Execute the program specified by path in a new process.
[clinic start generated code]*/
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]*/
{
return py_posix_spawn(1, module, path, argv, env, file_actions,
setpgroup, resetids, setsigmask, setsigdef,
scheduler);
}
#endif /* HAVE_POSIX_SPAWNP */
#if defined(HAVE_SPAWNV) || defined(HAVE_WSPAWNV) #if defined(HAVE_SPAWNV) || defined(HAVE_WSPAWNV)
@ -13084,6 +13150,7 @@ static PyMethodDef posix_methods[] = {
OS_GETPRIORITY_METHODDEF OS_GETPRIORITY_METHODDEF
OS_SETPRIORITY_METHODDEF OS_SETPRIORITY_METHODDEF
OS_POSIX_SPAWN_METHODDEF OS_POSIX_SPAWN_METHODDEF
OS_POSIX_SPAWNP_METHODDEF
OS_READLINK_METHODDEF OS_READLINK_METHODDEF
OS_RENAME_METHODDEF OS_RENAME_METHODDEF
OS_REPLACE_METHODDEF OS_REPLACE_METHODDEF

8
aclocal.m4 vendored
View File

@ -1,6 +1,6 @@
# generated automatically by aclocal 1.15.1 -*- Autoconf -*- # generated automatically by aclocal 1.15 -*- Autoconf -*-
# Copyright (C) 1996-2017 Free Software Foundation, Inc. # Copyright (C) 1996-2014 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation # This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
@ -13,7 +13,7 @@
m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
dnl serial 11 (pkg-config-0.29) dnl serial 11 (pkg-config-0.29.1)
dnl dnl
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>. dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com> dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
@ -55,7 +55,7 @@ dnl
dnl See the "Since" comment for each macro you use to see what version dnl See the "Since" comment for each macro you use to see what version
dnl of the macros you require. dnl of the macros you require.
m4_defun([PKG_PREREQ], m4_defun([PKG_PREREQ],
[m4_define([PKG_MACROS_VERSION], [0.29]) [m4_define([PKG_MACROS_VERSION], [0.29.1])
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
])dnl PKG_PREREQ ])dnl PKG_PREREQ

2
configure vendored
View File

@ -11447,7 +11447,7 @@ for ac_func in alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
initgroups kill killpg lchown lockf linkat lstat lutimes mmap \ initgroups kill killpg lchown lockf linkat lstat lutimes mmap \
memrchr mbrtowc mkdirat mkfifo \ memrchr mbrtowc mkdirat mkfifo \
mkfifoat mknod mknodat mktime mremap nice openat pathconf pause pipe2 plock poll \ mkfifoat mknod mknodat mktime mremap nice openat pathconf pause pipe2 plock poll \
posix_fallocate posix_fadvise posix_spawn pread preadv preadv2 \ posix_fallocate posix_fadvise posix_spawn posix_spawnp pread preadv preadv2 \
pthread_init pthread_kill putenv pwrite pwritev pwritev2 readlink readlinkat readv realpath renameat \ pthread_init pthread_kill putenv pwrite pwritev pwritev2 readlink readlinkat readv realpath renameat \
sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \ sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \
setgid sethostname \ setgid sethostname \

View File

@ -3505,7 +3505,7 @@ AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
initgroups kill killpg lchown lockf linkat lstat lutimes mmap \ initgroups kill killpg lchown lockf linkat lstat lutimes mmap \
memrchr mbrtowc mkdirat mkfifo \ memrchr mbrtowc mkdirat mkfifo \
mkfifoat mknod mknodat mktime mremap nice openat pathconf pause pipe2 plock poll \ mkfifoat mknod mknodat mktime mremap nice openat pathconf pause pipe2 plock poll \
posix_fallocate posix_fadvise posix_spawn pread preadv preadv2 \ posix_fallocate posix_fadvise posix_spawn posix_spawnp pread preadv preadv2 \
pthread_init pthread_kill putenv pwrite pwritev pwritev2 readlink readlinkat readv realpath renameat \ pthread_init pthread_kill putenv pwrite pwritev pwritev2 readlink readlinkat readv realpath renameat \
sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \ sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \
setgid sethostname \ setgid sethostname \

View File

@ -732,6 +732,9 @@
/* Define to 1 if you have the `posix_spawn' function. */ /* Define to 1 if you have the `posix_spawn' function. */
#undef HAVE_POSIX_SPAWN #undef HAVE_POSIX_SPAWN
/* Define to 1 if you have the `posix_spawnp' function. */
#undef HAVE_POSIX_SPAWNP
/* Define to 1 if you have the `pread' function. */ /* Define to 1 if you have the `pread' function. */
#undef HAVE_PREAD #undef HAVE_PREAD