Update of /cvsroot/pywin32/pywin32/pyisapi/src
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5536
Modified Files:
PythonEng.cpp PythonEng.h pyISAPI.cpp
Log Message:
Reorganize the C++ code so that we can support 'reloading' the extension
or filter. By raising a special exception, the Python code can force the
framework to reload the main module, and re-instantiate the handlers.
Index: pyISAPI.cpp
===================================================================
RCS file: /cvsroot/pywin32/pywin32/pyisapi/src/pyISAPI.cpp,v
retrieving revision 1.1
retrieving revision 1.2
diff -C2 -d -r1.1 -r1.2
*** pyISAPI.cpp 1 Sep 2004 03:07:12 -0000 1.1
--- pyISAPI.cpp 4 Sep 2004 09:28:50 -0000 1.2
***************
*** 32,37 ****
#include "pyFilterObjects.h"
static CPythonEngine pyEngine;
! static CPythonEngine pyFilterEngine;
bool g_IsFrozen = false;
--- 32,49 ----
#include "pyFilterObjects.h"
+ static const char *name_ext_factory = "__ExtensionFactory__";
+ static const char *name_ext_init = "GetExtensionVersion";
+ static const char *name_ext_do = "HttpExtensionProc";
+ static const char *name_ext_term = "TerminateExtension";
+
+ static const char *name_filter_factory = "__FilterFactory__";
+ static const char *name_filter_init = "GetFilterVersion";
+ static const char *name_filter_do = "HttpFilterProc";
+ static const char *name_filter_term = "TerminateFilter";
+
static CPythonEngine pyEngine;
! static CPythonHandler filterHandler;
! static CPythonHandler extensionHandler;
!
bool g_IsFrozen = false;
***************
*** 52,69 ****
{
pVer->dwExtensionVersion = MAKELONG( HSE_VERSION_MINOR, HSE_VERSION_MAJOR );
!
! // stage 1: ensure Python ready to go
! if (!pyEngine.InitMainInterp()){
! TRACE("Unable to initialse python interpreter");
! return false;
! }
! if (!pyEngine.LoadHandler("__ExtensionFactory__")) {
! // LoadHandler has reported any errors to Python.
TRACE("Unable to load Python handler");
return false;
}
- if (!pyEngine.SetCallback("GetExtensionVersion"))
- return FALSE;
-
PyObject *resultobject = NULL;
bool bRetStatus = true;
--- 64,74 ----
{
pVer->dwExtensionVersion = MAKELONG( HSE_VERSION_MINOR, HSE_VERSION_MAJOR );
! // ensure our handler ready to go
! if (!extensionHandler.Init(&pyEngine, name_ext_factory,
! name_ext_init, name_ext_do, name_ext_term)) {
! // already have reported any errors to Python.
TRACE("Unable to load Python handler");
return false;
}
PyObject *resultobject = NULL;
bool bRetStatus = true;
***************
*** 72,76 ****
// create the Python object
PyVERSION_INFO *pyVO = new PyVERSION_INFO(pVer);
! resultobject = pyEngine.Callback("N", pyVO);
if (! resultobject) {
ExtensionError(NULL, "Extension version function failed!");
--- 77,81 ----
// create the Python object
PyVERSION_INFO *pyVO = new PyVERSION_INFO(pVer);
! resultobject = extensionHandler.Callback(HANDLER_INIT, "N", pyVO);
if (! resultobject) {
ExtensionError(NULL, "Extension version function failed!");
***************
*** 88,93 ****
Py_XDECREF(resultobject);
PyGILState_Release(state);
- if (bRetStatus)
- bRetStatus = pyEngine.SetCallback("HttpExtensionProc");
return bRetStatus;
}
--- 93,96 ----
***************
*** 99,103 ****
CControlBlock * pcb = new CControlBlock(pECB);
PyECB *pyECB = new PyECB(pcb);
! PyObject *resultobject = pyEngine.Callback("N", pyECB);
if (! resultobject) {
ExtensionError(pcb, "HttpExtensionProc function failed!");
--- 102,106 ----
CControlBlock * pcb = new CControlBlock(pECB);
PyECB *pyECB = new PyECB(pcb);
! PyObject *resultobject = extensionHandler.Callback(HANDLER_DO, "N", pyECB);
if (! resultobject) {
ExtensionError(pcb, "HttpExtensionProc function failed!");
***************
*** 119,142 ****
{
// extension is being terminated
! BOOL bRetStatus = pyEngine.SetCallback("TerminateExtension");
! if (bRetStatus) {
! PyGILState_STATE state = PyGILState_Ensure();
! PyObject *resultobject = pyEngine.Callback("i", dwFlags);
! if (! resultobject) {
! FilterError(NULL, "Extension term function failed!");
! bRetStatus = false;
! } else {
! if (resultobject == Py_None)
! bRetStatus = TRUE;
! else if (PyInt_Check(resultobject))
! bRetStatus = PyInt_AsLong(resultobject) ? true : false;
! else {
! FilterError(NULL, "Extension term should return an int, or None");
! bRetStatus = FALSE;
! }
}
- Py_XDECREF(resultobject);
- PyGILState_Release(state);
}
return bRetStatus;
}
--- 122,144 ----
{
// extension is being terminated
! BOOL bRetStatus;
! PyGILState_STATE state = PyGILState_Ensure();
! PyObject *resultobject = extensionHandler.Callback(HANDLER_TERM, "i", dwFlags);
! if (! resultobject) {
! ExtensionError(NULL, "Extension term function failed!");
! bRetStatus = false;
! } else {
! if (resultobject == Py_None)
! bRetStatus = TRUE;
! else if (PyInt_Check(resultobject))
! bRetStatus = PyInt_AsLong(resultobject) ? true : false;
! else {
! ExtensionError(NULL, "Extension term should return an int, or None");
! bRetStatus = FALSE;
}
}
+ Py_XDECREF(resultobject);
+ PyGILState_Release(state);
+ extensionHandler.Term();
return bRetStatus;
}
***************
*** 145,157 ****
{
pVer->dwFilterVersion = HTTP_FILTER_REVISION;
! if (!pyFilterEngine.InitMainInterp() ||
! !pyFilterEngine.LoadHandler("__FilterFactory__"))
! return FALSE;
! if (!pyFilterEngine.SetCallback("GetFilterVersion"))
return FALSE;
PyGILState_STATE state = PyGILState_Ensure();
PyFILTER_VERSION *pyFV = new PyFILTER_VERSION(pVer);
! PyObject *resultobject = pyFilterEngine.Callback("N", pyFV);
BOOL bRetStatus;
if (! resultobject) {
--- 147,159 ----
{
pVer->dwFilterVersion = HTTP_FILTER_REVISION;
! // ensure our handler ready to go
! if (!filterHandler.Init(&pyEngine, name_filter_factory,
! name_filter_init, name_filter_do, name_filter_term))
! // error already imported.
return FALSE;
PyGILState_STATE state = PyGILState_Ensure();
PyFILTER_VERSION *pyFV = new PyFILTER_VERSION(pVer);
! PyObject *resultobject = filterHandler.Callback(HANDLER_INIT, "N", pyFV);
BOOL bRetStatus;
if (! resultobject) {
***************
*** 170,183 ****
Py_XDECREF(resultobject);
PyGILState_Release(state);
- if (bRetStatus)
- // All future callbacks are the filter proc!
- bRetStatus = pyFilterEngine.SetCallback("HttpFilterProc");
-
return bRetStatus;
- /* Specify the types and order of notification */
- // Need to call Python so it can set all this.
- // pVer->dwFlags = (SF_NOTIFY_PREPROC_HEADERS | SF_NOTIFY_NONSECURE_PORT | SF_NOTIFY_URL_MAP | SF_NOTIFY_SEND_RAW_DATA | SF_NOTIFY_ORDER_DEFAULT);
- // strcpy(pVer->lpszFilterDesc, "Python sample filter");
- // return true;
}
--- 172,176 ----
***************
*** 186,190 ****
DWORD action;
PyGILState_STATE state = PyGILState_Ensure();
!
PyObject *resultobject = NULL;
--- 179,183 ----
DWORD action;
PyGILState_STATE state = PyGILState_Ensure();
!
PyObject *resultobject = NULL;
***************
*** 192,196 ****
CFilterContext fc(phfc, NotificationType, pvData);
PyHFC *pyHFC = new PyHFC(&fc);
! resultobject = pyFilterEngine.Callback("O", pyHFC);
if (! resultobject) {
FilterError(&fc, "Filter function failed!");
--- 185,189 ----
CFilterContext fc(phfc, NotificationType, pvData);
PyHFC *pyHFC = new PyHFC(&fc);
! resultobject = filterHandler.Callback(HANDLER_DO, "O", pyHFC);
if (! resultobject) {
FilterError(&fc, "Filter function failed!");
***************
*** 216,224 ****
BOOL WINAPI TerminateFilter(DWORD status)
{
- if (!pyFilterEngine.SetCallback("TerminateFilter"))
- return FALSE;
BOOL bRetStatus;
PyGILState_STATE state = PyGILState_Ensure();
! PyObject *resultobject = pyFilterEngine.Callback("i", status);
if (! resultobject) {
FilterError(NULL, "Filter version function failed!");
--- 209,215 ----
BOOL WINAPI TerminateFilter(DWORD status)
{
BOOL bRetStatus;
PyGILState_STATE state = PyGILState_Ensure();
! PyObject *resultobject = filterHandler.Callback(HANDLER_TERM, "i", status);
if (! resultobject) {
FilterError(NULL, "Filter version function failed!");
***************
*** 237,241 ****
PyGILState_Release(state);
// filter is being terminated
! pyFilterEngine.ShutdownInterp();
return bRetStatus;
}
--- 228,232 ----
PyGILState_Release(state);
// filter is being terminated
! filterHandler.Term();
return bRetStatus;
}
Index: PythonEng.cpp
===================================================================
RCS file: /cvsroot/pywin32/pywin32/pyisapi/src/PythonEng.cpp,v
retrieving revision 1.1
retrieving revision 1.2
diff -C2 -d -r1.1 -r1.2
*** PythonEng.cpp 1 Sep 2004 03:07:12 -0000 1.1
--- PythonEng.cpp 4 Sep 2004 09:28:50 -0000 1.2
***************
*** 43,48 ****
CRITICAL_SECTION CPythonEngine::m_initLock;
bool CPythonEngine::m_haveInit = false;
! CPythonEngine::CPythonEngine() : m_handler(0), m_callback(0)
{
InitializeCriticalSection(&m_initLock);
--- 43,49 ----
CRITICAL_SECTION CPythonEngine::m_initLock;
bool CPythonEngine::m_haveInit = false;
+ PyObject * CPythonEngine::m_reload_exception = NULL;
! CPythonEngine::CPythonEngine()
{
InitializeCriticalSection(&m_initLock);
***************
*** 80,85 ****
PySys_SetObject("isapidllhandle", obh);
Py_XDECREF(obh);
!
PyGILState_Release(old_state);
m_haveInit = true;
}
--- 81,92 ----
PySys_SetObject("isapidllhandle", obh);
Py_XDECREF(obh);
! // Locate the special exception we use to trigger a reload.
! PyObject *isapi_package = PyImport_ImportModule("isapi");
! if (isapi_package)
! m_reload_exception = PyObject_GetAttrString(isapi_package,
! "InternalReloadException");
! Py_XDECREF(isapi_package);
PyGILState_Release(old_state);
+ FindModuleName();
m_haveInit = true;
}
***************
*** 87,99 ****
}
! bool CPythonEngine::LoadHandler(char *factory_name)
{
- PyObject *m;
TCHAR szFilePath[_MAX_PATH];
TCHAR szBase[_MAX_FNAME];
- TCHAR szErrBuf[1024];
TCHAR *module_name;
-
- assert(m_handler==NULL); // should only be called once.
// If a name for the module has been magically setup (eg, via a frozen
--- 94,102 ----
}
! void CPythonEngine::FindModuleName()
{
TCHAR szFilePath[_MAX_PATH];
TCHAR szBase[_MAX_FNAME];
TCHAR *module_name;
// If a name for the module has been magically setup (eg, via a frozen
***************
*** 115,128 ****
}
}
PyGILState_STATE old_state = PyGILState_Ensure();
! if (!(m = PyImport_ImportModule(module_name))) {
_snprintf(szErrBuf, sizeof(szErrBuf)/sizeof(szErrBuf[0]),
! "Failed to import callback module '%s'", module_name);
ExtensionError(NULL, szErrBuf);
}
if (m) {
! if (!((m_handler = PyObject_CallMethod(m, factory_name, NULL)))) {
_snprintf(szErrBuf, sizeof(szErrBuf)/sizeof(szErrBuf[0]),
! "Factory function '%s' failed", factory_name);
ExtensionError(NULL, szErrBuf);
}
--- 118,205 ----
}
}
+ strncpy(m_module_name, module_name, sizeof(m_module_name)/sizeof(m_module_name[0]));
+ }
+
+ bool CPythonEngine::AddToPythonPath(LPCTSTR pPathName)
+ {
+ PyObject *obPathList = PySys_GetObject(_T("path"));
+ if (obPathList==NULL) {
+ return false;
+ }
+
+ PyObject *obNew = PyString_FromString(pPathName);
+ if (obNew==NULL) {
+ return false;
+ }
+
+ bool bFnd=false;
+ for (int i=0; i<PyList_Size(obPathList); i++){
+ PyObject * obItem = PyList_GetItem(obPathList, i);
+ if(PyObject_Compare(obNew, obItem) == 0){
+ bFnd = true;
+ break;
+ }
+ }
+
+ if (!bFnd)
+ PyList_Insert(obPathList, 0, obNew);
+
+ Py_XDECREF(obNew);
+ return true;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ //
+ // The callback manager
+ //
+ CPythonHandler::CPythonHandler() :
+ m_namefactory(0),
+ m_nameinit(0),
+ m_namedo(0),
+ m_nameterm(0),
+ m_callback_init(0),
+ m_callback_do(0),
+ m_callback_term(0),
+ m_handler(0)
+ {
+ return;
+ }
+
+ bool CPythonHandler::Init(
+ CPythonEngine *engine,
+ const char *factory, const char *nameinit, const char *namedo,
+ const char *nameterm)
+ {
+ if (!engine->InitMainInterp())
+ return false;
+ m_nameinit = nameinit;
+ m_namedo = namedo;
+ m_nameterm = nameterm;
+ m_namefactory = factory;
+ m_engine = engine;
+ return LoadHandler(false);
+ }
+
+ bool CPythonHandler::LoadHandler(bool reload)
+ {
+ char szErrBuf[1024];
+ PyObject *m;
PyGILState_STATE old_state = PyGILState_Ensure();
! m = PyImport_ImportModule(m_engine->m_module_name);
! if (m && reload) {
! PyObject *m_orig = m;
! m = PyImport_ReloadModule(m);
! Py_DECREF(m_orig);
! }
! if (!m) {
_snprintf(szErrBuf, sizeof(szErrBuf)/sizeof(szErrBuf[0]),
! "Failed to import callback module '%s'", m_engine->m_module_name);
ExtensionError(NULL, szErrBuf);
}
if (m) {
! Py_XDECREF(m_handler);
! if (!((m_handler = PyObject_CallMethod(m, (char *)m_namefactory, NULL)))) {
_snprintf(szErrBuf, sizeof(szErrBuf)/sizeof(szErrBuf[0]),
! "Factory function '%s' failed", m_namefactory);
ExtensionError(NULL, szErrBuf);
}
***************
*** 133,167 ****
}
! // Set the current 'callback' - all future callbacks will be made to
! // the fetched method.
! bool CPythonEngine::SetCallback(const char *cbname)
{
! assert(m_handler);
! if (!m_handler)
! return NULL;
PyGILState_STATE old_state = PyGILState_Ensure();
!
! Py_XDECREF(m_callback);
! m_callback = PyObject_GetAttrString(m_handler, (char *)cbname);
! if (!m_callback)
ExtensionError(NULL, "Failed to locate the callback");
PyGILState_Release(old_state);
! return m_callback != NULL;
}
// NOTE: Caller must setup and release thread-state - as we return a PyObject,
// the caller must at least Py_DECREF it, so must hold the lock.
! PyObject *CPythonEngine::Callback(
! const char *format /* = NULL */,
! ...
)
{
! assert(m_callback);
! if (!m_callback)
return NULL;
va_list va;
! PyObject *args, *retval;
if (format && *format) {
--- 210,268 ----
}
!
! bool CPythonHandler::CheckCallback(const char *cbname, PyObject **cb)
{
! if (*cb!=NULL)
! return true; // already have the callback.
PyGILState_STATE old_state = PyGILState_Ensure();
! if (!m_handler) {
! PyErr_SetString(PyExc_RuntimeError, "The handler failed to load");
! return false;
! }
! *cb = PyObject_GetAttrString(m_handler, (char *)cbname);
! if (!*cb)
ExtensionError(NULL, "Failed to locate the callback");
PyGILState_Release(old_state);
! return (*cb) != NULL;
}
// NOTE: Caller must setup and release thread-state - as we return a PyObject,
// the caller must at least Py_DECREF it, so must hold the lock.
! PyObject *CPythonHandler::DoCallback(
! HANDLER_TYPE typ,
! PyObject *args
)
{
! PyObject **ppcb;
! const char *cb_name;
! switch(typ) {
! case HANDLER_INIT:
! ppcb = &m_callback_init;
! cb_name = m_nameinit;
! break;
! case HANDLER_TERM:
! ppcb = &m_callback_term;
! cb_name = m_nameterm;
! break;
! default:
! ppcb = &m_callback_do;
! cb_name = m_namedo;
! break;
! }
! if (!CheckCallback(cb_name, ppcb))
return NULL;
+ return PyObject_Call(*ppcb, args, NULL);
+ }
+
+ PyObject *CPythonHandler::Callback(
+ HANDLER_TYPE typ,
+ const char *format /* = NULL */,
+ ...
+ )
+ {
va_list va;
! PyObject *args;
if (format && *format) {
***************
*** 186,227 ****
args = a;
}
! retval = PyObject_Call(m_callback, args, NULL);
Py_DECREF(args);
! return retval;
}
! void CPythonEngine::ShutdownInterp(void)
{
// never shut down - Python leaks badly and has other
// side effects if you repeatedly Init then Term
! }
!
! bool CPythonEngine::AddToPythonPath(LPCTSTR pPathName)
! {
! PyObject *obPathList = PySys_GetObject(_T("path"));
! if (obPathList==NULL) {
! return false;
! }
!
! PyObject *obNew = PyString_FromString(pPathName);
! if (obNew==NULL) {
! return false;
! }
!
! bool bFnd=false;
! for (int i=0; i<PyList_Size(obPathList); i++){
! PyObject * obItem = PyList_GetItem(obPathList, i);
! if(PyObject_Compare(obNew, obItem) == 0){
! bFnd = true;
! break;
! }
! }
!
! if (!bFnd)
! PyList_Insert(obPathList, 0, obNew);
!
! Py_XDECREF(obNew);
! return true;
}
--- 287,339 ----
args = a;
}
!
! PyObject *ret = DoCallback(typ, args);
! if (!ret) {
! if (m_engine->m_reload_exception &&
! PyErr_ExceptionMatches(m_engine->m_reload_exception)) {
! PyErr_Clear();
! // Need to call term first
! PyObject *temp_args = Py_BuildValue("(i)", 0);
! ret = DoCallback(HANDLER_TERM, temp_args);
! Py_XDECREF(temp_args);
! if (!ret) {
! ExtensionError(NULL, "Terminating for reload failed");
! PyErr_Clear();
! }
! Py_XDECREF(ret);
! // Now force the reload and refresh of all callbacks.
! if (!LoadHandler(true))
! return NULL;
! Py_XDECREF(m_callback_init);
! m_callback_init = NULL;
! Py_XDECREF(m_callback_do);
! m_callback_do = NULL;
! Py_XDECREF(m_callback_term);
! m_callback_term = NULL;
! // call init again
! temp_args = Py_BuildValue("(z)", NULL);
! ret = DoCallback(HANDLER_INIT, temp_args);
! Py_XDECREF(temp_args);
! if (!ret) {
! ExtensionError(NULL, "Reinitializing after import failed");
! PyErr_Clear();
! }
! Py_XDECREF(ret);
! // And make the original call again.
! ret = DoCallback(typ, args);
! }
! }
Py_DECREF(args);
! return ret;
}
! void CPythonHandler::Term(void)
{
// never shut down - Python leaks badly and has other
// side effects if you repeatedly Init then Term
! Py_XDECREF(m_callback_init);
! Py_XDECREF(m_callback_do);
! Py_XDECREF(m_callback_term);
}
Index: PythonEng.h
===================================================================
RCS file: /cvsroot/pywin32/pywin32/pyisapi/src/PythonEng.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -C2 -d -r1.1 -r1.2
*** PythonEng.h 1 Sep 2004 03:07:12 -0000 1.1
--- PythonEng.h 4 Sep 2004 09:28:50 -0000 1.2
***************
*** 49,66 ****
~CPythonEngine();
bool InitMainInterp(void);
! void ShutdownInterp(void);
! bool LoadHandler(char *factory_name);
! PyObject *GetHandler() {return m_handler;}
! bool SetCallback(const char *callbackName);
! PyObject *Callback(const char *szFormat, ...);
protected:
bool AddToPythonPath(LPCTSTR pPathName);
! PyObject *m_handler;
// couple of vars used to ensure that we intialis exactly once
static CRITICAL_SECTION m_initLock;
static bool m_haveInit;
- PyObject * m_callback;
};
// general error handler
--- 49,93 ----
~CPythonEngine();
bool InitMainInterp(void);
! char m_module_name[_MAX_FNAME];
! static PyObject * m_reload_exception;
protected:
+
bool AddToPythonPath(LPCTSTR pPathName);
! void FindModuleName();
// couple of vars used to ensure that we intialis exactly once
static CRITICAL_SECTION m_initLock;
static bool m_haveInit;
};
+ typedef enum {
+ HANDLER_INIT,
+ HANDLER_DO,
+ HANDLER_TERM,
+ } HANDLER_TYPE;
+
+ class CPythonHandler
+ {
+ public:
+ CPythonHandler();
+ bool Init(CPythonEngine *engine,
+ const char *factory, const char *nameinit, const char *namedo,
+ const char *nameterm);
+ void Term();
+ PyObject *Callback(HANDLER_TYPE typ, const char *szFormat, ...);
+ protected:
+ PyObject *DoCallback(HANDLER_TYPE typ, PyObject *args);
+
+ bool LoadHandler(bool reload);
+ bool CPythonHandler::CheckCallback(const char *cbname, PyObject **cb);
+ const char *m_namefactory;
+ const char *m_nameinit;
+ const char *m_namedo;
+ const char *m_nameterm;
+ PyObject *m_callback_init; // reference to instance methods.87
+ PyObject *m_callback_do;
+ PyObject *m_callback_term;
+ PyObject *m_handler; // reference to the class instance.
+ CPythonEngine *m_engine;
+ };
// general error handler
|