mercurial/util.py
changeset 48940 2974cdda819b
parent 48913 f254fc73d956
child 48946 642e31cb55f0
equal deleted inserted replaced
48939:37537a4d2695 48940:2974cdda819b
    23 import io
    23 import io
    24 import itertools
    24 import itertools
    25 import locale
    25 import locale
    26 import mmap
    26 import mmap
    27 import os
    27 import os
    28 import platform as pyplatform
       
    29 import re as remod
    28 import re as remod
    30 import shutil
    29 import shutil
    31 import stat
    30 import stat
    32 import sys
    31 import sys
    33 import time
    32 import time
  2903 else:
  2902 else:
  2904     tonativeeol = pycompat.identity
  2903     tonativeeol = pycompat.identity
  2905     fromnativeeol = pycompat.identity
  2904     fromnativeeol = pycompat.identity
  2906     nativeeolwriter = pycompat.identity
  2905     nativeeolwriter = pycompat.identity
  2907 
  2906 
  2908 if pyplatform.python_implementation() == b'CPython' and sys.version_info < (
  2907 
  2909     3,
  2908 # TODO delete since workaround variant for Python 2 no longer needed.
  2910     0,
  2909 def iterfile(fp):
  2911 ):
  2910     return fp
  2912     # There is an issue in CPython that some IO methods do not handle EINTR
       
  2913     # correctly. The following table shows what CPython version (and functions)
       
  2914     # are affected (buggy: has the EINTR bug, okay: otherwise):
       
  2915     #
       
  2916     #                | < 2.7.4 | 2.7.4 to 2.7.12 | >= 3.0
       
  2917     #   --------------------------------------------------
       
  2918     #    fp.__iter__ | buggy   | buggy           | okay
       
  2919     #    fp.read*    | buggy   | okay [1]        | okay
       
  2920     #
       
  2921     # [1]: fixed by changeset 67dc99a989cd in the cpython hg repo.
       
  2922     #
       
  2923     # Here we workaround the EINTR issue for fileobj.__iter__. Other methods
       
  2924     # like "read*" work fine, as we do not support Python < 2.7.4.
       
  2925     #
       
  2926     # Although we can workaround the EINTR issue for fp.__iter__, it is slower:
       
  2927     # "for x in fp" is 4x faster than "for x in iter(fp.readline, '')" in
       
  2928     # CPython 2, because CPython 2 maintains an internal readahead buffer for
       
  2929     # fp.__iter__ but not other fp.read* methods.
       
  2930     #
       
  2931     # On modern systems like Linux, the "read" syscall cannot be interrupted
       
  2932     # when reading "fast" files like on-disk files. So the EINTR issue only
       
  2933     # affects things like pipes, sockets, ttys etc. We treat "normal" (S_ISREG)
       
  2934     # files approximately as "fast" files and use the fast (unsafe) code path,
       
  2935     # to minimize the performance impact.
       
  2936 
       
  2937     def iterfile(fp):
       
  2938         fastpath = True
       
  2939         if type(fp) is file:
       
  2940             fastpath = stat.S_ISREG(os.fstat(fp.fileno()).st_mode)
       
  2941         if fastpath:
       
  2942             return fp
       
  2943         else:
       
  2944             # fp.readline deals with EINTR correctly, use it as a workaround.
       
  2945             return iter(fp.readline, b'')
       
  2946 
       
  2947 
       
  2948 else:
       
  2949     # PyPy and CPython 3 do not have the EINTR issue thus no workaround needed.
       
  2950     def iterfile(fp):
       
  2951         return fp
       
  2952 
  2911 
  2953 
  2912 
  2954 def iterlines(iterator):
  2913 def iterlines(iterator):
  2955     # type: (Iterator[bytes]) -> Iterator[bytes]
  2914     # type: (Iterator[bytes]) -> Iterator[bytes]
  2956     for chunk in iterator:
  2915     for chunk in iterator: