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: |