Skip to content

Commit 8cc8300

Browse files
committed
Make run-tests.php check for tcp fwrite edge cases
When the recipient is busy or the payload is large, fwrite can block or return a value smaller than the length of the stream. workers in run-tests.php communicates over tcp sockets with the manager. https://cirrus-ci.com/task/5315675320221696?logs=tests#L130 showed notices for fwrite/unserialize This is a similar approach to the approach used in https://github.com/phan/phan/blob/v5/src/Phan/LanguageServer/ProtocolStreamWriter.php for the tcp language server writing.
1 parent 3331832 commit 8cc8300

File tree

1 file changed

+33
-1
lines changed

1 file changed

+33
-1
lines changed

run-tests.php

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1645,11 +1645,43 @@ function run_all_tests_parallel(array $test_files, array $env, $redir_tested): v
16451645
}
16461646
}
16471647

1648+
/**
1649+
* Calls fwrite and retries when network writes fail with errors such as "Resource temporarily unavailable"
1650+
*
1651+
* @param resource $stream the stream to fwrite to
1652+
* @param string $data
1653+
* @return int|false
1654+
*/
1655+
function safe_fwrite($stream, string $data)
1656+
{
1657+
// safe_fwrite was tested by adding $message['unused'] = str_repeat('a', 20_000_000); in send_message()
1658+
// fwrites on tcp sockets can return false or less than strlen if the recipient is busy.
1659+
// (e.g. fwrite(): Send of 577 bytes failed with errno=35 Resource temporarily unavailable)
1660+
$bytes_written = 0;
1661+
while ($bytes_written < strlen($data)) {
1662+
$n = @fwrite($stream, substr($data, $bytes_written));
1663+
if ($n === false) {
1664+
$write_streams = [$stream];
1665+
$read_streams = [];
1666+
$except_streams = [];
1667+
/* Wait for up to 10 seconds for the stream to be ready to write again. */
1668+
stream_select($read_streams, $write_streams, $except_streams, 10);
1669+
$n = @fwrite($stream, substr($data, $bytes_written));
1670+
if ($n === false) {
1671+
echo "ERROR: send_message() Failed to write chunk after stream_select: " . error_get_last()['message'] . "\n";
1672+
return false;
1673+
}
1674+
}
1675+
$bytes_written += $n;
1676+
}
1677+
return $bytes_written;
1678+
}
1679+
16481680
function send_message($stream, array $message): void
16491681
{
16501682
$blocking = stream_get_meta_data($stream)["blocked"];
16511683
stream_set_blocking($stream, true);
1652-
fwrite($stream, base64_encode(serialize($message)) . "\n");
1684+
safe_fwrite($stream, base64_encode(serialize($message)) . "\n");
16531685
stream_set_blocking($stream, $blocking);
16541686
}
16551687

0 commit comments

Comments
 (0)