[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/src/Application/ -> DaemonApplication.php (source)

   1  <?php
   2  
   3  /**
   4   * Joomla! Content Management System
   5   *
   6   * @copyright  (C) 2012 Open Source Matters, Inc. <https://www.joomla.org>
   7   * @license    GNU General Public License version 2 or later; see LICENSE.txt
   8   */
   9  
  10  namespace Joomla\CMS\Application;
  11  
  12  use Joomla\CMS\Filesystem\Folder;
  13  use Joomla\CMS\Input\Cli;
  14  use Joomla\CMS\Log\Log;
  15  use Joomla\Event\DispatcherInterface;
  16  use Joomla\Registry\Registry;
  17  
  18  // phpcs:disable PSR1.Files.SideEffects
  19  \defined('JPATH_PLATFORM') or die;
  20  // phpcs:enable PSR1.Files.SideEffects
  21  
  22  /**
  23   * Class to turn CliApplication applications into daemons.  It requires CLI and PCNTL support built into PHP.
  24   *
  25   * @link   https://www.php.net/manual/en/book.pcntl.php
  26   * @link   https://www.php.net/manual/en/features.commandline.php
  27   * @since  1.7.0
  28   */
  29  abstract class DaemonApplication extends CliApplication
  30  {
  31      /**
  32       * @var    array  The available POSIX signals to be caught by default.
  33       * @link   https://www.php.net/manual/pcntl.constants.php
  34       * @since  1.7.0
  35       */
  36      protected static $signals = array(
  37          'SIGHUP',
  38          'SIGINT',
  39          'SIGQUIT',
  40          'SIGILL',
  41          'SIGTRAP',
  42          'SIGABRT',
  43          'SIGIOT',
  44          'SIGBUS',
  45          'SIGFPE',
  46          'SIGUSR1',
  47          'SIGSEGV',
  48          'SIGUSR2',
  49          'SIGPIPE',
  50          'SIGALRM',
  51          'SIGTERM',
  52          'SIGSTKFLT',
  53          'SIGCLD',
  54          'SIGCHLD',
  55          'SIGCONT',
  56          'SIGTSTP',
  57          'SIGTTIN',
  58          'SIGTTOU',
  59          'SIGURG',
  60          'SIGXCPU',
  61          'SIGXFSZ',
  62          'SIGVTALRM',
  63          'SIGPROF',
  64          'SIGWINCH',
  65          'SIGPOLL',
  66          'SIGIO',
  67          'SIGPWR',
  68          'SIGSYS',
  69          'SIGBABY',
  70          'SIG_BLOCK',
  71          'SIG_UNBLOCK',
  72          'SIG_SETMASK',
  73      );
  74  
  75      /**
  76       * @var    boolean  True if the daemon is in the process of exiting.
  77       * @since  1.7.0
  78       */
  79      protected $exiting = false;
  80  
  81      /**
  82       * @var    integer  The parent process id.
  83       * @since  3.0.0
  84       */
  85      protected $parentId = 0;
  86  
  87      /**
  88       * @var    integer  The process id of the daemon.
  89       * @since  1.7.0
  90       */
  91      protected $processId = 0;
  92  
  93      /**
  94       * @var    boolean  True if the daemon is currently running.
  95       * @since  1.7.0
  96       */
  97      protected $running = false;
  98  
  99      /**
 100       * Class constructor.
 101       *
 102       * @param   Cli                  $input       An optional argument to provide dependency injection for the application's
 103       *                                            input object.  If the argument is a JInputCli object that object will become
 104       *                                            the application's input object, otherwise a default input object is created.
 105       * @param   Registry             $config      An optional argument to provide dependency injection for the application's
 106       *                                            config object.  If the argument is a Registry object that object will become
 107       *                                            the application's config object, otherwise a default config object is created.
 108       * @param   DispatcherInterface  $dispatcher  An optional argument to provide dependency injection for the application's
 109       *                                            event dispatcher.  If the argument is a DispatcherInterface object that object will become
 110       *                                            the application's event dispatcher, if it is null then the default event dispatcher
 111       *                                            will be created based on the application's loadDispatcher() method.
 112       *
 113       * @since   1.7.0
 114       */
 115      public function __construct(Cli $input = null, Registry $config = null, DispatcherInterface $dispatcher = null)
 116      {
 117          // Verify that the process control extension for PHP is available.
 118          if (!\defined('SIGHUP')) {
 119              Log::add('The PCNTL extension for PHP is not available.', Log::ERROR);
 120              throw new \RuntimeException('The PCNTL extension for PHP is not available.');
 121          }
 122  
 123          // Verify that POSIX support for PHP is available.
 124          if (!\function_exists('posix_getpid')) {
 125              Log::add('The POSIX extension for PHP is not available.', Log::ERROR);
 126              throw new \RuntimeException('The POSIX extension for PHP is not available.');
 127          }
 128  
 129          // Call the parent constructor.
 130          parent::__construct($input, $config, null, null, $dispatcher);
 131  
 132          // Set some system limits.
 133          @set_time_limit($this->config->get('max_execution_time', 0));
 134  
 135          if ($this->config->get('max_memory_limit') !== null) {
 136              ini_set('memory_limit', $this->config->get('max_memory_limit', '256M'));
 137          }
 138  
 139          // Flush content immediately.
 140          ob_implicit_flush();
 141      }
 142  
 143      /**
 144       * Method to handle POSIX signals.
 145       *
 146       * @param   integer  $signal  The received POSIX signal.
 147       *
 148       * @return  void
 149       *
 150       * @since   1.7.0
 151       * @see     pcntl_signal()
 152       * @throws  \RuntimeException
 153       */
 154      public static function signal($signal)
 155      {
 156          // Log all signals sent to the daemon.
 157          Log::add('Received signal: ' . $signal, Log::DEBUG);
 158  
 159          // Let's make sure we have an application instance.
 160          if (!is_subclass_of(static::$instance, CliApplication::class)) {
 161              Log::add('Cannot find the application instance.', Log::EMERGENCY);
 162              throw new \RuntimeException('Cannot find the application instance.');
 163          }
 164  
 165          // Fire the onReceiveSignal event.
 166          static::$instance->triggerEvent('onReceiveSignal', array($signal));
 167  
 168          switch ($signal) {
 169              case SIGINT:
 170              case SIGTERM:
 171                  // Handle shutdown tasks
 172                  if (static::$instance->running && static::$instance->isActive()) {
 173                      static::$instance->shutdown();
 174                  } else {
 175                      static::$instance->close();
 176                  }
 177                  break;
 178              case SIGHUP:
 179                  // Handle restart tasks
 180                  if (static::$instance->running && static::$instance->isActive()) {
 181                      static::$instance->shutdown(true);
 182                  } else {
 183                      static::$instance->close();
 184                  }
 185                  break;
 186              case SIGCHLD:
 187                  // A child process has died
 188                  while (static::$instance->pcntlWait($signal, WNOHANG || WUNTRACED) > 0) {
 189                      usleep(1000);
 190                  }
 191                  break;
 192              case SIGCLD:
 193                  while (static::$instance->pcntlWait($signal, WNOHANG) > 0) {
 194                      $signal = static::$instance->pcntlChildExitStatus($signal);
 195                  }
 196                  break;
 197              default:
 198                  break;
 199          }
 200      }
 201  
 202      /**
 203       * Check to see if the daemon is active.  This does not assume that $this daemon is active, but
 204       * only if an instance of the application is active as a daemon.
 205       *
 206       * @return  boolean  True if daemon is active.
 207       *
 208       * @since   1.7.0
 209       */
 210      public function isActive()
 211      {
 212          // Get the process id file location for the application.
 213          $pidFile = $this->config->get('application_pid_file');
 214  
 215          // If the process id file doesn't exist then the daemon is obviously not running.
 216          if (!is_file($pidFile)) {
 217              return false;
 218          }
 219  
 220          // Read the contents of the process id file as an integer.
 221          $fp = fopen($pidFile, 'r');
 222          $pid = fread($fp, filesize($pidFile));
 223          $pid = (int) $pid;
 224          fclose($fp);
 225  
 226          // Check to make sure that the process id exists as a positive integer.
 227          if (!$pid) {
 228              return false;
 229          }
 230  
 231          // Check to make sure the process is active by pinging it and ensure it responds.
 232          if (!posix_kill($pid, 0)) {
 233              // No response so remove the process id file and log the situation.
 234              @ unlink($pidFile);
 235              Log::add('The process found based on PID file was unresponsive.', Log::WARNING);
 236  
 237              return false;
 238          }
 239  
 240          return true;
 241      }
 242  
 243      /**
 244       * Load an object or array into the application configuration object.
 245       *
 246       * @param   mixed  $data  Either an array or object to be loaded into the configuration object.
 247       *
 248       * @return  DaemonApplication  Instance of $this to allow chaining.
 249       *
 250       * @since   1.7.0
 251       */
 252      public function loadConfiguration($data)
 253      {
 254          /*
 255           * Setup some application metadata options.  This is useful if we ever want to write out startup scripts
 256           * or just have some sort of information available to share about things.
 257           */
 258  
 259          // The application author name.  This string is used in generating startup scripts and has
 260          // a maximum of 50 characters.
 261          $tmp = (string) $this->config->get('author_name', 'Joomla Platform');
 262          $this->config->set('author_name', (\strlen($tmp) > 50) ? substr($tmp, 0, 50) : $tmp);
 263  
 264          // The application author email.  This string is used in generating startup scripts.
 265          $tmp = (string) $this->config->get('author_email', '[email protected]');
 266          $this->config->set('author_email', filter_var($tmp, FILTER_VALIDATE_EMAIL));
 267  
 268          // The application name.  This string is used in generating startup scripts.
 269          $tmp = (string) $this->config->get('application_name', 'DaemonApplication');
 270          $this->config->set('application_name', (string) preg_replace('/[^A-Z0-9_-]/i', '', $tmp));
 271  
 272          // The application description.  This string is used in generating startup scripts.
 273          $tmp = (string) $this->config->get('application_description', 'A generic Joomla Platform application.');
 274          $this->config->set('application_description', filter_var($tmp, FILTER_SANITIZE_STRING));
 275  
 276          /*
 277           * Setup the application path options.  This defines the default executable name, executable directory,
 278           * and also the path to the daemon process id file.
 279           */
 280  
 281          // The application executable daemon.  This string is used in generating startup scripts.
 282          $tmp = (string) $this->config->get('application_executable', basename($this->input->executable));
 283          $this->config->set('application_executable', $tmp);
 284  
 285          // The home directory of the daemon.
 286          $tmp = (string) $this->config->get('application_directory', \dirname($this->input->executable));
 287          $this->config->set('application_directory', $tmp);
 288  
 289          // The pid file location.  This defaults to a path inside the /tmp directory.
 290          $name = $this->config->get('application_name');
 291          $tmp = (string) $this->config->get('application_pid_file', strtolower('/tmp/' . $name . '/' . $name . '.pid'));
 292          $this->config->set('application_pid_file', $tmp);
 293  
 294          /*
 295           * Setup the application identity options.  It is important to remember if the default of 0 is set for
 296           * either UID or GID then changing that setting will not be attempted as there is no real way to "change"
 297           * the identity of a process from some user to root.
 298           */
 299  
 300          // The user id under which to run the daemon.
 301          $tmp = (int) $this->config->get('application_uid', 0);
 302          $options = array('options' => array('min_range' => 0, 'max_range' => 65000));
 303          $this->config->set('application_uid', filter_var($tmp, FILTER_VALIDATE_INT, $options));
 304  
 305          // The group id under which to run the daemon.
 306          $tmp = (int) $this->config->get('application_gid', 0);
 307          $options = array('options' => array('min_range' => 0, 'max_range' => 65000));
 308          $this->config->set('application_gid', filter_var($tmp, FILTER_VALIDATE_INT, $options));
 309  
 310          // Option to kill the daemon if it cannot switch to the chosen identity.
 311          $tmp = (bool) $this->config->get('application_require_identity', 1);
 312          $this->config->set('application_require_identity', $tmp);
 313  
 314          /*
 315           * Setup the application runtime options.  By default our execution time limit is infinite obviously
 316           * because a daemon should be constantly running unless told otherwise.  The default limit for memory
 317           * usage is 256M, which admittedly is a little high, but remember it is a "limit" and PHP's memory
 318           * management leaves a bit to be desired :-)
 319           */
 320  
 321          // The maximum execution time of the application in seconds.  Zero is infinite.
 322          $tmp = $this->config->get('max_execution_time');
 323  
 324          if ($tmp !== null) {
 325              $this->config->set('max_execution_time', (int) $tmp);
 326          }
 327  
 328          // The maximum amount of memory the application can use.
 329          $tmp = $this->config->get('max_memory_limit', '256M');
 330  
 331          if ($tmp !== null) {
 332              $this->config->set('max_memory_limit', (string) $tmp);
 333          }
 334  
 335          return $this;
 336      }
 337  
 338      /**
 339       * Execute the daemon.
 340       *
 341       * @return  void
 342       *
 343       * @since   1.7.0
 344       */
 345      public function execute()
 346      {
 347          // Trigger the onBeforeExecute event
 348          $this->triggerEvent('onBeforeExecute');
 349  
 350          // Enable basic garbage collection.
 351          gc_enable();
 352  
 353          Log::add('Starting ' . $this->name, Log::INFO);
 354  
 355          // Set off the process for becoming a daemon.
 356          if ($this->daemonize()) {
 357              // Declare ticks to start signal monitoring. When you declare ticks, PCNTL will monitor
 358              // incoming signals after each tick and call the relevant signal handler automatically.
 359              declare(ticks=1);
 360  
 361              // Start the main execution loop.
 362              while (true) {
 363                  // Perform basic garbage collection.
 364                  $this->gc();
 365  
 366                  // Don't completely overload the CPU.
 367                  usleep(1000);
 368  
 369                  // Execute the main application logic.
 370                  $this->doExecute();
 371              }
 372          } else {
 373              // We were not able to daemonize the application so log the failure and die gracefully.
 374              Log::add('Starting ' . $this->name . ' failed', Log::INFO);
 375          }
 376  
 377          // Trigger the onAfterExecute event.
 378          $this->triggerEvent('onAfterExecute');
 379      }
 380  
 381      /**
 382       * Restart daemon process.
 383       *
 384       * @return  void
 385       *
 386       * @since   1.7.0
 387       */
 388      public function restart()
 389      {
 390          Log::add('Stopping ' . $this->name, Log::INFO);
 391          $this->shutdown(true);
 392      }
 393  
 394      /**
 395       * Stop daemon process.
 396       *
 397       * @return  void
 398       *
 399       * @since   1.7.0
 400       */
 401      public function stop()
 402      {
 403          Log::add('Stopping ' . $this->name, Log::INFO);
 404          $this->shutdown();
 405      }
 406  
 407      /**
 408       * Method to change the identity of the daemon process and resources.
 409       *
 410       * @return  boolean  True if identity successfully changed
 411       *
 412       * @since   1.7.0
 413       * @see     posix_setuid()
 414       */
 415      protected function changeIdentity()
 416      {
 417          // Get the group and user ids to set for the daemon.
 418          $uid = (int) $this->config->get('application_uid', 0);
 419          $gid = (int) $this->config->get('application_gid', 0);
 420  
 421          // Get the application process id file path.
 422          $file = $this->config->get('application_pid_file');
 423  
 424          // Change the user id for the process id file if necessary.
 425          if ($uid && (fileowner($file) != $uid) && (!@ chown($file, $uid))) {
 426              Log::add('Unable to change user ownership of the process id file.', Log::ERROR);
 427  
 428              return false;
 429          }
 430  
 431          // Change the group id for the process id file if necessary.
 432          if ($gid && (filegroup($file) != $gid) && (!@ chgrp($file, $gid))) {
 433              Log::add('Unable to change group ownership of the process id file.', Log::ERROR);
 434  
 435              return false;
 436          }
 437  
 438          // Set the correct home directory for the process.
 439          if ($uid && ($info = posix_getpwuid($uid)) && is_dir($info['dir'])) {
 440              system('export HOME="' . $info['dir'] . '"');
 441          }
 442  
 443          // Change the user id for the process necessary.
 444          if ($uid && (posix_getuid() != $uid) && (!@ posix_setuid($uid))) {
 445              Log::add('Unable to change user ownership of the process.', Log::ERROR);
 446  
 447              return false;
 448          }
 449  
 450          // Change the group id for the process necessary.
 451          if ($gid && (posix_getgid() != $gid) && (!@ posix_setgid($gid))) {
 452              Log::add('Unable to change group ownership of the process.', Log::ERROR);
 453  
 454              return false;
 455          }
 456  
 457          // Get the user and group information based on uid and gid.
 458          $user = posix_getpwuid($uid);
 459          $group = posix_getgrgid($gid);
 460  
 461          Log::add('Changed daemon identity to ' . $user['name'] . ':' . $group['name'], Log::INFO);
 462  
 463          return true;
 464      }
 465  
 466      /**
 467       * Method to put the application into the background.
 468       *
 469       * @return  boolean
 470       *
 471       * @since   1.7.0
 472       * @throws  \RuntimeException
 473       */
 474      protected function daemonize()
 475      {
 476          // Is there already an active daemon running?
 477          if ($this->isActive()) {
 478              Log::add($this->name . ' daemon is still running. Exiting the application.', Log::EMERGENCY);
 479  
 480              return false;
 481          }
 482  
 483          // Reset Process Information
 484          $this->safeMode = !!@ ini_get('safe_mode');
 485          $this->processId = 0;
 486          $this->running = false;
 487  
 488          // Detach process!
 489          try {
 490              // Check if we should run in the foreground.
 491              if (!$this->input->get('f')) {
 492                  // Detach from the terminal.
 493                  $this->detach();
 494              } else {
 495                  // Setup running values.
 496                  $this->exiting = false;
 497                  $this->running = true;
 498  
 499                  // Set the process id.
 500                  $this->processId = (int) posix_getpid();
 501                  $this->parentId = $this->processId;
 502              }
 503          } catch (\RuntimeException $e) {
 504              Log::add('Unable to fork.', Log::EMERGENCY);
 505  
 506              return false;
 507          }
 508  
 509          // Verify the process id is valid.
 510          if ($this->processId < 1) {
 511              Log::add('The process id is invalid; the fork failed.', Log::EMERGENCY);
 512  
 513              return false;
 514          }
 515  
 516          // Clear the umask.
 517          @ umask(0);
 518  
 519          // Write out the process id file for concurrency management.
 520          if (!$this->writeProcessIdFile()) {
 521              Log::add('Unable to write the pid file at: ' . $this->config->get('application_pid_file'), Log::EMERGENCY);
 522  
 523              return false;
 524          }
 525  
 526          // Attempt to change the identity of user running the process.
 527          if (!$this->changeIdentity()) {
 528              // If the identity change was required then we need to return false.
 529              if ($this->config->get('application_require_identity')) {
 530                  Log::add('Unable to change process owner.', Log::CRITICAL);
 531  
 532                  return false;
 533              } else {
 534                  Log::add('Unable to change process owner.', Log::WARNING);
 535              }
 536          }
 537  
 538          // Setup the signal handlers for the daemon.
 539          if (!$this->setupSignalHandlers()) {
 540              return false;
 541          }
 542  
 543          // Change the current working directory to the application working directory.
 544          @ chdir($this->config->get('application_directory'));
 545  
 546          return true;
 547      }
 548  
 549      /**
 550       * This is truly where the magic happens.  This is where we fork the process and kill the parent
 551       * process, which is essentially what turns the application into a daemon.
 552       *
 553       * @return  void
 554       *
 555       * @since   3.0.0
 556       * @throws  \RuntimeException
 557       */
 558      protected function detach()
 559      {
 560          Log::add('Detaching the ' . $this->name . ' daemon.', Log::DEBUG);
 561  
 562          // Attempt to fork the process.
 563          $pid = $this->fork();
 564  
 565          // If the pid is positive then we successfully forked, and can close this application.
 566          if ($pid) {
 567              // Add the log entry for debugging purposes and exit gracefully.
 568              Log::add('Ending ' . $this->name . ' parent process', Log::DEBUG);
 569              $this->close();
 570          } else {
 571              // We are in the forked child process.
 572              // Setup some protected values.
 573              $this->exiting = false;
 574              $this->running = true;
 575  
 576              // Set the parent to self.
 577              $this->parentId = $this->processId;
 578          }
 579      }
 580  
 581      /**
 582       * Method to fork the process.
 583       *
 584       * @return  integer  The child process id to the parent process, zero to the child process.
 585       *
 586       * @since   1.7.0
 587       * @throws  \RuntimeException
 588       */
 589      protected function fork()
 590      {
 591          // Attempt to fork the process.
 592          $pid = $this->pcntlFork();
 593  
 594          // If the fork failed, throw an exception.
 595          if ($pid === -1) {
 596              throw new \RuntimeException('The process could not be forked.');
 597          } elseif ($pid === 0) {
 598              // Update the process id for the child.
 599              $this->processId = (int) posix_getpid();
 600          } else {
 601              // Log the fork in the parent.
 602              // Log the fork.
 603              Log::add('Process forked ' . $pid, Log::DEBUG);
 604          }
 605  
 606          // Trigger the onFork event.
 607          $this->postFork();
 608  
 609          return $pid;
 610      }
 611  
 612      /**
 613       * Method to perform basic garbage collection and memory management in the sense of clearing the
 614       * stat cache.  We will probably call this method pretty regularly in our main loop.
 615       *
 616       * @return  void
 617       *
 618       * @since   1.7.0
 619       */
 620      protected function gc()
 621      {
 622          // Perform generic garbage collection.
 623          gc_collect_cycles();
 624  
 625          // Clear the stat cache so it doesn't blow up memory.
 626          clearstatcache();
 627      }
 628  
 629      /**
 630       * Method to attach the DaemonApplication signal handler to the known signals.  Applications
 631       * can override these handlers by using the pcntl_signal() function and attaching a different
 632       * callback method.
 633       *
 634       * @return  boolean
 635       *
 636       * @since   1.7.0
 637       * @see     pcntl_signal()
 638       */
 639      protected function setupSignalHandlers()
 640      {
 641          // We add the error suppression for the loop because on some platforms some constants are not defined.
 642          foreach (self::$signals as $signal) {
 643              // Ignore signals that are not defined.
 644              if (!\defined($signal) || !\is_int(\constant($signal)) || (\constant($signal) === 0)) {
 645                  // Define the signal to avoid notices.
 646                  Log::add('Signal "' . $signal . '" not defined. Defining it as null.', Log::DEBUG);
 647                  \define($signal, null);
 648  
 649                  // Don't listen for signal.
 650                  continue;
 651              }
 652  
 653              // Attach the signal handler for the signal.
 654              if (!$this->pcntlSignal(\constant($signal), array('DaemonApplication', 'signal'))) {
 655                  Log::add(sprintf('Unable to reroute signal handler: %s', $signal), Log::EMERGENCY);
 656  
 657                  return false;
 658              }
 659          }
 660  
 661          return true;
 662      }
 663  
 664      /**
 665       * Method to shut down the daemon and optionally restart it.
 666       *
 667       * @param   boolean  $restart  True to restart the daemon on exit.
 668       *
 669       * @return  void
 670       *
 671       * @since   1.7.0
 672       */
 673      protected function shutdown($restart = false)
 674      {
 675          // If we are already exiting, chill.
 676          if ($this->exiting) {
 677              return;
 678          } else {
 679              // If not, now we are.
 680              $this->exiting = true;
 681          }
 682  
 683          // If we aren't already daemonized then just kill the application.
 684          if (!$this->running && !$this->isActive()) {
 685              Log::add('Process was not daemonized yet, just halting current process', Log::INFO);
 686              $this->close();
 687          }
 688  
 689          // Only read the pid for the parent file.
 690          if ($this->parentId == $this->processId) {
 691              // Read the contents of the process id file as an integer.
 692              $fp = fopen($this->config->get('application_pid_file'), 'r');
 693              $pid = fread($fp, filesize($this->config->get('application_pid_file')));
 694              $pid = (int) $pid;
 695              fclose($fp);
 696  
 697              // Remove the process id file.
 698              @ unlink($this->config->get('application_pid_file'));
 699  
 700              // If we are supposed to restart the daemon we need to execute the same command.
 701              if ($restart) {
 702                  $this->close(exec(implode(' ', $GLOBALS['argv']) . ' > /dev/null &'));
 703              } else {
 704                  // If we are not supposed to restart the daemon let's just kill -9.
 705                  passthru('kill -9 ' . $pid);
 706                  $this->close();
 707              }
 708          }
 709      }
 710  
 711      /**
 712       * Method to write the process id file out to disk.
 713       *
 714       * @return  boolean
 715       *
 716       * @since   1.7.0
 717       */
 718      protected function writeProcessIdFile()
 719      {
 720          // Verify the process id is valid.
 721          if ($this->processId < 1) {
 722              Log::add('The process id is invalid.', Log::EMERGENCY);
 723  
 724              return false;
 725          }
 726  
 727          // Get the application process id file path.
 728          $file = $this->config->get('application_pid_file');
 729  
 730          if (empty($file)) {
 731              Log::add('The process id file path is empty.', Log::ERROR);
 732  
 733              return false;
 734          }
 735  
 736          // Make sure that the folder where we are writing the process id file exists.
 737          $folder = \dirname($file);
 738  
 739          if (!is_dir($folder) && !Folder::create($folder)) {
 740              Log::add('Unable to create directory: ' . $folder, Log::ERROR);
 741  
 742              return false;
 743          }
 744  
 745          // Write the process id file out to disk.
 746          if (!file_put_contents($file, $this->processId)) {
 747              Log::add('Unable to write process id file: ' . $file, Log::ERROR);
 748  
 749              return false;
 750          }
 751  
 752          // Make sure the permissions for the process id file are accurate.
 753          if (!chmod($file, 0644)) {
 754              Log::add('Unable to adjust permissions for the process id file: ' . $file, Log::ERROR);
 755  
 756              return false;
 757          }
 758  
 759          return true;
 760      }
 761  
 762      /**
 763       * Method to handle post-fork triggering of the onFork event.
 764       *
 765       * @return  void
 766       *
 767       * @since   3.0.0
 768       */
 769      protected function postFork()
 770      {
 771          // Trigger the onFork event.
 772          $this->triggerEvent('onFork');
 773      }
 774  
 775      /**
 776       * Method to return the exit code of a terminated child process.
 777       *
 778       * @param   integer  $status  The status parameter is the status parameter supplied to a successful call to pcntl_waitpid().
 779       *
 780       * @return  integer  The child process exit code.
 781       *
 782       * @see     pcntl_wexitstatus()
 783       * @since   1.7.3
 784       */
 785      protected function pcntlChildExitStatus($status)
 786      {
 787          return pcntl_wexitstatus($status);
 788      }
 789  
 790      /**
 791       * Method to return the exit code of a terminated child process.
 792       *
 793       * @return  integer  On success, the PID of the child process is returned in the parent's thread
 794       *                   of execution, and a 0 is returned in the child's thread of execution. On
 795       *                   failure, a -1 will be returned in the parent's context, no child process
 796       *                   will be created, and a PHP error is raised.
 797       *
 798       * @see     pcntl_fork()
 799       * @since   1.7.3
 800       */
 801      protected function pcntlFork()
 802      {
 803          return pcntl_fork();
 804      }
 805  
 806      /**
 807       * Method to install a signal handler.
 808       *
 809       * @param   integer   $signal   The signal number.
 810       * @param   callable  $handler  The signal handler which may be the name of a user created function,
 811       *                              or method, or either of the two global constants SIG_IGN or SIG_DFL.
 812       * @param   boolean   $restart  Specifies whether system call restarting should be used when this
 813       *                              signal arrives.
 814       *
 815       * @return  boolean  True on success.
 816       *
 817       * @see     pcntl_signal()
 818       * @since   1.7.3
 819       */
 820      protected function pcntlSignal($signal, $handler, $restart = true)
 821      {
 822          return pcntl_signal($signal, $handler, $restart);
 823      }
 824  
 825      /**
 826       * Method to wait on or return the status of a forked child.
 827       *
 828       * @param   integer  &$status  Status information.
 829       * @param   integer  $options  If wait3 is available on your system (mostly BSD-style systems),
 830       *                             you can provide the optional options parameter.
 831       *
 832       * @return  integer  The process ID of the child which exited, -1 on error or zero if WNOHANG
 833       *                   was provided as an option (on wait3-available systems) and no child was available.
 834       *
 835       * @see     pcntl_wait()
 836       * @since   1.7.3
 837       */
 838      protected function pcntlWait(&$status, $options = 0)
 839      {
 840          return pcntl_wait($status, $options);
 841      }
 842  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer