U
    lufҏ                     @   sX  d Z ddlZddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlZddlmZ ddlmZmZmZmZmZ ddlmZ ddlmZmZmZ ddlZddlmZmZmZmZm Z m!Z!m"Z"m#Z# ej$rddlm%Z%m&Z&m'Z' dd	l(m)Z) ne*Z)G d
d de)Z+e!dZ,e!de+dZ-G dd deZ.G dd de*Z/G dd de*Z0dS )a  An I/O event loop for non-blocking sockets.

In Tornado 6.0, `.IOLoop` is a wrapper around the `asyncio` event loop, with a
slightly different interface. The `.IOLoop` interface is now provided primarily
for backwards compatibility; new code should generally use the `asyncio` event
loop interface directly. The `IOLoop.current` class method provides the
`IOLoop` instance corresponding to the running `asyncio` event loop.

    N)isawaitable)Future	is_futurechain_futurefuture_set_exc_infofuture_add_done_callback)app_log)ConfigurableTimeoutErrorimport_object)UnionAnyTypeOptionalCallableTypeVarTuple	Awaitable)DictListSet)Protocolc                   @   s(   e Zd ZedddZddddZdS )_Selectablereturnc                 C   s   d S N selfr   r   2/tmp/pip-unpacked-wheel-bmg6zs32/tornado/ioloop.pyfileno=   s    z_Selectable.filenoNc                 C   s   d S r   r   r   r   r   r   close@   s    z_Selectable.close)__name__
__module____qualname__intr    r!   r   r   r   r   r   <   s   r   _T_S)boundc                       s  e Zd ZdZdZdZdZdZe Z	e
 Zededd fd	d
Zed dddZddddZeddddZejed dddZejedpeed  dddZedqeed  dddZddddZddddZeddddZeddddZddd d!Zeee dd"d#Zeee dd$d%Z dredd&d'd(Z!dsedd*d+d,Z"eje#e$e#e#gdf e#dd-d.d/Z%eje&e$e&e#gdf e#dd-d0d/Z%e'e#e(f e$d1 e#dd-d2d/Z%e'e#e(f e#dd3d4d5Z)e'e#e(f dd6d7d8Z*ddd9d:Z+ddd;d<Z,dte$ee- ed=d>d?Z.e-dd@dAZ/e'e-e0j1f e$eee2dBdCdDZ3e-e$eee2dEdFdGZ4e-e$eee2dHdIdJZ5e2ddKdLdMZ6e$eeddNdOdPZ7e$eeddNdQdRZ8e$eeddNdSdTZ9dUe$dVgdf ddWdXdYZ:ee;j<j= e$dZe>f edVd[d\d]Z?e;j<j=dd^d_d`Z@e$g ef ddadbdcZAeBddddedfZCe'e#e(f eDe#e'e#e(f f d6dgdhZEe'e#e(f dd6didjZFeBddkdldmZGeBddkdndoZH  ZIS )uIOLoopa  An I/O event loop.

    As of Tornado 6.0, `IOLoop` is a wrapper around the `asyncio` event loop.

    Example usage for a simple TCP server:

    .. testcode::

        import asyncio
        import errno
        import functools
        import socket

        import tornado
        from tornado.iostream import IOStream

        async def handle_connection(connection, address):
            stream = IOStream(connection)
            message = await stream.read_until_close()
            print("message from client:", message.decode().strip())

        def connection_ready(sock, fd, events):
            while True:
                try:
                    connection, address = sock.accept()
                except BlockingIOError:
                    return
                connection.setblocking(0)
                io_loop = tornado.ioloop.IOLoop.current()
                io_loop.spawn_callback(handle_connection, connection, address)

        async def main():
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            sock.setblocking(0)
            sock.bind(("", 8888))
            sock.listen(128)

            io_loop = tornado.ioloop.IOLoop.current()
            callback = functools.partial(connection_ready, sock)
            io_loop.add_handler(sock.fileno(), callback, io_loop.READ)
            await asyncio.Event().wait()

        if __name__ == "__main__":
            asyncio.run(main())

    .. testoutput::
       :hide:

    Most applications should not attempt to construct an `IOLoop` directly,
    and instead initialize the `asyncio` event loop and use `IOLoop.current()`.
    In some cases, such as in test frameworks when initializing an `IOLoop`
    to be run in a secondary thread, it may be appropriate to construct
    an `IOLoop` with ``IOLoop(make_current=False)``.

    In general, an `IOLoop` cannot survive a fork or be shared across processes
    in any way. When multiple processes are being used, each process should
    create its own `IOLoop`, which also implies that any objects which depend on
    the `IOLoop` (such as `.AsyncHTTPClient`) must also be created in the child
    processes. As a guideline, anything that starts processes (including the
    `tornado.process` and `multiprocessing` modules) should do so as early as
    possible, ideally the first thing the application does after loading its
    configuration, and *before* any calls to `.IOLoop.start` or `asyncio.run`.

    .. versionchanged:: 4.2
       Added the ``make_current`` keyword argument to the `IOLoop`
       constructor.

    .. versionchanged:: 5.0

       Uses the `asyncio` event loop by default. The ``IOLoop.configure`` method
       cannot be used on Python 3 except to redundantly specify the `asyncio`
       event loop.

    .. versionchanged:: 6.3
       ``make_current=True`` is now the default when creating an IOLoop -
       previously the default was to make the event loop current if there wasn't
       already a current one.
    r            z$Union[None, str, Type[Configurable]]N)implkwargsr   c                    sR   ddl m} t|trt|}t|tr:t||s:tdtt	| j
|f| d S )Nr   )BaseAsyncIOLoopz5only AsyncIOLoop is allowed when asyncio is available)tornado.platform.asyncior/   
isinstancestrr   type
issubclassRuntimeErrorsuperr)   	configure)clsr-   r.   r/   	__class__r   r   r7      s    
zIOLoop.configurer   c                   C   s   t  S )aK  Deprecated alias for `IOLoop.current()`.

        .. versionchanged:: 5.0

           Previously, this method returned a global singleton
           `IOLoop`, in contrast with the per-thread `IOLoop` returned
           by `current()`. In nearly all cases the two were the same
           (when they differed, it was generally used from non-Tornado
           threads to communicate back to the main thread's `IOLoop`).
           This distinction is not present in `asyncio`, so in order
           to facilitate integration with that package `instance()`
           was changed to be an alias to `current()`. Applications
           using the cross-thread communications aspect of
           `instance()` should instead set their own global variable
           to point to the `IOLoop` they want to use.

        .. deprecated:: 5.0
        )r)   currentr   r   r   r   instance   s    zIOLoop.instancec                 C   s   |    dS )a`  Deprecated alias for `make_current()`.

        .. versionchanged:: 5.0

           Previously, this method would set this `IOLoop` as the
           global singleton used by `IOLoop.instance()`. Now that
           `instance()` is an alias for `current()`, `install()`
           is an alias for `make_current()`.

        .. deprecated:: 5.0
        N)make_currentr   r   r   r   install   s    zIOLoop.installc                   C   s   t   dS )ak  Deprecated alias for `clear_current()`.

        .. versionchanged:: 5.0

           Previously, this method would clear the `IOLoop` used as
           the global singleton by `IOLoop.instance()`. Now that
           `instance()` is an alias for `current()`,
           `clear_instance()` is an alias for `clear_current()`.

        .. deprecated:: 5.0

        N)r)   clear_currentr   r   r   r   clear_instance   s    zIOLoop.clear_instancec                   C   s   d S r   r   r   r   r   r   r;      s    zIOLoop.currentT)r<   r   c                 C   s   d S r   r   r<   r   r   r   r;      s    c                 C   s   zt  }W n0 tk
r<   | s&Y dS t  }t | Y nX ztj| W S  tk
rz   | rrddlm	} | }nd}Y nX |S )aC  Returns the current thread's `IOLoop`.

        If an `IOLoop` is currently running or has been marked as
        current by `make_current`, returns that instance.  If there is
        no current `IOLoop` and ``instance`` is true, creates one.

        .. versionchanged:: 4.1
           Added ``instance`` argument to control the fallback to
           `IOLoop.instance()`.
        .. versionchanged:: 5.0
           On Python 3, control of the current `IOLoop` is delegated
           to `asyncio`, with this and other methods as pass-through accessors.
           The ``instance`` argument now controls whether an `IOLoop`
           is created automatically when there is none, instead of
           whether we fall back to `IOLoop.instance()` (which is now
           an alias for this method). ``instance=False`` is deprecated,
           since even if we do not create an `IOLoop`, this method
           may initialize the asyncio loop.

        .. deprecated:: 6.2
           It is deprecated to call ``IOLoop.current()`` when no `asyncio`
           event loop is running.
        Nr   )AsyncIOMainLoop)
asyncioZget_event_loopr5   Znew_event_loopZset_event_loopr)   _ioloop_for_asyncioKeyErrorr0   rB   )r<   ZlooprB   r;   r   r   r   r;      s    
c                 C   s   t jdtdd |   dS )a  Makes this the `IOLoop` for the current thread.

        An `IOLoop` automatically becomes current for its thread
        when it is started, but it is sometimes useful to call
        `make_current` explicitly before starting the `IOLoop`,
        so that code run at startup time can find the right
        instance.

        .. versionchanged:: 4.1
           An `IOLoop` created while there is no current `IOLoop`
           will automatically become current.

        .. versionchanged:: 5.0
           This method also sets the current `asyncio` event loop.

        .. deprecated:: 6.2
           Setting and clearing the current event loop through Tornado is
           deprecated. Use ``asyncio.set_event_loop`` instead if you need this.
        z6make_current is deprecated; start the event loop first   
stacklevelN)warningswarnDeprecationWarning_make_currentr   r   r   r   r=   %  s    zIOLoop.make_currentc                 C   s
   t  d S r   NotImplementedErrorr   r   r   r   rL   @  s    zIOLoop._make_currentc                   C   s   t jdtdd t  dS )zClears the `IOLoop` for the current thread.

        Intended primarily for use by test frameworks in between tests.

        .. versionchanged:: 5.0
           This method also clears the current `asyncio` event loop.
        .. deprecated:: 6.2
        zclear_current is deprecatedrF   rG   N)rI   rJ   rK   r)   _clear_currentr   r   r   r   r?   D  s    
zIOLoop.clear_currentc                  C   s    t jdd} | d k	r|   d S )NFrA   )r)   r;   _clear_current_hook)oldr   r   r   rO   U  s    zIOLoop._clear_currentc                 C   s   dS )zInstance method called when an IOLoop ceases to be current.

        May be overridden by subclasses as a counterpart to make_current.
        Nr   r   r   r   r   rP   [  s    zIOLoop._clear_current_hookc                 C   s   t S r   )r)   )r8   r   r   r   configurable_baseb  s    zIOLoop.configurable_basec                 C   s   ddl m} |S )Nr   )AsyncIOLoop)r0   rS   )r8   rS   r   r   r   configurable_defaultf  s    zIOLoop.configurable_default)r=   r   c                 C   s   |r|    d S r   )rL   )r   r=   r   r   r   
initializel  s    zIOLoop.initializeF)all_fdsr   c                 C   s
   t  dS )a  Closes the `IOLoop`, freeing any resources used.

        If ``all_fds`` is true, all file descriptors registered on the
        IOLoop will be closed (not just the ones created by the
        `IOLoop` itself).

        Many applications will only use a single `IOLoop` that runs for the
        entire lifetime of the process.  In that case closing the `IOLoop`
        is not necessary since everything will be cleaned up when the
        process exits.  `IOLoop.close` is provided mainly for scenarios
        such as unit tests, which create and destroy a large number of
        ``IOLoops``.

        An `IOLoop` must be completely stopped before it can be closed.  This
        means that `IOLoop.stop()` must be called *and* `IOLoop.start()` must
        be allowed to return before attempting to call `IOLoop.close()`.
        Therefore the call to `close` will usually appear just after
        the call to `start` rather than near the call to `stop`.

        .. versionchanged:: 3.1
           If the `IOLoop` implementation supports non-integer objects
           for "file descriptors", those objects will have their
           ``close`` method when ``all_fds`` is true.
        NrM   )r   rV   r   r   r   r!   p  s    zIOLoop.close)fdhandlereventsr   c                 C   s   d S r   r   r   rW   rX   rY   r   r   r   add_handler  s    zIOLoop.add_handlerc                 C   s   d S r   r   rZ   r   r   r   r[     s    ).Nc                 C   s
   t  dS )a+  Registers the given handler to receive the given events for ``fd``.

        The ``fd`` argument may either be an integer file descriptor or
        a file-like object with a ``fileno()`` and ``close()`` method.

        The ``events`` argument is a bitwise or of the constants
        ``IOLoop.READ``, ``IOLoop.WRITE``, and ``IOLoop.ERROR``.

        When an event occurs, ``handler(fd, events)`` will be run.

        .. versionchanged:: 4.0
           Added the ability to pass file-like objects in addition to
           raw file descriptors.
        NrM   rZ   r   r   r   r[     s    )rW   rY   r   c                 C   s
   t  dS )zChanges the events we listen for ``fd``.

        .. versionchanged:: 4.0
           Added the ability to pass file-like objects in addition to
           raw file descriptors.
        NrM   )r   rW   rY   r   r   r   update_handler  s    zIOLoop.update_handler)rW   r   c                 C   s
   t  dS )zStop listening for events on ``fd``.

        .. versionchanged:: 4.0
           Added the ability to pass file-like objects in addition to
           raw file descriptors.
        NrM   r   rW   r   r   r   remove_handler  s    zIOLoop.remove_handlerc                 C   s
   t  dS )zStarts the I/O loop.

        The loop will run until one of the callbacks calls `stop()`, which
        will make the loop stop after the current event iteration completes.
        NrM   r   r   r   r   start  s    zIOLoop.startc                 C   s
   t  dS )a  Stop the I/O loop.

        If the event loop is not currently running, the next call to `start()`
        will return immediately.

        Note that even after `stop` has been called, the `IOLoop` is not
        completely stopped until `IOLoop.start` has also returned.
        Some work that was scheduled before the call to `stop` may still
        be run before the `IOLoop` shuts down.
        NrM   r   r   r   r   stop  s    zIOLoop.stop)functimeoutr   c                    s   dgdd fdd} | |dk	rVddfdd} | |}  |dk	rp| d dk	std  sd  std| d 	 S )	a  Starts the `IOLoop`, runs the given function, and stops the loop.

        The function must return either an awaitable object or
        ``None``. If the function returns an awaitable object, the
        `IOLoop` will run until the awaitable is resolved (and
        `run_sync()` will return the awaitable's result). If it raises
        an exception, the `IOLoop` will stop and the exception will be
        re-raised to the caller.

        The keyword-only argument ``timeout`` may be used to set
        a maximum duration for the function.  If the timeout expires,
        a `asyncio.TimeoutError` is raised.

        This method is useful to allow asynchronous calls in a
        ``main()`` function::

            async def main():
                # do stuff...

            if __name__ == '__main__':
                IOLoop.current().run_sync(main)

        .. versionchanged:: 4.3
           Returning a non-``None``, non-awaitable value is now an error.

        .. versionchanged:: 5.0
           If a timeout occurs, the ``func`` coroutine will be cancelled.

        .. versionchanged:: 6.2
           ``tornado.util.TimeoutError`` is now an alias to ``asyncio.TimeoutError``.
        Nr   c                     s   z&  } | d k	r$ddl m} || } W n0 tk
rV   t }|d< t|t  Y n,X t| rj| d< nt }|d< ||  d d k	st	
d fdd d S )Nr   )convert_yieldedc                    s      S r   )r`   )futurer   r   r   <lambda>      z.IOLoop.run_sync.<locals>.run.<locals>.<lambda>)Ztornado.genrc   	Exceptionr   r   sysexc_infor   Z
set_resultAssertionError
add_future)resultrc   Zfutra   future_cellr   r   r   run  s     

zIOLoop.run_sync.<locals>.runc                      s(    d d k	st  d  s$  d S )Nr   )rj   cancelr`   r   )rn   r   r   r   timeout_callback  s    z)IOLoop.run_sync.<locals>.timeout_callbackr   z$Operation timed out after %s seconds)
add_callbackadd_timeouttimer_   remove_timeoutrj   Z	cancelleddoner
   rl   )r   ra   rb   ro   rq   Ztimeout_handler   rm   r   run_sync  s     
	
zIOLoop.run_syncc                 C   s   t   S )a  Returns the current time according to the `IOLoop`'s clock.

        The return value is a floating-point number relative to an
        unspecified time in the past.

        Historically, the IOLoop could be customized to use e.g.
        `time.monotonic` instead of `time.time`, but this is not
        currently supported and so this method is equivalent to
        `time.time`.

        )rt   r   r   r   r   rt     s    zIOLoop.time)deadlinecallbackargsr.   r   c                 O   s\   t |tjr | j||f||S t |tjrL| j|  |  |f||S td| dS )a  Runs the ``callback`` at the time ``deadline`` from the I/O loop.

        Returns an opaque handle that may be passed to
        `remove_timeout` to cancel.

        ``deadline`` may be a number denoting a time (on the same
        scale as `IOLoop.time`, normally `time.time`), or a
        `datetime.timedelta` object for a deadline relative to the
        current time.  Since Tornado 4.0, `call_later` is a more
        convenient alternative for the relative case since it does not
        require a timedelta object.

        Note that it is not safe to call `add_timeout` from other threads.
        Instead, you must use `add_callback` to transfer control to the
        `IOLoop`'s thread, and then call `add_timeout` from there.

        Subclasses of IOLoop must implement either `add_timeout` or
        `call_at`; the default implementations of each will call
        the other.  `call_at` is usually easier to implement, but
        subclasses that wish to maintain compatibility with Tornado
        versions prior to 4.0 must use `add_timeout` instead.

        .. versionchanged:: 4.0
           Now passes through ``*args`` and ``**kwargs`` to the callback.
        Unsupported deadline %rN)	r1   numbersRealcall_atdatetime	timedeltart   total_seconds	TypeError)r   rx   ry   rz   r.   r   r   r   rs   +  s      zIOLoop.add_timeout)delayry   rz   r.   r   c                 O   s   | j |  | |f||S )a  Runs the ``callback`` after ``delay`` seconds have passed.

        Returns an opaque handle that may be passed to `remove_timeout`
        to cancel.  Note that unlike the `asyncio` method of the same
        name, the returned object does not have a ``cancel()`` method.

        See `add_timeout` for comments on thread-safety and subclassing.

        .. versionadded:: 4.0
        )r~   rt   )r   r   ry   rz   r.   r   r   r   
call_laterT  s    zIOLoop.call_later)whenry   rz   r.   r   c                 O   s   | j ||f||S )a  Runs the ``callback`` at the absolute time designated by ``when``.

        ``when`` must be a number using the same reference point as
        `IOLoop.time`.

        Returns an opaque handle that may be passed to `remove_timeout`
        to cancel.  Note that unlike the `asyncio` method of the same
        name, the returned object does not have a ``cancel()`` method.

        See `add_timeout` for comments on thread-safety and subclassing.

        .. versionadded:: 4.0
        )rs   )r   r   ry   rz   r.   r   r   r   r~   c  s    zIOLoop.call_at)rb   r   c                 C   s
   t  dS )zCancels a pending timeout.

        The argument is a handle as returned by `add_timeout`.  It is
        safe to call `remove_timeout` even if the callback has already
        been run.
        NrM   )r   rb   r   r   r   ru   u  s    zIOLoop.remove_timeout)ry   rz   r.   r   c                 O   s
   t  dS )a  Calls the given callback on the next I/O loop iteration.

        It is safe to call this method from any thread at any time,
        except from a signal handler.  Note that this is the **only**
        method in `IOLoop` that makes this thread-safety guarantee; all
        other interaction with the `IOLoop` must be done from that
        `IOLoop`'s thread.  `add_callback()` may be used to transfer
        control from other threads to the `IOLoop`'s thread.
        NrM   r   ry   rz   r.   r   r   r   rr   ~  s    
zIOLoop.add_callbackc                 O   s
   t  dS )a  Calls the given callback on the next I/O loop iteration.

        Intended to be afe for use from a Python signal handler; should not be
        used otherwise.

        .. deprecated:: 6.4
           Use ``asyncio.AbstractEventLoop.add_signal_handler`` instead.
           This method is suspected to have been broken since Tornado 5.0 and
           will be removed in version 7.0.
        NrM   r   r   r   r   add_callback_from_signal  s    zIOLoop.add_callback_from_signalc                 O   s   | j |f|| dS )zCalls the given callback on the next IOLoop iteration.

        As of Tornado 6.0, this method is equivalent to `add_callback`.

        .. versionadded:: 4.0
        Nrr   r   r   r   r   spawn_callback  s    zIOLoop.spawn_callbackz0Union[Future[_T], concurrent.futures.Future[_T]]z
Future[_T])rd   ry   r   c                    sD   t |tr | fdd n t|s,tt| fdd dS )aA  Schedules a callback on the ``IOLoop`` when the given
        `.Future` is finished.

        The callback is invoked with one argument, the
        `.Future`.

        This method only accepts `.Future` objects and not other
        awaitables (unlike most of Tornado where the two are
        interchangeable).
        c                    s    t | S r   )_run_callback	functoolspartialfry   r   r   r   re     rf   z#IOLoop.add_future.<locals>.<lambda>c                    s     | S r   r   r   r   r   r   re     rf   N)r1   r   Zadd_done_callbackr   rj   r   )r   rd   ry   r   r   r   rk     s    
	zIOLoop.add_future.)executorra   rz   r   c                    sh   |dkr:t | ds4ddlm} tjj| d d| _| j}|j|f| }t  | 	| fdd  S )	zRuns a function in a ``concurrent.futures.Executor``. If
        ``executor`` is ``None``, the IO loop's default executor will be used.

        Use `functools.partial` to pass keyword arguments to ``func``.

        .. versionadded:: 5.0
        N	_executorr   )	cpu_count   )max_workersc                    s
   t |  S r   )r   r   Zt_futurer   r   re     rf   z(IOLoop.run_in_executor.<locals>.<lambda>)
hasattrZtornado.processr   
concurrentfuturesZThreadPoolExecutorr   Zsubmitr   rk   )r   r   ra   rz   r   Zc_futurer   r   r   run_in_executor  s    
zIOLoop.run_in_executor)r   r   c                 C   s
   || _ dS )zfSets the default executor to use with :meth:`run_in_executor`.

        .. versionadded:: 5.0
        N)r   )r   r   r   r   r   set_default_executor  s    zIOLoop.set_default_executor)ry   r   c                 C   s   zR| }|dk	rPddl m} z||}W n |jk
r@   Y nX | || j W n8 tjk
rh   Y n$ tk
r   t	j
d|dd Y nX dS )zRuns a callback with error handling.

        .. versionchanged:: 6.0

           CancelledErrors are no longer logged.
        Nr   )genException in callback %rTri   )Ztornador   rc   ZBadYieldErrorrk   _discard_future_resultrC   ZCancelledErrorrg   r   error)r   ry   retr   r   r   r   r     s    zIOLoop._run_callback)rd   r   c                 C   s   |   dS )z;Avoid unhandled-exception warnings from spawned coroutines.N)rl   )r   rd   r   r   r   r     s    zIOLoop._discard_future_resultc                 C   s   t |tr||fS | |fS r   )r1   r%   r    r]   r   r   r   split_fd  s    
zIOLoop.split_fdc                 C   s<   z"t |trt| n|  W n tk
r6   Y nX d S r   )r1   r%   osr!   OSErrorr]   r   r   r   close_fd  s    
zIOLoop.close_fd)r   r   c                 C   s   | j | d S r   )_pending_tasksaddr   r   r   r   r   _register_task2  s    zIOLoop._register_taskc                 C   s   | j | d S r   )r   discardr   r   r   r   _unregister_task5  s    zIOLoop._unregister_task)T)T)T)F)N)Jr"   r#   r$   __doc__NONEREADWRITEERRORdictrD   setr   classmethodr   r7   staticmethodr<   r>   r@   typingoverloadr;   boolr   r=   rL   r?   rO   rP   r   r	   rR   rT   rU   r!   r%   r   r[   r'   r   r   r\   r^   r_   r`   floatrw   rt   r   r   objectrs   r   r~   ru   rr   r   r   rk   r   r   ZExecutorr&   r   r   r   r   r   r   r   r   r   r   __classcell__r   r   r9   r   r)   H   s   Q ,    
  		L*      	  #


r)   c                   @   sV   e Zd ZdZdddgZeeg df eddddZd e	d	d
dZ
d e	d	ddZdS )_Timeoutz2An IOLoop timeout, a UNIX timestamp and a callbackrx   ry   	tdeadlineN)rx   ry   io_loopr   c                 C   s8   t |tjstd| || _|| _|t|jf| _d S )Nr{   )	r1   r|   r}   r   rx   ry   nextZ_timeout_counterr   )r   rx   ry   r   r   r   r   __init__?  s    z_Timeout.__init__)otherr   c                 C   s   | j |j k S r   r   r   r   r   r   r   __lt__O  s    z_Timeout.__lt__c                 C   s   | j |j kS r   r   r   r   r   r   __le__R  s    z_Timeout.__le__)r"   r#   r$   r   	__slots__r   r   r)   r   r   r   r   r   r   r   r   r   9  s   
 
 r   c                   @   s   e Zd ZdZdeg ee f eej	e
f e
ddddZdddd	Zddd
dZedddZddddZddddZe
ddddZdS )PeriodicCallbacka  Schedules the given callback to be called periodically.

    The callback is called every ``callback_time`` milliseconds when
    ``callback_time`` is a float. Note that the timeout is given in
    milliseconds, while most other time-related functions in Tornado use
    seconds. ``callback_time`` may alternatively be given as a
    `datetime.timedelta` object.

    If ``jitter`` is specified, each callback time will be randomly selected
    within a window of ``jitter * callback_time`` milliseconds.
    Jitter can be used to reduce alignment of events with similar periods.
    A jitter of 0.1 means allowing a 10% variation in callback time.
    The window is centered on ``callback_time`` so the total number of calls
    within a given interval should not be significantly affected by adding
    jitter.

    If the callback runs for longer than ``callback_time`` milliseconds,
    subsequent invocations will be skipped to get back on schedule.

    `start` must be called after the `PeriodicCallback` is created.

    .. versionchanged:: 5.0
       The ``io_loop`` argument (deprecated since version 4.1) has been removed.

    .. versionchanged:: 5.1
       The ``jitter`` argument is added.

    .. versionchanged:: 6.2
       If the ``callback`` argument is a coroutine, and a callback runs for
       longer than ``callback_time``, subsequent invocations will be skipped.
       Previously this was only true for regular functions, not coroutines,
       which were "fire-and-forget" for `PeriodicCallback`.

       The ``callback_time`` argument now accepts `datetime.timedelta` objects,
       in addition to the previous numeric milliseconds.
    r   N)ry   callback_timejitterr   c                 C   sR   || _ t|tjr&|tjdd | _n|dkr6td|| _|| _d| _d | _d S )Nr*   )Zmillisecondsr   z4Periodic callback must have a positive callback_timeF)	ry   r1   r   r   r   
ValueErrorr   _running_timeout)r   ry   r   r   r   r   r   r   |  s    zPeriodicCallback.__init__r   c                 C   s(   t  | _d| _| j | _|   dS )zStarts the timer.TN)r)   r;   r   r   rt   _next_timeout_schedule_nextr   r   r   r   r_     s    
zPeriodicCallback.startc                 C   s(   d| _ | jdk	r$| j| j d| _dS )zStops the timer.FN)r   r   r   ru   r   r   r   r   r`     s    
zPeriodicCallback.stopc                 C   s   | j S )zfReturns ``True`` if this `.PeriodicCallback` has been started.

        .. versionadded:: 4.1
        )r   r   r   r   r   
is_running  s    zPeriodicCallback.is_runningc                    sl   | j s
d S zRz&|  }|d k	r0t|r0|I d H  W n& tk
rX   tjd| jdd Y nX W 5 |   X d S )Nr   Tr   )r   r   ry   r   rg   r   r   )r   valr   r   r   _run  s    zPeriodicCallback._runc                 C   s.   | j r*| | j  | j| j| j| _d S r   )r   _update_nextr   rt   rs   r   r   r   r   r   r   r   r     s    zPeriodicCallback._schedule_next)current_timer   c                 C   sn   | j d }| jr*|d| jt d   9 }| j|kr\|  jt|| j | d | 7  _n|  j|7  _d S )Ng     @@r*   g      ?)r   r   randomr   mathfloor)r   r   Zcallback_time_secr   r   r   r     s    


zPeriodicCallback._update_next)r   )r"   r#   r$   r   r   r   r   r   r   r   r   r   r_   r`   r   r   r   r   r   r   r   r   r   r   V  s   ) 
r   )1r   rC   concurrent.futuresr   r   r   r|   r   rh   rt   r   r   rI   inspectr   Ztornado.concurrentr   r   r   r   r   Ztornado.logr   Ztornado.utilr	   r
   r   r   r   r   r   r   r   r   r   r   TYPE_CHECKINGr   r   r   Ztyping_extensionsr   r   r   r&   r'   r)   r   r   r   r   r   r   <module>   s@   
(     v