U
    luf   ã                   @   s2   d Z ddlZddlmZmZmZ G dd„ dƒZdS )zWin32 compatibility utilities.é    N)ÚAnyÚCallableÚOptionalc                   @   sF   e Zd ZdZdeeg ef  ddœdd„Zdd„ Zdd	„ Z	d
d„ Z
dS )Úallow_interruptaD  Utility for fixing CTRL-C events on Windows.

    On Windows, the Python interpreter intercepts CTRL-C events in order to
    translate them into ``KeyboardInterrupt`` exceptions.  It (presumably)
    does this by setting a flag in its "console control handler" and
    checking it later at a convenient location in the interpreter.

    However, when the Python interpreter is blocked waiting for the ZMQ
    poll operation to complete, it must wait for ZMQ's ``select()``
    operation to complete before translating the CTRL-C event into the
    ``KeyboardInterrupt`` exception.

    The only way to fix this seems to be to add our own "console control
    handler" and perform some application-defined operation that will
    unblock the ZMQ polling operation in order to force ZMQ to pass control
    back to the Python interpreter.

    This context manager performs all that Windows-y stuff, providing you
    with a hook that is called when a CTRL-C event is intercepted.  This
    hook allows you to unblock your ZMQ poll operation immediately, which
    will then result in the expected ``KeyboardInterrupt`` exception.

    Without this context manager, your ZMQ-based application will not
    respond normally to CTRL-C events on Windows.  If a CTRL-C event occurs
    while blocked on ZMQ socket polling, the translation to a
    ``KeyboardInterrupt`` exception will be delayed until the I/O completes
    and control returns to the Python interpreter (this may never happen if
    you use an infinite timeout).

    A no-op implementation is provided on non-Win32 systems to avoid the
    application from having to conditionally use it.

    Example usage:

    .. sourcecode:: python

       def stop_my_application():
           # ...

       with allow_interrupt(stop_my_application):
           # main polling loop.

    In a typical ZMQ application, you would use the "self pipe trick" to
    send message to a ``PAIR`` socket in order to interrupt your blocking
    socket polling operation.

    In a Tornado event loop, you can use the ``IOLoop.stop`` method to
    unblock your I/O loop.
    N)ÚactionÚreturnc                 C   s   t jdkrdS |  |¡ dS )a  Translate ``action`` into a CTRL-C handler.

        ``action`` is a callable that takes no arguments and returns no
        value (returned value is ignored).  It must *NEVER* raise an
        exception.

        If unspecified, a no-op will be used.
        ÚntN)ÚosÚnameÚ_init_action)Úselfr   © r   ú3/tmp/pip-unpacked-wheel-h6ekxre8/zmq/utils/win32.pyÚ__init__?   s    	
zallow_interrupt.__init__c           
         s€   ddl m}m} ddlm}m} | d¡}|||ƒ}|j }| _||f|_	||_
ˆ d kr`dd„ ‰ ˆ | _|‡ fdd„ƒ}	|	| _d S )	Nr   )ÚWINFUNCTYPEÚwindll)ÚBOOLÚDWORDÚkernel32c                   S   s   d S )Nr   r   r   r   r   Ú<lambda>[   ó    z.allow_interrupt._init_action.<locals>.<lambda>c                    s   | dkrˆ ƒ  dS )Nr   r   )Úevent©r   r   r   Úhandle^   s    z,allow_interrupt._init_action.<locals>.handle)Úctypesr   r   Zctypes.wintypesr   r   ÚLoadLibraryÚSetConsoleCtrlHandlerÚ_SetConsoleCtrlHandlerÚargtypesÚrestyper   r   )
r   r   r   r   r   r   r   ZPHANDLER_ROUTINEr   r   r   r   r   r   L   s    

þ
zallow_interrupt._init_actionc                 C   s.   t jdkrdS |  | jd¡}|dkr*tƒ ‚dS )z"Install the custom CTRL-C handler.r   Né   r   ©r	   r
   r   r   ÚOSError)r   Úresultr   r   r   Ú	__enter__l   s
    
zallow_interrupt.__enter__c                 G   s.   t jdkrdS |  | jd¡}|dkr*tƒ ‚dS )z!Remove the custom CTRL-C handler.r   Nr   r!   )r   Úargsr#   r   r   r   Ú__exit__v   s
    
zallow_interrupt.__exit__)N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   r   r   r   r$   r&   r   r   r   r   r      s
   2 
r   )r*   r	   Útypingr   r   r   r   r   r   r   r   Ú<module>   s   