summaryrefslogtreecommitdiffstats
path: root/src/libs/xpcom18a4/python/src/loader/pyloader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/xpcom18a4/python/src/loader/pyloader.cpp')
-rw-r--r--src/libs/xpcom18a4/python/src/loader/pyloader.cpp435
1 files changed, 435 insertions, 0 deletions
diff --git a/src/libs/xpcom18a4/python/src/loader/pyloader.cpp b/src/libs/xpcom18a4/python/src/loader/pyloader.cpp
new file mode 100644
index 00000000..dc116f1d
--- /dev/null
+++ b/src/libs/xpcom18a4/python/src/loader/pyloader.cpp
@@ -0,0 +1,435 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Python XPCOM language bindings.
+ *
+ * The Initial Developer of the Original Code is
+ * ActiveState Tool Corp.
+ * Portions created by the Initial Developer are Copyright (C) 2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mark Hammond <mhammond@skippinet.com.au> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// pyloader
+//
+// Not part of the main Python _xpcom package, but a separate, thin DLL.
+//
+// The main loader and registrar for Python. A thin DLL that is designed to live in
+// the xpcom "components" directory. Simply locates and loads the standard
+// pyxpcom core library and transfers control to that.
+
+#include <PyXPCOM.h>
+
+#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 <dlfcn.h>
+#include <sys/stat.h>
+
+#endif
+
+#include "nsITimelineService.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<nsIFile> 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_LossyConvertUCS2toASCII 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,
+ nsIFile* location,
+ nsIModule** result)
+{
+ 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;
+ PyObject *obLocation = NULL;
+ PyObject *wrap_ret = NULL;
+ PyObject *args = NULL;
+ PyObject *mod = PyImport_ImportModule("xpcom.server");
+ if (!mod) goto done;
+ func = PyObject_GetAttrString(mod, "NS_GetModule");
+ if (func==NULL) goto done;
+ obServMgr = Py_nsISupports::PyObjectFromInterface(servMgr, NS_GET_IID(nsIComponentManager));
+ if (obServMgr==NULL) goto done;
+ obLocation = Py_nsISupports::PyObjectFromInterface(location, NS_GET_IID(nsIFile));
+ if (obLocation==NULL) goto done;
+ args = Py_BuildValue("OO", obServMgr, obLocation);
+ if (args==NULL) goto done;
+ wrap_ret = PyEval_CallObject(func, args);
+ if (wrap_ret==NULL) goto done;
+ Py_nsISupports::InterfaceFromPyObject(wrap_ret, NS_GET_IID(nsIModule), (nsISupports **)result, PR_FALSE, PR_FALSE);
+done:
+ nsresult nr = NS_OK;
+ if (PyErr_Occurred()) {
+ PyXPCOM_LogError("Obtaining the module object from Python failed.\n");
+ nr = PyXPCOM_SetCOMErrorFromPyException();
+ }
+ Py_XDECREF(func);
+ Py_XDECREF(obServMgr);
+ Py_XDECREF(obLocation);
+ Py_XDECREF(wrap_ret);
+ Py_XDECREF(mod);
+ Py_XDECREF(args);
+ return nr;
+}
+
+extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr,
+ nsIFile* location,
+ nsIModule** result)
+{
+#ifdef XP_UNIX
+ // *sob* - seems necessary to open the .so as RTLD_GLOBAL
+ 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");
+ 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);
+ va_end(marker);
+}
+/*** - 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);
+ va_end(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;
+}