Mercurial > pub > dyncall > bindings
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 |