Skip to content

Commit

Permalink
[chiptest] Fix UTF-8 decoding error in stdout/err (#16101)
Browse files Browse the repository at this point in the history
* [chiptest] Fix UTF-8 decoding error in stdout/err

This commit also unifies PIPE type for Linux and Darwin platforms. From
now, all platforms will use PTY-based PIPE for reading subprocess output
in real time (without 4k block buffering).

* Fix typo in comment.

Co-authored-by: Boris Zbarsky <[email protected]>
  • Loading branch information
2 people authored and pull[bot] committed Aug 17, 2023
1 parent ac382bd commit 3779127
Showing 1 changed file with 20 additions and 10 deletions.
30 changes: 20 additions & 10 deletions scripts/tests/chiptest/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,18 @@
import queue
import re
import subprocess
import sys
import threading


class LogPipe(threading.Thread):
"""Create PTY-based PIPE for IPC.
Python provides a built-in mechanism for creating comunication PIPEs for
subprocesses spawned with Popen(). However, created PIPEs will most likely
enable IO buffering in the spawned process. In order to trick such process
to flush its streams immediately, we are going to create a PIPE based on
pseudoterminal (PTY).
"""

def __init__(self, level, capture_delegate=None, name=None):
"""
Expand All @@ -32,12 +39,8 @@ def __init__(self, level, capture_delegate=None, name=None):

self.daemon = False
self.level = level
if sys.platform == 'darwin':
self.fd_read, self.fd_write = pty.openpty()
else:
self.fd_read, self.fd_write = os.pipe()

self.pipeReader = os.fdopen(self.fd_read)
self.fd_read, self.fd_write = pty.openpty()
self.reader = open(self.fd_read, encoding='utf-8', errors='ignore')
self.captured_logs = []
self.capture_delegate = capture_delegate
self.name = name
Expand All @@ -63,13 +66,20 @@ def fileno(self):

def run(self):
"""Run the thread, logging everything."""
for line in iter(self.pipeReader.readline, ''):
while True:
try:
line = self.reader.readline()
# It seems that Darwin platform returns empty string in case
# when writing side of PTY is closed (Linux raises OSError).
if line == '':
break
except OSError:
break
logging.log(self.level, line.strip('\n'))
self.captured_logs.append(line)
if self.capture_delegate:
self.capture_delegate.Log(self.name, line)

self.pipeReader.close()
self.reader.close()

def close(self):
"""Close the write end of the pipe."""
Expand Down

0 comments on commit 3779127

Please sign in to comment.