Bugfix for transferring malloc'ed data to a pyarray under windows with the capsule
This commit is contained in:
parent
32e5860352
commit
3f32176804
@ -22,65 +22,81 @@
|
|||||||
* Function passed to Python to use for cleanup of
|
* Function passed to Python to use for cleanup of
|
||||||
* foreignly obtained data.
|
* foreignly obtained data.
|
||||||
**/
|
**/
|
||||||
|
#define LASP_CAPSULE_NAME "pyarray_data_destructor"
|
||||||
static inline void capsule_cleanup(PyObject *capsule) {
|
static inline void capsule_cleanup(PyObject *capsule) {
|
||||||
void *memory = PyCapsule_GetPointer(capsule, NULL);
|
void *memory = PyCapsule_GetPointer(capsule, LASP_CAPSULE_NAME);
|
||||||
free(memory);
|
free(memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static inline PyObject *data_to_ndarray(void *data, int n_rows, int n_cols,
|
static inline PyObject *data_to_ndarray(void *data, int n_rows, int n_cols,
|
||||||
int typenum, bool transfer_ownership,
|
int typenum, bool transfer_ownership,
|
||||||
bool F_contiguous) {
|
bool F_contiguous) {
|
||||||
|
|
||||||
/* fprintf(stderr, "Enter data_to_ndarray\n"); */
|
/* fprintf(stderr, "Enter data_to_ndarray\n"); */
|
||||||
assert(data);
|
assert(data);
|
||||||
import_array();
|
import_array();
|
||||||
|
PyArray_Descr *descr = PyArray_DescrFromType(typenum);
|
||||||
|
if(!descr) return NULL;
|
||||||
|
|
||||||
npy_intp dims[2];
|
npy_intp dims[2] = {n_rows, n_cols};
|
||||||
if(F_contiguous){
|
npy_intp strides[2];
|
||||||
dims[0] = n_cols;
|
|
||||||
dims[1] = n_rows;
|
|
||||||
|
|
||||||
} else {
|
int flags = 0;
|
||||||
dims[0] = n_rows;
|
if(F_contiguous){
|
||||||
dims[1] = n_cols;
|
flags |= NPY_ARRAY_FARRAY;
|
||||||
|
strides[0] = descr->elsize;
|
||||||
|
strides[1] = descr->elsize*n_rows;
|
||||||
|
} else {
|
||||||
|
strides[0] = descr->elsize*n_rows;
|
||||||
|
strides[1] = descr->elsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* assert(n_rows > 0); */
|
||||||
|
/* assert(n_cols > 0); */
|
||||||
|
|
||||||
|
PyArrayObject *arr =
|
||||||
|
(PyArrayObject *)PyArray_NewFromDescr(
|
||||||
|
&PyArray_Type,
|
||||||
|
descr, // Description
|
||||||
|
2, // nd
|
||||||
|
dims, // dimensions
|
||||||
|
strides, // strides
|
||||||
|
data, // Data pointer
|
||||||
|
flags, // Flags
|
||||||
|
NULL // obj
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!arr) {
|
||||||
|
fprintf(stderr, "arr = 0!");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transfer_ownership == true) {
|
||||||
|
#ifdef MS_WIN64
|
||||||
|
// The default destructor of Python cannot free the data, as it is allocated
|
||||||
|
// with malloc. Therefore, with this code, we tell Numpy/Python to use
|
||||||
|
// the capsule_cleanup constructor. See:
|
||||||
|
// https://stackoverflow.com/questions/54269956/crash-of-jupyter-due-to-the-use-of-pyarray-enableflags/54278170#54278170
|
||||||
|
// Note that in general it was disadvised to build all C code with MinGW on
|
||||||
|
// Windows. We do it anyway, see if we find any problems on the way.
|
||||||
|
PyObject *capsule = PyCapsule_New(data, LASP_CAPSULE_NAME, capsule_cleanup);
|
||||||
|
int res = PyArray_SetBaseObject(arr, capsule);
|
||||||
|
if(res != 0) {
|
||||||
|
fprintf(stderr, "Failed to set base object of array!");
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
/* assert(n_rows > 0); */
|
#endif
|
||||||
/* assert(n_cols > 0); */
|
/* fprintf(stderr, "============Ownership transfer================\n"); */
|
||||||
|
PyArray_ENABLEFLAGS(arr, NPY_OWNDATA);
|
||||||
|
}
|
||||||
|
/* fprintf(stderr, "Exit data_to_ndarray\n"); */
|
||||||
|
|
||||||
PyArrayObject *arr =
|
return (PyObject *) arr;
|
||||||
(PyArrayObject *)PyArray_SimpleNewFromData(2, dims, typenum, data);
|
|
||||||
|
|
||||||
if (!arr) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (F_contiguous) {
|
|
||||||
arr = (PyArrayObject*) PyArray_Transpose(arr, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transfer_ownership == true) {
|
|
||||||
#ifdef MS_WIN64
|
|
||||||
// The default destructor of Python cannot free the data, as it is allocated
|
|
||||||
// with malloc. Therefore, with this code, we tell Numpy/Python to use
|
|
||||||
// the capsule_cleanup constructor. See:
|
|
||||||
// https://stackoverflow.com/questions/54269956/crash-of-jupyter-due-to-the-use-of-pyarray-enableflags/54278170#54278170
|
|
||||||
// Note that in general it was disadvised to build all C code with MinGW on
|
|
||||||
// Windows. We do it anyway, see if we find any problems on the way.
|
|
||||||
PyObject *capsule = PyCapsule_New(data, "data destructor", capsule_cleanup);
|
|
||||||
int res = PyArray_SetBaseObject(arr, capsule);
|
|
||||||
if(res != 0) {
|
|
||||||
fprintf(stderr, "Failed to set base object of array!");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
/* fprintf(stderr, "============Ownership transfer================\n"); */
|
|
||||||
PyArray_ENABLEFLAGS(arr, NPY_OWNDATA);
|
|
||||||
}
|
|
||||||
/* fprintf(stderr, "Exit data_to_ndarray\n"); */
|
|
||||||
|
|
||||||
return (PyObject *) arr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef LASP_CAPSULE_NAME
|
||||||
#endif // LASP_PYARRAY_H
|
#endif // LASP_PYARRAY_H
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
/**
|
/**
|
||||||
* Create a numpy array from an existing dmat.
|
* Create a numpy array from an existing dmat.
|
||||||
*
|
*
|
||||||
* @param mat dmat struccture containing array data and metadata.
|
* @param mat dmat structure containing array data and metadata.
|
||||||
* @param transfer_ownership If set to true, Numpy array will be responsible
|
* @param transfer_ownership If set to true, Numpy array will be responsible
|
||||||
* for freeing the data.
|
* for freeing the data.
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user