Back to index

lightning-sunbird  0.9+nobinonly
dllmain.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Python XPCOM language bindings.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * ActiveState Tool Corp.
00018  * Portions created by the Initial Developer are Copyright (C) 2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Mark Hammond <mhammond@skippinet.com.au> (original author)
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 //
00039 // This code is part of the XPCOM extensions for Python.
00040 //
00041 // Written May 2000 by Mark Hammond.
00042 //
00043 // Based heavily on the Python COM support, which is
00044 // (c) Mark Hammond and Greg Stein.
00045 //
00046 // (c) 2000, ActiveState corp.
00047 
00048 #include "PyXPCOM_std.h"
00049 #include <prthread.h>
00050 
00051 #ifdef XP_WIN
00052 #ifndef WIN32_LEAN_AND_MEAN
00053 #define WIN32_LEAN_AND_MEAN
00054 #endif
00055 #include "windows.h"
00056 #endif
00057 
00058 static PRInt32 g_cLockCount = 0;
00059 static PRLock *g_lockMain = nsnull;
00060 
00061 #ifndef PYXPCOM_USE_PYGILSTATE
00062 
00064 // Thread-state helpers/global functions.
00065 // Only used if there is no Python PyGILState_* API
00066 //
00067 static PyThreadState *ptsGlobal = nsnull;
00068 PyInterpreterState *PyXPCOM_InterpreterState = nsnull;
00069 PRUintn tlsIndex = 0;
00070 
00071 
00072 // This function must be called at some time when the interpreter lock and state is valid.
00073 // Called by init{module} functions and also COM factory entry point.
00074 void PyXPCOM_InterpreterState_Ensure()
00075 {
00076        if (PyXPCOM_InterpreterState==NULL) {
00077               PyThreadState *threadStateSave = PyThreadState_Swap(NULL);
00078               if (threadStateSave==NULL)
00079                      Py_FatalError("Can not setup interpreter state, as current state is invalid");
00080 
00081               PyXPCOM_InterpreterState = threadStateSave->interp;
00082               PyThreadState_Swap(threadStateSave);
00083        }
00084 }
00085 
00086 void PyXPCOM_InterpreterState_Free()
00087 {
00088        PyXPCOM_ThreadState_Free();
00089        PyXPCOM_InterpreterState = NULL; // Eek - should I be freeing something?
00090 }
00091 
00092 // This structure is stored in the TLS slot.  At this stage only a Python thread state
00093 // is kept, but this may change in the future...
00094 struct ThreadData{
00095        PyThreadState *ts;
00096 };
00097 
00098 // Ensure that we have a Python thread state available to use.
00099 // If this is called for the first time on a thread, it will allocate
00100 // the thread state.  This does NOT change the state of the Python lock.
00101 // Returns TRUE if a new thread state was created, or FALSE if a
00102 // thread state already existed.
00103 PRBool PyXPCOM_ThreadState_Ensure()
00104 {
00105        ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex);
00106        if (pData==NULL) { /* First request on this thread */
00107               /* Check we have an interpreter state */
00108               if (PyXPCOM_InterpreterState==NULL) {
00109                             Py_FatalError("Can not setup thread state, as have no interpreter state");
00110               }
00111               pData = (ThreadData *)nsMemory::Alloc(sizeof(ThreadData));
00112               if (!pData)
00113                      Py_FatalError("Out of memory allocating thread state.");
00114               memset(pData, 0, sizeof(*pData));
00115               if (NS_FAILED( PR_SetThreadPrivate( tlsIndex, pData ) ) ) {
00116                      NS_ABORT_IF_FALSE(0, "Could not create thread data for this thread!");
00117                      Py_FatalError("Could not thread private thread data!");
00118               }
00119               pData->ts = PyThreadState_New(PyXPCOM_InterpreterState);
00120               return PR_TRUE; // Did create a thread state state
00121        }
00122        return PR_FALSE; // Thread state was previously created
00123 }
00124 
00125 // Asuming we have a valid thread state, acquire the Python lock.
00126 void PyXPCOM_InterpreterLock_Acquire()
00127 {
00128        ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex);
00129        NS_ABORT_IF_FALSE(pData, "Have no thread data for this thread!");
00130        PyThreadState *thisThreadState = pData->ts;
00131        PyEval_AcquireThread(thisThreadState);
00132 }
00133 
00134 // Asuming we have a valid thread state, release the Python lock.
00135 void PyXPCOM_InterpreterLock_Release()
00136 {
00137        ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex);
00138        NS_ABORT_IF_FALSE(pData, "Have no thread data for this thread!");
00139        PyThreadState *thisThreadState = pData->ts;
00140        PyEval_ReleaseThread(thisThreadState);
00141 }
00142 
00143 // Free the thread state for the current thread
00144 // (Presumably previously create with a call to
00145 // PyXPCOM_ThreadState_Ensure)
00146 void PyXPCOM_ThreadState_Free()
00147 {
00148        ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex);
00149        if (!pData) return;
00150        PyThreadState *thisThreadState = pData->ts;
00151        PyThreadState_Delete(thisThreadState);
00152        PR_SetThreadPrivate(tlsIndex, NULL);
00153        nsMemory::Free(pData);
00154 }
00155 
00156 void PyXPCOM_ThreadState_Clear()
00157 {
00158        ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex);
00159        PyThreadState *thisThreadState = pData->ts;
00160        PyThreadState_Clear(thisThreadState);
00161 }
00162 #endif // PYXPCOM_USE_PYGILSTATE
00163 
00165 // Lock/exclusion global functions.
00166 //
00167 void PyXPCOM_AcquireGlobalLock(void)
00168 {
00169        NS_PRECONDITION(g_lockMain != nsnull, "Cant acquire a NULL lock!");
00170        PR_Lock(g_lockMain);
00171 }
00172 void PyXPCOM_ReleaseGlobalLock(void)
00173 {
00174        NS_PRECONDITION(g_lockMain != nsnull, "Cant release a NULL lock!");
00175        PR_Unlock(g_lockMain);
00176 }
00177 
00178 void PyXPCOM_DLLAddRef(void)
00179 {
00180        // Must be thread-safe, although cant have the Python lock!
00181        CEnterLeaveXPCOMFramework _celf;
00182        PRInt32 cnt = PR_AtomicIncrement(&g_cLockCount);
00183        if (cnt==1) { // First call 
00184               if (!Py_IsInitialized()) {
00185                      Py_Initialize();
00186                      // Make sure our Windows framework is all setup.
00187                      PyXPCOM_Globals_Ensure();
00188                      // Make sure we have _something_ as sys.argv.
00189                      if (PySys_GetObject("argv")==NULL) {
00190                             PyObject *path = PyList_New(0);
00191                             PyObject *str = PyString_FromString("");
00192                             PyList_Append(path, str);
00193                             PySys_SetObject("argv", path);
00194                             Py_XDECREF(path);
00195                             Py_XDECREF(str);
00196                      }
00197 
00198                      // Must force Python to start using thread locks, as
00199                      // we are free-threaded (maybe, I think, sometimes :-)
00200                      PyEval_InitThreads();
00201 #ifndef PYXPCOM_USE_PYGILSTATE
00202                      // Release Python lock, as first thing we do is re-get it.
00203                      ptsGlobal = PyEval_SaveThread();
00204 #endif
00205                      // NOTE: We never finalize Python!!
00206               }
00207        }
00208 }
00209 void PyXPCOM_DLLRelease(void)
00210 {
00211        PR_AtomicDecrement(&g_cLockCount);
00212 }
00213 
00214 void pyxpcom_construct(void)
00215 {
00216        g_lockMain = PR_NewLock();
00217 #ifndef PYXPCOM_USE_PYGILSTATE
00218        PRStatus status;
00219        status = PR_NewThreadPrivateIndex( &tlsIndex, NULL );
00220        NS_WARN_IF_FALSE(status==0, "Could not allocate TLS storage");
00221        if (NS_FAILED(status)) {
00222               PR_DestroyLock(g_lockMain);
00223               return; // PR_FALSE;
00224        }
00225 #endif // PYXPCOM_USE_PYGILSTATE
00226        return; // PR_TRUE;
00227 }
00228 
00229 void pyxpcom_destruct(void)
00230 {
00231        PR_DestroyLock(g_lockMain);
00232 #ifndef PYXPCOM_USE_PYGILSTATE
00233        // I can't locate a way to kill this - 
00234        // should I pass a dtor to PR_NewThreadPrivateIndex??
00235        // TlsFree(tlsIndex);
00236 #endif // PYXPCOM_USE_PYGILSTATE
00237 }
00238 
00239 // Yet another attempt at cross-platform library initialization and finalization.
00240 struct DllInitializer {
00241        DllInitializer() {
00242               pyxpcom_construct();
00243        }
00244        ~DllInitializer() {
00245               pyxpcom_destruct();
00246        }
00247 } dll_initializer;