From 7e0e73b385834ddf389e52f0c087941161f5e358 Mon Sep 17 00:00:00 2001 From: Ben Darnell Date: Mon, 4 Jul 2011 20:37:52 -0700 Subject: [PATCH] Clean up hacky fcntl emulation for windows. --- tornado/ioloop.py | 15 ++++++------ tornado/netutil.py | 13 ++-------- tornado/platform/auto.py | 31 ++++++++++++++++++++++++ tornado/platform/interface.py | 26 ++++++++++++++++++++ tornado/platform/posix.py | 23 ++++++++++++++++++ tornado/platform/windows.py | 45 ++++------------------------------- 6 files changed, 93 insertions(+), 60 deletions(-) create mode 100644 tornado/platform/auto.py create mode 100644 tornado/platform/interface.py create mode 100644 tornado/platform/posix.py diff --git a/tornado/ioloop.py b/tornado/ioloop.py index c8396fd4e..4bf64fc20 100644 --- a/tornado/ioloop.py +++ b/tornado/ioloop.py @@ -43,14 +43,17 @@ try: except ImportError: signal = None +from tornado.platform.auto import set_close_exec + try: import fcntl except ImportError: if os.name == 'nt': from tornado.platform import windows - from tornado.platform import windows as fcntl else: raise + + class IOLoop(object): """A level-triggered I/O loop. @@ -110,7 +113,7 @@ class IOLoop(object): def __init__(self, impl=None): self._impl = impl or _poll() if hasattr(self._impl, 'fileno'): - self._set_close_exec(self._impl.fileno()) + set_close_exec(self._impl.fileno()) self._handlers = {} self._events = {} self._callbacks = [] @@ -126,8 +129,8 @@ class IOLoop(object): r, w = os.pipe() self._set_nonblocking(r) self._set_nonblocking(w) - self._set_close_exec(r) - self._set_close_exec(w) + set_close_exec(r) + set_close_exec(w) self._waker_reader = os.fdopen(r, "rb", 0) self._waker_writer = os.fdopen(w, "wb", 0) else: @@ -420,10 +423,6 @@ class IOLoop(object): flags = fcntl.fcntl(fd, fcntl.F_GETFL) fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK) - def _set_close_exec(self, fd): - flags = fcntl.fcntl(fd, fcntl.F_GETFD) - fcntl.fcntl(fd, fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC) - class _Timeout(object): """An IOLoop timeout, a UNIX timestamp and a callback""" diff --git a/tornado/netutil.py b/tornado/netutil.py index 2b177ad1e..6d6c5ce11 100644 --- a/tornado/netutil.py +++ b/tornado/netutil.py @@ -16,16 +16,9 @@ """Miscellaneous network utility code.""" -import os import socket -try: - import fcntl -except ImportError: - if os.name == 'nt': - from tornado.platform import windows as fcntl - else: - raise +from tornado.platform.auto import set_close_exec def bind_sockets(port, address=None, family=socket.AF_UNSPEC, backlog=128): """Creates listening sockets bound to the given port and address. @@ -58,9 +51,7 @@ def bind_sockets(port, address=None, family=socket.AF_UNSPEC, backlog=128): 0, flags): af, socktype, proto, canonname, sockaddr = res sock = socket.socket(af, socktype, proto) - flags = fcntl.fcntl(sock.fileno(), fcntl.F_GETFD) - flags |= fcntl.FD_CLOEXEC - fcntl.fcntl(sock.fileno(), fcntl.F_SETFD, flags) + set_close_exec(sock.fileno()) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) if af == socket.AF_INET6: # On linux, ipv6 sockets accept ipv4 too by default, diff --git a/tornado/platform/auto.py b/tornado/platform/auto.py new file mode 100644 index 000000000..9bc411daa --- /dev/null +++ b/tornado/platform/auto.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +# +# Copyright 2011 Facebook +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +"""Implementation of platform-specific functionality. + +For each function or class described in `tornado.platform.interface`, +the appropriate platform-specific implementation exists in this module. +Most code that needs access to this functionality should do e.g.:: + + from tornado.platform.auto import set_close_exec +""" + +import os + +if os.name == 'nt': + from .windows import set_close_exec +else: + from .posix import set_close_exec diff --git a/tornado/platform/interface.py b/tornado/platform/interface.py new file mode 100644 index 000000000..fb5e61802 --- /dev/null +++ b/tornado/platform/interface.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +# +# Copyright 2011 Facebook +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +"""Interfaces for platform-specific functionality. + +This module exists primarily for documentation purposes and as base classes +for other tornado.platform modules. Most code should import the appropriate +implementation from `tornado.platform.auto`. +""" + +def set_close_exec(fd): + """Sets the close-on-exec bit (``FD_CLOEXEC``)for a file descriptor.""" + raise NotImplementedError() diff --git a/tornado/platform/posix.py b/tornado/platform/posix.py new file mode 100644 index 000000000..673660de4 --- /dev/null +++ b/tornado/platform/posix.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python +# +# Copyright 2011 Facebook +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +"""Posix implementations of platform-specific functionality.""" + +import fcntl + +def set_close_exec(fd): + flags = fcntl.fcntl(fd, fcntl.F_GETFD) + fcntl.fcntl(fd, fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC) diff --git a/tornado/platform/windows.py b/tornado/platform/windows.py index 7e8bedc2c..e138dc184 100644 --- a/tornado/platform/windows.py +++ b/tornado/platform/windows.py @@ -3,16 +3,9 @@ import ctypes import ctypes.wintypes -import os import socket import errno - -# See: http://msdn.microsoft.com/en-us/library/ms738573(VS.85).aspx -ioctlsocket = ctypes.windll.ws2_32.ioctlsocket -ioctlsocket.argtypes = (ctypes.wintypes.HANDLE, ctypes.wintypes.LONG, ctypes.wintypes.ULONG) -ioctlsocket.restype = ctypes.c_int - # See: http://msdn.microsoft.com/en-us/library/ms724935(VS.85).aspx SetHandleInformation = ctypes.windll.kernel32.SetHandleInformation SetHandleInformation.argtypes = (ctypes.wintypes.HANDLE, ctypes.wintypes.DWORD, ctypes.wintypes.DWORD) @@ -21,40 +14,10 @@ SetHandleInformation.restype = ctypes.wintypes.BOOL HANDLE_FLAG_INHERIT = 0x00000001 -F_GETFD = 1 -F_SETFD = 2 -F_GETFL = 3 -F_SETFL = 4 - -FD_CLOEXEC = 1 - -os.O_NONBLOCK = 2048 - -FIONBIO = 126 - - -def fcntl(fd, op, arg=0): - if op == F_GETFD or op == F_GETFL: - return 0 - elif op == F_SETFD: - # Check that the flag is CLOEXEC and translate - if arg == FD_CLOEXEC: - success = SetHandleInformation(fd, HANDLE_FLAG_INHERIT, 0) - if not success: - raise ctypes.GetLastError() - else: - raise ValueError("Unsupported arg") - #elif op == F_SETFL: - ## Check that the flag is NONBLOCK and translate - #if arg == os.O_NONBLOCK: - ##pass - #result = ioctlsocket(fd, FIONBIO, 1) - #if result != 0: - #raise ctypes.GetLastError() - #else: - #raise ValueError("Unsupported arg") - else: - raise ValueError("Unsupported op") +def set_close_exec(fd): + success = SetHandleInformation(fd, HANDLE_FLAG_INHERIT, 0) + if not success: + raise ctypes.GetLastError() class Pipe(object): -- 2.47.2