Skip to content

Prevent blocking empty fread()#26

Open
divinity76 wants to merge 9 commits intochrome-php:1.8from
divinity76:patch-5
Open

Prevent blocking empty fread()#26
divinity76 wants to merge 9 commits intochrome-php:1.8from
divinity76:patch-5

Conversation

@divinity76
Copy link

@divinity76 divinity76 commented Mar 16, 2026

There is an issue where this fread can block up to 5 seconds when there is nothing to read.

Fix it by not issuing fread() if stream_select() say there is nothing to read.

Also encountered a strange issue on PHP8.4.12 Ubuntu24.04 where stream_select() would incorrectly return 0 if we had never ran fread() on the socket, so made a workaround to always call fread the first time, even if stream_select() say there is nothing to read.

Reproduce script:

<?php

declare(strict_types=1);
require_once(__DIR__ . '/vendor/autoload.php');
$chromeBinary = "/snap/bin/chromium";
$browser_factory = new \HeadlessChromium\BrowserFactory($chromeBinary);
$browser_factory->setOptions([
    "headless" => true,
    "noSandbox" => true,
    'customFlags' => [
        // docker ...
        '--disable-dev-shm-usage',
    ]
]);
$browser = $browser_factory->createBrowser();
$page = $browser->createPage();
$highscore = -INF;
$page->navigate("http://example.com")->waitForNavigation();

for ($i = 0; $i < 100; ++$i) {
$t = microtime(true);
$url = $page->getCurrentUrl();
$t = microtime(true) - $t;
if ($t > $highscore) {
    echo "New highscore: $t seconds for $url\n";
    $highscore = $t;
}
}

output before this patch:

hans@DESKTOP-EE15SLU:~/projects/chrome/hans$ php reproduce.php 
New highscore: 1.0967254638672E-5 seconds for getCurrentUrl() on https://example.com/
New highscore: 0.0005338191986084 seconds for getCurrentUrl() on https://example.com/
New highscore: 0.021073818206787 seconds for getCurrentUrl() on https://example.com/
New highscore: 0.96735405921936 seconds for getCurrentUrl() on https://example.com/
New highscore: 3.1658289432526 seconds for getCurrentUrl() on https://example.com/
New highscore: 5.0055141448975 seconds for getCurrentUrl() on https://example.com/
New highscore: 5.0062091350555 seconds for getCurrentUrl() on https://example.com/
New highscore: 5.0073070526123 seconds for getCurrentUrl() on https://example.com/
New highscore: 5.0073978900909 seconds for getCurrentUrl() on https://example.com/
New highscore: 5.0115480422974 seconds for getCurrentUrl() on https://example.com/
^C

(Had to ctrl+c cancel it because it was taking so long...)
Output after this patch:

hans@DESKTOP-EE15SLU:~/projects/chrome/hans$ php reproduce.php 
New highscore: 9.0599060058594E-6 seconds for getCurrentUrl() on https://example.com/
hans@DESKTOP-EE15SLU:~/projects/chrome/hans$ php reproduce.php 
New highscore: 5.9604644775391E-6 seconds for getCurrentUrl() on https://example.com/
hans@DESKTOP-EE15SLU:~/projects/chrome/hans$ php reproduce.php 
New highscore: 1.0967254638672E-5 seconds for getCurrentUrl() on https://example.com/
New highscore: 2.0027160644531E-5 seconds for getCurrentUrl() on https://example.com/
hans@DESKTOP-EE15SLU:~/projects/chrome/hans$ 
  • Consistently execute in a fraction of a second 👍

There is an issue where this fread can block up to 5 seconds.

Fix it by not issuing fread() if stream_select() say there is nothing to read.

Encountered a strange issue on Ubuntu24.04 where stream_select() would incorrectly return 0 if we had never ran fread() on the socket, so made a workaround to always call fread the first time, even if socket_select() say there is nothing to read.


- resolves chrome-php/chrome#711
- resolves chrome-php/chrome#646
- resolves chrome-php/chrome#704

- probably resolves chrome-php/chrome#710
@divinity76 divinity76 changed the title Prevent blocking fread() Prevent blocking empty fread() Mar 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant