Skip to content

Commit cd82299

Browse files
committed
Use Once to ensure thread safety of initializing Numpy API
1 parent e874dd2 commit cd82299

File tree

2 files changed

+12
-5
lines changed

2 files changed

+12
-5
lines changed

src/npyffi/array.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use pyo3::ffi::{self, PyObject, PyTypeObject};
44
use std::ops::Deref;
55
use std::os::raw::*;
66
use std::ptr;
7+
use std::sync::{Once, ONCE_INIT};
78

89
use npyffi::*;
910

@@ -36,19 +37,21 @@ pub static PY_ARRAY_API: PyArrayAPI = PyArrayAPI {
3637
__private_field: (),
3738
};
3839

39-
///
4040
pub struct PyArrayAPI {
4141
__private_field: (),
4242
}
4343

4444
impl Deref for PyArrayAPI {
4545
type Target = PyArrayAPI_Inner;
4646
fn deref(&self) -> &Self::Target {
47+
static INIT_API: Once = ONCE_INIT;
4748
static mut ARRAY_API_CACHE: PyArrayAPI_Inner = PyArrayAPI_Inner(ptr::null());
4849
unsafe {
49-
// TODO: this operation is 'mostly safe' because of GIL, but not completely thread safe
5050
if ARRAY_API_CACHE.0.is_null() {
51-
ARRAY_API_CACHE = PyArrayAPI_Inner(get_numpy_api(MOD_NAME, CAPSULE_NAME));
51+
let api = get_numpy_api(MOD_NAME, CAPSULE_NAME);
52+
INIT_API.call_once(move || {
53+
ARRAY_API_CACHE = PyArrayAPI_Inner(api);
54+
});
5255
}
5356
&ARRAY_API_CACHE
5457
}

src/npyffi/ufunc.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use std::ops::Deref;
44
use std::os::raw::*;
55
use std::ptr;
6+
use std::sync::{Once, ONCE_INIT};
67

78
use pyo3::ffi::PyObject;
89

@@ -24,11 +25,14 @@ pub struct PyUFuncAPI {
2425
impl Deref for PyUFuncAPI {
2526
type Target = PyUFuncAPI_Inner;
2627
fn deref(&self) -> &Self::Target {
28+
static INIT_API: Once = ONCE_INIT;
2729
static mut UFUNC_API_CACHE: PyUFuncAPI_Inner = PyUFuncAPI_Inner(ptr::null());
2830
unsafe {
29-
// TODO: this operation is 'mostly safe' because of GIL, but not completely thread safe
3031
if UFUNC_API_CACHE.0.is_null() {
31-
UFUNC_API_CACHE = PyUFuncAPI_Inner(get_numpy_api(MOD_NAME, CAPSULE_NAME));
32+
let api = get_numpy_api(MOD_NAME, CAPSULE_NAME);
33+
INIT_API.call_once(move || {
34+
UFUNC_API_CACHE = PyUFuncAPI_Inner(api);
35+
});
3236
}
3337
&UFUNC_API_CACHE
3438
}

0 commit comments

Comments
 (0)