diff --git a/LICENSE-APACHE b/LICENSE-APACHE index a1de698c..5f66d4ee 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -1,4 +1,4 @@ -Copyright (c) 2015-present MagicStack Inc. http://magic.io +Copyright (C) 2016-present the uvloop authors and contributors. Apache License Version 2.0, January 2004 diff --git a/LICENSE-MIT b/LICENSE-MIT index e6b42c6f..40fd0230 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,6 +1,6 @@ The MIT License -Copyright (c) 2015-present MagicStack Inc. http://magic.io +Copyright (C) 2016-present the uvloop authors and contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/uvloop/handles/stream.pxd b/uvloop/handles/stream.pxd index 21ac6279..da6b8f67 100644 --- a/uvloop/handles/stream.pxd +++ b/uvloop/handles/stream.pxd @@ -21,7 +21,6 @@ cdef class UVStream(UVBaseTransport): cdef inline _init(self, Loop loop, object protocol, Server server, object waiter, object context) - cdef inline _exec_write(self) cdef inline _shutdown(self) cdef inline _accept(self, UVStream server) @@ -31,7 +30,15 @@ cdef class UVStream(UVBaseTransport): cdef inline __reading_started(self) cdef inline __reading_stopped(self) - cdef inline _write(self, object data) + # The user API firstly calls _buffer_write() to buffer up user data chunks, + # potentially multiple times in writelines(), and then call _start_write() + # to start writing either immediately or in the next iteration. + cdef inline _buffer_write(self, object data) + cdef inline _start_write(self) + + # _exec_write() is the method that does the actual send, and _try_write() + # is a fast-path used in _exec_write() to send a single chunk. + cdef inline _exec_write(self) cdef inline _try_write(self, object data) cdef _close(self) diff --git a/uvloop/handles/stream.pyx b/uvloop/handles/stream.pyx index 4757ce7a..d1bb4ced 100644 --- a/uvloop/handles/stream.pyx +++ b/uvloop/handles/stream.pyx @@ -162,7 +162,7 @@ cdef class _StreamWriteContext: PyObject_GetBuffer( buf, &p_pybufs[py_bufs_len], PyBUF_SIMPLE) except Exception: - # This shouldn't ever happen, as `UVStream._write` + # This shouldn't ever happen, as `UVStream._buffer_write` # casts non-bytes objects to `memoryviews`. ctx.py_bufs_len = py_bufs_len ctx.free_bufs() @@ -407,7 +407,7 @@ cdef class UVStream(UVBaseTransport): return written - cdef inline _write(self, object data): + cdef inline _buffer_write(self, object data): cdef int dlen if not PyBytes_CheckExact(data): @@ -420,6 +420,7 @@ cdef class UVStream(UVBaseTransport): self._buffer_size += dlen self._buffer.append(data) + cdef inline _start_write(self): if (not self._protocol_paused and (self._handle).write_queue_size == 0 and self._buffer_size > self._high_water): @@ -443,10 +444,10 @@ cdef class UVStream(UVBaseTransport): # If not all of the data was sent successfully, # we might need to pause the protocol. self._maybe_pause_protocol() - return - self._maybe_pause_protocol() - self._loop._queue_write(self) + elif self._buffer_size > 0: + self._maybe_pause_protocol() + self._loop._queue_write(self) cdef inline _exec_write(self): cdef: @@ -679,7 +680,8 @@ cdef class UVStream(UVBaseTransport): if self._conn_lost: self._conn_lost += 1 return - self._write(buf) + self._buffer_write(buf) + self._start_write() def writelines(self, bufs): self._ensure_alive() @@ -690,7 +692,8 @@ cdef class UVStream(UVBaseTransport): self._conn_lost += 1 return for buf in bufs: - self._write(buf) + self._buffer_write(buf) + self._start_write() def write_eof(self): self._ensure_alive()