class SslHandshakingTransport(BaseSocketTransport): __slots__ = ["connected_dfr"] def __init__(self, reactor, sslsock): BaseSocketTransport.__init__(self, reactor, sslsock) self.connected_dfr = ReactorDeferred(self.reactor) def handshake(self): if not self.connected_dfr.is_set(): self._handshake() return self.connected_dfr def _handshake(self): try: self.sock.do_handshake() except ssl.SSLError as ex: if ex.errno == ssl.SSL_ERROR_WANT_READ: self.reactor.register_read(self) elif ex.errno == ssl.SSL_ERROR_WANT_WRITE: self.reactor.register_write(self) else: self.connected_dfr.throw(ex) else: sock = self.sock self.detach() trns = SslStreamTransport(self.reactor, sock) self.connected_dfr.set(trns) def on_read(self): self.reactor.unregister_read(self) self._handshake() def on_write(self): self.reactor.unregister_write(self) self._handshake()
def recvfrom(self, count=-1): if count < 0 or count > self.MAX_DATAGRAM_SIZE: count = self.MAX_DATAGRAM_SIZE if self._ongoing_read: raise OverlappingRequestError("overlapping recvfrom") self._ongoing_read = True def read_finished(size, exc): self._ongoing_read = False if exc: dfr.throw(exc) else: data = buf[:size] addrinfo = (sockaddr.addr_str, sockaddr.port) dfr.set((data, addrinfo)) dfr = ReactorDeferred(self.reactor) overlapped = self.reactor._get_overlapped(read_finished) try: buf, sockaddr, _ = winsock.WSARecvFromSocket( self.sock, count, overlapped) except Exception as ex: self._ongoing_read = False self.reactor._discard_overlapped(overlapped) dfr.throw(ex) return dfr
def __init__(self): self._active = False self._jobs = MinHeap() self._callbacks = [] #self._rcallbacks = [] self._subsystems = [] self.started = ReactorDeferred(weakref.proxy(self))
def recvfrom(self, count = -1): if count < 0 or count > self.MAX_DATAGRAM_SIZE: count = self.MAX_DATAGRAM_SIZE if self._ongoing_read: raise OverlappingRequestError("overlapping recvfrom") self._ongoing_read = True def read_finished(size, exc): self._ongoing_read = False if exc: dfr.throw(exc) else: data = buf[:size] addrinfo = (sockaddr.addr_str, sockaddr.port) dfr.set((data, addrinfo)) dfr = ReactorDeferred(self.reactor) overlapped = self.reactor._get_overlapped(read_finished) try: buf, sockaddr, _ = winsock.WSARecvFromSocket(self.sock, count, overlapped) except Exception as ex: self._ongoing_read = False self.reactor._discard_overlapped(overlapped) dfr.throw(ex) return dfr
class Process(object): def __init__(self, reactor, proc, cmdline): self.reactor = reactor self.cmdline = cmdline self._proc = proc self.stdin = BufferedTransport(self.reactor.io._wrap_pipe(proc.stdin, "w")) self.stdout = BufferedTransport(self.reactor.io._wrap_pipe(proc.stdout, "r")) self.stderr = BufferedTransport(self.reactor.io._wrap_pipe(proc.stderr, "r")) self.pid = proc.pid self.wait_dfr = ReactorDeferred(self.reactor) def __repr__(self): return "<Process %r: %r (%s)>" % (self.pid, self.cmdline, "alive" if self.is_alive() else "dead") def on_termination(self): self.wait_dfr.set(self.returncode) @property def returncode(self): return self._proc.returncode def is_alive(self): return self._proc.poll() is None def signal(self, sig): self._proc.send_signal(sig) @reactive def terminate(self): self._proc.terminate() def wait(self): return self.wait_dfr
def read(self, count): if self._read_req: raise OverlappingRequestError("overlapping reads") dfr = ReactorDeferred(self.reactor) if self._eof: dfr.set(None) elif count <= 0: dfr.set("") else: self._read_req = (dfr, count) self.reactor.register_read(self) return dfr
def __init__(self, reactor, proc, cmdline): self.reactor = reactor self.cmdline = cmdline self._proc = proc self.stdin = BufferedTransport( self.reactor.io._wrap_pipe(proc.stdin, "w")) self.stdout = BufferedTransport( self.reactor.io._wrap_pipe(proc.stdout, "r")) self.stderr = BufferedTransport( self.reactor.io._wrap_pipe(proc.stderr, "r")) self.pid = proc.pid self.wait_dfr = ReactorDeferred(self.reactor)
class PipeTransport(StreamTransport): #__slots__ = ["mode", "name", "_flush_dfr", "auto_flush"] def __init__(self, reactor, fileobj, mode, auto_flush=True): if mode not in ("r", "w", "rw"): raise ValueError("invalid mode") StreamTransport.__init__(self, reactor, fileobj) self.name = getattr(self.fileobj, "name", None) self.mode = mode self._flush_dfr = None self.auto_flush = auto_flush if "r" not in mode: self.read = self._wrong_mode self.properties.pop("readable", None) if "w" not in mode: self.flush = self._wrong_mode self.write = self._wrong_mode self.properties.pop("writable", None) if fcntl: self._unblock(self.fileno()) @staticmethod def _wrong_mode(*args): raise IOError("wrong mode for operation") @staticmethod def _unblock(fd): flags = fcntl.fcntl(fd, fcntl.F_GETFL, 0) fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK) def isatty(self): return self.fileobj.isatty() def flush(self): if not self._flush_dfr: self._flush_dfr = ReactorDeferred(self.reactor) self.reactor.register_write(self) return self._flush_dfr def _flush(self): self.fileobj.flush() os.fsync(self.fileno()) if self._flush_dfr: self._flush_dfr.set() self._flush_dfr = None def on_write(self): StreamTransport.on_write(self) if self.auto_flush or self._flush_dfr: self._flush()
def recvfrom(self, count=-1): if self._read_req: raise OverlappingRequestError("overlapping recvfrom") dfr = ReactorDeferred(self.reactor) self._read_req = (dfr, count) self.reactor.register_read(self) return dfr
def write(self, data): if self._write_req: raise OverlappingRequestError("overlapping writes") dfr = ReactorDeferred(self.reactor) self._write_req = (dfr, data) self.reactor.register_write(self) return dfr
class PipeTransport(StreamTransport): #__slots__ = ["mode", "name", "_flush_dfr", "auto_flush"] def __init__(self, reactor, fileobj, mode, auto_flush = True): if mode not in ("r", "w", "rw"): raise ValueError("invalid mode") StreamTransport.__init__(self, reactor, fileobj) self.name = getattr(self.fileobj, "name", None) self.mode = mode self._flush_dfr = None self.auto_flush = auto_flush if "r" not in mode: self.read = self._wrong_mode self.properties.pop("readable", None) if "w" not in mode: self.flush = self._wrong_mode self.write = self._wrong_mode self.properties.pop("writable", None) if fcntl: self._unblock(self.fileno()) @staticmethod def _wrong_mode(*args): raise IOError("wrong mode for operation") @staticmethod def _unblock(fd): flags = fcntl.fcntl(fd, fcntl.F_GETFL, 0) fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK) def isatty(self): return self.fileobj.isatty() def flush(self): if not self._flush_dfr: self._flush_dfr = ReactorDeferred(self.reactor) self.reactor.register_write(self) return self._flush_dfr def _flush(self): self.fileobj.flush() os.fsync(self.fileno()) if self._flush_dfr: self._flush_dfr.set() self._flush_dfr = None def on_write(self): StreamTransport.on_write(self) if self.auto_flush or self._flush_dfr: self._flush()
def sendto(self, addr, data): if len(data) > self.MAX_DATAGRAM_SIZE: raise TransportError("data too long") if self._write_req: raise OverlappingRequestError("overlapping sendto") dfr = ReactorDeferred(self.reactor) self._write_req = (dfr, addr, data) self.reactor.register_write(self) return dfr
def __init__(self, reactor, proc, cmdline): self.reactor = reactor self.cmdline = cmdline self._proc = proc self.stdin = BufferedTransport(self.reactor.io._wrap_pipe(proc.stdin, "w")) self.stdout = BufferedTransport(self.reactor.io._wrap_pipe(proc.stdout, "r")) self.stderr = BufferedTransport(self.reactor.io._wrap_pipe(proc.stderr, "r")) self.pid = proc.pid self.wait_dfr = ReactorDeferred(self.reactor)
def accept(self): def accept_finished(size, exc): if exc: self.reactor.call(trns.close) dfr.throw(exc) else: dfr.set(trns) dfr = ReactorDeferred(self.reactor) overlapped = self.reactor._get_overlapped(accept_finished) try: sock = socket.socket(self.sock.family, self.sock.type) # this is needed here to register the new socket with its IOCP trns = self.factory(self.reactor, sock) fd = sock.fileno() buffer = win32file.AllocateReadBuffer(win32file.CalculateSocketEndPointSize(fd)) win32file.AcceptEx(self.fileno(), fd, buffer, overlapped) except Exception as ex: self.reactor._discard_overlapped(overlapped) dfr.throw(ex) return dfr
def schedule(self, interval, func, *args, **kwargs): def wrapper(): try: res = func(*args, **kwargs) except Exception as ex: dfr.throw(ex) else: dfr.set(res) functools.update_wrapper(wrapper, func) dfr = ReactorDeferred(self.reactor) self.reactor.call_at(time.time() + interval, wrapper) return dfr
def accept(self): def accept_finished(size, exc): if exc: self.reactor.call(trns.close) dfr.throw(exc) else: dfr.set(trns) dfr = ReactorDeferred(self.reactor) overlapped = self.reactor._get_overlapped(accept_finished) try: sock = socket.socket(self.sock.family, self.sock.type) # this is needed here to register the new socket with its IOCP trns = self.factory(self.reactor, sock) fd = sock.fileno() buffer = win32file.AllocateReadBuffer( win32file.CalculateSocketEndPointSize(fd)) win32file.AcceptEx(self.fileno(), fd, buffer, overlapped) except Exception as ex: self.reactor._discard_overlapped(overlapped) dfr.throw(ex) return dfr
def sendto(self, addr, data): if len(data) > self.MAX_DATAGRAM_SIZE: raise TransportError("data too long") if self._ongoing_write: raise OverlappingRequestError("overlapping sendto") self._ongoing_write = True def write_finished(size, exc): self._ongoing_write = False if exc: dfr.throw(exc) else: dfr.set(size) # return actual sent size dfr = ReactorDeferred(self.reactor) overlapped = self.reactor._get_overlapped(write_finished) try: winsock.WSASendToSocket(self.sock, data, addr, overlapped) except Exception as ex: self._ongoing_read = False self.reactor._discard_overlapped(overlapped) dfr.throw(ex) return dfr
class Process(object): def __init__(self, reactor, proc, cmdline): self.reactor = reactor self.cmdline = cmdline self._proc = proc self.stdin = BufferedTransport( self.reactor.io._wrap_pipe(proc.stdin, "w")) self.stdout = BufferedTransport( self.reactor.io._wrap_pipe(proc.stdout, "r")) self.stderr = BufferedTransport( self.reactor.io._wrap_pipe(proc.stderr, "r")) self.pid = proc.pid self.wait_dfr = ReactorDeferred(self.reactor) def __repr__(self): return "<Process %r: %r (%s)>" % (self.pid, self.cmdline, "alive" if self.is_alive() else "dead") def on_termination(self): self.wait_dfr.set(self.returncode) @property def returncode(self): return self._proc.returncode def is_alive(self): return self._proc.poll() is None def signal(self, sig): self._proc.send_signal(sig) @reactive def terminate(self): self._proc.terminate() def wait(self): return self.wait_dfr
def read(self, count): # XXX: # The ReadFile function may fail with ERROR_INVALID_USER_BUFFER or # ERROR_NOT_ENOUGH_MEMORY whenever there are too many outstanding # asynchronous I/O requests. # # XXX: # http://support.microsoft.com/kb/156932 -- ReadFile may return # immediately, need to check that condition if self._ongoing_read: raise OverlappingRequestError("overlapping reads") self._ongoing_read = True def read_finished(size, exc): if size == 0: data = None # EOF else: data = bytes(buf[:size]) self._ongoing_read = False if exc: dfr.throw(exc) else: dfr.set(data) dfr = ReactorDeferred(self.reactor) count = min(count, self.MAX_READ_SIZE) if count <= 0: self._ongoing_read = False dfr.set("") return dfr overlapped = self._get_read_overlapped(read_finished) try: buf = win32file.AllocateReadBuffer(count) win32file.ReadFile(self.fileno(), buf, overlapped) except Exception as ex: self.reactor._discard_overlapped(overlapped) self._ongoing_read = False if isinstance(ex, pywintypes.error ) and ex.winerror in win32iocp.IGNORED_ERRORS: # why can't windows be just a little consistent?! # why can't a set of APIs share the same semantics for all kinds # of handles? grrrrr dfr.set(None) else: dfr.throw(ex) return dfr
class ConnectingSocketTransport(BaseSocketTransport): __slots__ = ["addr", "connected_dfr", "_connecting"] def __init__(self, reactor, sock, addr): BaseSocketTransport.__init__(self, reactor, sock) self.addr = addr self.connected_dfr = ReactorDeferred(self.reactor) self._connecting = False def connect(self, timeout=None): if self._connecting: raise OverlappingRequestError("already connecting") self._connecting = True if timeout is not None: self.reactor.jobs.schedule(timeout, self._cancel) self.reactor.register_write(self) self._attempt_connect() return self.connected_dfr def on_write(self): self._attempt_connect() def _attempt_connect(self): if self.connected_dfr.is_set(): self.detach() return err = self.sock.connect_ex(self.addr) if err in (errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK): return if err == errno.EINVAL and sys.platform == "win32": return sock = self.sock self.detach() if err in (0, errno.EISCONN): self.connected_dfr.set(SocketStreamTransport(self.reactor, sock)) else: self.connected_dfr.throw(socket.error(err, errno.errorcode[err])) def _cancel(self): if self.connected_dfr.is_set(): return self.close() self.connected_dfr.throw(socket.timeout("connection timed out"))
class ConnectingSocketTransport(BaseSocketTransport): __slots__ = ["addr", "connected_dfr", "_connecting"] def __init__(self, reactor, sock, addr): BaseSocketTransport.__init__(self, reactor, sock) self.addr = addr self.connected_dfr = ReactorDeferred(self.reactor) self._connecting = False def connect(self, timeout = None): if self._connecting: raise OverlappingRequestError("already connecting") self._connecting = True if timeout is not None: self.reactor.jobs.schedule(timeout, self._cancel) self.reactor.register_write(self) self._attempt_connect() return self.connected_dfr def on_write(self): self._attempt_connect() def _attempt_connect(self): if self.connected_dfr.is_set(): self.detach() return err = self.sock.connect_ex(self.addr) if err in (errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK): return if err == errno.EINVAL and sys.platform == "win32": return sock = self.sock self.detach() if err in (0, errno.EISCONN): self.connected_dfr.set(SocketStreamTransport(self.reactor, sock)) else: self.connected_dfr.throw(socket.error(err, errno.errorcode[err])) def _cancel(self): if self.connected_dfr.is_set(): return self.close() self.connected_dfr.throw(socket.timeout("connection timed out"))
def schedule_every(self, interval, func, *args, **kwargs): def wrapper(): try: res = func(*args, **kwargs) except Exception as ex: dfr.throw(ex) else: if res is False: dfr.set() else: ts = t0 + (((time.time() - t0) // interval) + 1) * interval self.reactor.call_at(ts, wrapper) functools.update_wrapper(wrapper, func) dfr = ReactorDeferred(self.reactor) t0 = time.time() self.reactor.call_at(t0, wrapper) return dfr
def read(self, count): # XXX: # The ReadFile function may fail with ERROR_INVALID_USER_BUFFER or # ERROR_NOT_ENOUGH_MEMORY whenever there are too many outstanding # asynchronous I/O requests. # # XXX: # http://support.microsoft.com/kb/156932 -- ReadFile may return # immediately, need to check that condition if self._ongoing_read: raise OverlappingRequestError("overlapping reads") self._ongoing_read = True def read_finished(size, exc): if size == 0: data = None # EOF else: data = bytes(buf[:size]) self._ongoing_read = False if exc: dfr.throw(exc) else: dfr.set(data) dfr = ReactorDeferred(self.reactor) count = min(count, self.MAX_READ_SIZE) if count <= 0: self._ongoing_read = False dfr.set("") return dfr overlapped = self._get_read_overlapped(read_finished) try: buf = win32file.AllocateReadBuffer(count) win32file.ReadFile(self.fileno(), buf, overlapped) except Exception as ex: self.reactor._discard_overlapped(overlapped) self._ongoing_read = False if isinstance(ex, pywintypes.error) and ex.winerror in win32iocp.IGNORED_ERRORS: # why can't windows be just a little consistent?! # why can't a set of APIs share the same semantics for all kinds # of handles? grrrrr dfr.set(None) else: dfr.throw(ex) return dfr
def write(self, data): # XXX: # The WriteFile function may fail with ERROR_INVALID_USER_BUFFER or # ERROR_NOT_ENOUGH_MEMORY whenever there are too many outstanding # asynchronous I/O requests. # # XXX: # http://support.microsoft.com/kb/156932 -- WriteFile may return # immediately, need to check that condition if self._ongoing_write: raise OverlappingRequestError("overlapping writes") self._ongoing_write = True remaining = [data] def write_finished(size, exc): remaining[0] = remaining[0][size:] if exc: dfr.throw(exc) elif not remaining[0]: self._ongoing_write = False dfr.set() else: write_some() def write_some(): if not remaining[0]: self._ongoing_write = False dfr.set() return chunk = remaining[0][:self.MAX_READ_SIZE] overlapped = self._get_read_overlapped(write_finished) try: win32file.WriteFile(self.fileno(), chunk, overlapped) except Exception as ex: self._ongoing_write = False self.reactor._discard_overlapped(overlapped) dfr.throw(ex) dfr = ReactorDeferred(self.reactor) write_some() return dfr
def call(self, func, *args, **kwargs): def worker(): try: res = func(*args, **kwargs) except Exception as ex: dfr.throw(ex) else: dfr.set(res) finally: self._threads.discard(thd) self.reactor._wakeup() dfr = ReactorDeferred(self.reactor) tid = self.ID_GENERATOR.next() thd = threading.Thread(name="thread-%d" % (tid, ), target=worker) self._threads.add(thd) thd.setDaemon(True) thd.start() return dfr
def connect_tcp(self, host, port, timeout=None): def connect_finished(size, overlapped): trns_dfr.set(trns) yield self.reactor.started hostaddr = yield self.resolve(host) trns_dfr = ReactorDeferred(self.reactor) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setblocking(False) sock.bind(('0.0.0.0', 0)) # ConnectEx requires the socket to be bound # this is required here to register the new socket with its IOCP trns = SocketStreamTransport(self.reactor, sock) overlapped = self.reactor._get_overlapped(connect_finished) try: win32file.ConnectEx(sock.fileno(), (hostaddr, port), overlapped) except Exception: self.reactor._discard_overlapped(overlapped) raise yield trns_dfr rreturn(trns)
class BaseReactor(object): if sys.platform == "win32": MAX_TIMEOUT = 0.2 # to process Ctrl+C else: MAX_TIMEOUT = 1 SUBSYSTEMS = GENERIC_SUBSYSTEMS def __init__(self): self._active = False self._jobs = MinHeap() self._callbacks = [] #self._rcallbacks = [] self._subsystems = [] self.started = ReactorDeferred(weakref.proxy(self)) @classmethod def supported(cls): return False #=========================================================================== # Core #=========================================================================== def install_subsystem(self, factory): subs = factory(weakref.proxy(self)) if hasattr(self, subs.NAME): raise ValueError("attribute %r already exists" % (subs.NAME,)) setattr(self, subs.NAME, subs) subs._init() self._subsystems.append(subs.NAME) def uninstall_subsystem(self, name): subs = getattr(self, name) subs._unload() #subs.reactor = None def _install_builtin_subsystems(self): for factory in self.SUBSYSTEMS: self.install_subsystem(factory) def start(self): if self._active: raise ReactorError("reactor already running") self._active = True self.started.set() try: while self._active: self._work() except KeyboardInterrupt: pass finally: self._active = False def stop(self): if not self._active: return self._active = False self.started.cancel() for name in self._subsystems: self.call(self.uninstall_subsystem, name) self._wakeup() def run(self, func): self.call(func, self) self.start() #=========================================================================== # Internal #=========================================================================== def _wakeup(self): raise NotImplementedError() def _work(self): now = time.time() timeout = self._process_jobs(now) if self._callbacks: timeout = 0 self._handle_transports(min(timeout, self.MAX_TIMEOUT)) self._process_callbacks() def _process_jobs(self, now): while self._jobs: ts, func, args, kwargs = self._jobs.peek() if now < ts: return ts - now self._jobs.pop() self._callbacks.append((func, args, kwargs)) return self.MAX_TIMEOUT def _process_callbacks(self): callbacks = self._callbacks self._callbacks = [] for cb, args, kwargs in callbacks: cb(*args, **kwargs) #=========================================================================== # Callbacks #=========================================================================== def call(self, func, *args, **kwargs): self._callbacks.append((func, args, kwargs)) def call_at(self, ts, func, *args, **kwargs): self._jobs.push((ts, func, args, kwargs))
def accept(self): if self._accept_dfr: raise OverlappingRequestError("overlapping accept") self._accept_dfr = ReactorDeferred(self.reactor) self.reactor.register_read(self) return self._accept_dfr
def __init__(self, reactor, sock, addr): BaseSocketTransport.__init__(self, reactor, sock) self.addr = addr self.connected_dfr = ReactorDeferred(self.reactor) self._connecting = False
def call(self, func, *args, **kwargs): dfr = ReactorDeferred(self.reactor) self._tasks.put((dfr, func, args, kwargs)) self._spawn_workers() return dfr
def __init__(self, reactor, sslsock): BaseSocketTransport.__init__(self, reactor, sslsock) self.connected_dfr = ReactorDeferred(self.reactor)
class BaseReactor(object): if sys.platform == "win32": MAX_TIMEOUT = 0.2 # to process Ctrl+C else: MAX_TIMEOUT = 1 SUBSYSTEMS = GENERIC_SUBSYSTEMS def __init__(self): self._active = False self._jobs = MinHeap() self._callbacks = [] #self._rcallbacks = [] self._subsystems = [] self.started = ReactorDeferred(weakref.proxy(self)) @classmethod def supported(cls): return False #=========================================================================== # Core #=========================================================================== def install_subsystem(self, factory): subs = factory(weakref.proxy(self)) if hasattr(self, subs.NAME): raise ValueError("attribute %r already exists" % (subs.NAME, )) setattr(self, subs.NAME, subs) subs._init() self._subsystems.append(subs.NAME) def uninstall_subsystem(self, name): subs = getattr(self, name) subs._unload() #subs.reactor = None def _install_builtin_subsystems(self): for factory in self.SUBSYSTEMS: self.install_subsystem(factory) def start(self): if self._active: raise ReactorError("reactor already running") self._active = True self.started.set() try: while self._active: self._work() except KeyboardInterrupt: pass finally: self._active = False def stop(self): if not self._active: return self._active = False self.started.cancel() for name in self._subsystems: self.call(self.uninstall_subsystem, name) self._wakeup() def run(self, func): self.call(func, self) self.start() #=========================================================================== # Internal #=========================================================================== def _wakeup(self): raise NotImplementedError() def _work(self): now = time.time() timeout = self._process_jobs(now) if self._callbacks: timeout = 0 self._handle_transports(min(timeout, self.MAX_TIMEOUT)) self._process_callbacks() def _process_jobs(self, now): while self._jobs: ts, func, args, kwargs = self._jobs.peek() if now < ts: return ts - now self._jobs.pop() self._callbacks.append((func, args, kwargs)) return self.MAX_TIMEOUT def _process_callbacks(self): callbacks = self._callbacks self._callbacks = [] for cb, args, kwargs in callbacks: cb(*args, **kwargs) #=========================================================================== # Callbacks #=========================================================================== def call(self, func, *args, **kwargs): self._callbacks.append((func, args, kwargs)) def call_at(self, ts, func, *args, **kwargs): self._jobs.push((ts, func, args, kwargs))
def _request_console_read(self): self._assure_started() if not self._console_input_dfr or self._console_input_dfr.is_set(): self._console_input_dfr = ReactorDeferred(self.reactor) return self._console_input_dfr
def flush(self): if not self._flush_dfr: self._flush_dfr = ReactorDeferred(self.reactor) self.reactor.register_write(self) return self._flush_dfr
class IOSubsystem(Subsystem): NAME = "io" def _init(self): # self._console_thd = None # if winconsole.Console.is_attached(): # print "console attached" # self.console = winconsole.Console() # self._console_buffer = "" # self._console_input_dfr = None # self._console_thd = threading.Thread(target = self._console_input_thread) # self._console_thd.daemon = True # self._console_thd_started = False # else: # self.console = None # # check if stdin has FLAG_FILE_FLAG_OVERLAPPED by trying to register # # it with the IOCP # handle = msvcrt.get_osfhandle(sys.stdin.fileno()) # try: # self.reactor._port.register(handle) # except win32file.error: # print "no OVERLAPPED" # self._console_buffer = "" # self._console_input_dfr = None # self._console_thd = threading.Thread(target = self._console_input_thread) # self._console_thd.daemon = True # self._console_thd_started = False # else: # print "OVERLAPPED enabled" # # successfully registered with IOCP -- PipeTransport will work # # just fine # pass self._stdin = None self._stdout = None self._stderr = None #def _unload(self): # if self.console: # self.console.close() # self.console = None @property def stdin(self): if not self._stdin: #if getattr(self, "_console_thd", False): # self._stdin = ConsoleInputTransport(self.reactor) #else: self._stdin = PipeTransport(self.reactor, sys.stdin, "r") return self._stdin @property def stdout(self): if not self._stdout: #if getattr(self, "_console_thd", False): # self._stdout = BlockingStreamTransport(self, sys.stdout) #else: self._stdout = PipeTransport(self.reactor, sys.stdout, "w") return self._stdout @property def stderr(self): if not self._stderr: #if getattr(self, "_console_thd", False): # self._stderr = BlockingStreamTransport(self, sys.stdout) #else: self._stderr = PipeTransport(self.reactor, sys.stderr, "w") return self._stderr def _assure_started(self): if getattr(self, "_console_thd", False) and not self._console_thd_started: self._console_thd.start() self._console_thd_started = True def _request_console_read(self): self._assure_started() if not self._console_input_dfr or self._console_input_dfr.is_set(): self._console_input_dfr = ReactorDeferred(self.reactor) return self._console_input_dfr def _console_input_thread(self): while self.reactor._active: data = os.read(sys.stdin.fileno(), 1000) self._console_buffer += data if self._console_input_dfr and not self._console_input_dfr.is_set( ): self._console_input_dfr.set(self._console_buffer) self._console_buffer = "" self._console_input_dfr = None self.reactor._wakeup() def _wrap_pipe(self, fileobj, mode): return PipeTransport(self.reactor, fileobj, mode) @reactive def open(self, filename, mode): yield self.reactor.started fobj, access = win32iocp.WinFile.open(filename, mode) rreturn(FileTransport(self.reactor, fobj, access)) @reactive def pipe(self): yield self.reactor.started rh, wh = win32iocp.create_overlapped_pipe() rtrns = PipeTransport(self.reactor, win32iocp.WinFile(rh), "r") wtrns = PipeTransport(self.reactor, win32iocp.WinFile(wh), "w") rreturn((rtrns, wtrns))
class IOSubsystem(Subsystem): NAME = "io" def _init(self): # self._console_thd = None # if winconsole.Console.is_attached(): # print "console attached" # self.console = winconsole.Console() # self._console_buffer = "" # self._console_input_dfr = None # self._console_thd = threading.Thread(target = self._console_input_thread) # self._console_thd.daemon = True # self._console_thd_started = False # else: # self.console = None # # check if stdin has FLAG_FILE_FLAG_OVERLAPPED by trying to register # # it with the IOCP # handle = msvcrt.get_osfhandle(sys.stdin.fileno()) # try: # self.reactor._port.register(handle) # except win32file.error: # print "no OVERLAPPED" # self._console_buffer = "" # self._console_input_dfr = None # self._console_thd = threading.Thread(target = self._console_input_thread) # self._console_thd.daemon = True # self._console_thd_started = False # else: # print "OVERLAPPED enabled" # # successfully registered with IOCP -- PipeTransport will work # # just fine # pass self._stdin = None self._stdout = None self._stderr = None #def _unload(self): # if self.console: # self.console.close() # self.console = None @property def stdin(self): if not self._stdin: #if getattr(self, "_console_thd", False): # self._stdin = ConsoleInputTransport(self.reactor) #else: self._stdin = PipeTransport(self.reactor, sys.stdin, "r") return self._stdin @property def stdout(self): if not self._stdout: #if getattr(self, "_console_thd", False): # self._stdout = BlockingStreamTransport(self, sys.stdout) #else: self._stdout = PipeTransport(self.reactor, sys.stdout, "w") return self._stdout @property def stderr(self): if not self._stderr: #if getattr(self, "_console_thd", False): # self._stderr = BlockingStreamTransport(self, sys.stdout) #else: self._stderr = PipeTransport(self.reactor, sys.stderr, "w") return self._stderr def _assure_started(self): if getattr(self, "_console_thd", False) and not self._console_thd_started: self._console_thd.start() self._console_thd_started = True def _request_console_read(self): self._assure_started() if not self._console_input_dfr or self._console_input_dfr.is_set(): self._console_input_dfr = ReactorDeferred(self.reactor) return self._console_input_dfr def _console_input_thread(self): while self.reactor._active: data = os.read(sys.stdin.fileno(), 1000) self._console_buffer += data if self._console_input_dfr and not self._console_input_dfr.is_set(): self._console_input_dfr.set(self._console_buffer) self._console_buffer = "" self._console_input_dfr = None self.reactor._wakeup() def _wrap_pipe(self, fileobj, mode): return PipeTransport(self.reactor, fileobj, mode) @reactive def open(self, filename, mode): yield self.reactor.started fobj, access = win32iocp.WinFile.open(filename, mode) rreturn(FileTransport(self.reactor, fobj, access)) @reactive def pipe(self): yield self.reactor.started rh, wh = win32iocp.create_overlapped_pipe() rtrns = PipeTransport(self.reactor, win32iocp.WinFile(rh), "r") wtrns = PipeTransport(self.reactor, win32iocp.WinFile(wh), "w") rreturn((rtrns, wtrns))