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