pcntl_fork: parent process stops after child process exits

38 Views Asked by At

When the child process created by pcntl_fork() runs exit(0) also the parent process ends.

I say end and not exist, because I see a strange behavior: the request ends with an empty output (with HTTP code 200), but when I make a new request the previous ones appear in the Xdebug call stack in VSC that are still running.

In this image I made 2 requests:

Xdebug call stack in VSC

Am I doing somthing wrong?

<?php
class Register extends Auth
{

    public function  sendInvite(string $email, bool $isRegistred = false, string $token = ''): bool
    {
        if (!$isRegistred) {
            $this->db->insert('users', ["email" => $email]);
        }
        if (!$token) {
            $code = $this->generateInvite($email);
        } else {
            $code = $token;
        }

        include_once __DIR__ . "/../send-email.php";
        $comapny = COMPANY_NAME;
        $lang = $this->lang;
        $temaplates = $this->db->get('settings', ['value [JSON]'], ['name' => 'templates']);
        $template = $temaplates['value']['invitation_mail'];
        $map = ['email' => $email, 'link' => WEBSITE_URL . '/register/verify/?token=' . $code, 'company' => $comapny];
        $templateParserd = ShortcodeReplacer($template, $map);
        $html = "<!DOCTYPE html><html lang=\"%s\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Invito</title></head><body>%s</body></html>";
        $html = sprintf($html, $lang, $templateParserd);
        $smtp = new SendEmail([$email], "Verify your email", $html);
        $result = $smtp->send();
        if ($result['status'] == 'error') {
            eje($result['message'], EJE_ERROR);
        } else {
            eje("Email inviata con successo", EJE_SUCCESS);
        }
        return false;
    }

    public function generateInvite(string $email)
    {
        // pipe creation
        if (!function_exists('pcntl_fork')) {
            eje('PCNTL functions not available on this PHP installation', EJE_ERROR);
            die;
        }

        $pipe = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);

        if ($pipe === false) {
            eje('Failed to create pipe', EJE_ERROR);
            exit();
        }

        $pid = pcntl_fork();

        if ($pid == -1) {
            die('Failed to fork');
        } elseif ($pid) {
            // Parent process
            fclose($pipe[0]); // Closes the reading side of the pipe

            $data_received = fread($pipe[1], 1024);
            do {
                $data_received = fread($pipe[1], 1024);
                usleep(100);
            } while (!$data_received);

            $code = $data_received;

            fclose($pipe[1]); // Closes the writing side of the pipe


            pcntl_waitpid($pid, $status); // Wait for the specific child process to exit

            return $code;
        } else {
            // Child process
            fclose($pipe[1]); // Closes the writing side of the pipe
            $code = $this->generateInvitationCode($email);
            fwrite($pipe[0], $code);

            fclose($pipe[0]); // Closes the reading side of the pipe
            // return $code;
            exit(0); // Terminate the child process
        }
    }
}

The expected behavior I after the child process exits, the parent process in the method generateInvite() will return $code to sendInvite(), where was called in the first place.

0

There are 0 best solutions below