Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
92b8322e
Commit
92b8322e
authored
Jan 16, 2019
by
Joannah Nanjekye
Committed by
Victor Stinner
Jan 16, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
bpo-35674: Add os.posix_spawnp() (GH-11554)
Add a new os.posix_spawnp() function.
parent
9daecf37
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
322 additions
and
112 deletions
+322
-112
Doc/library/os.rst
Doc/library/os.rst
+17
-0
Lib/test/test_posix.py
Lib/test/test_posix.py
+119
-71
Misc/NEWS.d/next/Library/2019-01-14-14-13-08.bpo-35674.kamWqz.rst
...S.d/next/Library/2019-01-14-14-13-08.bpo-35674.kamWqz.rst
+2
-0
Modules/clinic/posixmodule.c.h
Modules/clinic/posixmodule.c.h
+74
-1
Modules/posixmodule.c
Modules/posixmodule.c
+101
-34
aclocal.m4
aclocal.m4
+4
-4
configure
configure
+1
-1
configure.ac
configure.ac
+1
-1
pyconfig.h.in
pyconfig.h.in
+3
-0
No files found.
Doc/library/os.rst
View file @
92b8322e
...
@@ -3396,6 +3396,10 @@ written in Python, such as a mail server's external command delivery program.
...
@@ -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.
...
@@ -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)
...
...
Lib/test/test_posix.py
View file @
92b8322e
...
@@ -1489,10 +1489,10 @@ class PosixGroupsTester(unittest.TestCase):
...
@@ -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):
...
@@ -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,7 +1519,7 @@ class TestPosixSpawn(unittest.TestCase):
...
@@ -1519,7 +1519,7 @@ 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
:
...
@@ -1538,14 +1538,14 @@ class TestPosixSpawn(unittest.TestCase):
...
@@ -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):
...
@@ -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):
...
@@ -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):
...
@@ -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,7 +1588,7 @@ class TestPosixSpawn(unittest.TestCase):
...
@@ -1588,7 +1588,7 @@ 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"
)
...
@@ -1599,7 +1599,7 @@ class TestPosixSpawn(unittest.TestCase):
...
@@ -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,15 +1609,15 @@ class TestPosixSpawn(unittest.TestCase):
...
@@ -1609,15 +1609,15 @@ 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
])
...
@@ -1630,7 +1630,7 @@ class TestPosixSpawn(unittest.TestCase):
...
@@ -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,15 +1646,15 @@ class TestPosixSpawn(unittest.TestCase):
...
@@ -1646,15 +1646,15 @@ 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
])
...
@@ -1670,7 +1670,7 @@ class TestPosixSpawn(unittest.TestCase):
...
@@ -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):
...
@@ -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,7 +1704,7 @@ class TestPosixSpawn(unittest.TestCase):
...
@@ -1704,7 +1704,7 @@ 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
)
...
@@ -1713,28 +1713,28 @@ class TestPosixSpawn(unittest.TestCase):
...
@@ -1713,28 +1713,28 @@ class TestPosixSpawn(unittest.TestCase):
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
)])
...
@@ -1752,7 +1752,7 @@ class TestPosixSpawn(unittest.TestCase):
...
@@ -1752,7 +1752,7 @@ 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
:
...
@@ -1770,8 +1770,8 @@ class TestPosixSpawn(unittest.TestCase):
...
@@ -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):
...
@@ -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
()
...
...
Misc/NEWS.d/next/Library/2019-01-14-14-13-08.bpo-35674.kamWqz.rst
0 → 100644
View file @
92b8322e
Add a new :func:`os.posix_spawnp` function.
Patch by Joannah Nanjekye.
\ No newline at end of file
Modules/clinic/posixmodule.c.h
View file @
92b8322e
...
@@ -1791,6 +1791,75 @@ exit:
...
@@ -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:
...
@@ -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:
...
@@ -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]*/
Modules/posixmodule.c
View file @
92b8322e
...
@@ -5381,39 +5381,12 @@ fail:
...
@@ -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,
...
@@ -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
#ifdef HAVE_POSIX_SPAWNP
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
,
err_code
=
posix_spawn
(
&
pid
,
path
->
narrow
,
file_actionsp
,
attrp
,
argvlist
,
envlist
);
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:
...
@@ -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[] = {
...
@@ -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
...
...
aclocal.m4
View file @
92b8322e
# generated automatically by aclocal 1.15
.1
-*- Autoconf -*-
# generated automatically by aclocal 1.15 -*- Autoconf -*-
# Copyright (C) 1996-201
7
Free Software Foundation, Inc.
# Copyright (C) 1996-201
4
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 @@
...
@@ -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
...
@@ -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
...
...
configure
View file @
92b8322e
...
@@ -11447,7 +11447,7 @@ for ac_func in alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
...
@@ -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 p
osix_spawnp p
read 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
\
...
...
configure.ac
View file @
92b8322e
...
@@ -3505,7 +3505,7 @@ AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
...
@@ -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 p
osix_spawnp p
read 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 \
...
...
pyconfig.h.in
View file @
92b8322e
...
@@ -732,6 +732,9 @@
...
@@ -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
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment