~ubuntu-branches/ubuntu/trusty/python3.4/trusty-proposed

« back to all changes in this revision

Viewing changes to Modules/_ctypes/callbacks.c

  • Committer: Package Import Robot
  • Author(s): Matthias Klose
  • Date: 2013-11-25 09:44:27 UTC
  • Revision ID: package-import@ubuntu.com-20131125094427-lzxj8ap5w01lmo7f
Tags: upstream-3.4~b1
ImportĀ upstreamĀ versionĀ 3.4~b1

Show diffs side-by-side

added added

removed removed

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