def fork_worker(self, job):
        """Invoked by ``work`` method. ``fork_worker`` does the actual forking to create the child
        process that will process the job. It's also responsible for monitoring the child process
        and handling hangs and crashes.

        Finally, the ``process`` method actually processes the job by eventually calling the Job
        instance's ``perform`` method.

        """
        logger.debug('picked up job')
        logger.debug('job details: %s' % job)
        self.before_fork(job)
        self.child = os.fork()
        if self.child:
            self._setproctitle("Forked %s at %s" %
                               (self.child,
                                datetime.datetime.now()))
            logger.info('Forked %s at %s' % (self.child,
                                              datetime.datetime.now()))

            try:
                start = datetime.datetime.now()

                # waits for the result or times out
                while True:
                    pid, status = os.waitpid(self.child, os.WNOHANG)
                    if pid != 0:
                        if os.WIFEXITED(status) and os.WEXITSTATUS(status) == 0:
                            break
                        if os.WIFSTOPPED(status):
                            logger.warning("Process stopped by signal %d" % os.WSTOPSIG(status))
                        else:
                            if os.WIFSIGNALED(status):
                                raise CrashError("Unexpected exit by signal %d" % os.WTERMSIG(status))
                            raise CrashError("Unexpected exit status %d" % os.WEXITSTATUS(status))

                    time.sleep(0.5)

                    now = datetime.datetime.now()
                    if self.timeout and ((now - start).seconds > self.timeout):
                        os.kill(self.child, signal.SIGKILL)
                        os.waitpid(-1, os.WNOHANG)
                        raise TimeoutError("Timed out after %d seconds" % self.timeout)

            except OSError as ose:
                import errno

                if ose.errno != errno.EINTR:
                    raise ose
            except JobError:
                self._handle_job_exception(job)
            finally:
                # If the child process' job called os._exit manually we need to
                # finish the clean up here.
                if self.job():
                    self.done_working(job)

            logger.debug('done waiting')
        else:
            self._setproctitle("Processing %s since %s" %
                               (job,
                                datetime.datetime.now()))
            logger.info('Processing %s since %s' %
                         (job, datetime.datetime.now()))
            self.after_fork(job)

            # re-seed the Python PRNG after forking, otherwise
            # all job process will share the same sequence of
            # random numbers
            random.seed()

            self.process(job)
            os._exit(0)
        self.child = None
Invoked by ``work`` method. ``fork_worker`` does the actual forking to create the child
        process that will process the job. It's also responsible for monitoring the child process
        and handling hangs and crashes.

        Finally, the ``process`` method actually processes the job by eventually calling the Job
        instance's ``perform`` method.