LCOV - code coverage report
Current view: top level - libreoffice/workdir/unxlngi6.pro/UnpackedTarball/python3/Modules/_ctypes - callbacks.c (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 184 0.0 %
Date: 2012-12-17 Functions: 0 9 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : #include "Python.h"
       2             : #include "frameobject.h"
       3             : 
       4             : #include <ffi.h>
       5             : #ifdef MS_WIN32
       6             : #include <windows.h>
       7             : #endif
       8             : #include "ctypes.h"
       9             : 
      10             : /**************************************************************/
      11             : 
      12             : static void
      13           0 : CThunkObject_dealloc(PyObject *_self)
      14             : {
      15           0 :     CThunkObject *self = (CThunkObject *)_self;
      16           0 :     PyObject_GC_UnTrack(self);
      17           0 :     Py_XDECREF(self->converters);
      18           0 :     Py_XDECREF(self->callable);
      19           0 :     Py_XDECREF(self->restype);
      20           0 :     if (self->pcl_write)
      21           0 :         ffi_closure_free(self->pcl_write);
      22           0 :     PyObject_GC_Del(self);
      23           0 : }
      24             : 
      25             : static int
      26           0 : CThunkObject_traverse(PyObject *_self, visitproc visit, void *arg)
      27             : {
      28           0 :     CThunkObject *self = (CThunkObject *)_self;
      29           0 :     Py_VISIT(self->converters);
      30           0 :     Py_VISIT(self->callable);
      31           0 :     Py_VISIT(self->restype);
      32           0 :     return 0;
      33             : }
      34             : 
      35             : static int
      36           0 : CThunkObject_clear(PyObject *_self)
      37             : {
      38           0 :     CThunkObject *self = (CThunkObject *)_self;
      39           0 :     Py_CLEAR(self->converters);
      40           0 :     Py_CLEAR(self->callable);
      41           0 :     Py_CLEAR(self->restype);
      42           0 :     return 0;
      43             : }
      44             : 
      45             : PyTypeObject PyCThunk_Type = {
      46             :     PyVarObject_HEAD_INIT(NULL, 0)
      47             :     "_ctypes.CThunkObject",
      48             :     sizeof(CThunkObject),                       /* tp_basicsize */
      49             :     sizeof(ffi_type),                           /* tp_itemsize */
      50             :     CThunkObject_dealloc,                       /* tp_dealloc */
      51             :     0,                                          /* tp_print */
      52             :     0,                                          /* tp_getattr */
      53             :     0,                                          /* tp_setattr */
      54             :     0,                                          /* tp_reserved */
      55             :     0,                                          /* tp_repr */
      56             :     0,                                          /* tp_as_number */
      57             :     0,                                          /* tp_as_sequence */
      58             :     0,                                          /* tp_as_mapping */
      59             :     0,                                          /* tp_hash */
      60             :     0,                                          /* tp_call */
      61             :     0,                                          /* tp_str */
      62             :     0,                                          /* tp_getattro */
      63             :     0,                                          /* tp_setattro */
      64             :     0,                                          /* tp_as_buffer */
      65             :     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,                            /* tp_flags */
      66             :     "CThunkObject",                             /* tp_doc */
      67             :     CThunkObject_traverse,                      /* tp_traverse */
      68             :     CThunkObject_clear,                         /* tp_clear */
      69             :     0,                                          /* tp_richcompare */
      70             :     0,                                          /* tp_weaklistoffset */
      71             :     0,                                          /* tp_iter */
      72             :     0,                                          /* tp_iternext */
      73             :     0,                                          /* tp_methods */
      74             :     0,                                          /* tp_members */
      75             : };
      76             : 
      77             : /**************************************************************/
      78             : 
      79             : static void
      80           0 : PrintError(char *msg, ...)
      81             : {
      82             :     char buf[512];
      83           0 :     PyObject *f = PySys_GetObject("stderr");
      84             :     va_list marker;
      85             : 
      86           0 :     va_start(marker, msg);
      87           0 :     vsnprintf(buf, sizeof(buf), msg, marker);
      88           0 :     va_end(marker);
      89           0 :     if (f != NULL && f != Py_None)
      90           0 :         PyFile_WriteString(buf, f);
      91           0 :     PyErr_Print();
      92           0 : }
      93             : 
      94             : 
      95             : /* after code that pyrex generates */
      96           0 : void _ctypes_add_traceback(char *funcname, char *filename, int lineno)
      97             : {
      98           0 :     PyObject *py_globals = 0;
      99           0 :     PyCodeObject *py_code = 0;
     100           0 :     PyFrameObject *py_frame = 0;
     101             : 
     102           0 :     py_globals = PyDict_New();
     103           0 :     if (!py_globals) goto bad;
     104           0 :     py_code = PyCode_NewEmpty(filename, funcname, lineno);
     105           0 :     if (!py_code) goto bad;
     106           0 :     py_frame = PyFrame_New(
     107             :         PyThreadState_Get(), /*PyThreadState *tstate,*/
     108             :         py_code,             /*PyCodeObject *code,*/
     109             :         py_globals,          /*PyObject *globals,*/
     110             :         0                    /*PyObject *locals*/
     111             :         );
     112           0 :     if (!py_frame) goto bad;
     113           0 :     py_frame->f_lineno = lineno;
     114           0 :     PyTraceBack_Here(py_frame);
     115             :   bad:
     116           0 :     Py_XDECREF(py_globals);
     117           0 :     Py_XDECREF(py_code);
     118           0 :     Py_XDECREF(py_frame);
     119           0 : }
     120             : 
     121             : #ifdef MS_WIN32
     122             : /*
     123             :  * We must call AddRef() on non-NULL COM pointers we receive as arguments
     124             :  * to callback functions - these functions are COM method implementations.
     125             :  * The Python instances we create have a __del__ method which calls Release().
     126             :  *
     127             :  * The presence of a class attribute named '_needs_com_addref_' triggers this
     128             :  * behaviour.  It would also be possible to call the AddRef() Python method,
     129             :  * after checking for PyObject_IsTrue(), but this would probably be somewhat
     130             :  * slower.
     131             :  */
     132             : static void
     133             : TryAddRef(StgDictObject *dict, CDataObject *obj)
     134             : {
     135             :     IUnknown *punk;
     136             : 
     137             :     if (NULL == PyDict_GetItemString((PyObject *)dict, "_needs_com_addref_"))
     138             :         return;
     139             : 
     140             :     punk = *(IUnknown **)obj->b_ptr;
     141             :     if (punk)
     142             :         punk->lpVtbl->AddRef(punk);
     143             :     return;
     144             : }
     145             : #endif
     146             : 
     147             : /******************************************************************************
     148             :  *
     149             :  * Call the python object with all arguments
     150             :  *
     151             :  */
     152           0 : static void _CallPythonObject(void *mem,
     153             :                               ffi_type *restype,
     154             :                               SETFUNC setfunc,
     155             :                               PyObject *callable,
     156             :                               PyObject *converters,
     157             :                               int flags,
     158             :                               void **pArgs)
     159             : {
     160             :     Py_ssize_t i;
     161             :     PyObject *result;
     162           0 :     PyObject *arglist = NULL;
     163             :     Py_ssize_t nArgs;
     164           0 :     PyObject *error_object = NULL;
     165             :     int *space;
     166             : #ifdef WITH_THREAD
     167           0 :     PyGILState_STATE state = PyGILState_Ensure();
     168             : #endif
     169             : 
     170           0 :     nArgs = PySequence_Length(converters);
     171             :     /* Hm. What to return in case of error?
     172             :        For COM, 0xFFFFFFFF seems better than 0.
     173             :     */
     174           0 :     if (nArgs < 0) {
     175           0 :         PrintError("BUG: PySequence_Length");
     176           0 :         goto Done;
     177             :     }
     178             : 
     179           0 :     arglist = PyTuple_New(nArgs);
     180           0 :     if (!arglist) {
     181           0 :         PrintError("PyTuple_New()");
     182           0 :         goto Done;
     183             :     }
     184           0 :     for (i = 0; i < nArgs; ++i) {
     185             :         /* Note: new reference! */
     186           0 :         PyObject *cnv = PySequence_GetItem(converters, i);
     187             :         StgDictObject *dict;
     188           0 :         if (cnv)
     189           0 :             dict = PyType_stgdict(cnv);
     190             :         else {
     191           0 :             PrintError("Getting argument converter %d\n", i);
     192           0 :             goto Done;
     193             :         }
     194             : 
     195           0 :         if (dict && dict->getfunc && !_ctypes_simple_instance(cnv)) {
     196           0 :             PyObject *v = dict->getfunc(*pArgs, dict->size);
     197           0 :             if (!v) {
     198           0 :                 PrintError("create argument %d:\n", i);
     199           0 :                 Py_DECREF(cnv);
     200           0 :                 goto Done;
     201             :             }
     202           0 :             PyTuple_SET_ITEM(arglist, i, v);
     203             :             /* XXX XXX XX
     204             :                We have the problem that c_byte or c_short have dict->size of
     205             :                1 resp. 4, but these parameters are pushed as sizeof(int) bytes.
     206             :                BTW, the same problem occurs when they are pushed as parameters
     207             :             */
     208           0 :         } else if (dict) {
     209             :             /* Hm, shouldn't we use PyCData_AtAddress() or something like that instead? */
     210           0 :             CDataObject *obj = (CDataObject *)PyObject_CallFunctionObjArgs(cnv, NULL);
     211           0 :             if (!obj) {
     212           0 :                 PrintError("create argument %d:\n", i);
     213           0 :                 Py_DECREF(cnv);
     214           0 :                 goto Done;
     215             :             }
     216           0 :             if (!CDataObject_Check(obj)) {
     217           0 :                 Py_DECREF(obj);
     218           0 :                 Py_DECREF(cnv);
     219           0 :                 PrintError("unexpected result of create argument %d:\n", i);
     220           0 :                 goto Done;
     221             :             }
     222           0 :             memcpy(obj->b_ptr, *pArgs, dict->size);
     223           0 :             PyTuple_SET_ITEM(arglist, i, (PyObject *)obj);
     224             : #ifdef MS_WIN32
     225             :             TryAddRef(dict, obj);
     226             : #endif
     227             :         } else {
     228           0 :             PyErr_SetString(PyExc_TypeError,
     229             :                             "cannot build parameter");
     230           0 :             PrintError("Parsing argument %d\n", i);
     231           0 :             Py_DECREF(cnv);
     232           0 :             goto Done;
     233             :         }
     234           0 :         Py_DECREF(cnv);
     235             :         /* XXX error handling! */
     236           0 :         pArgs++;
     237             :     }
     238             : 
     239             : #define CHECK(what, x) \
     240             : if (x == NULL) _ctypes_add_traceback(what, "_ctypes/callbacks.c", __LINE__ - 1), PyErr_Print()
     241             : 
     242           0 :     if (flags & (FUNCFLAG_USE_ERRNO | FUNCFLAG_USE_LASTERROR)) {
     243           0 :         error_object = _ctypes_get_errobj(&space);
     244           0 :         if (error_object == NULL)
     245           0 :             goto Done;
     246           0 :         if (flags & FUNCFLAG_USE_ERRNO) {
     247           0 :             int temp = space[0];
     248           0 :             space[0] = errno;
     249           0 :             errno = temp;
     250             :         }
     251             : #ifdef MS_WIN32
     252             :         if (flags & FUNCFLAG_USE_LASTERROR) {
     253             :             int temp = space[1];
     254             :             space[1] = GetLastError();
     255             :             SetLastError(temp);
     256             :         }
     257             : #endif
     258             :     }
     259             : 
     260           0 :     result = PyObject_CallObject(callable, arglist);
     261           0 :     CHECK("'calling callback function'", result);
     262             : 
     263             : #ifdef MS_WIN32
     264             :     if (flags & FUNCFLAG_USE_LASTERROR) {
     265             :         int temp = space[1];
     266             :         space[1] = GetLastError();
     267             :         SetLastError(temp);
     268             :     }
     269             : #endif
     270           0 :     if (flags & FUNCFLAG_USE_ERRNO) {
     271           0 :         int temp = space[0];
     272           0 :         space[0] = errno;
     273           0 :         errno = temp;
     274             :     }
     275           0 :     Py_XDECREF(error_object);
     276             : 
     277           0 :     if ((restype != &ffi_type_void) && result) {
     278             :         PyObject *keep;
     279             :         assert(setfunc);
     280             : #ifdef WORDS_BIGENDIAN
     281             :         /* See the corresponding code in callproc.c, around line 961 */
     282             :         if (restype->type != FFI_TYPE_FLOAT && restype->size < sizeof(ffi_arg))
     283             :             mem = (char *)mem + sizeof(ffi_arg) - restype->size;
     284             : #endif
     285           0 :         keep = setfunc(mem, result, 0);
     286           0 :         CHECK("'converting callback result'", keep);
     287             :         /* keep is an object we have to keep alive so that the result
     288             :            stays valid.  If there is no such object, the setfunc will
     289             :            have returned Py_None.
     290             : 
     291             :            If there is such an object, we have no choice than to keep
     292             :            it alive forever - but a refcount and/or memory leak will
     293             :            be the result.  EXCEPT when restype is py_object - Python
     294             :            itself knows how to manage the refcount of these objects.
     295             :         */
     296           0 :         if (keep == NULL) /* Could not convert callback result. */
     297           0 :             PyErr_WriteUnraisable(callable);
     298           0 :         else if (keep == Py_None) /* Nothing to keep */
     299           0 :             Py_DECREF(keep);
     300           0 :         else if (setfunc != _ctypes_get_fielddesc("O")->setfunc) {
     301           0 :             if (-1 == PyErr_WarnEx(PyExc_RuntimeWarning,
     302             :                                    "memory leak in callback function.",
     303             :                                    1))
     304           0 :                 PyErr_WriteUnraisable(callable);
     305             :         }
     306             :     }
     307           0 :     Py_XDECREF(result);
     308             :   Done:
     309           0 :     Py_XDECREF(arglist);
     310             : #ifdef WITH_THREAD
     311           0 :     PyGILState_Release(state);
     312             : #endif
     313           0 : }
     314             : 
     315           0 : static void closure_fcn(ffi_cif *cif,
     316             :                         void *resp,
     317             :                         void **args,
     318             :                         void *userdata)
     319             : {
     320           0 :     CThunkObject *p = (CThunkObject *)userdata;
     321             : 
     322           0 :     _CallPythonObject(resp,
     323             :                       p->ffi_restype,
     324             :                       p->setfunc,
     325             :                       p->callable,
     326             :                       p->converters,
     327             :                       p->flags,
     328             :                       args);
     329           0 : }
     330             : 
     331           0 : static CThunkObject* CThunkObject_new(Py_ssize_t nArgs)
     332             : {
     333             :     CThunkObject *p;
     334             :     int i;
     335             : 
     336           0 :     p = PyObject_GC_NewVar(CThunkObject, &PyCThunk_Type, nArgs);
     337           0 :     if (p == NULL) {
     338           0 :         PyErr_NoMemory();
     339           0 :         return NULL;
     340             :     }
     341             : 
     342           0 :     p->pcl_exec = NULL;
     343           0 :     p->pcl_write = NULL;
     344           0 :     memset(&p->cif, 0, sizeof(p->cif));
     345           0 :     p->converters = NULL;
     346           0 :     p->callable = NULL;
     347           0 :     p->setfunc = NULL;
     348           0 :     p->ffi_restype = NULL;
     349             : 
     350           0 :     for (i = 0; i < nArgs + 1; ++i)
     351           0 :         p->atypes[i] = NULL;
     352           0 :     PyObject_GC_Track((PyObject *)p);
     353           0 :     return p;
     354             : }
     355             : 
     356           0 : CThunkObject *_ctypes_alloc_callback(PyObject *callable,
     357             :                                     PyObject *converters,
     358             :                                     PyObject *restype,
     359             :                                     int flags)
     360             : {
     361             :     int result;
     362             :     CThunkObject *p;
     363             :     Py_ssize_t nArgs, i;
     364             :     ffi_abi cc;
     365             : 
     366           0 :     nArgs = PySequence_Size(converters);
     367           0 :     p = CThunkObject_new(nArgs);
     368           0 :     if (p == NULL)
     369           0 :         return NULL;
     370             : 
     371             :     assert(CThunk_CheckExact((PyObject *)p));
     372             : 
     373           0 :     p->pcl_write = ffi_closure_alloc(sizeof(ffi_closure),
     374             :                                                                          &p->pcl_exec);
     375           0 :     if (p->pcl_write == NULL) {
     376           0 :         PyErr_NoMemory();
     377           0 :         goto error;
     378             :     }
     379             : 
     380           0 :     p->flags = flags;
     381           0 :     for (i = 0; i < nArgs; ++i) {
     382           0 :         PyObject *cnv = PySequence_GetItem(converters, i);
     383           0 :         if (cnv == NULL)
     384           0 :             goto error;
     385           0 :         p->atypes[i] = _ctypes_get_ffi_type(cnv);
     386           0 :         Py_DECREF(cnv);
     387             :     }
     388           0 :     p->atypes[i] = NULL;
     389             : 
     390           0 :     Py_INCREF(restype);
     391           0 :     p->restype = restype;
     392           0 :     if (restype == Py_None) {
     393           0 :         p->setfunc = NULL;
     394           0 :         p->ffi_restype = &ffi_type_void;
     395             :     } else {
     396           0 :         StgDictObject *dict = PyType_stgdict(restype);
     397           0 :         if (dict == NULL || dict->setfunc == NULL) {
     398           0 :           PyErr_SetString(PyExc_TypeError,
     399             :                           "invalid result type for callback function");
     400           0 :           goto error;
     401             :         }
     402           0 :         p->setfunc = dict->setfunc;
     403           0 :         p->ffi_restype = &dict->ffi_type_pointer;
     404             :     }
     405             : 
     406           0 :     cc = FFI_DEFAULT_ABI;
     407             : #if defined(MS_WIN32) && !defined(_WIN32_WCE) && !defined(MS_WIN64)
     408             :     if ((flags & FUNCFLAG_CDECL) == 0)
     409             :         cc = FFI_STDCALL;
     410             : #endif
     411           0 :     result = ffi_prep_cif(&p->cif, cc,
     412             :                           Py_SAFE_DOWNCAST(nArgs, Py_ssize_t, int),
     413             :                           _ctypes_get_ffi_type(restype),
     414             :                           &p->atypes[0]);
     415           0 :     if (result != FFI_OK) {
     416           0 :         PyErr_Format(PyExc_RuntimeError,
     417             :                      "ffi_prep_cif failed with %d", result);
     418           0 :         goto error;
     419             :     }
     420             : #if defined(X86_DARWIN) || defined(POWERPC_DARWIN)
     421             :     result = ffi_prep_closure(p->pcl_write, &p->cif, closure_fcn, p);
     422             : #else
     423           0 :     result = ffi_prep_closure_loc(p->pcl_write, &p->cif, closure_fcn,
     424             :                                   p,
     425             :                                   p->pcl_exec);
     426             : #endif
     427           0 :     if (result != FFI_OK) {
     428           0 :         PyErr_Format(PyExc_RuntimeError,
     429             :                      "ffi_prep_closure failed with %d", result);
     430           0 :         goto error;
     431             :     }
     432             : 
     433           0 :     Py_INCREF(converters);
     434           0 :     p->converters = converters;
     435           0 :     Py_INCREF(callable);
     436           0 :     p->callable = callable;
     437           0 :     return p;
     438             : 
     439             :   error:
     440           0 :     Py_XDECREF(p);
     441           0 :     return NULL;
     442             : }
     443             : 
     444             : #ifdef MS_WIN32
     445             : 
     446             : static void LoadPython(void)
     447             : {
     448             :     if (!Py_IsInitialized()) {
     449             : #ifdef WITH_THREAD
     450             :         PyEval_InitThreads();
     451             : #endif
     452             :         Py_Initialize();
     453             :     }
     454             : }
     455             : 
     456             : /******************************************************************/
     457             : 
     458             : long Call_GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
     459             : {
     460             :     PyObject *mod, *func, *result;
     461             :     long retval;
     462             :     static PyObject *context;
     463             : 
     464             :     if (context == NULL)
     465             :         context = PyUnicode_InternFromString("_ctypes.DllGetClassObject");
     466             : 
     467             :     mod = PyImport_ImportModuleNoBlock("ctypes");
     468             :     if (!mod) {
     469             :         PyErr_WriteUnraisable(context ? context : Py_None);
     470             :         /* There has been a warning before about this already */
     471             :         return E_FAIL;
     472             :     }
     473             : 
     474             :     func = PyObject_GetAttrString(mod, "DllGetClassObject");
     475             :     Py_DECREF(mod);
     476             :     if (!func) {
     477             :         PyErr_WriteUnraisable(context ? context : Py_None);
     478             :         return E_FAIL;
     479             :     }
     480             : 
     481             :     {
     482             :         PyObject *py_rclsid = PyLong_FromVoidPtr((void *)rclsid);
     483             :         PyObject *py_riid = PyLong_FromVoidPtr((void *)riid);
     484             :         PyObject *py_ppv = PyLong_FromVoidPtr(ppv);
     485             :         if (!py_rclsid || !py_riid || !py_ppv) {
     486             :             Py_XDECREF(py_rclsid);
     487             :             Py_XDECREF(py_riid);
     488             :             Py_XDECREF(py_ppv);
     489             :             Py_DECREF(func);
     490             :             PyErr_WriteUnraisable(context ? context : Py_None);
     491             :             return E_FAIL;
     492             :         }
     493             :         result = PyObject_CallFunctionObjArgs(func,
     494             :                                               py_rclsid,
     495             :                                               py_riid,
     496             :                                               py_ppv,
     497             :                                               NULL);
     498             :         Py_DECREF(py_rclsid);
     499             :         Py_DECREF(py_riid);
     500             :         Py_DECREF(py_ppv);
     501             :     }
     502             :     Py_DECREF(func);
     503             :     if (!result) {
     504             :         PyErr_WriteUnraisable(context ? context : Py_None);
     505             :         return E_FAIL;
     506             :     }
     507             : 
     508             :     retval = PyLong_AsLong(result);
     509             :     if (PyErr_Occurred()) {
     510             :         PyErr_WriteUnraisable(context ? context : Py_None);
     511             :         retval = E_FAIL;
     512             :     }
     513             :     Py_DECREF(result);
     514             :     return retval;
     515             : }
     516             : 
     517             : STDAPI DllGetClassObject(REFCLSID rclsid,
     518             :                          REFIID riid,
     519             :                          LPVOID *ppv)
     520             : {
     521             :     long result;
     522             : #ifdef WITH_THREAD
     523             :     PyGILState_STATE state;
     524             : #endif
     525             : 
     526             :     LoadPython();
     527             : #ifdef WITH_THREAD
     528             :     state = PyGILState_Ensure();
     529             : #endif
     530             :     result = Call_GetClassObject(rclsid, riid, ppv);
     531             : #ifdef WITH_THREAD
     532             :     PyGILState_Release(state);
     533             : #endif
     534             :     return result;
     535             : }
     536             : 
     537             : long Call_CanUnloadNow(void)
     538             : {
     539             :     PyObject *mod, *func, *result;
     540             :     long retval;
     541             :     static PyObject *context;
     542             : 
     543             :     if (context == NULL)
     544             :         context = PyUnicode_InternFromString("_ctypes.DllCanUnloadNow");
     545             : 
     546             :     mod = PyImport_ImportModuleNoBlock("ctypes");
     547             :     if (!mod) {
     548             : /*              OutputDebugString("Could not import ctypes"); */
     549             :         /* We assume that this error can only occur when shutting
     550             :            down, so we silently ignore it */
     551             :         PyErr_Clear();
     552             :         return E_FAIL;
     553             :     }
     554             :     /* Other errors cannot be raised, but are printed to stderr */
     555             :     func = PyObject_GetAttrString(mod, "DllCanUnloadNow");
     556             :     Py_DECREF(mod);
     557             :     if (!func) {
     558             :         PyErr_WriteUnraisable(context ? context : Py_None);
     559             :         return E_FAIL;
     560             :     }
     561             : 
     562             :     result = PyObject_CallFunction(func, NULL);
     563             :     Py_DECREF(func);
     564             :     if (!result) {
     565             :         PyErr_WriteUnraisable(context ? context : Py_None);
     566             :         return E_FAIL;
     567             :     }
     568             : 
     569             :     retval = PyLong_AsLong(result);
     570             :     if (PyErr_Occurred()) {
     571             :         PyErr_WriteUnraisable(context ? context : Py_None);
     572             :         retval = E_FAIL;
     573             :     }
     574             :     Py_DECREF(result);
     575             :     return retval;
     576             : }
     577             : 
     578             : /*
     579             :   DllRegisterServer and DllUnregisterServer still missing
     580             : */
     581             : 
     582             : STDAPI DllCanUnloadNow(void)
     583             : {
     584             :     long result;
     585             : #ifdef WITH_THREAD
     586             :     PyGILState_STATE state = PyGILState_Ensure();
     587             : #endif
     588             :     result = Call_CanUnloadNow();
     589             : #ifdef WITH_THREAD
     590             :     PyGILState_Release(state);
     591             : #endif
     592             :     return result;
     593             : }
     594             : 
     595             : #ifndef Py_NO_ENABLE_SHARED
     596             : BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvRes)
     597             : {
     598             :     switch(fdwReason) {
     599             :     case DLL_PROCESS_ATTACH:
     600             :         DisableThreadLibraryCalls(hinstDLL);
     601             :         break;
     602             :     }
     603             :     return TRUE;
     604             : }
     605             : #endif
     606             : 
     607             : #endif
     608             : 
     609             : /*
     610             :  Local Variables:
     611             :  compile-command: "cd .. && python setup.py -q build_ext"
     612             :  End:
     613             : */

Generated by: LCOV version 1.10