Penggunaan fungsi WEXITSTATUS pada PHP

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 ?

Bài mới nhất

Chủ Đề