mirror of
https://github.com/wxWidgets/Phoenix.git
synced 2025-12-16 09:40:07 +01:00
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxPython/Phoenix/trunk@73655 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
238 lines
5.1 KiB
C
238 lines
5.1 KiB
C
/*
|
|
* 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) 2013 Riverbank Computing Limited <info@riverbankcomputing.com>
|
|
*
|
|
* 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.
|
|
*
|
|
* This copy of SIP may also used under the terms of the GNU General Public
|
|
* License v2 or v3 as published by the Free Software Foundation which can be
|
|
* found in the files LICENSE-GPL2 and LICENSE-GPL3 included in this package.
|
|
*
|
|
* 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(int auto_alloc);
|
|
|
|
#endif
|
|
|
|
|
|
static pendingDef *get_pending(int auto_alloc);
|
|
|
|
|
|
/*
|
|
* Get the address etc. of any C/C++ object waiting to be wrapped.
|
|
*/
|
|
int sipGetPending(void **pp, sipWrapper **op, int *fp)
|
|
{
|
|
pendingDef *pd;
|
|
|
|
if ((pd = get_pending(TRUE)) == NULL)
|
|
return -1;
|
|
|
|
*pp = pd->cpp;
|
|
*op = pd->owner;
|
|
*fp = pd->flags;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Return TRUE if anything is pending.
|
|
*/
|
|
int sipIsPending()
|
|
{
|
|
pendingDef *pd;
|
|
|
|
if ((pd = get_pending(FALSE)) == NULL)
|
|
return FALSE;
|
|
|
|
return (pd->cpp != NULL);
|
|
}
|
|
|
|
|
|
/*
|
|
* Convert a new C/C++ pointer to a Python instance.
|
|
*/
|
|
PyObject *sipWrapSimpleInstance(void *cppPtr, const sipTypeDef *td,
|
|
sipWrapper *owner, int flags)
|
|
{
|
|
static PyObject *nullargs = NULL;
|
|
|
|
pendingDef old_pending, *pd;
|
|
PyObject *self;
|
|
|
|
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.
|
|
*/
|
|
if ((pd = get_pending(TRUE)) == NULL)
|
|
return NULL;
|
|
|
|
old_pending = *pd;
|
|
|
|
pd->cpp = cppPtr;
|
|
pd->owner = owner;
|
|
pd->flags = flags;
|
|
|
|
self = PyObject_Call((PyObject *)sipTypeAsPyTypeObject(td), nullargs, NULL);
|
|
|
|
*pd = old_pending;
|
|
|
|
return self;
|
|
}
|
|
|
|
|
|
/*
|
|
* This is called from a newly created thread to initialise some thread local
|
|
* storage.
|
|
*/
|
|
#if SIP_API_MAJOR_NR != 9
|
|
#error Remove deprecated sip_api_start_thread().
|
|
#endif
|
|
void sip_api_start_thread(void)
|
|
{
|
|
/*
|
|
* The thread local storage allocation now happens when it is needed, so
|
|
* this is now redundant.
|
|
*/
|
|
}
|
|
|
|
|
|
/*
|
|
* Handle the termination of a thread.
|
|
*/
|
|
void sip_api_end_thread(void)
|
|
{
|
|
#ifdef WITH_THREAD
|
|
threadDef *thread;
|
|
PyGILState_STATE gil = PyGILState_Ensure();
|
|
|
|
if ((thread = currentThreadDef(FALSE)) != NULL)
|
|
thread->thr_ident = 0;
|
|
|
|
PyGILState_Release(gil);
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
* Return the pending data for the current thread, allocating it if necessary,
|
|
* or NULL if there was an error.
|
|
*/
|
|
static pendingDef *get_pending(int auto_alloc)
|
|
{
|
|
#ifdef WITH_THREAD
|
|
threadDef *thread;
|
|
|
|
if ((thread = currentThreadDef(auto_alloc)) == NULL)
|
|
return NULL;
|
|
|
|
return &thread->pending;
|
|
#else
|
|
static pendingDef pending;
|
|
|
|
return &pending;
|
|
#endif
|
|
}
|
|
|
|
|
|
#ifdef WITH_THREAD
|
|
|
|
/*
|
|
* Return the thread data for the current thread, allocating it if necessary,
|
|
* or NULL if there was an error.
|
|
*/
|
|
static threadDef *currentThreadDef(int auto_alloc)
|
|
{
|
|
threadDef *thread, *empty = NULL;
|
|
long ident = PyThread_get_thread_ident();
|
|
|
|
/* See if we already know about the thread. */
|
|
for (thread = threads; thread != NULL; thread = thread->next)
|
|
{
|
|
if (thread->thr_ident == ident)
|
|
return thread;
|
|
|
|
if (thread->thr_ident == 0)
|
|
empty = thread;
|
|
}
|
|
|
|
if (!auto_alloc)
|
|
{
|
|
/* This is not an error. */
|
|
return NULL;
|
|
}
|
|
|
|
if (empty != NULL)
|
|
{
|
|
/* Use an empty entry in the list. */
|
|
thread = empty;
|
|
}
|
|
else if ((thread = sip_api_malloc(sizeof (threadDef))) == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
thread->next = threads;
|
|
threads = thread;
|
|
}
|
|
|
|
thread->thr_ident = ident;
|
|
thread->pending.cpp = NULL;
|
|
|
|
return thread;
|
|
}
|
|
|
|
#endif
|