K i-dZddlZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl Z ddl mZddlmZmZmZmZmZddlmZddlmZmZmZddlZddlmZmZmZmZm Z m!Z!m"Z"m#Z#ejHrddlm%Z%m&Z&m'Z'm(Z(dd l)m*Z*ne+Z*Gd d e*Z,e!d Z-e!d e,Z.GddeZ/GddZ0GddZ1y)aAn 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_futurefuture_set_exc_infofuture_add_done_callback)app_log) Configurable TimeoutError import_object)UnionAnyTypeOptionalCallableTypeVarTuple Awaitable)DictListSet TypedDict)Protocolc eZdZdefdZddZy) _SelectablereturncyNselfs T/mnt/ssd/data/python-lab/Trading/venv/lib/python3.12/site-packages/tornado/ioloop.pyfilenoz_Selectable.fileno= Ncyrrr s r"closez_Selectable.close@r$r%rN)__name__ __module__ __qualname__intr#r'rr%r"rr<s   r%r_T_S)boundc eZdZdZdZdZdZdZeZ e Z e ddde d d ffd ZedHd ZdId ZedIdZej(edHdZej(edJded edfdZedJded edfdZdIdZdIdZedIdZedIdZdIdZe d eefdZe d eefdZ dJded d fdZ!dKded d fdZ"ej(de#de$e#e#gd fd e#d d fd!Z%ej(de&de$e&e#gd fd e#d d fd"Z%de'e#e(fde$d#d e#d d fd$Z%de'e#e(fd e#d d fd%Z)de'e#e(fd d fd&Z*dId'Z+dId(Z,dLd)e$d*ee-d e fd+Z.d e-fd,Z/d-e'e-e0jbfd.e$d/e de d e2f d0Z3d1e-d.e$d/e de d e2f d2Z4d3e-d.e$d/e de d e2f d4Z5d*e2d d fd5Z6d.e$d/e de d d fd6Z7d.e$d/e de d d fd7Z8d.e$d/e de d d fd8Z9d9d:d.e$d;gd fd d fd<Z:d=ee;jxjzd)e$d>e>fd/e d d;fd?Z?d=e;jxjzd d fd@Z@d.e$ge fd d fdAZAd9eBd d fdBZCde'e#e(fd eDe#e'e#e(fffdCZEde'e#e(fd d fdDZFdEeBd d fdFZGdEeBd d fdGZHxZIS)MIOLoopa 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()) 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. rimplz$Union[None, str, Type[Configurable]]kwargsrNc ddlm}t|tr t |}t|t rt ||s tdt|$|fi|y)Nr)BaseAsyncIOLoopz5only AsyncIOLoop is allowed when asyncio is available) tornado.platform.asyncior8 isinstancestrr type issubclass RuntimeErrorsuper configure)clsr5r6r8 __class__s r"r@zIOLoop.configuresM = dC  &D dD !*T?*KVW W $)&)r%c*tjS)aKDeprecated 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 )r1currentrr%r"instancezIOLoop.instances(~~r%c$|jy)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 s r"installzIOLoop.installs r%c,tjy)akDeprecated 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)r1 clear_currentrr%r"clear_instancezIOLoop.clear_instances r%cyrrrr%r"rDzIOLoop.current r%rEcyrrrEs r"rDzIOLoop.currentrMr%c tj} t j |S#t$r0|sYytj}tj|YLwxYw#t$r|rddlm }|}Y|Sd}Y|SwxYw)aCReturns 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) asyncioget_event_loopr>new_event_loopset_event_loopr1_ioloop_for_asyncioKeyErrorr9rQ)rElooprQrDs r"rDzIOLoop.currents2 )))+D --d3 3 )))+D  " "4 (  ) D)+ s+*A& A#)A#"A#&BBBc\tjdtd|jy)aMakes 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)warningswarnDeprecationWarning _make_currentr s r"rGzIOLoop.make_current"s'(  D  r%ctrNotImplementedErrorr s r"r`zIOLoop._make_current=s !##r%cdtjdtdtj y)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 zclear_current is deprecatedrZr[N)r]r^r_r1_clear_currentrr%r"rJzIOLoop.clear_currentAs'  )  r%cVtjd}||jyy)NFrO)r1rD_clear_current_hook)olds r"rezIOLoop._clear_currentRs(nnen, ?  # # % r%cy)zInstance method called when an IOLoop ceases to be current. May be overridden by subclasses as a counterpart to make_current. Nrr s r"rgzIOLoop._clear_current_hookXs r%ctSr)r1)rAs r"configurable_basezIOLoop.configurable_base_s r%cddlm}|S)Nr) AsyncIOLoop)r9rm)rArms r"configurable_defaultzIOLoop.configurable_defaultcs 8r%rGc*|r|jyyr)r`)r!rGs r" initializezIOLoop.initializeis      r%all_fdsct)aCloses 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. rb)r!rqs r"r'z IOLoop.closems 2"##r%fdhandlereventscyrrr!rsrtrus r" add_handlerzIOLoop.add_handler r%cyrrrws r"rxzIOLoop.add_handlerryr%).Nct)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. rbrws r"rxzIOLoop.add_handlers ""##r%ct)zChanges the events we listen for ``fd``. .. versionchanged:: 4.0 Added the ability to pass file-like objects in addition to raw file descriptors. rb)r!rsrus r"update_handlerzIOLoop.update_handler "##r%ct)zStop listening for events on ``fd``. .. versionchanged:: 4.0 Added the ability to pass file-like objects in addition to raw file descriptors. rbr!rss r"remove_handlerzIOLoop.remove_handlerr~r%ct)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. rbr s r"startz IOLoop.starts "##r%ct)aStop 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. rbr s r"stopz IOLoop.stops "##r%functimeoutctjrtdttt d}dddd fd }j ||*d fd }jj|z|}j|jdJdjsdjsdrtd |ztd djS) aStarts 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``. FutureCell)futuretimeout_calledNFcP }|ddlm}||}t|r|d<n!t}|d<|j | dJjdfdy#t $r0t}|d<t |tjYXwxYw)Nr)convert_yieldedrc$jSr)r)rr!s r"z.IOLoop.run_sync..run..s $))+r%) tornado.genrrr set_result Exceptionrsysexc_info add_future)resultrfutr future_cellr!s r"runzIOLoop.run_sync..runs +%;,V4F V$,2K) (C,/K)NN6*x(4 44 OOK13M N 9h(+ H%#C8 9sA,,6B%$B%cfdd<dJdjsjyy)NTrr)cancelr)rr!sr"timeout_callbackz)IOLoop.run_sync..timeout_callback s@04 ,- #8,888"8,335IIK6r%rrz$Operation timed out after %s secondsz+Event loop stopped before Future completed.r()typing TYPE_CHECKINGrrrbool add_callback add_timeouttimerremove_timeout cancelleddoner r>r)r!rrrrrtimeout_handlers`` @r"run_synczIOLoop.run_syncs@   "&)9TRJ"&?  O* #   "--diikG.CEUVN      /8$000 x * * ,K4I4N4N4P+,"#IG#STT##PQQ8$++--r%c*tjS)aReturns 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`. )rr s r"rz IOLoop.time%syy{r%deadlinecallbackargsc t|tjr|j||g|i|St|tj r6|j|j |jz|g|i|Std|z)aRuns 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 %r) r:numbersRealcall_atdatetime timedeltar total_seconds TypeError)r!rrrr6s r"rzIOLoop.add_timeout3s@ h -4<<(DTDVD D ("4"4 54<< h4466CGKQ 5@A Ar%delaycR|j|j|z|g|i|S)aRuns 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 )rr)r!rrrr6s r" call_laterzIOLoop.call_later\s,t||DIIK%/KDKFKKr%whenc0|j||g|i|S)aRuns 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 )r)r!rrrr6s r"rzIOLoop.call_atks#  th@@@@r%ct)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. rb)r!rs r"rzIOLoop.remove_timeout}r~r%ct)aCalls 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. rbr!rrr6s r"rzIOLoop.add_callbacks "##r%ct)aCalls 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. rbrs r"add_callback_from_signalzIOLoop.add_callback_from_signals "##r%c0|j|g|i|y)zCalls the given callback on the next IOLoop iteration. As of Tornado 6.0, this method is equivalent to `add_callback`. .. versionadded:: 4.0 Nrrs r"spawn_callbackzIOLoop.spawn_callbacks (4T4V4r%rz0Union[Future[_T], concurrent.futures.Future[_T]]z Future[_T]ct|tr|jfdyt|sJt |fdy)aASchedules 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). cNjtj|Sr) _run_callback functoolspartialfrr!s r"rz#IOLoop.add_future..s$,,Y->->x-KLr%c(j|Srrrs r"rz#IOLoop.add_future..st7H7HST7Ur%N)r:radd_done_callbackrr)r!rrs` `r"rzIOLoop.add_futures? ff %  $ $L V$ $$ %V-U Vr%executor.c|Kt|ds3ddlm}tjj |dz|_|j }|j|g|}t|j|fdS)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 _executorr) cpu_count) max_workersct|Sr)r)rt_futures r"rz(IOLoop.run_in_executor..sLH,Er%) hasattrtornado.processr concurrentfuturesThreadPoolExecutorrsubmitrr)r!rrrrc_futurers @r"run_in_executorzIOLoop.run_in_executors|  4-5!+!3!3!F!F!*q"G"~~H"8??4/$/8 "EFr%c||_y)zfSets the default executor to use with :meth:`run_in_executor`. .. versionadded:: 5.0 N)r)r!rs r"set_default_executorzIOLoop.set_default_executors "r%c" |}|5ddlm} |j|}|j||jyy#|j $rYywxYw#t j$rYyt$rtjd|dYywxYw)zRuns a callback with error handling. .. versionchanged:: 6.0 CancelledErrors are no longer logged. Nr)genException in callback %rTr) tornadorrr_discard_future_result BadYieldErrorrRCancelledErrorrr error)r!rretrs r"rzIOLoop._run_callbacks O*C' F--c2COOC)D)DE(( %%   O MM4h N Os9AAAAAAAB+ B Bc$|jy)z;Avoid unhandled-exception warnings from spawned coroutines.N)r)r!rs r"rzIOLoop._discard_future_result s  r%cNt|tr||fS|j|fSr)r:r,r#rs r"split_fdzIOLoop.split_fds'$ b# r6Myy{Br%c t|trtj|y|jy#t$rYywxYwr)r:r,osr'OSErrorrs r"close_fdzIOLoop.close_fd&s7 "c"     s%99 AArc:|jj|yr)_pending_tasksaddr!rs r"_register_taskzIOLoop._register_task:s "r%c:|jj|yr)rdiscardrs r"_unregister_taskzIOLoop._unregister_task=s ##A&r%)rr1r()T)Fr)Jr)r*r+__doc__NONEREADWRITEERRORdictrVsetr classmethodrr@ staticmethodrErHrKroverloadrDrrrGr`rJrergrr rkrnrpr'r,rrxr.r rr}rrrfloatrrrrobjectrrrrrrrrrrExecutorr-rrrrrrrrrr __classcell__)rBs@r"r1r1HsEK\ D D E E&UN *9 *EH *  * *  *    __   __ $ (8*<  *$*(8*<**X6$  &&  $|"4T,%7 !t!t!$T$d$6 __  (#sT)9 : DG    __  'S 48 BE   $[()$44/0W  WB:--667sBw   8"Z-?-?-H-H"T"Ohr3w&7ODO<V[() sE#{*++ ,,5k!12t(##4#'&'T'r%r1cZeZdZdZgdZdedegdfdeddfdZd dde fd Z d dde fd Z y) _Timeoutz2An IOLoop timeout, a UNIX timestamp and a callback)rr tdeadlinerrNio_looprct|tjstd|z||_||_|t |jf|_y)Nr) r:rrrrrnext_timeout_counterr)r!rrrs r"__init__z_Timeout.__init__GsK(GLL15@A A     )) * r%otherc4|j|jkSrrr!r s r"__lt__z_Timeout.__lt__Ws~~//r%c4|j|jkSrrrs r"__le__z_Timeout.__le__Zs~~00r%) r)r*r+r __slots__rrr1r rrrrr%r"rrAs`<6I    )1"d();  FL    0J0401J141r%rc eZdZdZ ddegeefdeeje fde ddfdZ ddZ dd Z defd Zdd Zdd Zd e ddfdZy)PeriodicCallbackaSchedules 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 callback_timejitterrNc||_t|tjr|tjdz |_n|dkr t d||_||_d|_d|_y)Nr2) millisecondsrz4Periodic callback must have a positive callback_timeF) rr:rrr ValueErrorr_running_timeout)r!rrrs r"r zPeriodicCallback.__init__se ! mX%7%7 8!.1C1CQR1S!SD ! !WXX!.D    r%ctj|_d|_|jj |_|j y)zStarts the timer.TN)r1rDrrr _next_timeout_schedule_nextr s r"rzPeriodicCallback.starts: ~~'  !\\..0 r%cd|_|j-|jj|jd|_yy)zStops the timer.FN)rrrrr s r"rzPeriodicCallback.stops5 == $ LL ' ' 6 DM %r%c|jS)zfReturns ``True`` if this `.PeriodicCallback` has been started. .. versionadded:: 4.1 )rr s r" is_runningzPeriodicCallback.is_runnings }}r%c&K|jsy |j}|t|r |d{|j y7#t$r%t j d|jdY@wxYw#|j wxYww)NrTr)rrrrr rr)r!vals r"_runzPeriodicCallback._runsz}}  "--/C;s#3     !  T MM4dmmd S T    !sCB"A A A B A +A96A<8A99A<<BBc|jr_|j|jj|jj |j |j |_yyr)r _update_nextrrrrr%rr s r"rzPeriodicCallback._schedule_nextsK ==   dll//1 2 LL44T5G5GSDM r% current_timecT|jdz }|jr*|d|jtjdz zzz}|j|kr?|xjt j ||jz |z dz|zz c_y|xj|z c_y)Ng@@r2g?)rrrandomrmathfloor)r!r(callback_time_secs r"r'zPeriodicCallback._update_nexts ..7 ;; dkkV]]_s5J&K!L L     -    L4+=+==ARRSVWW!#" " $   "3 3 r%)rr()r)r*r+rrrrr rrrr rrrr"r%rr'rr%r"rr^s#R 2x 223X//67   "!D "T 4444r%r)2rrRconcurrent.futuresrrrrrrrr+r*r]inspectrtornado.concurrentrrrrr tornado.logr tornado.utilr r r rr rrrrrrrrrrrrtyping_extensionsrrrr-r.r1rrrr%r"r4s   BB RRR 11*H (  T] T%v '\v 'r11:|4|4r%