comparison python/pydc/pydcext.c @ 30:baf087cf5971

- fixed two ref counting problems - minor improvements
author Tassilo Philipp
date Fri, 10 Apr 2020 20:35:19 +0200
parents 6cc2b7fc7ea2
children 622914f1f3bf
comparison
equal deleted inserted replaced
29:6cc2b7fc7ea2 30:baf087cf5971
21 21
22 22
23 #if ( (PY_VERSION_HEX < 0x02070000) \ 23 #if ( (PY_VERSION_HEX < 0x02070000) \
24 || ((PY_VERSION_HEX >= 0x03000000) \ 24 || ((PY_VERSION_HEX >= 0x03000000) \
25 && (PY_VERSION_HEX < 0x03010000)) ) 25 && (PY_VERSION_HEX < 0x03010000)) )
26 # define DcPyCObject_FromVoidPtr(ptr, dtor) PyCObject_FromVoidPtr((ptr), (dtor)) 26 # define DcPyCObject_FromVoidPtr(ptr, dtor) PyCObject_FromVoidPtr((ptr), (dtor)) // !new ref!
27 # define DcPyCObject_AsVoidPtr(ppobj) PyCObject_AsVoidPtr((ppobj)) 27 # define DcPyCObject_AsVoidPtr(ppobj) PyCObject_AsVoidPtr((ppobj))
28 # define DcPyCObject_SetVoidPtr(ppobj, ptr) PyCObject_SetVoidPtr((ppobj), (ptr)) 28 # define DcPyCObject_SetVoidPtr(ppobj, ptr) PyCObject_SetVoidPtr((ppobj), (ptr))
29 #else 29 #else
30 # define USE_CAPSULE_API 30 # define USE_CAPSULE_API
31 # define DcPyCObject_FromVoidPtr(ptr, dtor) PyCapsule_New((ptr), NULL, (dtor)) 31 # define DcPyCObject_FromVoidPtr(ptr, dtor) PyCapsule_New((ptr), NULL, (dtor)) // !new ref!
32 # define DcPyCObject_AsVoidPtr(ppobj) PyCapsule_GetPointer((ppobj), NULL) 32 # define DcPyCObject_AsVoidPtr(ppobj) PyCapsule_GetPointer((ppobj), NULL)
33 # define DcPyCObject_SetVoidPtr(ppobj, ptr) //@@@ unsure what to do, cannot/shouldn't call this with a null pointer as this wants to call the dtor, so not doing anything: PyCapsule_SetPointer((ppobj), (ptr)) // this might need to call the dtor to behave like PyCObject_SetVoidPtr? 33 # define DcPyCObject_SetVoidPtr(ppobj, ptr) //@@@ unsure what to do, cannot/shouldn't call this with a null pointer as this wants to call the dtor, so not doing anything: PyCapsule_SetPointer((ppobj), (ptr)) // this might need to call the dtor to behave like PyCObject_SetVoidPtr?
34 #endif 34 #endif
35 35
36 #if PY_MAJOR_VERSION >= 3 36 #if PY_MAJOR_VERSION >= 3
80 libhandle = dlLoadLibrary(libpath); 80 libhandle = dlLoadLibrary(libpath);
81 81
82 if (!libhandle) 82 if (!libhandle)
83 return PyErr_Format(PyExc_RuntimeError, "dlLoadLibrary('%s') failed", libpath); 83 return PyErr_Format(PyExc_RuntimeError, "dlLoadLibrary('%s') failed", libpath);
84 84
85 return DcPyCObject_FromVoidPtr(libhandle, &free_library); 85 return DcPyCObject_FromVoidPtr(libhandle, &free_library); // !new ref!
86 } 86 }
87 87
88 /* find function */ 88 /* find function */
89 89
90 static PyObject* 90 static PyObject*
104 104
105 funcptr = dlFindSymbol(libhandle, symbol); 105 funcptr = dlFindSymbol(libhandle, symbol);
106 if (!funcptr) 106 if (!funcptr)
107 return PyErr_Format(PyExc_RuntimeError, "symbol '%s' not found", symbol); 107 return PyErr_Format(PyExc_RuntimeError, "symbol '%s' not found", symbol);
108 108
109 return DcPyCObject_FromVoidPtr(funcptr, NULL); 109 return DcPyCObject_FromVoidPtr(funcptr, NULL); // !new ref!
110 } 110 }
111 111
112 /* free function */ 112 /* free function */
113 113
114 static PyObject* 114 static PyObject*
125 return PyErr_Format(PyExc_RuntimeError, "libhandle is NULL"); 125 return PyErr_Format(PyExc_RuntimeError, "libhandle is NULL");
126 126
127 dlFreeLibrary(libhandle); 127 dlFreeLibrary(libhandle);
128 DcPyCObject_SetVoidPtr(pcobj, NULL); 128 DcPyCObject_SetVoidPtr(pcobj, NULL);
129 129
130 //don't think I need to release it, as the pyobj is not equivalent to the held handle
131 //Py_XDECREF(pcobj); // release ref from pydc_load()
132
130 Py_RETURN_NONE; 133 Py_RETURN_NONE;
131 } 134 }
132 135
133 136
134 #include "dyncall.h" 137 #include "dyncall.h"
135 #include "dyncall_signature.h" 138 #include "dyncall_signature.h"
136 139
137 DCCallVM* gpCall; 140 DCCallVM* gpCall = NULL;
138 141
139 142
140 /* call function */ 143 /* call function */
141 144
142 static PyObject* 145 static PyObject*
292 dcArgDouble(gpCall, PyFloat_AsDouble(po)); 295 dcArgDouble(gpCall, PyFloat_AsDouble(po));
293 break; 296 break;
294 297
295 case DC_SIGCHAR_POINTER: 298 case DC_SIGCHAR_POINTER:
296 { 299 {
300 PyObject* bo = NULL;
297 DCpointer p; 301 DCpointer p;
298 if ( PyUnicode_Check(po) ) { 302 if ( PyUnicode_Check(po) ) {
299 PyObject* bo = PyUnicode_AsEncodedString(po, "utf-8", "strict"); // Owned reference @@@ 303 if((bo = PyUnicode_AsEncodedString(po, "utf-8", "strict"))) // !new ref!
300 if (bo) {
301 p = PyBytes_AS_STRING(bo); // Borrowed pointer 304 p = PyBytes_AS_STRING(bo); // Borrowed pointer
302 //p = strdup(my_result);
303 //Py_DECREF(bo);
304 }
305 } else if ( DcPyString_Check(po) ) 305 } else if ( DcPyString_Check(po) )
306 p = (DCpointer) DcPyString_AsString(po); 306 p = (DCpointer) DcPyString_AsString(po);
307 #if PY_MAJOR_VERSION < 3 307 #if PY_MAJOR_VERSION < 3
308 else if ( PyInt_Check(po) ) 308 else if ( PyInt_Check(po) )
309 p = (DCpointer) PyInt_AS_LONG(po); 309 p = (DCpointer) PyInt_AS_LONG(po);
310 #endif 310 #endif
311 else if ( PyLong_Check(po) ) 311 else if ( PyLong_Check(po) )
312 p = (DCpointer) PyLong_AsVoidPtr(po); 312 p = (DCpointer) PyLong_AsVoidPtr(po);
313 else 313 else
314 return PyErr_Format( PyExc_RuntimeError, "arg %d - expecting a promoting pointer-type (int,string)", pos ); //@@@ error message needs to specify python types 314 return PyErr_Format( PyExc_RuntimeError, "arg %d - expecting a promoting pointer-type (int,string)", pos ); //@@@ error message could be better
315 dcArgPointer(gpCall, p); 315 dcArgPointer(gpCall, p);
316 Py_XDECREF(bo);
316 } 317 }
317 break; 318 break;
318 319
319 case DC_SIGCHAR_STRING: 320 case DC_SIGCHAR_STRING:
320 { 321 {
322 PyObject* bo = NULL;
321 const char* p; 323 const char* p;
322 if ( PyUnicode_Check(po) ) { 324 if ( PyUnicode_Check(po) ) {
323 PyObject* bo = PyUnicode_AsEncodedString(po, "utf-8", "strict"); // Owned reference @@@ 325 if((bo = PyUnicode_AsEncodedString(po, "utf-8", "strict"))) // !new ref!
324 if (bo) {
325 p = PyBytes_AS_STRING(bo); // Borrowed pointer 326 p = PyBytes_AS_STRING(bo); // Borrowed pointer
326 //p = strdup(my_result);@@@
327 //Py_DECREF(bo);@@@
328 }
329 } else if ( DcPyString_Check(po) ) { 327 } else if ( DcPyString_Check(po) ) {
330 p = DcPyString_AsString(po); 328 p = DcPyString_AsString(po);
331 } else { 329 } else
332 return PyErr_Format( PyExc_RuntimeError, "arg %d - expecting a string", pos ); //@@@ error message needs to specify python types 330 return PyErr_Format( PyExc_RuntimeError, "arg %d - expecting a string", pos );
333 }
334 dcArgPointer(gpCall, (DCpointer) p); 331 dcArgPointer(gpCall, (DCpointer) p);
332 Py_XDECREF(bo);
335 } 333 }
336 break; 334 break;
337 335
338 default: 336 default:
339 return PyErr_Format( PyExc_RuntimeError, "unknown signature character '%c'", ch); 337 return PyErr_Format( PyExc_RuntimeError, "unknown signature character '%c'", ch);
348 346
349 347
350 ch = *++ptr; 348 ch = *++ptr;
351 switch(ch) 349 switch(ch)
352 { 350 {
353 case DC_SIGCHAR_VOID: dcCallVoid (gpCall, pfunc); Py_RETURN_NONE; 351 // every line creates a new reference passed back to python
354 case DC_SIGCHAR_BOOL: return dcCallBool (gpCall, pfunc)?Py_True:Py_False; 352 case DC_SIGCHAR_VOID: dcCallVoid (gpCall, pfunc); Py_RETURN_NONE; // !new ref!
355 case DC_SIGCHAR_CHAR: return Py_BuildValue("b", dcCallChar (gpCall, pfunc)); 353 case DC_SIGCHAR_BOOL: if(dcCallBool (gpCall, pfunc)){Py_RETURN_TRUE;}else{Py_RETURN_FALSE;} // !new ref!
356 case DC_SIGCHAR_UCHAR: return Py_BuildValue("B", dcCallChar (gpCall, pfunc)); 354 case DC_SIGCHAR_CHAR: return Py_BuildValue("b", dcCallChar (gpCall, pfunc)); // !new ref!
357 case DC_SIGCHAR_SHORT: return Py_BuildValue("h", dcCallShort (gpCall, pfunc)); 355 case DC_SIGCHAR_UCHAR: return Py_BuildValue("B", dcCallChar (gpCall, pfunc)); // !new ref!
358 case DC_SIGCHAR_USHORT: return Py_BuildValue("H", dcCallShort (gpCall, pfunc)); 356 case DC_SIGCHAR_SHORT: return Py_BuildValue("h", dcCallShort (gpCall, pfunc)); // !new ref!
359 case DC_SIGCHAR_INT: return Py_BuildValue("i", dcCallInt (gpCall, pfunc)); 357 case DC_SIGCHAR_USHORT: return Py_BuildValue("H", dcCallShort (gpCall, pfunc)); // !new ref!
360 case DC_SIGCHAR_UINT: return Py_BuildValue("I", dcCallInt (gpCall, pfunc)); 358 case DC_SIGCHAR_INT: return Py_BuildValue("i", dcCallInt (gpCall, pfunc)); // !new ref!
361 case DC_SIGCHAR_LONG: return Py_BuildValue("l", dcCallLong (gpCall, pfunc)); 359 case DC_SIGCHAR_UINT: return Py_BuildValue("I", dcCallInt (gpCall, pfunc)); // !new ref!
362 case DC_SIGCHAR_ULONG: return Py_BuildValue("k", dcCallLong (gpCall, pfunc)); 360 case DC_SIGCHAR_LONG: return Py_BuildValue("l", dcCallLong (gpCall, pfunc)); // !new ref!
363 case DC_SIGCHAR_LONGLONG: return Py_BuildValue("L", dcCallLongLong(gpCall, pfunc)); 361 case DC_SIGCHAR_ULONG: return Py_BuildValue("k", dcCallLong (gpCall, pfunc)); // !new ref!
364 case DC_SIGCHAR_ULONGLONG: return Py_BuildValue("K", dcCallLongLong(gpCall, pfunc)); 362 case DC_SIGCHAR_LONGLONG: return Py_BuildValue("L", dcCallLongLong(gpCall, pfunc)); // !new ref!
365 case DC_SIGCHAR_FLOAT: return Py_BuildValue("f", dcCallFloat (gpCall, pfunc)); 363 case DC_SIGCHAR_ULONGLONG: return Py_BuildValue("K", dcCallLongLong(gpCall, pfunc)); // !new ref!
366 case DC_SIGCHAR_DOUBLE: return Py_BuildValue("d", dcCallDouble (gpCall, pfunc)); 364 case DC_SIGCHAR_FLOAT: return Py_BuildValue("f", dcCallFloat (gpCall, pfunc)); // !new ref!
367 case DC_SIGCHAR_STRING: return Py_BuildValue("s", dcCallPointer (gpCall, pfunc)); 365 case DC_SIGCHAR_DOUBLE: return Py_BuildValue("d", dcCallDouble (gpCall, pfunc)); // !new ref!
368 case DC_SIGCHAR_POINTER: return Py_BuildValue("n", dcCallPointer (gpCall, pfunc)); // @@@test, this used to be 'p' which doesn't exist, 'n' is for "Py_ssize_t" 366 case DC_SIGCHAR_STRING: return Py_BuildValue("s", dcCallPointer (gpCall, pfunc)); // !new ref!
367 case DC_SIGCHAR_POINTER: return Py_BuildValue("n", dcCallPointer (gpCall, pfunc)); // !new ref!
369 default: return PyErr_Format(PyExc_RuntimeError, "invalid return type signature"); 368 default: return PyErr_Format(PyExc_RuntimeError, "invalid return type signature");
370 } 369 }
371 } 370 }
372 371
373 372
374 373
374 // module deinit
375 static void deinit_pydc(void* x)
376 {
377 if(gpCall) {
378 dcFree(gpCall);
379 gpCall = NULL;
380 }
381 }
375 382
376 383
377 #define PYDC_TO_STR_(x) #x 384 #define PYDC_TO_STR_(x) #x
378 #define PYDC_TO_STR(x) PYDC_TO_STR_(x) 385 #define PYDC_TO_STR(x) PYDC_TO_STR_(x)
379 #define PYDC_CONCAT_(x, y) x ## y 386 #define PYDC_CONCAT_(x, y) x ## y
401 {NULL,NULL,0,NULL} 408 {NULL,NULL,0,NULL}
402 }; 409 };
403 410
404 PyObject* m; 411 PyObject* m;
405 #if PY_MAJOR_VERSION >= 3 412 #if PY_MAJOR_VERSION >= 3
406 static struct PyModuleDef moddef = { PyModuleDef_HEAD_INIT, PYDC_MOD_NAME_STR, PYDC_MOD_DESC_STR, -1, pydcMethods, NULL, NULL, NULL, NULL }; 413 static struct PyModuleDef moddef = { PyModuleDef_HEAD_INIT, PYDC_MOD_NAME_STR, PYDC_MOD_DESC_STR, -1, pydcMethods, NULL, NULL, NULL, deinit_pydc };
407 m = PyModule_Create(&moddef); 414 m = PyModule_Create(&moddef);
408 #else 415 #else
409 m = Py_InitModule3(PYDC_MOD_NAME_STR, pydcMethods, PYDC_MOD_DESC_STR); 416 m = Py_InitModule3(PYDC_MOD_NAME_STR, pydcMethods, PYDC_MOD_DESC_STR);
417 // NOTE: there is no way to pass a pointer to deinit_pydc - see PEP 3121 for details
410 #endif 418 #endif
411 419
412 if(m) 420 if(m)
413 gpCall = dcNewCallVM(4096); //@@@ one shared callvm for the entire module, this is not reentrant 421 gpCall = dcNewCallVM(4096); //@@@ one shared callvm for the entire module, this is not reentrant
414 422