Hi all,

I'm currently building an application in which I needed to embed WebWare in 
a DLL. This Dll serves multiple purposes: it exposes the object model of the 
application so that PSP scripts can call into it (done as a built-in Python 
extension module), it acts as an adapter redirecting the web server requests 
to the app server and it embeds a Python interpreter used to launch and 
control the WebWare app server.

Here's the Python script (derived from ThreadedAppServerService) that I am 
controlling from the Dll:

#!/usr/bin/env python
"""
HCAppSrv:
Modified version of the original ThreadedAppServerService code (removed all 
SCM stuff)
"""

import os, sys, time, cStringIO

class HCAppSrv:

        def __init__(self):
                self.server = None
                # Fix the current working directory -- this gets initialized 
incorrectly
                # for some reason when run as an NT service.
                try:
                        os.chdir(os.path.abspath(os.path.dirname(__file__)))
                except:
                        pass

        def Stop(self, args):
                # And set running to 0 in the server.  If it hasn't started yet, we'll
                # have to wait until it does.
                while self.server is None:
                        time.sleep(1.0)
                self.server.initiateShutdown()

        def Start(self, args):
                try:
                        # Temporarily suck up stdout and stderr into a cStringIO

                        if args[0] == "SERVICE":
                                stdoutAndStderr = cStringIO.StringIO()
                                sys.stdout = sys.stderr = stdoutAndStderr

                        # Import the ThreadedAppServer
                        if '' not in sys.path:
                                sys.path = [''] + sys.path

                        os.chdir(os.pardir)

                        from WebKit.ThreadedAppServer import ThreadedAppServer

                        self.server = ThreadedAppServer(self.workDir())

                        # Now switch the output to a logfile
                        if args[0] == "SERVICE":
                                sys.stdout = sys.stderr = 
open('EmbeddedAppServer.Log', 'a+')
                                sys.stdout.write('-' * 68 + '\n')
                                sys.stdout.write(stdoutAndStderr.getvalue())

                                del stdoutAndStderr

                        print "AppServer is running..."

                        self.server.mainloop()
                        self.server._closeThread.join()

                        print "AppServer has ended!"

                except Exception, e: #Need to kill the Sweeper thread somehow
                        print e
                        print "Exception! Exiting AppServer"
                        if 1: #See the traceback from an exception
                                tb = sys.exc_info()
                                print tb[0]
                                print tb[1]
                                import traceback
                                traceback.print_tb(tb[2])
                        if self.server:
                                self.server.running=0
                                self.server.shutDown()
                        raise

        def workDir(self):
                return None

if __name__=='__main__':
        AppSrv = HCAppSrv()
        AppSrv.Start("DEBUG")


In order to launch the WebWare app server without blocking the rest of the 
execution in the dll, a Win32 thread is dedicated to loading the module 
implementing the HCAppSrv class and calling HCAppSrv.Start(). Note: Start() 
is not supposed to return until the WebWare app server gets shutdown by a 
call to HCAppSrv.Stop() later.

The thread launching the app server caches the PyObject pointer to the 
instance of HCAppSrv class that it created(m_pAppSrvInst = 
PyEval_CallObject(pclass, pargs) and does not call Py_DECREF on it. This is 
intended so that the pointer to the running instance of HCAppSrv can be 
reused later when HCAppSrv.Stop() needs to be called.

Up to this point, everything works fine: the app server starts up and serves 
any requested PSP page and makes successful calls into the C++ object model 
exposed by the DLL.

It is only when the time comes to call HCAppSrv.Stop() that things go wrong. 
The main thread of the application calls HCAppSrv.Stop() by using the cached 
PyObject* pointer to the running instance of the class and attempts to 
invoke Stop() which results in an exception deep down in the Python 
interpreter. Here's the back trace that I get when debugging under VC++:

PyDict_SetItem(_object * 0x00000000, _object * 0x01d856c0, _object * 
0x01d6c578) line 510 + 3 bytes
PyDict_SetItemString(_object * 0x00000000, char * 0x1e136a00, _object * 
0x01d6c578) line 1883 + 17 bytes
PySys_SetObject(char * 0x1e136a00, _object * 0x01d6c578) line 63 + 17 bytes
set_exc_info(_ts * 0x02243340, _object * 0x01d6c578, _object * 0x022448e8, 
_object * 0x02244c58) line 2644 + 14 bytes
eval_frame(_frame * 0x02240a50) line 2284 + 30 bytes
PyEval_EvalCodeEx(PyCodeObject * 0x020e9c08, _object * 0x020ee448, _object * 
0x00000000, _object * * 0x022148e0, int 0, _object * * 0x022148e0, int 0, 
_object * * 0x00000000, int 0, _object * 0x00000000) line 2585 + 9 bytes
fast_function(_object * 0x020a0ec8, _object * * * 0x01a5ec80, int 0, int 0, 
int 0) line 3164 + 65 bytes
eval_frame(_frame * 0x02214770) line 2025 + 37 bytes
PyEval_EvalCodeEx(PyCodeObject * 0x020daf50, _object * 0x020ee448, _object * 
0x00000000, _object * * 0x01fd06c0, int 2, _object * * 0x01fd06c8, int 0, 
_object * * 0x020ede4c, int 1, _object * 0x00000000) line 2585 + 9 bytes
fast_function(_object * 0x020d60c0, _object * * * 0x01a5eeac, int 2, int 2, 
int 0) line 3164 + 65 bytes
eval_frame(_frame * 0x01fd0568) line 2025 + 37 bytes
PyEval_EvalCodeEx(PyCodeObject * 0x020da3d8, _object * 0x020ee448, _object * 
0x00000000, _object * * 0x01ffc078, int 1, _object * * 0x01ffc07c, int 0, 
_object * * 0x00000000, int 0, _object * 0x00000000) line 2585 + 9 bytes
fast_function(_object * 0x020d6148, _object * * * 0x01a5f0d8, int 1, int 1, 
int 0) line 3164 + 65 bytes
eval_frame(_frame * 0x01ffbf20) line 2025 + 37 bytes
PyEval_EvalCodeEx(PyCodeObject * 0x020df1d0, _object * 0x020ee448, _object * 
0x00000000, _object * * 0x02197b08, int 1, _object * * 0x02197b0c, int 0, 
_object * * 0x00000000, int 0, _object * 0x00000000) line 2585 + 9 bytes
fast_function(_object * 0x020ef970, _object * * * 0x01a5f304, int 1, int 1, 
int 0) line 3164 + 65 bytes
eval_frame(_frame * 0x021979b0) line 2025 + 37 bytes
PyEval_EvalCodeEx(PyCodeObject * 0x01e03e60, _object * 0x01def340, _object * 
0x00000000, _object * * 0x01d9b1c4, int 1, _object * * 0x01d9b1c8, int 0, 
_object * * 0x00000000, int 0, _object * 0x00000000) line 2585 + 9 bytes
fast_function(_object * 0x01e59300, _object * * * 0x01a5f530, int 1, int 1, 
int 0) line 3164 + 65 bytes
eval_frame(_frame * 0x01d9b068) line 2025 + 37 bytes
PyEval_EvalCodeEx(PyCodeObject * 0x01d72300, _object * 0x01d97730, _object * 
0x00000000, _object * * 0x01d911f4, int 2, _object * * 0x00000000, int 0, 
_object * * 0x00000000, int 0, _object * 0x00000000) line 2585 + 9 bytes
function_call(_object * 0x01dd7bd8, _object * 0x01d911e0, _object * 
0x00000000) line 379 + 64 bytes
PyObject_Call(_object * 0x01dd7bd8, _object * 0x01d911e0, _object * 
0x00000000) line 1684 + 15 bytes
instancemethod_call(_object * 0x01dd7bd8, _object * 0x01d911e0, _object * 
0x00000000) line 2276 + 17 bytes
PyObject_Call(_object * 0x01fe0f78, _object * 0x01d8e238, _object * 
0x00000000) line 1684 + 15 bytes
PyEval_CallObjectWithKeywords(_object * 0x01fe0f78, _object * 0x01d8e238, 
_object * 0x00000000) line 3049 + 17 bytes
CWebWareLauncher::OnStop() line 268 + 18 bytes

I'm at a loss because everything "looks" right: HCAppSrv.Stop() is called 
exactly like HCAppSrv.Start() except for the fact that it is invoked from a 
different thread and references the cached instance of the app server. I 
can't see what I'm missing.

If anyone on this list is familiar with embedding Python and Python 
threading or has embedded WebWare in a similar fashion before, please share 
your thoughts :) I'll be glad to email you the C++ source code if you think 
you can help with this.

Regards,
Fabien.


_________________________________________________________________
Chat with friends online, try MSN Messenger: http://messenger.msn.com



-------------------------------------------------------
This SF.NET email is sponsored by: AMD - Your access to the experts
on Hammer Technology! Open Source & Linux Developers, register now
for the AMD Developer Symposium. Code: EX8664
http://www.developwithamd.com/developerlab
_______________________________________________
Webware-discuss mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/webware-discuss

Reply via email to