1
+ DEF __PREALLOCED_BUFS = 4
2
+
1
3
@cython.no_gc_clear
2
4
@ cython.freelist (DEFAULT_FREELIST_SIZE)
3
5
cdef class _StreamWriteContext:
@@ -8,6 +10,10 @@ cdef class _StreamWriteContext:
8
10
9
11
list buffers
10
12
13
+ uv.uv_buf_t uv_bufs_sml[__PREALLOCED_BUFS]
14
+ Py_buffer py_bufs_sml[__PREALLOCED_BUFS]
15
+ bint py_bufs_sml_inuse
16
+
11
17
uv.uv_buf_t* uv_bufs
12
18
Py_buffer* py_bufs
13
19
ssize_t py_bufs_len
@@ -22,6 +28,11 @@ cdef class _StreamWriteContext:
22
28
23
29
self .closed = 1
24
30
31
+ if self .py_bufs_sml_inuse:
32
+ for i in range (self .py_bufs_len):
33
+ PyBuffer_Release(& self .py_bufs_sml[i])
34
+ self .py_bufs_sml_inuse = 0
35
+
25
36
if self .uv_bufs is not NULL :
26
37
PyMem_Free(self .uv_bufs)
27
38
self .uv_bufs = NULL
@@ -41,67 +52,92 @@ cdef class _StreamWriteContext:
41
52
cdef _StreamWriteContext new(UVStream stream, list buffers):
42
53
cdef:
43
54
_StreamWriteContext ctx
44
- int py_bufs_idx = 0
45
55
int uv_bufs_idx = 0
56
+ int py_bufs_len = 0
57
+
58
+ Py_buffer* p_pybufs
59
+ uv.uv_buf_t* p_uvbufs
46
60
47
61
ctx = _StreamWriteContext.__new__ (_StreamWriteContext)
48
62
ctx.stream = None
49
63
ctx.closed = 1
50
64
ctx.py_bufs_len = 0
65
+ ctx.py_bufs_sml_inuse = 0
51
66
ctx.uv_bufs = NULL
52
67
ctx.py_bufs = NULL
53
68
ctx.buffers = buffers
54
69
ctx.stream = stream
55
70
56
- for buf in buffers:
57
- if not PyBytes_CheckExact(buf) and \
58
- not PyByteArray_CheckExact(buf):
59
- ctx.py_bufs_len += 1
60
-
61
- if ctx.py_bufs_len > 0 :
62
- ctx.py_bufs = < Py_buffer* > PyMem_Malloc(
63
- ctx.py_bufs_len * sizeof(Py_buffer))
64
- if ctx.py_bufs is NULL :
71
+ if len (buffers) <= __PREALLOCED_BUFS:
72
+ # We've got a small number of buffers to write, don't
73
+ # need to use malloc.
74
+ ctx.py_bufs_sml_inuse = 1
75
+ p_pybufs = < Py_buffer* > & ctx.py_bufs_sml
76
+ p_uvbufs = < uv.uv_buf_t* > & ctx.uv_bufs_sml
77
+
78
+ else :
79
+ for buf in buffers:
80
+ if not PyBytes_CheckExact(buf) and \
81
+ not PyByteArray_CheckExact(buf):
82
+ py_bufs_len += 1
83
+
84
+ if py_bufs_len > 0 :
85
+ ctx.py_bufs = < Py_buffer* > PyMem_Malloc(
86
+ py_bufs_len * sizeof(Py_buffer))
87
+ if ctx.py_bufs is NULL :
88
+ raise MemoryError ()
89
+
90
+ ctx.uv_bufs = < uv.uv_buf_t* > PyMem_Malloc(
91
+ len (buffers) * sizeof(uv.uv_buf_t))
92
+ if ctx.uv_bufs is NULL :
65
93
raise MemoryError ()
66
94
67
- ctx.uv_bufs = < uv.uv_buf_t* > PyMem_Malloc(
68
- len (buffers) * sizeof(uv.uv_buf_t))
69
- if ctx.uv_bufs is NULL :
70
- raise MemoryError ()
95
+ p_pybufs = ctx.py_bufs
96
+ p_uvbufs = ctx.uv_bufs
71
97
98
+ py_bufs_len = 0
72
99
for buf in buffers:
73
100
if PyBytes_CheckExact(buf):
74
- ctx.uv_bufs [uv_bufs_idx].base = PyBytes_AS_STRING(buf)
75
- ctx.uv_bufs [uv_bufs_idx].len = Py_SIZE(buf)
101
+ p_uvbufs [uv_bufs_idx].base = PyBytes_AS_STRING(buf)
102
+ p_uvbufs [uv_bufs_idx].len = Py_SIZE(buf)
76
103
77
104
elif PyByteArray_CheckExact(buf):
78
- ctx.uv_bufs [uv_bufs_idx].base = PyByteArray_AS_STRING(buf)
79
- ctx.uv_bufs [uv_bufs_idx].len = Py_SIZE(buf)
105
+ p_uvbufs [uv_bufs_idx].base = PyByteArray_AS_STRING(buf)
106
+ p_uvbufs [uv_bufs_idx].len = Py_SIZE(buf)
80
107
81
108
else :
82
109
try :
83
110
PyObject_GetBuffer(
84
- buf, & ctx.py_bufs[py_bufs_idx ], PyBUF_SIMPLE)
111
+ buf, & p_pybufs[py_bufs_len ], PyBUF_SIMPLE)
85
112
except :
86
- PyMem_Free(ctx.uv_bufs)
87
- ctx.uv_bufs = NULL
88
- for i in range (py_bufs_idx):
89
- PyBuffer_Release(& ctx.py_bufs[i])
90
- PyMem_Free(ctx.py_bufs)
91
- ctx.py_bufs = NULL
92
- ctx.py_bufs_len = 0
93
- raise
113
+ # This shouldn't ever happen, since UVStream._write
114
+ # casts non-bytes and non-bytearrays to memoryviews.
94
115
95
- ctx.uv_bufs[uv_bufs_idx].base = \
96
- < char * > ctx.py_bufs[py_bufs_idx].buf
116
+ if ctx.py_bufs_sml_inuse:
117
+ for i in range (py_bufs_len):
118
+ PyBuffer_Release(& ctx.py_bufs_sml[i])
119
+ ctx.py_bufs_sml_inuse = 0
97
120
98
- ctx.uv_bufs[uv_bufs_idx].len = \
99
- ctx.py_bufs[py_bufs_idx].len
121
+ if ctx.uv_bufs is not NULL :
122
+ PyMem_Free(ctx.uv_bufs)
123
+ ctx.uv_bufs = NULL
100
124
101
- py_bufs_idx += 1
125
+ if ctx.py_bufs is not NULL :
126
+ for i in range (py_bufs_len):
127
+ PyBuffer_Release(& ctx.py_bufs[i])
128
+ PyMem_Free(ctx.py_bufs)
129
+ ctx.py_bufs = NULL
130
+
131
+ raise
132
+
133
+ p_uvbufs[uv_bufs_idx].base = < char * > p_pybufs[py_bufs_len].buf
134
+ p_uvbufs[uv_bufs_idx].len = p_pybufs[py_bufs_len].len
135
+
136
+ py_bufs_len += 1
102
137
103
138
uv_bufs_idx += 1
104
139
140
+ ctx.py_bufs_len = py_bufs_len
105
141
ctx.req.data = < void * > ctx
106
142
107
143
IF DEBUG:
@@ -339,11 +375,18 @@ cdef class UVStream(UVBaseTransport):
339
375
340
376
ctx = _StreamWriteContext.new(self , self ._buffer)
341
377
342
- err = uv.uv_write(& ctx.req,
343
- < uv.uv_stream_t* > self ._handle,
344
- ctx.uv_bufs,
345
- len (self ._buffer),
346
- __uv_stream_on_write)
378
+ if ctx.py_bufs_sml_inuse:
379
+ err = uv.uv_write(& ctx.req,
380
+ < uv.uv_stream_t* > self ._handle,
381
+ ctx.uv_bufs_sml,
382
+ len (self ._buffer),
383
+ __uv_stream_on_write)
384
+ else :
385
+ err = uv.uv_write(& ctx.req,
386
+ < uv.uv_stream_t* > self ._handle,
387
+ ctx.uv_bufs,
388
+ len (self ._buffer),
389
+ __uv_stream_on_write)
347
390
348
391
self ._buffer_size = 0
349
392
self ._buffer = []
0 commit comments