@@ -742,6 +742,20 @@ cdef class Loop:
742742
743743 return result
744744
745+ cdef _has_reader(self , fileobj):
746+ cdef:
747+ UVPoll poll
748+
749+ self ._check_closed()
750+ fd = self ._fileobj_to_fd(fileobj)
751+
752+ try :
753+ poll = < UVPoll> (self ._polls[fd])
754+ except KeyError :
755+ return False
756+
757+ return poll.is_reading()
758+
745759 cdef _add_writer(self , fileobj, Handle handle):
746760 cdef:
747761 UVPoll poll
@@ -791,6 +805,20 @@ cdef class Loop:
791805
792806 return result
793807
808+ cdef _has_writer(self , fileobj):
809+ cdef:
810+ UVPoll poll
811+
812+ self ._check_closed()
813+ fd = self ._fileobj_to_fd(fileobj)
814+
815+ try :
816+ poll = < UVPoll> (self ._polls[fd])
817+ except KeyError :
818+ return False
819+
820+ return poll.is_writing()
821+
794822 cdef _getaddrinfo(self , object host, object port,
795823 int family, int type ,
796824 int proto, int flags,
@@ -845,35 +873,17 @@ cdef class Loop:
845873 nr.query(addr, flags)
846874 return fut
847875
848- cdef _new_reader_future(self , sock):
849- def _on_cancel (fut ):
850- # Check if the future was cancelled and if the socket
851- # is still open, i.e.
852- #
853- # loop.remove_reader(sock)
854- # sock.close()
855- # fut.cancel()
856- #
857- # wasn't called by the user.
858- if fut.cancelled() and sock.fileno() != - 1 :
859- self ._remove_reader(sock)
860-
861- fut = self ._new_future()
862- fut.add_done_callback(_on_cancel)
863- return fut
864-
865- cdef _new_writer_future(self , sock):
866- def _on_cancel (fut ):
867- if fut.cancelled() and sock.fileno() != - 1 :
868- self ._remove_writer(sock)
869-
870- fut = self ._new_future()
871- fut.add_done_callback(_on_cancel)
872- return fut
873-
874876 cdef _sock_recv(self , fut, sock, n):
875- cdef:
876- Handle handle
877+ if UVLOOP_DEBUG:
878+ if fut.cancelled():
879+ # Shouldn't happen with _SyncSocketReaderFuture.
880+ raise RuntimeError (
881+ f' _sock_recv is called on a cancelled Future' )
882+
883+ if not self ._has_reader(sock):
884+ raise RuntimeError (
885+ f' socket {sock!r} does not have a reader '
886+ f' in the _sock_recv callback' )
877887
878888 try :
879889 data = sock.recv(n)
@@ -889,8 +899,16 @@ cdef class Loop:
889899 self ._remove_reader(sock)
890900
891901 cdef _sock_recv_into(self , fut, sock, buf):
892- cdef:
893- Handle handle
902+ if UVLOOP_DEBUG:
903+ if fut.cancelled():
904+ # Shouldn't happen with _SyncSocketReaderFuture.
905+ raise RuntimeError (
906+ f' _sock_recv_into is called on a cancelled Future' )
907+
908+ if not self ._has_reader(sock):
909+ raise RuntimeError (
910+ f' socket {sock!r} does not have a reader '
911+ f' in the _sock_recv_into callback' )
894912
895913 try :
896914 data = sock.recv_into(buf)
@@ -910,6 +928,17 @@ cdef class Loop:
910928 Handle handle
911929 int n
912930
931+ if UVLOOP_DEBUG:
932+ if fut.cancelled():
933+ # Shouldn't happen with _SyncSocketReaderFuture.
934+ raise RuntimeError (
935+ f' _sock_sendall is called on a cancelled Future' )
936+
937+ if not self ._has_writer(sock):
938+ raise RuntimeError (
939+ f' socket {sock!r} does not have a writer '
940+ f' in the _sock_sendall callback' )
941+
913942 try :
914943 n = sock.send(data)
915944 except (BlockingIOError, InterruptedError):
@@ -940,9 +969,6 @@ cdef class Loop:
940969 self ._add_writer(sock, handle)
941970
942971 cdef _sock_accept(self , fut, sock):
943- cdef:
944- Handle handle
945-
946972 try :
947973 conn, address = sock.accept()
948974 conn.setblocking(False )
@@ -2217,7 +2243,7 @@ cdef class Loop:
22172243 if self ._debug and sock.gettimeout() != 0 :
22182244 raise ValueError (" the socket must be non-blocking" )
22192245
2220- fut = self ._new_reader_future (sock)
2246+ fut = _SyncSocketReaderFuture (sock, self )
22212247 handle = new_MethodHandle3(
22222248 self ,
22232249 " Loop._sock_recv" ,
@@ -2243,7 +2269,7 @@ cdef class Loop:
22432269 if self ._debug and sock.gettimeout() != 0 :
22442270 raise ValueError (" the socket must be non-blocking" )
22452271
2246- fut = self ._new_reader_future (sock)
2272+ fut = _SyncSocketReaderFuture (sock, self )
22472273 handle = new_MethodHandle3(
22482274 self ,
22492275 " Loop._sock_recv_into" ,
@@ -2294,7 +2320,7 @@ cdef class Loop:
22942320 data = memoryview(data)
22952321 data = data[n:]
22962322
2297- fut = self ._new_writer_future (sock)
2323+ fut = _SyncSocketWriterFuture (sock, self )
22982324 handle = new_MethodHandle3(
22992325 self ,
23002326 " Loop._sock_sendall" ,
@@ -2324,7 +2350,7 @@ cdef class Loop:
23242350 if self ._debug and sock.gettimeout() != 0 :
23252351 raise ValueError (" the socket must be non-blocking" )
23262352
2327- fut = self ._new_reader_future (sock)
2353+ fut = _SyncSocketReaderFuture (sock, self )
23282354 handle = new_MethodHandle2(
23292355 self ,
23302356 " Loop._sock_accept" ,
@@ -2908,6 +2934,36 @@ cdef inline void __loop_free_buffer(Loop loop):
29082934 loop._recv_buffer_in_use = 0
29092935
29102936
2937+ class _SyncSocketReaderFuture (aio_Future ):
2938+
2939+ def __init__ (self , sock , loop ):
2940+ aio_Future.__init__ (self , loop = loop)
2941+ self .__sock = sock
2942+ self .__loop = loop
2943+
2944+ def cancel (self ):
2945+ if self .__sock is not None and self .__sock.fileno() != - 1 :
2946+ self .__loop.remove_reader(self .__sock)
2947+ self .__sock = None
2948+
2949+ aio_Future.cancel(self )
2950+
2951+
2952+ class _SyncSocketWriterFuture (aio_Future ):
2953+
2954+ def __init__ (self , sock , loop ):
2955+ aio_Future.__init__ (self , loop = loop)
2956+ self .__sock = sock
2957+ self .__loop = loop
2958+
2959+ def cancel (self ):
2960+ if self .__sock is not None and self .__sock.fileno() != - 1 :
2961+ self .__loop.remove_writer(self .__sock)
2962+ self .__sock = None
2963+
2964+ aio_Future.cancel(self )
2965+
2966+
29112967include " cbhandles.pyx"
29122968include " pseudosock.pyx"
29132969
0 commit comments