Back to index

lightning-sunbird  0.9+nobinonly
Defines | Typedefs | Functions | Variables
pyloader.cpp File Reference
#include <Python.h>
#include "nsIComponentLoader.h"
#include "nsISupports.h"
#include "nsIModule.h"
#include "nsDirectoryServiceDefs.h"
#include "nsILocalFile.h"
#include "nsString.h"
#include "nsXPIDLString.h"
#include "stdlib.h"
#include "stdarg.h"
#include "nsReadableUtils.h"
#include "nsCRT.h"
#include "nspr.h"
#include "nsITimelineService.h"

Go to the source code of this file.


#define TRACEBACK_FETCH_ERROR(what)   {errMsg = what; goto done;}


typedef nsresult(* pfnPyXPCOM_NSGetModule )(nsIComponentManager *servMgr, nsIFile *location, nsIModule **result)


static char * PyTraceback_AsString (PyObject *exc_tb)
static void LogError (const char *fmt,...)
static void LogDebug (const char *fmt,...)
void AddStandardPaths ()
NS_EXPORT nsresult NSGetModule (nsIComponentManager *servMgr, nsIFile *location, nsIModule **result)
void LogMessage (const char *prefix, const char *pszMessageText)
void LogMessage (const char *prefix, nsACString &text)
static void VLogF (const char *prefix, const char *fmt, va_list argptr)


pfnPyXPCOM_NSGetModule pfnEntryPoint = nsnull

Define Documentation

#define TRACEBACK_FETCH_ERROR (   what)    {errMsg = what; goto done;}

Definition at line 327 of file pyloader.cpp.

Typedef Documentation

Definition at line 85 of file pyloader.cpp.

Function Documentation

Definition at line 98 of file pyloader.cpp.

       // 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");
       nsAutoString pathBuf;
       PyObject *obPath = PySys_GetObject("path");
       if (!obPath) {
              LogError("The Python XPCOM loader could not get the Python sys.path variable\n");
       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);
       // 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());
       // 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'");

Here is the call graph for this function:

Here is the caller graph for this function:

static void LogDebug ( const char *  fmt,
) [static]

Definition at line 316 of file pyloader.cpp.


Here is the caller graph for this function:

static void LogError ( const char *  fmt,
) [static]

Definition at line 259 of file pyloader.cpp.

       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);
              } else
                     streamout += "Can convert exception to a string!";
              streamout += ": ";
              if (exc_val != NULL) {
                     temp = PyObject_Str(exc_val);
                     if (temp) {
                            streamout += PyString_AsString(temp);
                     } else
                            streamout += "Can convert exception value to a string!";
              streamout += "\n";
              LogMessage("PyXPCOM Exception:", streamout);
       PyErr_Restore(exc_typ, exc_val, exc_tb);

Here is the call graph for this function:

Here is the caller graph for this function:

void LogMessage ( const char *  prefix,
const char *  pszMessageText 

Definition at line 239 of file pyloader.cpp.

       PR_fprintf(PR_STDERR, "%s", pszMessageText);
void LogMessage ( const char *  prefix,
nsACString &  text 

Definition at line 244 of file pyloader.cpp.

Here is the call graph for this function:

NS_EXPORT nsresult NSGetModule ( nsIComponentManager servMgr,
nsIFile location,
nsIModule **  result 

Definition at line 137 of file pyloader.cpp.

#ifdef XP_UNIX
       // *sob* - seems necessary to open the .so as RTLD_GLOBAL
       PRBool bDidInitPython = !Py_IsInitialized(); // well, I will next line, anyway :-)
       if (bDidInitPython) {
              NS_TIMELINE_START_TIMER("PyXPCOM: Python initializing");
              if (!Py_IsInitialized()) {
                     LogError("Python initialization failed!\n");
                     return NS_ERROR_FAILURE;
#ifndef NS_DEBUG
              Py_OptimizeFlag = 1;
#endif // NS_DEBUG
              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");
       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
              threadState = threadStateCreated = Py_NewInterpreter();
       PyGILState_STATE state = PyGILState_Ensure();
       if (pfnEntryPoint == nsnull) {
              PyObject *mod = PyImport_ImportModule("xpcom._xpcom");
              if (mod==NULL) {
                     LogError("Could not import the Python XPCOM extension\n");
                     return NS_ERROR_FAILURE;
              PyObject *obpfn = PyObject_GetAttrString(mod, "_NSGetModule_FuncPtr");
              void *pfn = NULL;
              if (obpfn) {
                     NS_ABORT_IF_FALSE(PyLong_Check(obpfn)||PyInt_Check(obpfn), "xpcom._NSGetModule_FuncPtr is not a long!");
                     pfn = PyLong_AsVoidPtr(obpfn);
              pfnEntryPoint = (pfnPyXPCOM_NSGetModule)pfn;
       if (pfnEntryPoint==NULL) {
              LogError("Could not load main Python entry point\n");
              return NS_ERROR_FAILURE;

       // 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.
       // Abandon the thread-lock, as the first thing Python does
       // is re-establish the lock (the Python thread-state story SUCKS!!!)
       if (threadStateCreated) {
              PyEval_ReleaseLock(); // see Py_NewInterpreter call above 
       } else {
              PyThreadState *threadStateSave = PyThreadState_Swap(NULL);
              if (threadStateSave)
       // 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");
       NS_TIMELINE_START_TIMER("PyXPCOM: PyXPCOM NSGetModule entry point");
       nsresult rc = (*pfnEntryPoint)(servMgr, location, result);
       NS_TIMELINE_STOP_TIMER("PyXPCOM: PyXPCOM NSGetModule entry point");
       NS_TIMELINE_MARK_TIMER("PyXPCOM: PyXPCOM NSGetModule entry point");
       return rc;

Here is the call graph for this function:

Here is the caller graph for this function:

char * PyTraceback_AsString ( PyObject *  exc_tb) [static]

Definition at line 329 of file pyloader.cpp.

       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,
       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 */
       obFuncStringIO = PyObject_GetAttrString(obStringIO, "getvalue");
       if (obFuncStringIO==NULL)
              TRACEBACK_FETCH_ERROR("cant find getvalue function\n");
       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.
       /* 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);
       return result;

Here is the call graph for this function:

Here is the caller graph for this function:

static void VLogF ( const char *  prefix,
const char *  fmt,
va_list  argptr 
) [static]

Definition at line 250 of file pyloader.cpp.

       char buff[512];

       vsprintf(buff, fmt, argptr);

       LogMessage(prefix, buff);

Here is the call graph for this function:

Here is the caller graph for this function:

Variable Documentation

Definition at line 90 of file pyloader.cpp.