Skip to content

Commit

Permalink
retry dup2 on EBUSY
Browse files Browse the repository at this point in the history
  • Loading branch information
minrk committed Jun 22, 2017
1 parent 85b9433 commit 6e2e906
Showing 1 changed file with 21 additions and 2 deletions.
23 changes: 21 additions & 2 deletions wurlitzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@

from contextlib import contextmanager
import ctypes
import errno
from fcntl import fcntl, F_GETFL, F_SETFL
import io
import os
import select
import sys
import threading
import time
import warnings

libc = ctypes.CDLL(None)
Expand All @@ -42,6 +44,23 @@
# don't respect ascii
_default_encoding = 'utf8' # pragma: no cover

def dup2(a, b, timeout=3):
"""Like os.dup2, but retry on EBUSY"""
dup_err = None
# give FDs 3 seconds to not be busy anymore
for i in range(int(10 * timeout)):
try:
return os.dup2(a, b)
except OSError as e:
dup_err = e
if e.errno == errno.EBUSY:
time.sleep(0.1)
else:
raise
if dup_err:
raise dup_err


class Wurlitzer(object):
"""Class for Capturing Process-level FD output via dup2
Expand Down Expand Up @@ -78,7 +97,7 @@ def _setup_pipe(self, name):
self._save_fds[name] = save_fd

pipe_out, pipe_in = os.pipe()
os.dup2(pipe_in, real_fd)
dup2(pipe_in, real_fd)
os.close(pipe_in)
self._real_fds[name] = real_fd

Expand Down Expand Up @@ -189,7 +208,7 @@ def __exit__(self, exc_type, exc_value, traceback):
# restore original state
for name, real_fd in self._real_fds.items():
save_fd = self._save_fds[name]
os.dup2(save_fd, real_fd)
dup2(save_fd, real_fd)
os.close(save_fd)
# finalize handle
self._finish_handle()
Expand Down

0 comments on commit 6e2e906

Please sign in to comment.