issue #406: don't leak FDs on failed child start.
This commit is contained in:
parent
6ff1e001da
commit
14b389cb46
|
@ -210,6 +210,9 @@ Core Library
|
||||||
:class:`mitogen.core.Broker` did not call :meth:`mitogen.core.Poller.close`
|
:class:`mitogen.core.Broker` did not call :meth:`mitogen.core.Poller.close`
|
||||||
during shutdown, leaking the underlying poller FD in masters and parents.
|
during shutdown, leaking the underlying poller FD in masters and parents.
|
||||||
|
|
||||||
|
* `#406 <https://github.com/dw/mitogen/issues/406>`_: connections could leak
|
||||||
|
FDs when a child process failed to start.
|
||||||
|
|
||||||
* `#411 <https://github.com/dw/mitogen/issues/411>`_: the SSH method typed
|
* `#411 <https://github.com/dw/mitogen/issues/411>`_: the SSH method typed
|
||||||
"``y``" rather than the requisite "``yes``" when `check_host_keys="accept"`
|
"``y``" rather than the requisite "``yes``" when `check_host_keys="accept"`
|
||||||
was configured. This would lead to connection timeouts due to the hung
|
was configured. This would lead to connection timeouts due to the hung
|
||||||
|
|
|
@ -211,7 +211,7 @@ def create_socketpair():
|
||||||
return parentfp, childfp
|
return parentfp, childfp
|
||||||
|
|
||||||
|
|
||||||
def detach_popen(*args, **kwargs):
|
def detach_popen(close_on_error=None, **kwargs):
|
||||||
"""
|
"""
|
||||||
Use :class:`subprocess.Popen` to construct a child process, then hack the
|
Use :class:`subprocess.Popen` to construct a child process, then hack the
|
||||||
Popen so that it forgets the child it created, allowing it to survive a
|
Popen so that it forgets the child it created, allowing it to survive a
|
||||||
|
@ -223,6 +223,8 @@ def detach_popen(*args, **kwargs):
|
||||||
delivered to this process, causing later 'legitimate' calls to fail with
|
delivered to this process, causing later 'legitimate' calls to fail with
|
||||||
ECHILD.
|
ECHILD.
|
||||||
|
|
||||||
|
:param list close_on_error:
|
||||||
|
Array of integer file descriptors to close on exception.
|
||||||
:returns:
|
:returns:
|
||||||
Process ID of the new child.
|
Process ID of the new child.
|
||||||
"""
|
"""
|
||||||
|
@ -230,7 +232,13 @@ def detach_popen(*args, **kwargs):
|
||||||
# handling, without tying the surrounding code into managing a Popen
|
# handling, without tying the surrounding code into managing a Popen
|
||||||
# object, which isn't possible for at least :mod:`mitogen.fork`. This
|
# object, which isn't possible for at least :mod:`mitogen.fork`. This
|
||||||
# should be replaced by a swappable helper class in a future version.
|
# should be replaced by a swappable helper class in a future version.
|
||||||
proc = subprocess.Popen(*args, **kwargs)
|
try:
|
||||||
|
proc = subprocess.Popen(**kwargs)
|
||||||
|
except Exception:
|
||||||
|
for fd in close_on_error or ():
|
||||||
|
os.close(fd)
|
||||||
|
raise
|
||||||
|
|
||||||
proc._child_created = False
|
proc._child_created = False
|
||||||
return proc.pid
|
return proc.pid
|
||||||
|
|
||||||
|
@ -277,6 +285,7 @@ def create_child(args, merge_stdio=False, stderr_pipe=False, preexec_fn=None):
|
||||||
stdout=childfp,
|
stdout=childfp,
|
||||||
close_fds=True,
|
close_fds=True,
|
||||||
preexec_fn=preexec_fn,
|
preexec_fn=preexec_fn,
|
||||||
|
close_on_error=[parentfp.fileno(), childfp.fileno()],
|
||||||
**extra
|
**extra
|
||||||
)
|
)
|
||||||
if stderr_pipe:
|
if stderr_pipe:
|
||||||
|
@ -344,6 +353,7 @@ def tty_create_child(args):
|
||||||
stdout=slave_fd,
|
stdout=slave_fd,
|
||||||
stderr=slave_fd,
|
stderr=slave_fd,
|
||||||
preexec_fn=_acquire_controlling_tty,
|
preexec_fn=_acquire_controlling_tty,
|
||||||
|
close_on_error=[master_fd, slave_fd],
|
||||||
close_fds=True,
|
close_fds=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -372,6 +382,7 @@ def hybrid_tty_create_child(args):
|
||||||
mitogen.core.set_block(childfp)
|
mitogen.core.set_block(childfp)
|
||||||
disable_echo(master_fd)
|
disable_echo(master_fd)
|
||||||
disable_echo(slave_fd)
|
disable_echo(slave_fd)
|
||||||
|
|
||||||
pid = detach_popen(
|
pid = detach_popen(
|
||||||
args=args,
|
args=args,
|
||||||
stdin=childfp,
|
stdin=childfp,
|
||||||
|
@ -379,6 +390,7 @@ def hybrid_tty_create_child(args):
|
||||||
stderr=slave_fd,
|
stderr=slave_fd,
|
||||||
preexec_fn=_acquire_controlling_tty,
|
preexec_fn=_acquire_controlling_tty,
|
||||||
close_fds=True,
|
close_fds=True,
|
||||||
|
close_on_error=[master_fd, slave_fd, parentfp.fileno(), childfp.fileno()],
|
||||||
)
|
)
|
||||||
|
|
||||||
os.close(slave_fd)
|
os.close(slave_fd)
|
||||||
|
|
Loading…
Reference in New Issue