/** * Start Forking * * @param ProcessInterface $ProcessObject * @final */ public final function Run($ProcessObject) { // Check for ProcessObject existence if (!$ProcessObject instanceof ProcessInterface) { throw new \Exception("Invalid Proccess object", E_ERROR); } // Set class property $this->ProcessObject = $ProcessObject; $pid = posix_getpid(); if ($this->PIDDir) { $this->Logger->debug("Touch process PID file {$pid}"); @touch("{$this->PIDDir}/{$pid}"); } $this->Logger->debug("Executing 'OnStartForking' routine"); // Run routines before threading $this->ProcessObject->OnStartForking(); $this->Logger->debug("'OnStartForking' successfully executed."); if (count($this->ProcessObject->ThreadArgs) != 0) { // Add handlers to signals $this->SignalHandler->SetSignalHandlers(); $this->Logger->debug("Executing ProcessObject::ForkThreads()"); // Start Threading $this->ForkThreads(); // Wait while threads working $iteration = 1; while (true) { if (count($this->PIDs) == 0) { break; } if ($this->ChildProcessExecTimeLimit != 0) { foreach ($this->PIDs as $ipid => $ipid_info) { if ($ipid_info['start_time'] + $this->ChildProcessExecTimeLimit < time()) { $this->Logger->error(sprintf(_("Maximum execution time of %s seconds exceeded in %s. Killing process..."), $this->ChildProcessExecTimeLimit, get_class($this->ProcessObject) . "(Child PID: {$ipid_info['pid']})")); posix_kill($ipid, SIGKILL); } } } if ($iteration++ == 10) { $this->Logger->debug("Goin to MPWL. PIDs(" . implode(", ", array_keys($this->PIDs)) . ")"); // Zomby does not need $pid = 1; while ($pid > 0) { $pid = pcntl_wait($status, WNOHANG | WUNTRACED); if ($pid > 0) { $this->Logger->debug("MPWL: pcntl_wait() from child with PID# {$pid} (Exit code: {$status})"); foreach ((array) $this->PIDs as $ipid => $ipid_info) { if ($ipid == $pid) { if ($this->PIDDir) { $this->Logger->debug("Delete thread PID file {$pid}"); @unlink($this->PIDDir . "/" . $pid); } unset($this->PIDs[$ipid]); } } } } sleep(2); $this->ForkThreads(); foreach ($this->PIDs as $ipid => $ipid_info) { $res = posix_kill($ipid, 0); $this->Logger->debug("MPWL: Sending 0 signal to {$ipid} = " . intval($res)); if ($res === false) { $this->Logger->debug("MPWL: Deleting '{$ipid}' from PIDs queue"); if ($this->PIDDir) { $this->Logger->debug("Delete thread PID file {$ipid}"); @unlink($this->PIDDir . "/" . $ipid); } unset($this->PIDs[$ipid]); } } $iteration = 1; } } } else { $this->Logger->debug("ProcessObject::ThreadArgs is empty. Nothing to do."); } $pid = posix_getpid(); if ($this->PIDDir) { $this->Logger->debug("Delete Process PID file {$pid}"); @unlink("{$this->PIDDir}/{$pid}"); } $this->Logger->debug("All childs exited. Executing OnEndForking routine"); // Run routines after forking $this->ProcessObject->OnEndForking(); $this->Logger->debug("Main process completed. Exiting..."); exit; }