@@ -107,18 +107,18 @@ impl Drop for GILGuard {
107
107
108
108
/// Release pool
109
109
struct ReleasePool {
110
- owned : Vec < * mut ffi:: PyObject > ,
111
- borrowed : Vec < * mut ffi:: PyObject > ,
112
- pointers : * mut Vec < * mut ffi:: PyObject > ,
110
+ owned : ArrayList < NonNull < ffi:: PyObject > > ,
111
+ borrowed : ArrayList < NonNull < ffi:: PyObject > > ,
112
+ pointers : * mut Vec < NonNull < ffi:: PyObject > > ,
113
113
obj : Vec < Box < any:: Any > > ,
114
114
p : spin:: Mutex < * mut Vec < * mut ffi:: PyObject > > ,
115
115
}
116
116
117
117
impl ReleasePool {
118
118
fn new ( ) -> ReleasePool {
119
119
ReleasePool {
120
- owned : Vec :: with_capacity ( 256 ) ,
121
- borrowed : Vec :: with_capacity ( 256 ) ,
120
+ owned : ArrayList :: new ( ) ,
121
+ borrowed : ArrayList :: new ( ) ,
122
122
pointers : Box :: into_raw ( Box :: new ( Vec :: with_capacity ( 256 ) ) ) ,
123
123
obj : Vec :: with_capacity ( 8 ) ,
124
124
p : spin:: Mutex :: new ( Box :: into_raw ( Box :: new ( Vec :: with_capacity ( 256 ) ) ) ) ,
@@ -127,39 +127,30 @@ impl ReleasePool {
127
127
128
128
unsafe fn release_pointers ( & mut self ) {
129
129
let mut v = self . p . lock ( ) ;
130
-
131
- // vec of pointers
132
- let ptr = * v;
133
- let vec: & ' static mut Vec < * mut ffi:: PyObject > = & mut * ptr;
130
+ let vec = & mut * * v;
134
131
if vec. is_empty ( ) {
135
132
return ;
136
133
}
137
134
138
135
// switch vectors
139
- * v = self . pointers ;
140
- self . pointers = ptr;
136
+ std:: mem:: swap ( & mut self . pointers , & mut * v) ;
141
137
drop ( v) ;
142
138
143
- // release py objects
139
+ // release PyObjects
144
140
for ptr in vec. iter_mut ( ) {
145
141
ffi:: Py_DECREF ( * ptr) ;
146
142
}
147
143
vec. set_len ( 0 ) ;
148
144
}
149
145
150
146
pub unsafe fn drain ( & mut self , owned : usize , borrowed : usize , pointers : bool ) {
151
- let len = self . owned . len ( ) ;
152
- if owned < len {
153
- for ptr in & mut self . owned [ owned..len] {
154
- ffi:: Py_DECREF ( * ptr) ;
155
- }
156
- self . owned . set_len ( owned) ;
157
- }
158
-
159
- let len = self . borrowed . len ( ) ;
160
- if borrowed < len {
161
- self . borrowed . set_len ( borrowed) ;
147
+ // Release owned objects(call decref)
148
+ while owned < self . owned . len ( ) {
149
+ let last = self . owned . pop_back ( ) . unwrap ( ) ;
150
+ ffi:: Py_DECREF ( last. as_ptr ( ) ) ;
162
151
}
152
+ // Release borrowed objects(don't call decref)
153
+ self . borrowed . truncate ( borrowed) ;
163
154
164
155
if pointers {
165
156
self . release_pointers ( ) ;
@@ -230,24 +221,19 @@ pub unsafe fn register_any<'p, T: 'static>(obj: T) -> &'p T {
230
221
. unwrap ( )
231
222
}
232
223
233
- pub unsafe fn register_pointer ( obj : NonNullPyObject ) {
234
- let pool: & ' static mut ReleasePool = & mut * POOL ;
235
-
236
- let mut v = pool. p . lock ( ) ;
237
- let pool: & ' static mut Vec < * mut ffi:: PyObject > = & mut * ( * v) ;
238
- pool. push ( obj. as_ptr ( ) ) ;
224
+ pub unsafe fn register_pointer ( obj : NonNull < ffi:: PyObject > ) {
225
+ let pool = & mut * POOL ;
226
+ ( * * pool. p . lock ( ) ) . push ( obj) ;
239
227
}
240
228
241
- pub unsafe fn register_owned ( _py : Python , obj : * mut ffi:: PyObject ) -> & PyObjectRef {
242
- let pool: & ' static mut ReleasePool = & mut * POOL ;
243
- pool. owned . push ( obj) ;
244
- & * ( & pool. owned [ pool. owned . len ( ) - 1 ] as * const * mut ffi:: PyObject as * const PyObjectRef )
229
+ pub unsafe fn register_owned ( _py : Python , obj : NonNull < ffi:: PyObject > ) -> & PyObjectRef {
230
+ let pool = & mut * POOL ;
231
+ & * ( pool. owned . push_back ( obj) as * const _ as * const PyObjectRef )
245
232
}
246
233
247
- pub unsafe fn register_borrowed ( _py : Python , obj : * mut ffi:: PyObject ) -> & PyObjectRef {
248
- let pool: & ' static mut ReleasePool = & mut * POOL ;
249
- pool. borrowed . push ( obj) ;
250
- & * ( & pool. borrowed [ pool. borrowed . len ( ) - 1 ] as * const * mut ffi:: PyObject as * const PyObjectRef )
234
+ pub unsafe fn register_borrowed ( _py : Python , obj : NonNull < ffi:: PyObject > ) -> & PyObjectRef {
235
+ let pool = & mut * POOL ;
236
+ & * ( pool. borrowed . push_back ( obj) as * const _ as * const PyObjectRef )
251
237
}
252
238
253
239
impl GILGuard {
@@ -277,6 +263,64 @@ impl GILGuard {
277
263
}
278
264
}
279
265
266
+ use self :: array_list:: ArrayList ;
267
+
268
+ mod array_list {
269
+ use std:: collections:: LinkedList ;
270
+ use std:: mem;
271
+
272
+ const BLOCK_SIZE : usize = 256 ;
273
+
274
+ /// A container type for Release Pool
275
+ /// See #271 for why this is crated
276
+ pub ( super ) struct ArrayList < T > {
277
+ inner : LinkedList < [ T ; BLOCK_SIZE ] > ,
278
+ length : usize ,
279
+ }
280
+
281
+ impl < T : Clone > ArrayList < T > {
282
+ pub fn new ( ) -> Self {
283
+ ArrayList {
284
+ inner : LinkedList :: new ( ) ,
285
+ length : 0 ,
286
+ }
287
+ }
288
+ pub fn push_back ( & mut self , item : T ) -> & T {
289
+ let next_idx = self . next_idx ( ) ;
290
+ if next_idx == 0 {
291
+ self . inner . push_back ( unsafe { mem:: uninitialized ( ) } ) ;
292
+ }
293
+ self . inner . back_mut ( ) . unwrap ( ) [ next_idx] = item;
294
+ self . length += 1 ;
295
+ & self . inner . back ( ) . unwrap ( ) [ next_idx]
296
+ }
297
+ pub fn pop_back ( & mut self ) -> Option < T > {
298
+ self . length -= 1 ;
299
+ let current_idx = self . next_idx ( ) ;
300
+ if self . length >= BLOCK_SIZE && current_idx == 0 {
301
+ let last_list = self . inner . pop_back ( ) ?;
302
+ return Some ( last_list[ 0 ] . clone ( ) ) ;
303
+ }
304
+ self . inner . back ( ) . map ( |arr| arr[ current_idx] . clone ( ) )
305
+ }
306
+ pub fn len ( & self ) -> usize {
307
+ self . length
308
+ }
309
+ pub fn truncate ( & mut self , new_len : usize ) {
310
+ if self . length <= new_len {
311
+ return ;
312
+ }
313
+ while self . inner . len ( ) > ( new_len + BLOCK_SIZE - 1 ) / BLOCK_SIZE {
314
+ self . inner . pop_back ( ) ;
315
+ }
316
+ self . length = new_len;
317
+ }
318
+ fn next_idx ( & self ) -> usize {
319
+ self . length % BLOCK_SIZE
320
+ }
321
+ }
322
+ }
323
+
280
324
#[ cfg( test) ]
281
325
mod test {
282
326
use super :: { GILPool , ReleasePool , POOL } ;
0 commit comments