From 1fff878c3706e28de359542d3dc7f102b2196efc Mon Sep 17 00:00:00 2001 From: Sebastian Brix Date: Wed, 27 May 2026 09:23:55 +0200 Subject: [PATCH] * Removed deprecated chr() #9940 * Fixed Psalm Warnings * Removed dead code * Added DaemonTest.php --- composer.json | 36 ++++++++++++++++++------------------ src/Daemon.php | 42 +++++++++++++++++++++++++++--------------- src/MainThread.php | 2 +- src/Service.php | 9 +++++---- src/Thread.php | 15 ++------------- tests/DaemonTest.php | 34 ++++++++++++++++++++++++++++++++++ 6 files changed, 87 insertions(+), 51 deletions(-) create mode 100644 tests/DaemonTest.php diff --git a/composer.json b/composer.json index bf66e11..3bd3c0e 100644 --- a/composer.json +++ b/composer.json @@ -1,20 +1,20 @@ { - "name": "graphit/concurrent", - "type": "library", - "authors": [ - { - "name": "Graph-IT", - "email": "info@graph-it.com" - } - ], - "require": { - "php": ">=7.4.0", - "ext-pcntl": "*", - "ext-posix": "*" - }, - "autoload": { - "psr-4": { - "Graphit\\Concurrent\\": "src/" - } + "name": "graphit/concurrent", + "type": "library", + "authors": [ + { + "name": "Graph-IT", + "email": "info@graph-it.com" } -} + ], + "require": { + "php": ">=8.4.0", + "ext-pcntl": "*", + "ext-posix": "*" + }, + "autoload": { + "psr-4": { + "Graphit\\Concurrent\\": "src/" + } + } +} \ No newline at end of file diff --git a/src/Daemon.php b/src/Daemon.php index 420ac13..d3fb50e 100644 --- a/src/Daemon.php +++ b/src/Daemon.php @@ -2,17 +2,19 @@ namespace Graphit\Concurrent; +use RuntimeException; + +/** @api */ abstract class Daemon extends Thread { - /** */ + #[\Override] public function start() { - if ($this->isRunning()) { - return false; - } + if ($this->isRunning()) return false; $fifo_file = '/tmp/thread_fifo_'.posix_getpid(); - posix_mkfifo($fifo_file, 0600); + if ( !posix_mkfifo($fifo_file, 0600)) + throw new RuntimeException("Unable to create fifo $fifo_file"); $starterpid = pcntl_fork(); if ($starterpid == -1) { // Unable to start Starter-Thread @@ -20,27 +22,32 @@ abstract class Daemon extends Thread } else if ($starterpid != 0) { // Pull Child-PID from Starter-Thread $fifo = fopen($fifo_file, 'r'); - $data = fread($fifo, 2); + if ($fifo === false) + throw new RuntimeException("Unable to open fifo $fifo_file"); + + $data = fgets($fifo); fclose($fifo); unlink($fifo_file); - $childpid = ord($data[0]) * 256 + ord($data[1]); - if ($childpid === 256*256-1) { - return false; - } + if ($data === false) + throw new RuntimeException("Unable to read childpid from fifo $fifo_file"); + + $childpid = self::parsePID(json_decode($data, flags: JSON_THROW_ON_ERROR)); + + if ($childpid === -1) return false; $this->pid = $childpid; return true; } else { // Execute Starter-Thread $childpid = pcntl_fork(); - if ($childpid == -1) { // Unable to start Child-Thread - $childpid = 256*256-1; - } - if ($childpid != 0) { // Push Child-PID from Starter-Thread - $data = chr((int)(floor($childpid / 256))).chr($childpid % 256); + if ($childpid !== 0) { // Push Child-PID from Starter-Thread + $data = json_encode($childpid, JSON_THROW_ON_ERROR); $fifo = fopen($fifo_file, 'w'); + if ($fifo === false) + throw new RuntimeException("Unable to open fifo $fifo_file"); + fwrite($fifo, $data); fclose($fifo); @@ -57,4 +64,9 @@ abstract class Daemon extends Thread exit(); } } + + private static function parsePID(mixed $value): int { + if (is_int($value)) return $value; + throw new RuntimeException("Unable to parse childpid into an int."); + } } diff --git a/src/MainThread.php b/src/MainThread.php index 1338a4b..a8f56d5 100644 --- a/src/MainThread.php +++ b/src/MainThread.php @@ -2,4 +2,4 @@ namespace Graphit\Concurrent; -class MainThread extends Thread { } +final class MainThread extends Thread { } diff --git a/src/Service.php b/src/Service.php index ba24f10..265099f 100644 --- a/src/Service.php +++ b/src/Service.php @@ -2,6 +2,7 @@ namespace Graphit\Concurrent; +/** @api */ abstract class Service extends Daemon { /** @var string */ @@ -18,7 +19,7 @@ abstract class Service extends Daemon } } - /** */ + #[\Override] public function isRunning() { if ( !$this->pid){ @@ -35,7 +36,7 @@ abstract class Service extends Daemon return $running; } - /** */ + #[\Override] public function stop() { while ($this->isRunning()) { @@ -44,7 +45,7 @@ abstract class Service extends Daemon } } - /** */ + #[\Override] public function setup() { parent::setup(); @@ -54,7 +55,7 @@ abstract class Service extends Daemon } } - /** */ + #[\Override] public function teardown() { if ($this->isRunning()) { diff --git a/src/Thread.php b/src/Thread.php index 8db0855..c3e3680 100644 --- a/src/Thread.php +++ b/src/Thread.php @@ -2,6 +2,7 @@ namespace Graphit\Concurrent; +/** @api */ abstract class Thread { /** @var int|null */ @@ -56,23 +57,11 @@ abstract class Thread } /** + * @param mixed $siginfo * @return void */ protected function chldHandler($siginfo) { - if (phpversion() == '8.2.9'){ - if (is_array($siginfo) && isset($siginfo['pid']) && is_int($siginfo['pid'])) { - $childpid = $siginfo['pid']; - - if (isset($this->children[$childpid])) { - $child = $this->children[$childpid]; - $child->isRunning(); - - unset($this->children[$childpid]); - } - } - } - while (($childpid = pcntl_waitpid(-1, $status, WNOHANG)) > 0) { if (isset($this->children[$childpid])) { $child = $this->children[$childpid]; diff --git a/tests/DaemonTest.php b/tests/DaemonTest.php new file mode 100644 index 0000000..f04133c --- /dev/null +++ b/tests/DaemonTest.php @@ -0,0 +1,34 @@ +getPid()."!\n"; + flush(); + while ( !$this->isStopped()){ + usleep(500000); + + echo "from daemon: Message!\n"; + flush(); + } + echo "from daemon: Stopped!\n"; + } + }); + + $this->assertTrue($d->start(), "from main: Unable to start daemon"); + + echo "from main: PID ".$d->getPid()."\n"; + sleep(2); + + $d->stop(); + } +} -- 2.43.0