def close(self): if self.iocp: poverlapped = LPOVERLAPPED() nbytes = DWORD() completion_key = c_ulong() while 1: rc = GetQueuedCompletionStatus( self.iocp, # HANDLE CompletionPort byref(nbytes), # LPDWORD lpNumberOfBytes byref(completion_key), # PULONG_PTR lpCompletionKey byref(poverlapped), 0 ) if not poverlapped: break else: act = poverlapped.contents.object if act in self.tokens: del self.tokens[act] CancelIo(act.sock._fd.fileno()) else: import warnings warnings.warn("act(%s) not in self.tokens" % act) CloseHandle(self.iocp) self.iocp = None if self.tokens: import warnings warnings.warn("self.tokens still pending: %s" % self.tokens) super(self.__class__, self).close()
def perform_sendall(act, overlapped): wsabuf = WSABUF() wsabuf.buf = c_char_p(act.buff[act.sent:]) wsabuf.len = len(act.buff)-act.sent nbytes = c_ulong() act.flags = wsabuf, nbytes return WSASend( act.sock._fd.fileno(), # SOCKET s byref(wsabuf), # LPWSABUF lpBuffers 1, # DWORD dwBufferCount byref(nbytes), # LPDWORD lpNumberOfBytesSent 0, # DWORD dwFlags overlapped, # LPWSAOVERLAPPED lpOverlapped None # LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine ), nbytes
def perform_recv(act, overlapped): wsabuf = WSABUF() buf = create_string_buffer(act.len) wsabuf.buf = cast(buf, c_char_p) wsabuf.len = act.len nbytes = c_ulong(0) flags = c_ulong(0) act.flags = buf rc = WSARecv( act.sock._fd.fileno(), # SOCKET s byref(wsabuf), # LPWSABUF lpBuffers 1, # DWORD dwBufferCount byref(nbytes), # LPDWORD lpNumberOfBytesRecvd byref(flags), # LPDWORD lpFlags overlapped, # LPWSAOVERLAPPED lpOverlapped None # LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine ) return rc, nbytes.value
def perform_accept(act, overlapped): act.conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM) act.cbuff = create_string_buffer((sizeof(sockaddr_in) + 16) * 2) nbytes = c_ulong() prot_info = WSAPROTOCOL_INFO() prot_info_len = c_int(sizeof(prot_info)) getsockopt(act.sock.fileno(), SOL_SOCKET, SO_PROTOCOL_INFOA, cast(byref(prot_info), c_char_p), byref(prot_info_len)) # BOOL return AcceptEx( act.sock._fd.fileno(), # SOCKET sListenSocket act.conn.fileno(), # SOCKET sAcceptSocket cast(act.cbuff, c_void_p), # PVOID lpOutputBuffer 0, # DWORD dwReceiveDataLength prot_info.iMaxSockAddr + 16, # DWORD dwLocalAddressLength prot_info.iMaxSockAddr + 16, # DWORD dwRemoteAddressLength nbytes, # LPDWORD lpdwBytesReceived overlapped # LPOVERLAPPED lpOverlapped ), 0
def run(self, timeout = 0): """ Calls GetQueuedCompletionStatus and handles completion via process_op. """ # same resolution as epoll ptimeout = int( timeout.days * 86400000 + timeout.microseconds / 1000 + timeout.seconds * 1000 if timeout else (self.m_resolution if timeout is None else 0) ) if self.tokens: scheduler = self.scheduler urgent = None # we use urgent as a optimisation: the last operation is returned #directly to the scheduler (the sched might just run it till it #goes to sleep) and not added in the sched.active queue while 1: try: poverlapped = LPOVERLAPPED() nbytes = DWORD() completion_key = c_ulong() #~ BOOL WINAPI GetQueuedCompletionStatus( #~ __in HANDLE CompletionPort, #~ __out LPDWORD lpNumberOfBytes, #~ __out PULONG_PTR lpCompletionKey, #~ __out LPOVERLAPPED *lpOverlapped, #~ __in DWORD dwMilliseconds #~ ); rc = GetQueuedCompletionStatus( self.iocp, # HANDLE CompletionPort byref(nbytes), # LPDWORD lpNumberOfBytes byref(completion_key), # PULONG_PTR lpCompletionKey byref(poverlapped), 0 if urgent else ptimeout ) overlap = poverlapped and poverlapped.contents nbytes = nbytes.value except RuntimeError, e: import warnings warnings.warn("RuntimeError(%s) on GetQueuedCompletionStatus." % e) # we will get "This overlapped object has lost all its # references so was destroyed" when we remove a operation, # it is garbage collected and the overlapped completes # afterwards break # well, this is a bit weird, if we get a aborted rc (via CancelIo #i suppose) evaluating the overlap crashes the interpeter #with a memory read error # also, we might get a "wait operation timed out", and no overlap pointer if rc != WSA_OPERATION_ABORTED and overlap: if urgent: op, coro = urgent urgent = None if op.prio & priority.OP: # imediately run the asociated coroutine step op, coro = scheduler.process_op( coro.run_op(op, scheduler), coro ) if coro: #TODO, what "op and " if op and (op.prio & priority.CORO): scheduler.active.appendleft( (op, coro) ) else: scheduler.active.append( (op, coro) ) if overlap.object: assert overlap.object in self.tokens urgent = self.process_op(rc, nbytes, overlap) else: #~ import warnings #~ warnings.warn("rc=(%s: %s) overlap=(%s)" % (rc, ctypes.FormatError(rc), overlap)) break return urgent
act.conn = act.sock.__class__(_sock=act.conn) return act def perform_connect(act, overlapped): # ConnectEx requires that the socket be bound beforehand try: # just in case we get a already-bound socket act.sock.bind(('0.0.0.0', 0)) except socket.error, exc: if exc[0] not in (errno.EINVAL, errno.WSAEINVAL): raise fileno = act.sock._fd.fileno() prot_info = WSAPROTOCOL_INFO() prot_info_len = c_int(sizeof(prot_info)) getsockopt(fileno, SOL_SOCKET, SO_PROTOCOL_INFOA, cast(byref(prot_info), c_char_p), byref(prot_info_len)) hints = addrinfo() hints.ai_family = prot_info.iAddressFamily hints.ai_socktype = prot_info.iSocketType hints.ai_protocol = prot_info.iProtocol result = addrinfo_p() getaddrinfo(act.addr[0], str(act.addr[1]), byref(hints), byref(result)); act.flags = result #~ act.sock.bind(('0.0.0.0', 0)) return ConnectEx( fileno, # SOCKET s result.contents.ai_addr, result.contents.ai_addrlen,