[php-src] Issue #7846: curl and other native libraries block pcntl async signal propagation
| From: | olsavmic | Date: | Tue, 28 Dec 2021 18:22:20 +0000 |
| Subject: | [php-src] Issue #7846: curl and other native libraries block pcntl async signal propagation | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-238611@lists.php.net to get a copy of this message | ||
Issue: https://github.com/php/php-src/issues/7846
Author: olsavmic
### Description
The following code:
```php
<?php
pcntl_async_signals(true);
$handler = function() {
echo 'HANDLER CALLED' . PHP_EOL;
pcntl_alarm(1);
};
pcntl_signal(SIGALRM, $handler);
pcntl_alarm(1);
while (true) {
$ch = curl_init();
//curl_setopt($ch, CURLOPT_NOPROGRESS, false);
//curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, function() {});
curl_setopt($ch, CURLOPT_URL, 'http://localhost/timeout.php');
curl_exec($ch);
curl_close($ch);
}
```
Gives following output:
```
Request started
HANDLER CALLED
Request done
```
But I expected this output instead:
```
Request started
HANDLER CALLED
HANDLER CALLED
HANDLER CALLED
HANDLER CALLED
HANDLER CALLED
HANDLER CALLED
HANDLER CALLED
HANDLER CALLED
HANDLER CALLED
Request done
```
PHP main thread is blocked during the entire request, the handler is called only after that. This
behaviour renders pcntl_async_signals unusable for most workloads (eg. sending heartbeats to keep
connections open during long running operations). The issue is not restricted to SIGALRM only, it
applies to all signals.
Such behaviour is not documented anywhere (including the RFC https://wiki.php.net/rfc/async_signals) yet the
same problem actually applies to other native libraries like PDO/mysqli,... (see already reported
issue for mysqli https://bugs.php.net/bug.php?id=81515)
If this is expected behaviour, it must be documented as right now it seems like the only RELIABLE
way to implement specific features but it behaves unpredictably with the use of 3rd party libraries
and it's very hard to debug.
Adding both
curl_setopt($ch, CURLOPT_NOPROGRESS, false); and curl_setopt($ch,
CURLOPT_PROGRESSFUNCTION, function() {}); fixes this particular issue but it's an
undocumented required configuration and most likely just a side-effect.
--------------------
Example of PDO query blocking:
```php
<?php
pcntl_async_signals(true);
$handler = function () {
echo 'Handler called';
pcntl_alarm(1);
};
pcntl_signal(SIGALRM, $handler);
pcntl_alarm(1);
$conn = new PDO('mysql:host=localhost;dbname=test', 'root', 'admin');
$conn->query("SELECT SLEEP(10)");
```
### PHP Version
8.1, 8.0
### Operating System
Debian Buster, MacOS