def terminate(self, *, force: bool=False, timeout: float=30.0,
                  step: float=1.0) -> None:
        '''Stop all scheduled and/or executing tasks, first by asking nicely,
        and then by waiting up to `timeout` seconds before forcefully stopping
        the asyncio event loop.'''

        if isinstance(self.monitor, asyncio.Future):
            Log.debug('cancelling task monitor')
            self.monitor.cancel()

        Log.debug('stopping tasks')
        for task in list(self.running_tasks):
            if task.task.done():
                Log.debug('task %s already stopped', task.name)
                self.running_tasks.discard(task)
            else:
                Log.debug('asking %s to stop', task.name)
                asyncio.ensure_future(task.stop(force=force))

        if timeout > 0 and (self.monitor or self.running_tasks):
            Log.debug('waiting %.1f seconds for remaining tasks (%d)...',
                      timeout, len(self.running_tasks))

            timeout -= step
            fn = functools.partial(self.terminate, force=force,
                                   timeout=timeout, step=step)
            return self.loop.call_later(step, fn)

        if timeout > 0:
            Log.debug('all tasks completed, stopping event loop')
        else:
            Log.debug('timed out waiting for tasks, stopping event loop')

        self.loop.stop()
Stop all scheduled and/or executing tasks, first by asking nicely,
        and then by waiting up to `timeout` seconds before forcefully stopping
        the asyncio event loop.