@@ -179,43 +179,62 @@ cdef class UVStream(UVBaseTransport):
179
179
180
180
cdef inline _try_write(self , object data):
181
181
cdef:
182
- int written
182
+ ssize_t written
183
183
bint used_buf = 0
184
184
Py_buffer py_buf
185
- uv.uv_buf_t uv_buf
185
+ void * buf
186
+ size_t blen
187
+ int saved_errno
188
+ int fd
186
189
187
190
if PyBytes_CheckExact(data):
188
- uv_buf.base = PyBytes_AS_STRING(data)
189
- uv_buf.len = Py_SIZE(data)
191
+ buf = < void * > PyBytes_AS_STRING(data)
192
+ blen = Py_SIZE(data)
190
193
elif PyByteArray_CheckExact(data):
191
- uv_buf.base = PyByteArray_AS_STRING(data)
192
- uv_buf.len = Py_SIZE(data)
194
+ buf = < void * > PyByteArray_AS_STRING(data)
195
+ blen = Py_SIZE(data)
193
196
else :
194
197
PyObject_GetBuffer(data, & py_buf, PyBUF_SIMPLE)
195
198
used_buf = 1
196
- uv_buf.base = < char * > py_buf.buf
197
- uv_buf.len = py_buf.len
199
+ buf = py_buf.buf
200
+ blen = py_buf.len
198
201
199
- written = uv.uv_try_write(
200
- < uv.uv_stream_t* > self ._handle,
201
- & uv_buf, 1 )
202
+ if blen == 0 :
203
+ # Empty data, do nothing.
204
+ return 0
205
+
206
+ fd = self ._fileno()
207
+ # Use `unistd.h/write` directly, it's faster than
208
+ # uv_try_write -- less layers of code. The error
209
+ # checking logic is copied from libuv.
210
+ written = system.write(fd, buf, blen)
211
+ while written == - 1 and (errno.errno == errno.EINTR or
212
+ (system.PLATFORM_IS_APPLE and
213
+ errno.errno == errno.EPROTOTYPE)):
214
+ # From libuv code (unix/stream.c):
215
+ # Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
216
+ # EPROTOTYPE can be returned while trying to write to a socket
217
+ # that is shutting down. If we retry the write, we should get
218
+ # the expected EPIPE instead.
219
+ written = system.write(fd, buf, blen)
220
+ saved_errno = errno.errno
202
221
203
222
if used_buf:
204
223
PyBuffer_Release(& py_buf)
205
224
206
225
if written < 0 :
207
- if written == uv.UV_EAGAIN:
226
+ if saved_errno == errno.EAGAIN or \
227
+ saved_errno == system.EWOULDBLOCK:
208
228
return - 1
209
229
else :
210
- exc = convert_error(written )
230
+ exc = convert_error(- saved_errno )
211
231
self ._fatal_error(exc, True )
212
232
return
213
233
214
234
IF DEBUG:
215
- if written > 0 :
216
- self ._loop._debug_stream_write_tries += 1
235
+ self ._loop._debug_stream_write_tries += 1
217
236
218
- if written == < int > uv_buf.len :
237
+ if < size_t > written == blen :
219
238
return 0
220
239
221
240
return written
@@ -229,6 +248,11 @@ cdef class UVStream(UVBaseTransport):
229
248
# Try to write without polling only when there is
230
249
# no data in write buffers.
231
250
sent = self ._try_write(data)
251
+ if sent is None :
252
+ # A `self._fatal_error` was called.
253
+ # It might not raise an exception under some
254
+ # conditions.
255
+ return
232
256
if sent == 0 :
233
257
# All data was successfully written.
234
258
return
0 commit comments