Content dated before 2011-04-08 [UTC] is licensed under CC BY-SA 2.5. Content dated from 2011-04-08 up to but not including 2018-05-02 [UTC] is licensed under CC BY-SA 3.0. Content dated on or after 2018-05-02 [UTC] is licensed under CC BY-SA 4.0. | Privacy
Content dated before 2011-04-08 [UTC] is licensed under CC BY-SA 2.5. Content dated from 2011-04-08 up to but not including 2018-05-02 [UTC] is licensed under CC BY-SA 3.0. Content dated on or after 2018-05-02 [UTC] is licensed under CC BY-SA 4.0. | Privacy
I'm using PCNTL to multiprocess a big script in PHP on an ubuntu server.
Here is the code [ simplified and commented ]
function signalHandler[$signo = null] {
$pid = posix_getpid[];
switch [$signo] {
case SIGTERM:
case SIGINT:
case SIGKILL:
// a process is asked to stop [from user or father]
exit[3];
break;
case SIGCHLD:
case SIGHUP:
// ignore signals
break;
case 10: // signal user 1
// a process finished its work
exit[0];
break;
case 12: // signal user 2
// a process got an error.
exit[3];
break;
default:
// nothing
}
}
public static function run[$nbProcess, $nbTasks, $taskFunc, $args] {
$pid = 0;
// there will be $nbTasks tasks to do, and no more than $nbProcess children must work at the same time
$MAX_PROCESS = $nbProcess;
$pidFather = posix_getpid[];
$data = array[];
pcntl_signal[SIGTERM, "signalHandler"];
pcntl_signal[SIGINT, "signalHandler"];
// pcntl_signal[SIGKILL, "signalHandler"]; // SIGKILL can't be overloaded
pcntl_signal[SIGCHLD, "signalHandler"];
pcntl_signal[SIGHUP, "signalHandler"];
pcntl_signal[10, "signalHandler"]; // user signal 1
pcntl_signal[12, "signalHandler"]; // user signal 2
for [$indexTask = 0; $indexTask < $nbTasks ; $indexTask++] {
$pid = pcntl_fork[];
// Father and new child both read code from here
if [$pid == -1] {
// log error
return false;
} elseif [$pid > 0] {
// We are in father process
// storing child id in an array
$arrayPid[$pid] = $indexTask;
} else {
// We are in child, nothing to do now
}
if [$pid == 0] {
// We are in child process
$pidChild = posix_getpid[];
try {
//$taskFunc is an array containing an object, and the method to call from that object
$ret = [array] call_user_func[$taskFunc, $indexTask, $args];// similar to $ret = [array] $taskFunc[$indexTask, $args];
$returnArray = array[
"tasknb" => $indexTask,
"time" => $timer,
"data" => $ret,
];
} catch[Exception $e] {
// some stuff to exit child
}
$pdata = array[];
array_push[$pdata, $returnArray];
$data_str = serialize[$pdata];
$shm_id = shmop_open[$pidChild, "c", 0644, strlen[$data_str]];
if [!$shm_id] {
// log error
} else {
if[shmop_write[$shm_id, $data_str, 0] != strlen[$data_str]] {
// log error
}
}
// We are in a child and job is done. Let's exit !
posix_kill[$pidChild, 10]; // sending user signal 1 [OK]
pcntl_signal_dispatch[];
} else {
// we are in father process,
// we check number of running children
while [count[$arrayPid] >= $MAX_PROCESS] {
// There are more children than allowed
// waiting for any child to send signal
$pid = pcntl_wait[$status];
// A child sent a signal !
if [$pid == -1] {
// log error
}
if [pcntl_wifexited[$status]] {
$statusChild = pcntl_wexitstatus[$status];
} else
$statusChild = $status;
// father [$pidFather] saw a child [$pid] exiting with status $statusChild [or $status ?]
// ^^^^ ^^^^^^
// [=3] [= random number ?]
if[isset[$arrayPid[$pid]]] {
// father knows this child
unset[$arrayPid[$pid]];
if [$statusChild == 0 || $statusChild == 10 || $statusChild == 255] {
// Child did not report any error
$shm_id = shmop_open[$pid, "a", 0, 0];
if [$shm_id === false]
// log error
else {
$shm_data = unserialize[shmop_read[$shm_id, 0, shmop_size[$shm_id]]];
shmop_delete[$shm_id];
shmop_close[$shm_id];
$data = array_merge[$data, $shm_data];
}
// kill [again] child
posix_kill[$pid, 10];
pcntl_signal_dispatch[];;
}
else {
// Child reported an error
}
}
}
}
}
}
The problem I'm facing is about the value returned by wexitstatus.
To make it simple, there is a father-process, that must create 200 threads.
He makes process one at a time, and wait for a process to finish if there are more than 8 threads actually running.
I added many logs, so I see a child finished its work.
I see it
calling the line posix_kill[$pidChild, 10];
.
I see the signal handler is called with signal user 1
[which results in an exit[0]
].
I see the father awakening, but when he gets the returned code from wexitstatus
, he sees a code 3, and so thinks the child got an error, whereas it has exited with code 0 !!.
The pid is the good child's pid.
Maybe I misunderstand how signals work... Any clue ?