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_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_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_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