Register a *callback* for the specified *event*. The function will be
    called with the #Job as its first argument. If *once* is #True, the
    listener will be removed after it has been invoked once or when the
    job is re-started.

    Note that if the event already ocurred, *callback* will be called
    immediately!

    # Arguments
    event (str, list of str): The name or multiple names of an event, or None
      to register the callback to be called for any event.
    callback (callable): A function.
    once (bool): Whether the callback is valid only once.

def add_listener(self, event, callback, once=False):
    """
    Register a *callback* for the specified *event*. The function will be
    called with the #Job as its first argument. If *once* is #True, the
    listener will be removed after it has been invoked once or when the
    job is re-started.

    Note that if the event already ocurred, *callback* will be called
    immediately!

    # Arguments
    event (str, list of str): The name or multiple names of an event, or None
      to register the callback to be called for any event.
    callback (callable): A function.
    once (bool): Whether the callback is valid only once.
    """

    if not callable(callback):
      raise TypeError('callback must be callable')
    if isinstance(event, str):
      event = [event]
    for evn in event:
      if evn not in self.__listeners:
        raise ValueError('invalid event type: {0!r}'.format(evn))
    for evn in event:
      event_passed = False
      with synchronized(self):
        event_passed = (evn in self.__event_set)
        if not (once and event_passed):
          self.__listeners[evn].append(Job._Listener(callback, once))

    # If the event already happened, we'll invoke the callback
    # immediately to make up for what it missed.
    if event_passed:
      callback(self, event)