1 /* Should be imported before Python.h */
2
3 #include <Python.h>
4
5 #define NO_IMPORT_ARRAY
6 #define PY_ARRAY_UNIQUE_SYMBOL _scipy_sparse_superlu_ARRAY_API
7
8 #include "_superluobject.h"
9 #include <setjmp.h>
10
11
12 /* Abort to be used inside the superlu module so that memory allocation
13 errors don't exit Python and memory allocated internal to SuperLU is freed.
14 Calling program should deallocate (using SUPERLU_FREE) all memory that could have
15 been allocated. (It's ok to FREE unallocated memory)---will be ignored.
16 */
17
18 #ifndef WITH_THREAD
19 static SuperLUGlobalObject superlu_py_global = {0};
20 #endif
21
get_tls_global(void)22 static SuperLUGlobalObject *get_tls_global(void)
23 {
24 #ifndef WITH_THREAD
25 if (superlu_py_global.memory_dict == NULL) {
26 superlu_py_global.memory_dict = PyDict_New();
27 }
28 return &superlu_py_global;
29 #else
30 PyObject *thread_dict;
31 SuperLUGlobalObject *obj;
32 const char *key = "scipy.sparse.linalg.dsolve._superlu.__global_object";
33
34 thread_dict = PyThreadState_GetDict();
35 if (thread_dict == NULL) {
36 /* Should never happen */
37 PyErr_SetString(PyExc_SystemError, "no thread state obtained");
38 return NULL;
39 }
40
41 obj = (SuperLUGlobalObject*)PyDict_GetItemString(thread_dict, key);
42 if (obj && Py_TYPE(obj) == &SuperLUGlobalType) {
43 return obj;
44 }
45
46 obj = (SuperLUGlobalObject*)PyObject_New(SuperLUGlobalObject, &SuperLUGlobalType);
47 if (obj == NULL) {
48 return (SuperLUGlobalObject*)PyErr_NoMemory();
49 }
50 obj->memory_dict = PyDict_New();
51 obj->jmpbuf_valid = 0;
52
53 PyDict_SetItemString(thread_dict, key, (PyObject *)obj);
54
55 return obj;
56 #endif
57 }
58
superlu_python_jmpbuf(void)59 jmp_buf *superlu_python_jmpbuf(void)
60 {
61 SuperLUGlobalObject *g;
62
63 g = get_tls_global();
64 if (g == NULL) {
65 abort();
66 }
67 g->jmpbuf_valid = 1;
68 return &g->jmpbuf;
69 }
70
superlu_python_module_abort(char * msg)71 void superlu_python_module_abort(char *msg)
72 {
73 SuperLUGlobalObject *g;
74 NPY_ALLOW_C_API_DEF;
75
76 NPY_ALLOW_C_API;
77 g = get_tls_global();
78 if (g == NULL) {
79 /* We have to longjmp (or SEGV results), but the
80 destination is not known --- no choice but abort.
81 However, this should never happen.
82 */
83 abort();
84 }
85 PyErr_SetString(PyExc_RuntimeError, msg);
86
87 if (!g->jmpbuf_valid) {
88 abort();
89 }
90
91 g->jmpbuf_valid = 0;
92 NPY_DISABLE_C_API;
93
94 longjmp(g->jmpbuf, -1);
95 }
96
superlu_python_module_malloc(size_t size)97 void *superlu_python_module_malloc(size_t size)
98 {
99 SuperLUGlobalObject *g;
100 PyObject *key = NULL;
101 void *mem_ptr;
102 NPY_ALLOW_C_API_DEF;
103
104 NPY_ALLOW_C_API;
105 g = get_tls_global();
106 if (g == NULL) {
107 return NULL;
108 }
109 mem_ptr = malloc(size);
110 if (mem_ptr == NULL) {
111 NPY_DISABLE_C_API;
112 return NULL;
113 }
114 key = PyLong_FromVoidPtr(mem_ptr);
115 if (key == NULL)
116 goto fail;
117 if (PyDict_SetItem(g->memory_dict, key, Py_None))
118 goto fail;
119 Py_DECREF(key);
120 NPY_DISABLE_C_API;
121
122 return mem_ptr;
123
124 fail:
125 Py_XDECREF(key);
126 NPY_DISABLE_C_API;
127 free(mem_ptr);
128 superlu_python_module_abort
129 ("superlu_malloc: Cannot set dictionary key value in malloc.");
130 return NULL;
131
132 }
133
superlu_python_module_free(void * ptr)134 void superlu_python_module_free(void *ptr)
135 {
136 SuperLUGlobalObject *g;
137 PyObject *key;
138 PyObject *ptype, *pvalue, *ptraceback;
139 NPY_ALLOW_C_API_DEF;
140
141 if (ptr == NULL)
142 return;
143
144 NPY_ALLOW_C_API;
145 g = get_tls_global();
146 if (g == NULL) {
147 abort();
148 }
149 PyErr_Fetch(&ptype, &pvalue, &ptraceback);
150 key = PyLong_FromVoidPtr(ptr);
151 /* This will only free the pointer if it could find it in the dictionary
152 * of already allocated pointers --- thus after abort, the module can free all
153 * the memory that "might" have been allocated to avoid memory leaks on abort
154 * calls.
155 */
156 if (!PyDict_DelItem(g->memory_dict, key)) {
157 free(ptr);
158 }
159 Py_DECREF(key);
160 PyErr_Restore(ptype, pvalue, ptraceback);
161 NPY_DISABLE_C_API;
162 return;
163 }
164
165
SuperLUGlobal_dealloc(SuperLUGlobalObject * self)166 static void SuperLUGlobal_dealloc(SuperLUGlobalObject *self)
167 {
168 PyObject *key, *value;
169 Py_ssize_t pos = 0;
170
171 while (PyDict_Next(self->memory_dict, &pos, &key, &value)) {
172 void *ptr;
173 ptr = PyLong_AsVoidPtr(value);
174 free(ptr);
175 }
176
177 Py_XDECREF(self->memory_dict);
178 PyObject_Del(self);
179 }
180
181
182 PyTypeObject SuperLUGlobalType = {
183 PyVarObject_HEAD_INIT(NULL, 0)
184 "_SuperLUGlobal",
185 sizeof(SuperLUGlobalObject),
186 0,
187 (destructor)SuperLUGlobal_dealloc, /* tp_dealloc */
188 0, /* tp_print */
189 0, /* tp_getattr */
190 0, /* tp_setattr */
191 0, /* tp_compare / tp_reserved */
192 0, /* tp_repr */
193 0, /* tp_as_number */
194 0, /* tp_as_sequence */
195 0, /* tp_as_mapping */
196 0, /* tp_hash */
197 0, /* tp_call */
198 0, /* tp_str */
199 0, /* tp_getattro */
200 0, /* tp_setattro */
201 0, /* tp_as_buffer */
202 Py_TPFLAGS_DEFAULT, /* tp_flags */
203 NULL, /* tp_doc */
204 0, /* tp_traverse */
205 0, /* tp_clear */
206 0, /* tp_richcompare */
207 0, /* tp_weaklistoffset */
208 0, /* tp_iter */
209 0, /* tp_iternext */
210 0, /* tp_methods */
211 0, /* tp_members */
212 0, /* tp_getset */
213 0, /* tp_base */
214 0, /* tp_dict */
215 0, /* tp_descr_get */
216 0, /* tp_descr_set */
217 0, /* tp_dictoffset */
218 0, /* tp_init */
219 0, /* tp_alloc */
220 0, /* tp_new */
221 0, /* tp_free */
222 0, /* tp_is_gc */
223 0, /* tp_bases */
224 0, /* tp_mro */
225 0, /* tp_cache */
226 0, /* tp_subclasses */
227 0, /* tp_weaklist */
228 0, /* tp_del */
229 0, /* tp_version_tag */
230 };
231
232
233 /*
234 * Stub for error handling; does nothing, as we don't want to spew debug output.
235 */
236
input_error(char * srname,int * info)237 int input_error(char *srname, int *info)
238 {
239 return 0;
240 }
241
242 /*
243 * Stubs for Harwell Subroutine Library functions that SuperLU tries to call.
244 */
245
mc64id_(int * a)246 void mc64id_(int *a)
247 {
248 superlu_python_module_abort("chosen functionality not available");
249 }
250
mc64ad_(int * a,int * b,int * c,int d[],int e[],double f[],int * g,int h[],int * i,int j[],int * k,double l[],int m[],int n[])251 void mc64ad_(int *a, int *b, int *c, int d[], int e[], double f[],
252 int *g, int h[], int *i, int j[], int *k, double l[],
253 int m[], int n[])
254 {
255 superlu_python_module_abort("chosen functionality not available");
256 }
257