Back to index

python3.2  3.2.2
Defines | Functions | Variables
callbacks.c File Reference
#include "Python.h"
#include "frameobject.h"
#include <ffi.h>
#include "ctypes.h"

Go to the source code of this file.

Defines

#define CHECK(what, x)   if (x == NULL) _ctypes_add_traceback(what, "_ctypes/callbacks.c", __LINE__ - 1), PyErr_Print()

Functions

static void CThunkObject_dealloc (PyObject *_self)
static int CThunkObject_traverse (PyObject *_self, visitproc visit, void *arg)
static int CThunkObject_clear (PyObject *_self)
static void PrintError (char *msg,...)
void _ctypes_add_traceback (char *funcname, char *filename, int lineno)
static void _CallPythonObject (void *mem, ffi_type *restype, SETFUNC setfunc, PyObject *callable, PyObject *converters, int flags, void **pArgs)
static void closure_fcn (ffi_cif *cif, void *resp, void **args, void *userdata)
static CThunkObjectCThunkObject_new (Py_ssize_t nArgs)
CThunkObject_ctypes_alloc_callback (PyObject *callable, PyObject *converters, PyObject *restype, int flags)

Variables

PyTypeObject PyCThunk_Type

Define Documentation

#define CHECK (   what,
  x 
)    if (x == NULL) _ctypes_add_traceback(what, "_ctypes/callbacks.c", __LINE__ - 1), PyErr_Print()

Function Documentation

static void _CallPythonObject ( void mem,
ffi_type restype,
SETFUNC  setfunc,
PyObject callable,
PyObject converters,
int  flags,
void **  pArgs 
) [static]

Definition at line 151 of file callbacks.c.

{
    Py_ssize_t i;
    PyObject *result;
    PyObject *arglist = NULL;
    Py_ssize_t nArgs;
    PyObject *error_object = NULL;
    int *space;
#ifdef WITH_THREAD
    PyGILState_STATE state = PyGILState_Ensure();
#endif

    nArgs = PySequence_Length(converters);
    /* Hm. What to return in case of error?
       For COM, 0xFFFFFFFF seems better than 0.
    */
    if (nArgs < 0) {
        PrintError("BUG: PySequence_Length");
        goto Done;
    }

    arglist = PyTuple_New(nArgs);
    if (!arglist) {
        PrintError("PyTuple_New()");
        goto Done;
    }
    for (i = 0; i < nArgs; ++i) {
        /* Note: new reference! */
        PyObject *cnv = PySequence_GetItem(converters, i);
        StgDictObject *dict;
        if (cnv)
            dict = PyType_stgdict(cnv);
        else {
            PrintError("Getting argument converter %d\n", i);
            goto Done;
        }

        if (dict && dict->getfunc && !_ctypes_simple_instance(cnv)) {
            PyObject *v = dict->getfunc(*pArgs, dict->size);
            if (!v) {
                PrintError("create argument %d:\n", i);
                Py_DECREF(cnv);
                goto Done;
            }
            PyTuple_SET_ITEM(arglist, i, v);
            /* XXX XXX XX
               We have the problem that c_byte or c_short have dict->size of
               1 resp. 4, but these parameters are pushed as sizeof(int) bytes.
               BTW, the same problem occurs when they are pushed as parameters
            */
        } else if (dict) {
            /* Hm, shouldn't we use PyCData_AtAddress() or something like that instead? */
            CDataObject *obj = (CDataObject *)PyObject_CallFunctionObjArgs(cnv, NULL);
            if (!obj) {
                PrintError("create argument %d:\n", i);
                Py_DECREF(cnv);
                goto Done;
            }
            if (!CDataObject_Check(obj)) {
                Py_DECREF(obj);
                Py_DECREF(cnv);
                PrintError("unexpected result of create argument %d:\n", i);
                goto Done;
            }
            memcpy(obj->b_ptr, *pArgs, dict->size);
            PyTuple_SET_ITEM(arglist, i, (PyObject *)obj);
#ifdef MS_WIN32
            TryAddRef(dict, obj);
#endif
        } else {
            PyErr_SetString(PyExc_TypeError,
                            "cannot build parameter");
            PrintError("Parsing argument %d\n", i);
            Py_DECREF(cnv);
            goto Done;
        }
        Py_DECREF(cnv);
        /* XXX error handling! */
        pArgs++;
    }

#define CHECK(what, x) \
if (x == NULL) _ctypes_add_traceback(what, "_ctypes/callbacks.c", __LINE__ - 1), PyErr_Print()

    if (flags & (FUNCFLAG_USE_ERRNO | FUNCFLAG_USE_LASTERROR)) {
        error_object = _ctypes_get_errobj(&space);
        if (error_object == NULL)
            goto Done;
        if (flags & FUNCFLAG_USE_ERRNO) {
            int temp = space[0];
            space[0] = errno;
            errno = temp;
        }
#ifdef MS_WIN32
        if (flags & FUNCFLAG_USE_LASTERROR) {
            int temp = space[1];
            space[1] = GetLastError();
            SetLastError(temp);
        }
#endif
    }

    result = PyObject_CallObject(callable, arglist);
    CHECK("'calling callback function'", result);

#ifdef MS_WIN32
    if (flags & FUNCFLAG_USE_LASTERROR) {
        int temp = space[1];
        space[1] = GetLastError();
        SetLastError(temp);
    }
#endif
    if (flags & FUNCFLAG_USE_ERRNO) {
        int temp = space[0];
        space[0] = errno;
        errno = temp;
    }
    Py_XDECREF(error_object);

    if ((restype != &ffi_type_void) && result) {
        PyObject *keep;
        assert(setfunc);
#ifdef WORDS_BIGENDIAN
        /* See the corresponding code in callproc.c, around line 961 */
        if (restype->type != FFI_TYPE_FLOAT && restype->size < sizeof(ffi_arg))
            mem = (char *)mem + sizeof(ffi_arg) - restype->size;
#endif
        keep = setfunc(mem, result, 0);
        CHECK("'converting callback result'", keep);
        /* keep is an object we have to keep alive so that the result
           stays valid.  If there is no such object, the setfunc will
           have returned Py_None.

           If there is such an object, we have no choice than to keep
           it alive forever - but a refcount and/or memory leak will
           be the result.  EXCEPT when restype is py_object - Python
           itself knows how to manage the refcount of these objects.
        */
        if (keep == NULL) /* Could not convert callback result. */
            PyErr_WriteUnraisable(callable);
        else if (keep == Py_None) /* Nothing to keep */
            Py_DECREF(keep);
        else if (setfunc != _ctypes_get_fielddesc("O")->setfunc) {
            if (-1 == PyErr_WarnEx(PyExc_RuntimeWarning,
                                   "memory leak in callback function.",
                                   1))
                PyErr_WriteUnraisable(callable);
        }
    }
    Py_XDECREF(result);
  Done:
    Py_XDECREF(arglist);
#ifdef WITH_THREAD
    PyGILState_Release(state);
#endif
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _ctypes_add_traceback ( char *  funcname,
char *  filename,
int  lineno 
)

Definition at line 95 of file callbacks.c.

{
    PyObject *py_globals = 0;
    PyCodeObject *py_code = 0;
    PyFrameObject *py_frame = 0;

    py_globals = PyDict_New();
    if (!py_globals) goto bad;
    py_code = PyCode_NewEmpty(filename, funcname, lineno);
    if (!py_code) goto bad;
    py_frame = PyFrame_New(
        PyThreadState_Get(), /*PyThreadState *tstate,*/
        py_code,             /*PyCodeObject *code,*/
        py_globals,          /*PyObject *globals,*/
        0                    /*PyObject *locals*/
        );
    if (!py_frame) goto bad;
    py_frame->f_lineno = lineno;
    PyTraceBack_Here(py_frame);
  bad:
    Py_XDECREF(py_globals);
    Py_XDECREF(py_code);
    Py_XDECREF(py_frame);
}

Here is the call graph for this function:

Here is the caller graph for this function:

CThunkObject* _ctypes_alloc_callback ( PyObject callable,
PyObject converters,
PyObject restype,
int  flags 
)

Definition at line 355 of file callbacks.c.

{
    int result;
    CThunkObject *p;
    Py_ssize_t nArgs, i;
    ffi_abi cc;

    nArgs = PySequence_Size(converters);
    p = CThunkObject_new(nArgs);
    if (p == NULL)
        return NULL;

    assert(CThunk_CheckExact((PyObject *)p));

    p->pcl_write = ffi_closure_alloc(sizeof(ffi_closure),
                                                                &p->pcl_exec);
    if (p->pcl_write == NULL) {
        PyErr_NoMemory();
        goto error;
    }

    p->flags = flags;
    for (i = 0; i < nArgs; ++i) {
        PyObject *cnv = PySequence_GetItem(converters, i);
        if (cnv == NULL)
            goto error;
        p->atypes[i] = _ctypes_get_ffi_type(cnv);
        Py_DECREF(cnv);
    }
    p->atypes[i] = NULL;

    Py_INCREF(restype);
    p->restype = restype;
    if (restype == Py_None) {
        p->setfunc = NULL;
        p->ffi_restype = &ffi_type_void;
    } else {
        StgDictObject *dict = PyType_stgdict(restype);
        if (dict == NULL || dict->setfunc == NULL) {
          PyErr_SetString(PyExc_TypeError,
                          "invalid result type for callback function");
          goto error;
        }
        p->setfunc = dict->setfunc;
        p->ffi_restype = &dict->ffi_type_pointer;
    }

    cc = FFI_DEFAULT_ABI;
#if defined(MS_WIN32) && !defined(_WIN32_WCE) && !defined(MS_WIN64)
    if ((flags & FUNCFLAG_CDECL) == 0)
        cc = FFI_STDCALL;
#endif
    result = ffi_prep_cif(&p->cif, cc,
                          Py_SAFE_DOWNCAST(nArgs, Py_ssize_t, int),
                          _ctypes_get_ffi_type(restype),
                          &p->atypes[0]);
    if (result != FFI_OK) {
        PyErr_Format(PyExc_RuntimeError,
                     "ffi_prep_cif failed with %d", result);
        goto error;
    }
#if defined(X86_DARWIN) || defined(POWERPC_DARWIN)
    result = ffi_prep_closure(p->pcl_write, &p->cif, closure_fcn, p);
#else
    result = ffi_prep_closure_loc(p->pcl_write, &p->cif, closure_fcn,
                              p,
                              p->pcl_exec);
#endif
    if (result != FFI_OK) {
        PyErr_Format(PyExc_RuntimeError,
                     "ffi_prep_closure failed with %d", result);
        goto error;
    }

    Py_INCREF(converters);
    p->converters = converters;
    Py_INCREF(callable);
    p->callable = callable;
    return p;

  error:
    Py_XDECREF(p);
    return NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void closure_fcn ( ffi_cif cif,
void resp,
void **  args,
void userdata 
) [static]

Definition at line 314 of file callbacks.c.

{
    CThunkObject *p = (CThunkObject *)userdata;

    _CallPythonObject(resp,
                      p->ffi_restype,
                      p->setfunc,
                      p->callable,
                      p->converters,
                      p->flags,
                      args);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int CThunkObject_clear ( PyObject _self) [static]

Definition at line 35 of file callbacks.c.

{
    CThunkObject *self = (CThunkObject *)_self;
    Py_CLEAR(self->converters);
    Py_CLEAR(self->callable);
    Py_CLEAR(self->restype);
    return 0;
}
static void CThunkObject_dealloc ( PyObject _self) [static]

Definition at line 13 of file callbacks.c.

{
    CThunkObject *self = (CThunkObject *)_self;
    Py_XDECREF(self->converters);
    Py_XDECREF(self->callable);
    Py_XDECREF(self->restype);
    if (self->pcl_write)
        ffi_closure_free(self->pcl_write);
    PyObject_GC_Del(self);
}

Here is the call graph for this function:

static CThunkObject* CThunkObject_new ( Py_ssize_t  nArgs) [static]

Definition at line 330 of file callbacks.c.

{
    CThunkObject *p;
    int i;

    p = PyObject_GC_NewVar(CThunkObject, &PyCThunk_Type, nArgs);
    if (p == NULL) {
        PyErr_NoMemory();
        return NULL;
    }

    p->pcl_exec = NULL;
    p->pcl_write = NULL;
    memset(&p->cif, 0, sizeof(p->cif));
    p->converters = NULL;
    p->callable = NULL;
    p->setfunc = NULL;
    p->ffi_restype = NULL;

    for (i = 0; i < nArgs + 1; ++i)
        p->atypes[i] = NULL;
    PyObject_GC_Track((PyObject *)p);
    return p;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int CThunkObject_traverse ( PyObject _self,
visitproc  visit,
void arg 
) [static]

Definition at line 25 of file callbacks.c.

{
    CThunkObject *self = (CThunkObject *)_self;
    Py_VISIT(self->converters);
    Py_VISIT(self->callable);
    Py_VISIT(self->restype);
    return 0;
}
static void PrintError ( char *  msg,
  ... 
) [static]

Definition at line 79 of file callbacks.c.

{
    char buf[512];
    PyObject *f = PySys_GetObject("stderr");
    va_list marker;

    va_start(marker, msg);
    vsnprintf(buf, sizeof(buf), msg, marker);
    va_end(marker);
    if (f != NULL && f != Py_None)
        PyFile_WriteString(buf, f);
    PyErr_Print();
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

Definition at line 44 of file callbacks.c.