49 lines
1.3 KiB
Python
49 lines
1.3 KiB
Python
###############################################################################
|
|
# Launch a subprocess using forkexec and make sure only the needed fd are
|
|
# shared in the two process.
|
|
#
|
|
# author: Thomas Moreau and Olivier Grisel
|
|
#
|
|
import os
|
|
import sys
|
|
|
|
if sys.platform == "darwin" and sys.version_info < (3, 3):
|
|
FileNotFoundError = OSError
|
|
|
|
|
|
def close_fds(keep_fds): # pragma: no cover
|
|
"""Close all the file descriptors except those in keep_fds."""
|
|
|
|
# Make sure to keep stdout and stderr open for logging purpose
|
|
keep_fds = set(keep_fds).union([1, 2])
|
|
|
|
# We try to retrieve all the open fds
|
|
try:
|
|
open_fds = set(int(fd) for fd in os.listdir('/proc/self/fd'))
|
|
except FileNotFoundError:
|
|
import resource
|
|
max_nfds = resource.getrlimit(resource.RLIMIT_NOFILE)[0]
|
|
open_fds = set(fd for fd in range(3, max_nfds))
|
|
open_fds.add(0)
|
|
|
|
for i in open_fds - keep_fds:
|
|
try:
|
|
os.close(i)
|
|
except OSError:
|
|
pass
|
|
|
|
|
|
def fork_exec(cmd, keep_fds, env=None):
|
|
|
|
# copy the environment variables to set in the child process
|
|
env = {} if env is None else env
|
|
child_env = os.environ.copy()
|
|
child_env.update(env)
|
|
|
|
pid = os.fork()
|
|
if pid == 0: # pragma: no cover
|
|
close_fds(keep_fds)
|
|
os.execve(sys.executable, cmd, child_env)
|
|
else:
|
|
return pid
|