This commit is contained in:
Kovid Goyal 2015-05-23 19:13:37 +05:30
parent 70f23a4c76
commit a514dc4fd7
2 changed files with 52 additions and 50 deletions

View File

@ -12,10 +12,9 @@ from Queue import Queue, Full
from threading import Thread, current_thread, Lock from threading import Thread, current_thread, Lock
from io import DEFAULT_BUFFER_SIZE, BytesIO from io import DEFAULT_BUFFER_SIZE, BytesIO
from calibre.constants import iswindows
from calibre.srv.errors import MaxSizeExceeded from calibre.srv.errors import MaxSizeExceeded
from calibre.srv.opts import Options from calibre.srv.opts import Options
from calibre.srv.utils import socket_errors_to_ignore, socket_error_eintr, socket_errors_nonblocking, Corked from calibre.srv.utils import socket_errors_to_ignore, socket_error_eintr, socket_errors_nonblocking, Corked, HandleInterrupt
from calibre.utils.socket_inheritance import set_socket_inherit from calibre.utils.socket_inheritance import set_socket_inherit
from calibre.utils.logging import ThreadSafeLog from calibre.utils.logging import ThreadSafeLog
@ -321,54 +320,6 @@ class SocketFile(object): # {{{
# }}} # }}}
class HandleInterrupt(object): # {{{
# On windows socket functions like accept(), recv(), send() are not
# interrupted by a Ctrl-C in the console. So to make Ctrl-C work we have to
# use this special context manager. See the echo server example at the
# bottom of this file for how to use it.
def __init__(self, action):
if not iswindows:
return # Interrupts work fine on POSIX
self.action = action
from ctypes import WINFUNCTYPE, windll
from ctypes.wintypes import BOOL, DWORD
kernel32 = windll.LoadLibrary('kernel32')
# <http://msdn.microsoft.com/en-us/library/ms686016.aspx>
PHANDLER_ROUTINE = WINFUNCTYPE(BOOL, DWORD)
self.SetConsoleCtrlHandler = kernel32.SetConsoleCtrlHandler
self.SetConsoleCtrlHandler.argtypes = (PHANDLER_ROUTINE, BOOL)
self.SetConsoleCtrlHandler.restype = BOOL
@PHANDLER_ROUTINE
def handle(event):
if event == 0: # CTRL_C_EVENT
if self.action is not None:
self.action()
self.action = None
# Typical C implementations would return 1 to indicate that
# the event was processed and other control handlers in the
# stack should not be executed. However, that would
# prevent the Python interpreter's handler from translating
# CTRL-C to a `KeyboardInterrupt` exception, so we pretend
# that we didn't handle it.
return 0
self.handle = handle
def __enter__(self):
if iswindows:
if self.SetConsoleCtrlHandler(self.handle, 1) == 0:
raise WindowsError()
def __exit__(self, *args):
if iswindows:
if self.SetConsoleCtrlHandler(self.handle, 0) == 0:
raise WindowsError()
# }}}
class Connection(object): # {{{ class Connection(object): # {{{
' A thin wrapper around an active socket ' ' A thin wrapper around an active socket '

View File

@ -12,6 +12,8 @@ from urlparse import parse_qs
import repr as reprlib import repr as reprlib
from email.utils import formatdate from email.utils import formatdate
from calibre.constants import iswindows
def http_date(timeval=None): def http_date(timeval=None):
return type('')(formatdate(timeval=timeval, usegmt=True)) return type('')(formatdate(timeval=timeval, usegmt=True))
@ -176,3 +178,52 @@ def eintr_retry_call(func, *args, **kwargs):
if getattr(e, 'errno', None) in socket_errors_eintr: if getattr(e, 'errno', None) in socket_errors_eintr:
continue continue
raise raise
class HandleInterrupt(object): # {{{
# On windows socket functions like accept(), recv(), send() are not
# interrupted by a Ctrl-C in the console. So to make Ctrl-C work we have to
# use this special context manager. See the echo server example at the
# bottom of this file for how to use it.
def __init__(self, action):
if not iswindows:
return # Interrupts work fine on POSIX
self.action = action
from ctypes import WINFUNCTYPE, windll
from ctypes.wintypes import BOOL, DWORD
kernel32 = windll.LoadLibrary('kernel32')
# <http://msdn.microsoft.com/en-us/library/ms686016.aspx>
PHANDLER_ROUTINE = WINFUNCTYPE(BOOL, DWORD)
self.SetConsoleCtrlHandler = kernel32.SetConsoleCtrlHandler
self.SetConsoleCtrlHandler.argtypes = (PHANDLER_ROUTINE, BOOL)
self.SetConsoleCtrlHandler.restype = BOOL
@PHANDLER_ROUTINE
def handle(event):
if event == 0: # CTRL_C_EVENT
if self.action is not None:
self.action()
self.action = None
# Typical C implementations would return 1 to indicate that
# the event was processed and other control handlers in the
# stack should not be executed. However, that would
# prevent the Python interpreter's handler from translating
# CTRL-C to a `KeyboardInterrupt` exception, so we pretend
# that we didn't handle it.
return 0
self.handle = handle
def __enter__(self):
if iswindows:
if self.SetConsoleCtrlHandler(self.handle, 1) == 0:
raise WindowsError()
def __exit__(self, *args):
if iswindows:
if self.SetConsoleCtrlHandler(self.handle, 0) == 0:
raise WindowsError()
# }}}