You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
224 lines
4.6 KiB
224 lines
4.6 KiB
15 years ago
|
/*
|
||
|
* Thread support for the SIP library. This module provides the hooks for
|
||
|
* C++ classes that provide a thread interface to interact properly with the
|
||
|
* Python threading infrastructure.
|
||
|
*
|
||
|
* Copyright (c) 2007
|
||
|
* Riverbank Computing Limited <info@riverbankcomputing.co.uk>
|
||
|
*
|
||
|
* This file is part of SIP.
|
||
|
*
|
||
|
* This copy of SIP is licensed for use under the terms of the SIP License
|
||
|
* Agreement. See the file LICENSE for more details.
|
||
|
*
|
||
|
* SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||
|
*/
|
||
|
|
||
|
|
||
|
#include "sip.h"
|
||
|
#include "sipint.h"
|
||
|
|
||
|
|
||
|
/*
|
||
|
* The data associated with pending request to wrap an object.
|
||
|
*/
|
||
|
typedef struct _pendingDef {
|
||
|
void *cpp; /* The C/C++ object ot be wrapped. */
|
||
|
sipWrapper *owner; /* The owner of the object. */
|
||
|
int flags; /* The flags. */
|
||
|
} pendingDef;
|
||
|
|
||
|
|
||
|
#ifdef WITH_THREAD
|
||
|
|
||
|
#include <pythread.h>
|
||
|
|
||
|
|
||
|
/*
|
||
|
* The per thread data we need to maintain.
|
||
|
*/
|
||
|
typedef struct _threadDef {
|
||
|
long thr_ident; /* The thread identifier. */
|
||
|
pendingDef pending; /* An object waiting to be wrapped. */
|
||
|
struct _threadDef *next; /* Next in the list. */
|
||
|
} threadDef;
|
||
|
|
||
|
|
||
|
static threadDef *threads = NULL; /* Linked list of threads. */
|
||
|
|
||
|
|
||
|
static threadDef *currentThreadDef(void);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
static pendingDef pending; /* An object waiting to be wrapped. */
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Get the address of any C/C++ object waiting to be wrapped.
|
||
|
*/
|
||
|
void *sipGetPending(sipWrapper **op, int *fp)
|
||
|
{
|
||
|
pendingDef *pp;
|
||
|
|
||
|
#ifdef WITH_THREAD
|
||
|
threadDef *td;
|
||
|
|
||
|
if ((td = currentThreadDef()) != NULL)
|
||
|
pp = &td->pending;
|
||
|
else
|
||
|
pp = &pending;
|
||
|
#else
|
||
|
pp = &pending;
|
||
|
#endif
|
||
|
|
||
|
if (pp->cpp != NULL)
|
||
|
{
|
||
|
if (op != NULL)
|
||
|
*op = pp->owner;
|
||
|
|
||
|
if (fp != NULL)
|
||
|
*fp = pp->flags;
|
||
|
}
|
||
|
|
||
|
return pp->cpp;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Convert a new C/C++ pointer to a Python instance.
|
||
|
*/
|
||
|
PyObject *sipWrapSimpleInstance(void *cppPtr, sipWrapperType *type,
|
||
|
sipWrapper *owner, int flags)
|
||
|
{
|
||
|
static PyObject *nullargs = NULL;
|
||
|
|
||
|
pendingDef old_pending;
|
||
|
PyObject *self;
|
||
|
#ifdef WITH_THREAD
|
||
|
threadDef *td;
|
||
|
#endif
|
||
|
|
||
|
if (nullargs == NULL && (nullargs = PyTuple_New(0)) == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
if (cppPtr == NULL)
|
||
|
{
|
||
|
Py_INCREF(Py_None);
|
||
|
return Py_None;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Object creation can trigger the Python garbage collector which in turn
|
||
|
* can execute arbitrary Python code which can then call this function
|
||
|
* recursively. Therefore we save any existing pending object before
|
||
|
* setting the new one.
|
||
|
*/
|
||
|
#ifdef WITH_THREAD
|
||
|
if ((td = currentThreadDef()) != NULL)
|
||
|
{
|
||
|
old_pending = td->pending;
|
||
|
|
||
|
td->pending.cpp = cppPtr;
|
||
|
td->pending.owner = owner;
|
||
|
td->pending.flags = flags;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
old_pending = pending;
|
||
|
|
||
|
pending.cpp = cppPtr;
|
||
|
pending.owner = owner;
|
||
|
pending.flags = flags;
|
||
|
}
|
||
|
#else
|
||
|
old_pending = pending;
|
||
|
|
||
|
pending.cpp = cppPtr;
|
||
|
pending.owner = owner;
|
||
|
pending.flags = flags;
|
||
|
#endif
|
||
|
|
||
|
self = PyObject_Call((PyObject *)type, nullargs, NULL);
|
||
|
|
||
|
#ifdef WITH_THREAD
|
||
|
if (td != NULL)
|
||
|
td->pending = old_pending;
|
||
|
else
|
||
|
pending = old_pending;
|
||
|
#else
|
||
|
pending = old_pending;
|
||
|
#endif
|
||
|
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* This is called from a newly created thread to initialise some thread local
|
||
|
* storage.
|
||
|
*/
|
||
|
void sip_api_start_thread(void)
|
||
|
{
|
||
|
#ifdef WITH_THREAD
|
||
|
threadDef *td;
|
||
|
|
||
|
/* Save the thread ID. First, find an empty slot in the list. */
|
||
|
for (td = threads; td != NULL; td = td->next)
|
||
|
if (td->thr_ident == 0)
|
||
|
break;
|
||
|
|
||
|
if (td == NULL)
|
||
|
{
|
||
|
td = sip_api_malloc(sizeof (threadDef));
|
||
|
td->next = threads;
|
||
|
threads = td;
|
||
|
}
|
||
|
|
||
|
if (td != NULL)
|
||
|
{
|
||
|
td->thr_ident = PyThread_get_thread_ident();
|
||
|
td->pending.cpp = NULL;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Handle the termination of a thread. The thread state should already have
|
||
|
* been handled by the last call to PyGILState_Release().
|
||
|
*/
|
||
|
void sip_api_end_thread(void)
|
||
|
{
|
||
|
#ifdef WITH_THREAD
|
||
|
threadDef *td;
|
||
|
|
||
|
/* We have the GIL at this point. */
|
||
|
if ((td = currentThreadDef()) != NULL)
|
||
|
td->thr_ident = 0;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifdef WITH_THREAD
|
||
|
|
||
|
/*
|
||
|
* Return the thread data for the current thread or NULL if it wasn't
|
||
|
* recognised.
|
||
|
*/
|
||
|
static threadDef *currentThreadDef(void)
|
||
|
{
|
||
|
threadDef *td;
|
||
|
long ident = PyThread_get_thread_ident();
|
||
|
|
||
|
for (td = threads; td != NULL; td = td->next)
|
||
|
if (td->thr_ident == ident)
|
||
|
break;
|
||
|
|
||
|
return td;
|
||
|
}
|
||
|
|
||
|
#endif
|