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