diff --git a/mozilla/extensions/python/xpcom/src/PyGBase.cpp b/mozilla/extensions/python/xpcom/src/PyGBase.cpp index 65c085e8c34..bcd26e98e29 100644 --- a/mozilla/extensions/python/xpcom/src/PyGBase.cpp +++ b/mozilla/extensions/python/xpcom/src/PyGBase.cpp @@ -142,8 +142,6 @@ PyG_Base::PyG_Base(PyObject *instance, const nsIID &iid) #endif // DEBUG_LIFETIMES Py_XINCREF(instance); // instance should never be NULL - but what's an X between friends! - PyXPCOM_DLLAddRef(); - #ifdef DEBUG_FULL LogF("PyGatewayBase: created %s", m_pPyObject ? m_pPyObject->ob_type->tp_name : ""); #endif @@ -169,7 +167,6 @@ PyG_Base::~PyG_Base() p->m_pBase = nsnull; m_pWeakRef = nsnull; } - PyXPCOM_DLLRelease(); } // Get the correct interface pointer for this object given the IID. diff --git a/mozilla/extensions/python/xpcom/src/PyISupports.cpp b/mozilla/extensions/python/xpcom/src/PyISupports.cpp index 13544ed05f5..02c80a8f77a 100644 --- a/mozilla/extensions/python/xpcom/src/PyISupports.cpp +++ b/mozilla/extensions/python/xpcom/src/PyISupports.cpp @@ -73,7 +73,6 @@ Py_nsISupports::Py_nsISupports(nsISupports *punk, const nsIID &iid, PyTypeObject m_iid = iid; // refcnt of object managed by caller. PR_AtomicIncrement(&cInterfaces); - PyXPCOM_DLLAddRef(); _Py_NewReference(this); } @@ -81,7 +80,6 @@ Py_nsISupports::~Py_nsISupports() { SafeRelease(this); PR_AtomicDecrement(&cInterfaces); - PyXPCOM_DLLRelease(); } /*static*/ nsISupports * diff --git a/mozilla/extensions/python/xpcom/src/PyXPCOM.h b/mozilla/extensions/python/xpcom/src/PyXPCOM.h index a3330ae05ec..a15f7aa4fcf 100644 --- a/mozilla/extensions/python/xpcom/src/PyXPCOM.h +++ b/mozilla/extensions/python/xpcom/src/PyXPCOM.h @@ -121,8 +121,9 @@ PYXPCOM_EXPORT PRBool PyXPCOM_FormatGivenException(nsCString &streamout, PyObject *exc_typ, PyObject *exc_val, PyObject *exc_tb); -// A couple of logging/error functions. These probably end up -// being written to the console service. +// A couple of logging/error functions. These now end up being written +// via the logging module, and via handlers added by the xpcom package, +// then are written to the JSConsole and the ConsoleService. // Log a warning for the user - something at runtime // they may care about, but nothing that prevents us actually @@ -621,6 +622,10 @@ public: ~CEnterLeaveXPCOMFramework() {PyXPCOM_ReleaseGlobalLock();} }; +// Initialize Python and do anything else necessary to get a function +// Python environment going... +PYXPCOM_EXPORT void PyXPCOM_EnsurePythonEnvironment(void); + // Python thread-lock stuff. Free-threading patches use different semantics, but // these are abstracted away here... //#include diff --git a/mozilla/extensions/python/xpcom/src/dllmain.cpp b/mozilla/extensions/python/xpcom/src/dllmain.cpp index 94c8866775d..b827e04c539 100644 --- a/mozilla/extensions/python/xpcom/src/dllmain.cpp +++ b/mozilla/extensions/python/xpcom/src/dllmain.cpp @@ -50,6 +50,12 @@ #include "nsIThread.h" #include "nsILocalFile.h" #include "nsTraceRefcntImpl.h" +#include "nsDirectoryServiceDefs.h" +#include "nsILocalFile.h" +#include "nsITimelineService.h" + +#include +#include "nspr.h" // PR_fprintf #ifdef XP_WIN #ifndef WIN32_LEAN_AND_MEAN @@ -58,7 +64,11 @@ #include "windows.h" #endif -static PRInt32 g_cLockCount = 0; +#ifdef XP_UNIX +#include +#include +#endif + static PRLock *g_lockMain = nsnull; PYXPCOM_EXPORT PyObject *PyXPCOM_Error = NULL; @@ -72,109 +82,6 @@ PyXPCOM_INTERFACE_DEFINE(Py_nsIInputStream, nsIInputStream, PyMethods_IInputStre PyXPCOM_INTERFACE_DEFINE(Py_nsIClassInfo, nsIClassInfo, PyMethods_IClassInfo) PyXPCOM_INTERFACE_DEFINE(Py_nsIVariant, nsIVariant, PyMethods_IVariant) -#ifndef PYXPCOM_USE_PYGILSTATE - -//////////////////////////////////////////////////////////// -// Thread-state helpers/global functions. -// Only used if there is no Python PyGILState_* API -// -static PyThreadState *ptsGlobal = nsnull; -PyInterpreterState *PyXPCOM_InterpreterState = nsnull; -PRUintn tlsIndex = 0; - - -// This function must be called at some time when the interpreter lock and state is valid. -// Called by init{module} functions and also COM factory entry point. -void PyXPCOM_InterpreterState_Ensure() -{ - if (PyXPCOM_InterpreterState==NULL) { - PyThreadState *threadStateSave = PyThreadState_Swap(NULL); - if (threadStateSave==NULL) - Py_FatalError("Can not setup interpreter state, as current state is invalid"); - - PyXPCOM_InterpreterState = threadStateSave->interp; - PyThreadState_Swap(threadStateSave); - } -} - -void PyXPCOM_InterpreterState_Free() -{ - PyXPCOM_ThreadState_Free(); - PyXPCOM_InterpreterState = NULL; // Eek - should I be freeing something? -} - -// This structure is stored in the TLS slot. At this stage only a Python thread state -// is kept, but this may change in the future... -struct ThreadData{ - PyThreadState *ts; -}; - -// Ensure that we have a Python thread state available to use. -// If this is called for the first time on a thread, it will allocate -// the thread state. This does NOT change the state of the Python lock. -// Returns TRUE if a new thread state was created, or FALSE if a -// thread state already existed. -PRBool PyXPCOM_ThreadState_Ensure() -{ - ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex); - if (pData==NULL) { /* First request on this thread */ - /* Check we have an interpreter state */ - if (PyXPCOM_InterpreterState==NULL) { - Py_FatalError("Can not setup thread state, as have no interpreter state"); - } - pData = (ThreadData *)nsMemory::Alloc(sizeof(ThreadData)); - if (!pData) - Py_FatalError("Out of memory allocating thread state."); - memset(pData, 0, sizeof(*pData)); - if (NS_FAILED( PR_SetThreadPrivate( tlsIndex, pData ) ) ) { - NS_ABORT_IF_FALSE(0, "Could not create thread data for this thread!"); - Py_FatalError("Could not thread private thread data!"); - } - pData->ts = PyThreadState_New(PyXPCOM_InterpreterState); - return PR_TRUE; // Did create a thread state state - } - return PR_FALSE; // Thread state was previously created -} - -// Asuming we have a valid thread state, acquire the Python lock. -void PyXPCOM_InterpreterLock_Acquire() -{ - ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex); - NS_ABORT_IF_FALSE(pData, "Have no thread data for this thread!"); - PyThreadState *thisThreadState = pData->ts; - PyEval_AcquireThread(thisThreadState); -} - -// Asuming we have a valid thread state, release the Python lock. -void PyXPCOM_InterpreterLock_Release() -{ - ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex); - NS_ABORT_IF_FALSE(pData, "Have no thread data for this thread!"); - PyThreadState *thisThreadState = pData->ts; - PyEval_ReleaseThread(thisThreadState); -} - -// Free the thread state for the current thread -// (Presumably previously create with a call to -// PyXPCOM_ThreadState_Ensure) -void PyXPCOM_ThreadState_Free() -{ - ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex); - if (!pData) return; - PyThreadState *thisThreadState = pData->ts; - PyThreadState_Delete(thisThreadState); - PR_SetThreadPrivate(tlsIndex, NULL); - nsMemory::Free(pData); -} - -void PyXPCOM_ThreadState_Clear() -{ - ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex); - PyThreadState *thisThreadState = pData->ts; - PyThreadState_Clear(thisThreadState); -} -#endif // PYXPCOM_USE_PYGILSTATE - //////////////////////////////////////////////////////////// // Lock/exclusion global functions. // @@ -192,65 +99,166 @@ PyXPCOM_ReleaseGlobalLock(void) PR_Unlock(g_lockMain); } -void PyXPCOM_DLLAddRef(void) +// Note we can't use the PyXPCOM_Log* functions as we are still booting +// up the xpcom support, which is what sets up the logger etc. So we +// just write directly to the console service and to stderr. +static void DoLogStartupMessage(const char *prefix, const char *fmt, va_list argptr) { - // Must be thread-safe, although can't have the Python lock! - CEnterLeaveXPCOMFramework _celf; - PRInt32 cnt = PR_AtomicIncrement(&g_cLockCount); - if (cnt==1) { // First call - if (!Py_IsInitialized()) { - Py_Initialize(); - // Make sure our Windows framework is all setup. - PyXPCOM_Globals_Ensure(); - // Make sure we have _something_ as sys.argv. - if (PySys_GetObject("argv")==NULL) { - PyObject *path = PyList_New(0); - PyObject *str = PyString_FromString(""); - PyList_Append(path, str); - PySys_SetObject("argv", path); - Py_XDECREF(path); - Py_XDECREF(str); - } + char buff[2048]; + PR_vsnprintf(buff, sizeof(buff), fmt, argptr); - // Must force Python to start using thread locks, as - // we are free-threaded (maybe, I think, sometimes :-) - PyEval_InitThreads(); -#ifndef PYXPCOM_USE_PYGILSTATE - // Release Python lock, as first thing we do is re-get it. - ptsGlobal = PyEval_SaveThread(); + nsCOMPtr consoleService = do_GetService(NS_CONSOLESERVICE_CONTRACTID); + if (consoleService) + consoleService->LogStringMessage(NS_ConvertASCIItoUTF16(buff).get()); + PR_fprintf(PR_STDERR,"%s\n", buff); +} + +static void LogStartupError(const char *fmt, ...) +{ + va_list marker; + va_start(marker, fmt); + DoLogStartupMessage("PyXPCOM Startup Error:", fmt, marker); +} + +static void LogStartupDebug(const char *fmt, ...) +{ +#ifdef NS_DEBUG + va_list marker; + va_start(marker, fmt); + DoLogStartupMessage("", fmt, marker); #endif - // NOTE: We never finalize Python!! - } +} + +// Ensure that any paths guaranteed by this package exist on sys.path +// Only called once as we are first loaded into the process. +void AddStandardPaths() +{ + // Put {bin}\Python on the path if it exists. + nsresult rv; + nsCOMPtr aFile; + rv = NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR, getter_AddRefs(aFile)); + if (NS_FAILED(rv)) { + LogStartupError("The Python XPCOM loader could not locate the 'bin' directory"); + return; + } + aFile->Append(NS_LITERAL_STRING("python")); + nsAutoString pathBuf; + aFile->GetPath(pathBuf); + PyObject *obPath = PySys_GetObject("path"); + if (!obPath) { + LogStartupError("The Python XPCOM loader could not get the Python sys.path variable"); + return; + } + // XXX - this should use the file-system encoding... + NS_LossyConvertUTF16toASCII pathCBuf(pathBuf); + // This is too early for effective LogDebug + LogStartupDebug("The Python XPCOM loader is adding '%s' to sys.path", + pathCBuf.get()); + PyObject *newStr = PyString_FromString(pathCBuf.get()); + PyList_Insert(obPath, 0, newStr); + Py_XDECREF(newStr); + // And now try and get Python to process this directory as a "site dir" + // - ie, look for .pth files, etc + nsCAutoString cmdBuf(NS_LITERAL_CSTRING("import site;site.addsitedir(r'") + pathCBuf + NS_LITERAL_CSTRING("')\n")); + if (0 != PyRun_SimpleString((char *)cmdBuf.get())) { + LogStartupError("The directory '%s' could not be added as a site directory", pathCBuf.get()); + PyErr_Clear(); + } + // and somewhat like Python itself (site, citecustomize), we attempt + // to import "sitepyxpcom" ignoring ImportError + if (NULL==PyImport_ImportModule("sitepyxpcom")) { + if (!PyErr_ExceptionMatches(PyExc_ImportError)) + LogStartupError("Failed to import 'sitepyxpcom'"); + PyErr_Clear(); } } -void PyXPCOM_DLLRelease(void) + +PYXPCOM_EXPORT void +PyXPCOM_EnsurePythonEnvironment(void) { - PR_AtomicDecrement(&g_cLockCount); + static PRBool bIsInitialized = PR_FALSE; + // Must be thread-safe + CEnterLeaveXPCOMFramework _celf; + if (bIsInitialized) + return; + +#if defined(XP_UNIX) && !defined(XP_MACOSX) + /* *sob* - seems necessary to open the .so as RTLD_GLOBAL. Without + this we see: + Traceback (most recent call last): + File "", line 1, in ? + File "/usr/lib/python2.4/logging/__init__.py", line 29, in ? + import sys, os, types, time, string, cStringIO, traceback + ImportError: /usr/lib/python2.4/lib-dynload/time.so: undefined + symbol: PyExc_IOError + + On osx, ShaneC writes that is it unnecessary (and fails anyway since + PYTHON_SO is wrong.) More clues about this welcome! + */ + + dlopen(PYTHON_SO,RTLD_NOW | RTLD_GLOBAL); +#endif + + PRBool bDidInitPython = !Py_IsInitialized(); // well, I will next line, anyway :-) + if (bDidInitPython) { + NS_TIMELINE_START_TIMER("PyXPCOM: Python initializing"); + Py_Initialize(); // NOTE: We never finalize Python!! +#ifndef NS_DEBUG + Py_OptimizeFlag = 1; +#endif // NS_DEBUG + // Must force Python to start using thread locks, as + // this is certainly a threaded environment we are playing in + PyEval_InitThreads(); + + NS_TIMELINE_STOP_TIMER("PyXPCOM: Python initializing"); + NS_TIMELINE_MARK_TIMER("PyXPCOM: Python initializing"); + } + // Get the Python interpreter state + NS_TIMELINE_START_TIMER("PyXPCOM: Python threadstate setup"); + PyGILState_STATE state = PyGILState_Ensure(); +#ifdef MOZ_TIMELINE + // If the timeline service is installed, see if we can install our hooks. + if (NULL==PyImport_ImportModule("timeline_hook")) { + if (!PyErr_ExceptionMatches(PyExc_ImportError)) + PyXPCOM_LogError("Failed to import 'timeline_hook'"); + PyErr_Clear(); // but don't care if we can't. + } +#endif + + // Make sure we have _something_ as sys.argv. + if (PySys_GetObject("argv")==NULL) { + PyObject *path = PyList_New(0); + PyObject *str = PyString_FromString(""); + PyList_Append(path, str); + PySys_SetObject("argv", path); + Py_XDECREF(path); + Py_XDECREF(str); + } + + // Add the standard extra paths we assume + AddStandardPaths(); + + // If we initialized Python, then we will also have acquired the thread + // lock. In that case, we want to leave it unlocked, so other threads + // are free to run, even if they aren't running Python code. + PyGILState_Release(bDidInitPython ? PyGILState_UNLOCKED : state); + + NS_TIMELINE_STOP_TIMER("PyXPCOM: Python threadstate setup"); + NS_TIMELINE_MARK_TIMER("PyXPCOM: Python threadstate setup"); + bIsInitialized = PR_TRUE; } void pyxpcom_construct(void) { + // Create the lock we will use to ensure startup thread + // safetly, but don't actually initialize Python yet. g_lockMain = PR_NewLock(); -#ifndef PYXPCOM_USE_PYGILSTATE - PRStatus status; - status = PR_NewThreadPrivateIndex( &tlsIndex, NULL ); - NS_ASSERTION(status==0, "Could not allocate TLS storage"); - if (NS_FAILED(status)) { - PR_DestroyLock(g_lockMain); - return; // PR_FALSE; - } -#endif // PYXPCOM_USE_PYGILSTATE return; // PR_TRUE; } void pyxpcom_destruct(void) { PR_DestroyLock(g_lockMain); -#ifndef PYXPCOM_USE_PYGILSTATE - // I can't locate a way to kill this - - // should I pass a dtor to PR_NewThreadPrivateIndex?? - // TlsFree(tlsIndex); -#endif // PYXPCOM_USE_PYGILSTATE } // Yet another attempt at cross-platform library initialization and finalization. @@ -271,10 +279,6 @@ PyXPCOM_Globals_Ensure() { PRBool rc = PR_TRUE; -#ifndef PYXPCOM_USE_PYGILSTATE - PyXPCOM_InterpreterState_Ensure(); -#endif - // The exception object - we load it from .py code! if (PyXPCOM_Error == NULL) { rc = PR_FALSE; diff --git a/mozilla/extensions/python/xpcom/src/loader/pyloader.cpp b/mozilla/extensions/python/xpcom/src/loader/pyloader.cpp index 126f7d40ef8..5f9ce3e5265 100644 --- a/mozilla/extensions/python/xpcom/src/loader/pyloader.cpp +++ b/mozilla/extensions/python/xpcom/src/loader/pyloader.cpp @@ -44,79 +44,14 @@ // pyxpcom core library and transfers control to that. #include - -#include "nsDirectoryServiceDefs.h" -#include "nsILocalFile.h" - -#include "nspr.h" // PR_fprintf - -#if (PY_VERSION_HEX >= 0x02030000) -#define PYXPCOM_USE_PYGILSTATE -#endif - -static char *PyTraceback_AsString(PyObject *exc_tb); - -#ifdef XP_WIN -#include "windows.h" -#endif - -#ifdef XP_UNIX -#include -#include - -#endif - #include "nsITimelineService.h" +#include "nsILocalFile.h" typedef nsresult (*pfnPyXPCOM_NSGetModule)(nsIComponentManager *servMgr, nsIFile* location, nsIModule** result); -static void LogError(const char *fmt, ...); -static void LogDebug(const char *fmt, ...); - -// Ensure that any paths guaranteed by this package exist on sys.path -// Only called once as we are first loaded into the process. -void AddStandardPaths() -{ - // Put {bin}\Python on the path if it exists. - nsresult rv; - nsCOMPtr aFile; - rv = NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR, getter_AddRefs(aFile)); - if (NS_FAILED(rv)) { - LogError("The Python XPCOM loader could not locate the 'bin' directory\n"); - return; - } - aFile->Append(NS_LITERAL_STRING("python")); - nsAutoString pathBuf; - aFile->GetPath(pathBuf); - PyObject *obPath = PySys_GetObject("path"); - if (!obPath) { - LogError("The Python XPCOM loader could not get the Python sys.path variable\n"); - return; - } - NS_LossyConvertUTF16toASCII pathCBuf(pathBuf); - LogDebug("The Python XPCOM loader is adding '%s' to sys.path\n", pathCBuf.get()); - PyObject *newStr = PyString_FromString(pathCBuf.get()); - PyList_Insert(obPath, 0, newStr); - Py_XDECREF(newStr); - // And now try and get Python to process this directory as a "site dir" - // - ie, look for .pth files, etc - nsCAutoString cmdBuf(NS_LITERAL_CSTRING("import site;site.addsitedir(r'") + pathCBuf + NS_LITERAL_CSTRING("')\n")); - if (0 != PyRun_SimpleString((char *)cmdBuf.get())) { - LogError("The directory '%s' could not be added as a site directory", pathCBuf.get()); - PyErr_Clear(); - } - // and somewhat like Python itself (site, citecustomize), we attempt - // to import "sitepyxpcom" ignoring ImportError - if (NULL==PyImport_ImportModule("sitepyxpcom")) { - if (!PyErr_ExceptionMatches(PyExc_ImportError)) - LogError("Failed to import 'sitepyxpcom'"); - PyErr_Clear(); - } -} - //////////////////////////////////////////////////////////// // This is the main entry point that delegates into Python nsresult PyXPCOM_NSGetModule(nsIComponentManager *servMgr, @@ -126,20 +61,6 @@ nsresult PyXPCOM_NSGetModule(nsIComponentManager *servMgr, NS_PRECONDITION(result!=NULL, "null result pointer in PyXPCOM_NSGetModule!"); NS_PRECONDITION(location!=NULL, "null nsIFile pointer in PyXPCOM_NSGetModule!"); NS_PRECONDITION(servMgr!=NULL, "null servMgr pointer in PyXPCOM_NSGetModule!"); -#ifndef LOADER_LINKS_WITH_PYTHON - if (!Py_IsInitialized()) { - Py_Initialize(); - if (!Py_IsInitialized()) { - PyXPCOM_LogError("Python initialization failed!\n"); - return NS_ERROR_FAILURE; - } - PyEval_InitThreads(); -#ifndef PYXPCOM_USE_PYGILSTATE - PyXPCOM_InterpreterState_Ensure(); -#endif - PyEval_SaveThread(); - } -#endif // LOADER_LINKS_WITH_PYTHON CEnterLeavePython _celp; PyObject *func = NULL; PyObject *obServMgr = NULL; @@ -178,268 +99,10 @@ extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr, nsIFile* location, nsIModule** result) { -#if defined(XP_UNIX) && !defined(XP_MACOSX) - /* *sob* - seems necessary to open the .so as RTLD_GLOBAL. Without - this we see: - Traceback (most recent call last): - File "", line 1, in ? - File "/usr/lib/python2.4/logging/__init__.py", line 29, in ? - import sys, os, types, time, string, cStringIO, traceback - ImportError: /usr/lib/python2.4/lib-dynload/time.so: undefined - symbol: PyExc_IOError - - On osx, ShaneC writes that is it unnecessary (and fails anyway since - PYTHON_SO is wrong.) More clues about this welcome! - */ - - dlopen(PYTHON_SO,RTLD_NOW | RTLD_GLOBAL); -#endif - PRBool bDidInitPython = !Py_IsInitialized(); // well, I will next line, anyway :-) - if (bDidInitPython) { - NS_TIMELINE_START_TIMER("PyXPCOM: Python initializing"); - Py_Initialize(); - if (!Py_IsInitialized()) { - LogError("Python initialization failed!\n"); - return NS_ERROR_FAILURE; - } -#ifndef NS_DEBUG - Py_OptimizeFlag = 1; -#endif // NS_DEBUG - PyEval_InitThreads(); - NS_TIMELINE_STOP_TIMER("PyXPCOM: Python initializing"); - NS_TIMELINE_MARK_TIMER("PyXPCOM: Python initializing"); - } - // Get the Python interpreter state - NS_TIMELINE_START_TIMER("PyXPCOM: Python threadstate setup"); -#ifndef PYXPCOM_USE_PYGILSTATE - PyThreadState *threadStateCreated = NULL; - PyThreadState *threadState = PyThreadState_Swap(NULL); - if (threadState==NULL) { - // no thread-state - set one up. - // *sigh* - what I consider a bug is that Python - // will deadlock unless we own the lock before creating - // a new interpreter (it appear Py_NewInterpreter has - // really only been tested/used with no thread lock - PyEval_AcquireLock(); - threadState = threadStateCreated = Py_NewInterpreter(); - PyThreadState_Swap(NULL); - } - PyEval_ReleaseLock(); - PyEval_AcquireThread(threadState); -#else - PyGILState_STATE state = PyGILState_Ensure(); -#endif // PYXPCOM_USE_PYGILSTATE -#ifdef MOZ_TIMELINE - // If the timeline service is installed, see if we can install our hooks. - if (NULL==PyImport_ImportModule("timeline_hook")) { - if (!PyErr_ExceptionMatches(PyExc_ImportError)) - LogError("Failed to import 'timeline_hook'"); - PyErr_Clear(); // but don't care if we can't. - } -#endif - // Add the standard paths always - we may not have been the first to - // init Python. - AddStandardPaths(); - -#ifndef PYXPCOM_USE_PYGILSTATE - // Abandon the thread-lock, as the first thing Python does - // is re-establish the lock (the Python thread-state story SUCKS!!!) - if (threadStateCreated) { - Py_EndInterpreter(threadStateCreated); - PyEval_ReleaseLock(); // see Py_NewInterpreter call above - } else { - PyEval_ReleaseThread(threadState); - PyThreadState *threadStateSave = PyThreadState_Swap(NULL); - if (threadStateSave) - PyThreadState_Delete(threadStateSave); - } -#else - // If we initialized Python, then we will also have acquired the thread - // lock. In that case, we want to leave it unlocked, so other threads - // are free to run, even if they aren't running Python code. - PyGILState_Release(bDidInitPython ? PyGILState_UNLOCKED : state); -#endif - - NS_TIMELINE_STOP_TIMER("PyXPCOM: Python threadstate setup"); - NS_TIMELINE_MARK_TIMER("PyXPCOM: Python threadstate setup"); + PyXPCOM_EnsurePythonEnvironment(); NS_TIMELINE_START_TIMER("PyXPCOM: PyXPCOM NSGetModule entry point"); nsresult rc = PyXPCOM_NSGetModule(servMgr, location, result); NS_TIMELINE_STOP_TIMER("PyXPCOM: PyXPCOM NSGetModule entry point"); NS_TIMELINE_MARK_TIMER("PyXPCOM: PyXPCOM NSGetModule entry point"); return rc; } - -// The internal helper that actually moves the -// formatted string to the target! - -void LogMessage(const char *prefix, const char *pszMessageText) -{ - PR_fprintf(PR_STDERR, "%s", pszMessageText); -} - -void LogMessage(const char *prefix, nsACString &text) -{ - LogMessage(prefix, nsPromiseFlatCString(text).get()); -} - -// A helper for the various logging routines. -static void VLogF(const char *prefix, const char *fmt, va_list argptr) -{ - char buff[512]; - - vsprintf(buff, fmt, argptr); - - LogMessage(prefix, buff); -} - -static void LogError(const char *fmt, ...) -{ - va_list marker; - va_start(marker, fmt); - VLogF("PyXPCOM Loader Error: ", fmt, marker); - // If we have a Python exception, also log that: - PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL; - PyErr_Fetch( &exc_typ, &exc_val, &exc_tb); - if (exc_typ) { - nsCAutoString streamout; - - if (exc_tb) { - const char *szTraceback = PyTraceback_AsString(exc_tb); - if (szTraceback == NULL) - streamout += "Can't get the traceback info!"; - else { - streamout += "Traceback (most recent call last):\n"; - streamout += szTraceback; - PyMem_Free((void *)szTraceback); - } - } - PyObject *temp = PyObject_Str(exc_typ); - if (temp) { - streamout += PyString_AsString(temp); - Py_DECREF(temp); - } else - streamout += "Can convert exception to a string!"; - streamout += ": "; - if (exc_val != NULL) { - temp = PyObject_Str(exc_val); - if (temp) { - streamout += PyString_AsString(temp); - Py_DECREF(temp); - } else - streamout += "Can convert exception value to a string!"; - } - streamout += "\n"; - LogMessage("PyXPCOM Exception:", streamout); - } - PyErr_Restore(exc_typ, exc_val, exc_tb); -} -/*** - not currently used - silence compiler warning. -static void LogWarning(const char *fmt, ...) -{ - va_list marker; - va_start(marker, fmt); - VLogF("PyXPCOM Loader Warning: ", fmt, marker); -} -***/ -#ifdef DEBUG -static void LogDebug(const char *fmt, ...) -{ - va_list marker; - va_start(marker, fmt); - VLogF("PyXPCOM Loader Debug: ", fmt, marker); -} -#else -static void LogDebug(const char *fmt, ...) -{ -} -#endif - -/* Obtains a string from a Python traceback. - This is the exact same string as "traceback.print_exc" would return. - - Pass in a Python traceback object (probably obtained from PyErr_Fetch()) - Result is a string which must be free'd using PyMem_Free() -*/ -#define TRACEBACK_FETCH_ERROR(what) {errMsg = what; goto done;} - -char *PyTraceback_AsString(PyObject *exc_tb) -{ - char *errMsg = NULL; /* a static that hold a local error message */ - char *result = NULL; /* a valid, allocated result. */ - PyObject *modStringIO = NULL; - PyObject *modTB = NULL; - PyObject *obFuncStringIO = NULL; - PyObject *obStringIO = NULL; - PyObject *obFuncTB = NULL; - PyObject *argsTB = NULL; - PyObject *obResult = NULL; - - /* Import the modules we need - cStringIO and traceback */ - modStringIO = PyImport_ImportModule("cStringIO"); - if (modStringIO==NULL) - TRACEBACK_FETCH_ERROR("cant import cStringIO\n"); - - modTB = PyImport_ImportModule("traceback"); - if (modTB==NULL) - TRACEBACK_FETCH_ERROR("cant import traceback\n"); - /* Construct a cStringIO object */ - obFuncStringIO = PyObject_GetAttrString(modStringIO, "StringIO"); - if (obFuncStringIO==NULL) - TRACEBACK_FETCH_ERROR("cant find cStringIO.StringIO\n"); - obStringIO = PyObject_CallObject(obFuncStringIO, NULL); - if (obStringIO==NULL) - TRACEBACK_FETCH_ERROR("cStringIO.StringIO() failed\n"); - /* Get the traceback.print_exception function, and call it. */ - obFuncTB = PyObject_GetAttrString(modTB, "print_tb"); - if (obFuncTB==NULL) - TRACEBACK_FETCH_ERROR("cant find traceback.print_tb\n"); - - argsTB = Py_BuildValue("OOO", - exc_tb ? exc_tb : Py_None, - Py_None, - obStringIO); - if (argsTB==NULL) - TRACEBACK_FETCH_ERROR("cant make print_tb arguments\n"); - - obResult = PyObject_CallObject(obFuncTB, argsTB); - if (obResult==NULL) - TRACEBACK_FETCH_ERROR("traceback.print_tb() failed\n"); - /* Now call the getvalue() method in the StringIO instance */ - Py_DECREF(obFuncStringIO); - obFuncStringIO = PyObject_GetAttrString(obStringIO, "getvalue"); - if (obFuncStringIO==NULL) - TRACEBACK_FETCH_ERROR("cant find getvalue function\n"); - Py_DECREF(obResult); - obResult = PyObject_CallObject(obFuncStringIO, NULL); - if (obResult==NULL) - TRACEBACK_FETCH_ERROR("getvalue() failed.\n"); - - /* And it should be a string all ready to go - duplicate it. */ - if (!PyString_Check(obResult)) - TRACEBACK_FETCH_ERROR("getvalue() did not return a string\n"); - - { // a temp scope so I can use temp locals. - char *tempResult = PyString_AsString(obResult); - result = (char *)PyMem_Malloc(strlen(tempResult)+1); - if (result==NULL) - TRACEBACK_FETCH_ERROR("memory error duplicating the traceback string"); - - strcpy(result, tempResult); - } // end of temp scope. -done: - /* All finished - first see if we encountered an error */ - if (result==NULL && errMsg != NULL) { - result = (char *)PyMem_Malloc(strlen(errMsg)+1); - if (result != NULL) - /* if it does, not much we can do! */ - strcpy(result, errMsg); - } - Py_XDECREF(modStringIO); - Py_XDECREF(modTB); - Py_XDECREF(obFuncStringIO); - Py_XDECREF(obStringIO); - Py_XDECREF(obFuncTB); - Py_XDECREF(argsTB); - Py_XDECREF(obResult); - return result; -}