public function fork($callable)
    {
        if (!is_callable($callable)) {
            throw new UnexpectedTypeException($callable, 'callable');
        }

        // allow the system to cleanup before forking
        $this->dispatcher->dispatch(Events::PRE_FORK);

        if (-1 === $pid = pcntl_fork()) {
            throw new ProcessControlException('Unable to fork a new process');
        }

        if (0 === $pid) {
            // reset the list of child processes
            $this->forks = array();

            // setup the shared memory
            $shm = $this->factory->createSharedMemory(null, $this->signal);
            $message = new ExitMessage();

            // phone home on shutdown
            register_shutdown_function(function() use($shm, $message) {
                $status = null;

                try {
                    $shm->send($message, false);
                } catch (\Exception $e) {
                    // probably an error serializing the result
                    $message->setResult(null);
                    $message->setError(Error::fromException($e));

                    $shm->send($message, false);

                    exit(2);
                }
            });

            // dispatch an event so the system knows it's in a new process
            $this->dispatcher->dispatch(Events::POST_FORK);

            if (!$this->debug) {
                ob_start();
            }

            try {
                $result = call_user_func($callable, $shm);

                $message->setResult($result);
                $status = is_integer($result) ? $result : 0;
            } catch (\Exception $e) {
                $message->setError(Error::fromException($e));
                $status = 1;
            }

            if (!$this->debug) {
                $message->setOutput(ob_get_clean());
            }

            exit($status);
        }

        // connect to shared memory
        $shm = $this->factory->createSharedMemory($pid);

        return $this->forks[$pid] = $this->factory->createFork($pid, $shm, $this->debug);
    }