nur-sery/src/app/launcher.php

83 lines
2.0 KiB
PHP

<?php
namespace nur\sery\app;
use nur\sery\os\proc\Cmd;
use nur\sery\output\msg;
use nur\sery\StateException;
class launcher {
static function launch(string $appClass, ...$args): int {
$cmd = new Cmd([
__DIR__."/../../lib/launch.php",
$appClass,
...$args,
]);
$cmd->addRedir("null");
$cmd->passthru($exitcode);
return $exitcode;
}
static function _start(array $args, Runfile $runfile): bool {
if ($runfile->isLocked()) return false;
$pid = pcntl_fork();
if ($pid == -1) {
# parent, impossible de forker
throw new StateException("unable to fork");
} elseif ($pid) {
# parent, fork ok
return true;
} else {
## child, fork ok
# Créer un groupe de process, pour pouvoir les tuer toutes en même temps
$runfile->tm_startPg();
$exitcode = -776;
try {
# puis lancer la commande
$cmd = new Cmd($args);
#XXX fichier de log?
#XXX charger /g/init.env
$cmd->addSource("/g/init.env");
$cmd->addRedir("null");
$cmd->fork_exec($exitcode);
return true;
} finally {
$runfile->wfStopped($exitcode);
}
}
}
static function _stop(Runfile $runfile): void {
$data = $runfile->read();
$pid = $data["pg_pid"];
if ($pid === null) {
msg::warning("$data[name]: groupe de process inconnu");
return;
}
msg::action("kill $pid");
if (!posix_kill(-$pid, SIGKILL)) {
switch (posix_get_last_error()) {
case PCNTL_ESRCH:
msg::afailure("process inexistant");
break;
case PCNTL_EPERM:
msg::afailure("process non accessible");
break;
case PCNTL_EINVAL:
msg::afailure("signal invalide");
break;
}
return;
}
$timeout = 10;
while ($runfile->tm_isUndead($pid)) {
sleep(1);
if (--$timeout == 0) {
msg::afailure("impossible d'arrêter la tâche");
return;
}
}
$runfile->wfStopped(-778);
msg::asuccess();
}
}