processManagerFilePath = $processManagerFilePath; } /* * @brief Run a process */ public function runProcess($cmd, $runningPath, $envArray, $postProcessCmd, $batchEnabled) { $process = new ProcessClass($cmd, $postProcessCmd); if (!$process->run($runningPath, $envArray)) return array("success" => false, "message" => "Cannot run the process"); $res = $this->concurrentAccessProcessManagerFile(array($this,'addProcessInProcessManagerFile'),$process); if (!$res['success']) { $process->stop(); return $res; } //Save process id in running path chdir($runningPath); file_put_contents("process_id", $res['result']['id'].PHP_EOL); $process->waitEndOfProcess(array($this,'waitEndOfProcess'),$batchEnabled); return $this->getProcessInfo($res['result']['id'],true); } /* * @brief Kill a process */ public function killProcess($id) { $res = $this->concurrentAccessProcessManagerFile(array($this,'killProcessFromId'),$id); return $res; } /* * @brief Get info about a process */ public function getProcessInfo($id,$update) { $res = $this->concurrentAccessProcessManagerFile(array($this,'getProcessInfoFromId'),array('id' => $id, 'update' => $update)); if (!$res['success']) return $res; return $res['result']; } /* * @brief Delete a process */ public function deleteProcess($id) { $res = $this->concurrentAccessProcessManagerFile(array($this,'deleteProcessFromId'),$id); return $res; } /* * @brief Wait the end of the execution (or the timeout) of a process. */ public function waitEndOfProcess($process, $batchEnabled) { if ($batchEnabled) if (time() - $process->getRunningStart() > KernelConfigClass::getTimeToBatchMode()) return false; return true; } /* * @brief Add a process in the manager file */ private function addProcessInProcessManagerFile($dom, $process) { $processId = "process_".CommonClass::generateRandomString(6).'_'.time().'_'.$process->getPID(); $processNode = $dom->createElement("process"); $processNode->setAttribute('xml:id', $processId); $dom->documentElement->appendChild($processNode); $this->updateProcessInProcessNode($dom, $processNode, $process); $dom->save($this->processManagerFilePath); return $this->getProcessInfoFromNode($processNode); } /* * @brief Protection for concurrent access to the manager file */ private function concurrentAccessProcessManagerFile($callback, $additionalParams) { $lockFile = $this->processManagerFilePath.".lockfile"; $fp = fopen($lockFile, "w+"); if ($fp === false) return array('success' => false, 'message' => 'Cannot open process manager lock file'); $res = true; if (flock($fp, LOCK_EX)) { if (!file_exists($this->processManagerFilePath)) $res = $this->createProcessManagerFile(); if ($res) { $dom = new DOMDocument("1.0","UTF-8"); $dom->preserveWhiteSpace = false; $dom->formatOutput = true; $res = $dom->load($this->processManagerFilePath); if ($res) $func_res = call_user_func($callback,$dom,$additionalParams); } } else $res = false; fclose($fp); if ($res) return array('success' => true, 'result' => $func_res); return array('success' => false, 'message' => 'Error during the concurrent access of the process manager file'); } /* * @brief Create a new manager file */ private function createProcessManagerFile() { $dom = new DOMDocument("1.0","UTF-8"); $dom->preserveWhiteSpace = false; $dom->formatOutput = true; $rootNode = $dom->createElement("processlist"); $dom->appendChild($rootNode); return $dom->save($this->processManagerFilePath); } /* * @brief Update process info if a node of the manager file */ private function updateProcessInProcessNode($dom, $processNode, $process) { $this->updateProcessStatusToNode($dom,$processNode,"cmd",$process->getCommand()); $this->updateProcessStatusToNode($dom,$processNode,"outputfile",$process->getOutputFile()); $this->updateProcessStatusToNode($dom,$processNode,"exitcodefile",$process->getExitCodeFile()); $this->updateProcessStatusToNode($dom,$processNode,"processfile",$process->getProcessFile()); $this->updateProcessStatusToNode($dom,$processNode,"exitcode",$process->getExitCode()); $this->updateProcessStatusToNode($dom,$processNode,"PID",$process->getPID()); $this->updateProcessStatusToNode($dom,$processNode,"runningpath",$process->getRunningPath()); $this->updateProcessStatusToNode($dom,$processNode,"runningstart",$process->getRunningStart()); $this->updateProcessStatusToNode($dom,$processNode,"isrunning",$process->isRunning() ? "true" : "false"); $this->updateProcessStatusToNode($dom,$processNode,"lastupdate",time()); } /* * @brief Extract process info from a node */ private function getProcessInfoFromNode($processNode) { return array( "id" => $processNode->getAttribute("xml:id"), "cmd" => $this->getNodeValueFromNode($processNode, "cmd"), "outputfile" => $this->getNodeValueFromNode($processNode, "outputfile"), "exitcodefile" => $this->getNodeValueFromNode($processNode, "exitcodefile"), "processfile" => $this->getNodeValueFromNode($processNode, "processfile"), "exitcode" => $this->getNodeValueFromNode($processNode, "exitcode"), "PID" => $this->getNodeValueFromNode($processNode, "PID"), "runningpath" => $this->getNodeValueFromNode($processNode, "runningpath"), "runningstart" => $this->getNodeValueFromNode($processNode, "runningstart"), "isrunning" => ($this->getNodeValueFromNode($processNode, "isrunning") == "true"), "iskilled" => ($this->getNodeValueFromNode($processNode, "iskilled") == "true"), "lastupdate" => $this->getNodeValueFromNode($processNode, "lastupdate") ); } /* * @brief Get a node by tag name and by a given parent node */ private function getNodeFromNode($parentNode, $name) { $nodes = $parentNode->getElementsByTagName($name); if ($nodes->length > 0) return $nodes->item(0); return NULL; } /* * @brief Get the value of a node by tag name and by a given parent node */ private function getNodeValueFromNode($parentNode, $name) { $node = $this->getNodeFromNode($parentNode, $name); if ($node == NULL) return NULL; return $node->nodeValue; } /* * @brief Update a process info in a process node */ private function updateProcessStatusToNode($dom, $parentNode, $name, $value) { $node = $this->getNodeFromNode($parentNode, $name); if ($node == NULL) { $node = $dom->createElement($name); $parentNode->appendChild($node); } $node->nodeValue = htmlspecialchars($value); return $node; } /* * @brief Create a Process from node */ private function getProcessFromNode($processNode) { $cmd = $this->getNodeValueFromNode($processNode, "cmd"); if ($cmd == NULL) return NULL; $process = new ProcessClass($cmd); if ($process === false) return NULL; $processInfo = $this->getProcessInfoFromNode($processNode); $outputFile = $processInfo["outputfile"]; $processFile = $processInfo["processfile"]; $exitCodeFile = $processInfo["exitcodefile"]; $pid = $processInfo["PID"]; $runningPath = $processInfo["runningpath"]; $runningStart = $processInfo["runningstart"]; $process->init($outputFile, $exitCodeFile, $processFile, $pid, $runningPath, $runningStart); return $process; } // Next element sibling for DOMElement function fNextEltSibling($node) { while ($node && ($node = $node->nextSibling)) { if ($node instanceof DOMElement) { break; } } return $node; } /* * @brief Get information about a process */ private function getProcessInfoFromId($dom, $args) { $id = $args['id']; $update = $args['update']; $processNodes = $dom->documentElement->getElementsByTagName("process"); $processNode = $processNodes->item(0); while ($processNode) { if ($processNode->getAttribute('xml:id') == $id) { if ($update) { $process = $this->getProcessFromNode($processNode); if (!isset($process)) return array('success' => false, 'message' => 'Error to retrieve process info'); $this->updateProcessInProcessNode($dom, $processNode, $process); $dom->save($this->processManagerFilePath); } $processInfo = $this->getProcessInfoFromNode($processNode); return array('success' => true, 'result' => $processInfo); } $processNode = $this->fNextEltSibling($processNode); } return array('success' => false, 'message' => 'Cannot get process from id'); } /* * @brief Delete a process */ private function deleteProcessFromId($dom, $id) { $processNodes = $dom->documentElement->getElementsByTagName("process"); $processNode = $processNodes->item(0); while ($processNode) { if ($processNode->getAttribute('xml:id') == $id) { $process = $this->getProcessFromNode($processNode); if (!isset($process)) return array('success' => false, 'message' => 'Error to retrieve process info'); $process->delete(); $dom->documentElement->removeChild($processNode); $dom->save($this->processManagerFilePath); return array('success' => true); } $processNode = $this->fNextEltSibling($processNode); } return array('success' => false, 'message' => 'Cannot get process from id'); } /* * @brief Kill a process */ private function killProcessFromId($dom, $id) { $processNodes = $dom->documentElement->getElementsByTagName("process"); $processNode = $processNodes->item(0); while ($processNode) { if ($processNode->getAttribute('xml:id') == $id) { $process = $this->getProcessFromNode($processNode); if (!isset($process)) return array('success' => false, 'message' => 'Error to retrieve process info'); $this->updateProcessStatusToNode($dom,$processNode,"isrunning","false"); $this->updateProcessStatusToNode($dom,$processNode,"iskilled","true"); if ($process->stop()) { $dom->save($this->processManagerFilePath); return array('success' => true); } return array('success' => false, 'message' => 'Cannot process from id'); } $processNode = $this->fNextEltSibling($processNode); } return array('success' => false, 'message' => 'Cannot kill process from id '.$id); } } ?>