r=benjamin@smedbergs.us, sr=jst git-svn-id: svn://10.0.0.236/trunk@213164 18797224-902f-48f8-a5cc-f745e15eee43
284 lines
9.7 KiB
C++
284 lines
9.7 KiB
C++
/* ***** 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 ***** */
|
|
|
|
//
|
|
// This code is part of the XPCOM extensions for Python.
|
|
//
|
|
// Written May 2000 by Mark Hammond.
|
|
//
|
|
// Based heavily on the Python COM support, which is
|
|
// (c) Mark Hammond and Greg Stein.
|
|
//
|
|
// (c) 2000, ActiveState corp.
|
|
|
|
#include "PyXPCOM_std.h"
|
|
#include "nsDirectoryServiceDefs.h"
|
|
#include "nsDirectoryServiceUtils.h"
|
|
#include "nsILocalFile.h"
|
|
#include "nsITimelineService.h"
|
|
|
|
#include "nspr.h" // PR_fprintf
|
|
|
|
#ifdef XP_WIN
|
|
#ifndef WIN32_LEAN_AND_MEAN
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#endif
|
|
#include "windows.h"
|
|
#endif
|
|
|
|
#ifdef XP_UNIX
|
|
#include <dlfcn.h>
|
|
#include <sys/stat.h>
|
|
#endif
|
|
|
|
static PRLock *g_lockMain = nsnull;
|
|
|
|
PYXPCOM_EXPORT PyObject *PyXPCOM_Error = NULL;
|
|
PYXPCOM_EXPORT PRBool PyXPCOM_ModuleInitialized = PR_FALSE;
|
|
|
|
PyXPCOM_INTERFACE_DEFINE(Py_nsIComponentManager, nsIComponentManager, PyMethods_IComponentManager)
|
|
PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfoManager, nsIInterfaceInfoManager, PyMethods_IInterfaceInfoManager)
|
|
PyXPCOM_INTERFACE_DEFINE(Py_nsIEnumerator, nsIEnumerator, PyMethods_IEnumerator)
|
|
PyXPCOM_INTERFACE_DEFINE(Py_nsISimpleEnumerator, nsISimpleEnumerator, PyMethods_ISimpleEnumerator)
|
|
PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfo, nsIInterfaceInfo, PyMethods_IInterfaceInfo)
|
|
PyXPCOM_INTERFACE_DEFINE(Py_nsIInputStream, nsIInputStream, PyMethods_IInputStream)
|
|
PyXPCOM_INTERFACE_DEFINE(Py_nsIClassInfo, nsIClassInfo, PyMethods_IClassInfo)
|
|
PyXPCOM_INTERFACE_DEFINE(Py_nsIVariant, nsIVariant, PyMethods_IVariant)
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Lock/exclusion global functions.
|
|
//
|
|
PYXPCOM_EXPORT void
|
|
PyXPCOM_AcquireGlobalLock(void)
|
|
{
|
|
NS_PRECONDITION(g_lockMain != nsnull, "Cant acquire a NULL lock!");
|
|
PR_Lock(g_lockMain);
|
|
}
|
|
|
|
PYXPCOM_EXPORT void
|
|
PyXPCOM_ReleaseGlobalLock(void)
|
|
{
|
|
NS_PRECONDITION(g_lockMain != nsnull, "Cant release a NULL lock!");
|
|
PR_Unlock(g_lockMain);
|
|
}
|
|
|
|
// 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;
|
|
// XXX - this needs more thought for XULRunner - we want to stick the global
|
|
// 'python' dir on sys.path (for xpcom etc), but also want to support a way
|
|
// of adding a local application directory (in the case of xulrunner) too.
|
|
// NS_XPCOM_CURRENT_PROCESS_DIR is the XULRunner app dir (ie, where application.ini lives)
|
|
// NS_GRE_DIR is the 'bin' dir for XULRunner itself.
|
|
rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(aFile));
|
|
if (NS_FAILED(rv)) {
|
|
PyXPCOM_LogError("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) {
|
|
PyXPCOM_LogError("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);
|
|
#ifdef NS_DEBUG
|
|
PR_fprintf(PR_STDERR,"The Python XPCOM loader is adding '%s' to sys.path\n",
|
|
pathCBuf.get());
|
|
#endif
|
|
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'"));
|
|
cmdBuf.Append(pathCBuf);
|
|
cmdBuf.Append(NS_LITERAL_CSTRING("')\n"));
|
|
if (0 != PyRun_SimpleString((char *)cmdBuf.get())) {
|
|
PyXPCOM_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
|
|
PyObject *mod = PyImport_ImportModule("sitepyxpcom");
|
|
if (NULL==mod) {
|
|
if (!PyErr_ExceptionMatches(PyExc_ImportError))
|
|
PyXPCOM_LogError("Failed to import 'sitepyxpcom'");
|
|
PyErr_Clear();
|
|
} else
|
|
Py_DECREF(mod);
|
|
}
|
|
|
|
static PRBool bIsInitialized = PR_FALSE;
|
|
// Our 'entry point' into initialization - just call this any time you
|
|
// like, and the world will be setup!
|
|
PYXPCOM_EXPORT void
|
|
PyXPCOM_EnsurePythonEnvironment(void)
|
|
{
|
|
// Must be thread-safe - but only while set to FALSE - so check for
|
|
// set before getting the lock - then check again after!
|
|
if (bIsInitialized)
|
|
return;
|
|
CEnterLeaveXPCOMFramework _celf;
|
|
if (bIsInitialized)
|
|
return; // another thread beat us to the init.
|
|
|
|
#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 "<string>", 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();
|
|
|
|
// The exception object pyxpcom uses.
|
|
if (PyXPCOM_Error == NULL) {
|
|
PRBool rc = PR_FALSE;
|
|
PyObject *mod = NULL;
|
|
|
|
mod = PyImport_ImportModule("xpcom");
|
|
if (mod!=NULL) {
|
|
PyXPCOM_Error = PyObject_GetAttrString(mod, "Exception");
|
|
Py_DECREF(mod);
|
|
}
|
|
rc = (PyXPCOM_Error != NULL);
|
|
}
|
|
|
|
// Register our custom interfaces.
|
|
Py_nsISupports::InitType();
|
|
Py_nsIComponentManager::InitType();
|
|
Py_nsIInterfaceInfoManager::InitType();
|
|
Py_nsIEnumerator::InitType();
|
|
Py_nsISimpleEnumerator::InitType();
|
|
Py_nsIInterfaceInfo::InitType();
|
|
Py_nsIInputStream::InitType();
|
|
Py_nsIClassInfo::InitType();
|
|
Py_nsIVariant::InitType();
|
|
|
|
bIsInitialized = PR_TRUE;
|
|
// import the xpcom module itself to setup the loggers etc.
|
|
// We must do this after setting bIsInitialized, as it too tries to
|
|
// initialize!
|
|
PyImport_ImportModule("xpcom");
|
|
|
|
// 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");
|
|
}
|
|
|
|
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();
|
|
return; // PR_TRUE;
|
|
}
|
|
|
|
void pyxpcom_destruct(void)
|
|
{
|
|
PR_DestroyLock(g_lockMain);
|
|
}
|
|
|
|
// Yet another attempt at cross-platform library initialization and finalization.
|
|
struct DllInitializer {
|
|
DllInitializer() {
|
|
pyxpcom_construct();
|
|
}
|
|
~DllInitializer() {
|
|
pyxpcom_destruct();
|
|
}
|
|
} dll_initializer;
|