]> granicus.if.org Git - php/commitdiff
Use the GIT for inter-thread marshalling.
authorWez Furlong <wez@php.net>
Mon, 20 May 2002 22:22:57 +0000 (22:22 +0000)
committerWez Furlong <wez@php.net>
Mon, 20 May 2002 22:22:57 +0000 (22:22 +0000)
sapi/activescript/php4activescript.h
sapi/activescript/php4as_scriptengine.h
sapi/activescript/scriptengine.cpp

index 423958fba0c9d781631b823c4cad0277ad4f00ba..2473a9c42570f4e39be7b62491e5296e39f072e7 100644 (file)
@@ -23,4 +23,3 @@ extern HINSTANCE module_handle;
 extern void activescript_error_func(int type, const char *error_msg, ...);
 extern void activescript_error_handler(int type, const char *error_filename,
                const uint error_lineno, const char *format, va_list args);
-
index 1d2314b5e25cb340dc57c89384dba704fbadd8e2..a996b24138ba4772957a8c2ffefdaf770c4af6bd 100644 (file)
@@ -38,12 +38,13 @@ enum {
        PHPSE_SET_SITE,
        PHPSE_ADD_TYPELIB,
        PHPSE_TRIGGER_ERROR,
-       PHPSE_GET_DISPATCH
+       PHPSE_GET_DISPATCH,
+       PHPSE_DUMMY_TICK,
 };
 
 struct php_active_script_get_dispatch_info {
        LPCOLESTR pstrItemName;
-       LPSTREAM dispatch;
+       DWORD dispatch;
 };
 
 struct php_active_script_add_named_item_info {
@@ -52,7 +53,7 @@ struct php_active_script_add_named_item_info {
        IUnknown *punk;
        ITypeInfo *ptyp;
        IDispatch *pdisp;
-       LPSTREAM marshal;
+       DWORD marshal;
 };
 
 struct php_active_script_add_scriptlet_info {
@@ -91,7 +92,7 @@ struct php_active_script_parse_proc_info {
        /* [in] */ DWORD dwSourceContextCookie;
        /* [in] */ ULONG ulStartingLineNumber;
        /* [in] */ DWORD dwFlags;
-       /* [out] */ IDispatch **ppdisp; 
+       DWORD dispcookie;
 };
 
 struct php_active_script_add_tlb_info {
index 8e1f92baaf4a5362e38bb4fc5ed0a1f0b7bf2893..da4f51baa539feef3762a7334ac2f16b9251395d 100644 (file)
  * running script in the PHP/Zend engine must take place on the engine
  * thread.  Likewise, calling back to the host must take place on the base
  * thread - the thread that set the script site.
- *
- * For talking to the site from engine thread, we use an invisible window:
- * the window processing is guaranteed to occur in the correct thread,
- * and the message queue provides a useful synchronization device.
- *
- * For talking to the engine from any other thread, the engine thread waits
- * for messages to arrive at it's message queue.  Since the only API for
- * dealing with thread messages is asynchronous, we use a mutex to ensure
- * that only one thread can talk to the engine at a time, and an event
- * object to signal to it that the processing is complete.
- *
  * */
 
 #define _WIN32_DCOM
@@ -57,58 +46,28 @@ extern "C" {
 #include "ext/com/php_COM.h"
 #include "ext/com/conversion.h"
 }
+#include "php_ticks.h"
 #include "php4as_scriptengine.h"
 #include "php4as_classfactory.h"
 #include <objbase.h>
 
-enum fragtype {
-       FRAG_MAIN,
-       FRAG_SCRIPTLET,
-       FRAG_PROCEDURE
-};
-
-typedef struct {
-       enum fragtype fragtype;
-       zend_op_array *opcodes;
-       char *code;
-       int persistent; /* should be retained for Clone */
-       int executed;   /* for "main" */
-       char *functionname;
-       unsigned int codelen;
-       unsigned int starting_line;
-       TPHPScriptingEngine *engine;
-       void *ptr;
-} code_frag;
-
-#define FRAG_CREATE_FUNC       (char*)-1
-static code_frag *compile_code_fragment(
-               enum fragtype fragtype,
-               char *functionname,
-               LPCOLESTR code,
-               ULONG starting_line,
-               EXCEPINFO *excepinfo,
-               TPHPScriptingEngine *engine
-               TSRMLS_DC);
-
-static int execute_code_fragment(code_frag *frag,
-               VARIANT *varResult,
-               EXCEPINFO *excepinfo
-               TSRMLS_DC);
-static void free_code_fragment(code_frag *frag);
-static code_frag *clone_code_fragment(code_frag *frag, TPHPScriptingEngine *engine TSRMLS_DC);
-
-/* Magic for handling threading correctly */
-static inline HRESULT SEND_THREAD_MESSAGE(TPHPScriptingEngine *engine, LONG msg, WPARAM wparam, LPARAM lparam TSRMLS_DC)
+/* {{{ trace */
+static inline void trace(char *fmt, ...)
 {
-       if (engine->m_enginethread == 0)
-               return E_UNEXPECTED;
-       if (tsrm_thread_id() == (engine)->m_enginethread) 
-               return (engine)->engine_thread_handler((msg), (wparam), (lparam), NULL TSRMLS_CC);
-       return (engine)->SendThreadMessage((msg), (wparam), (lparam));
-}
-       
+       va_list ap;
+       char buf[4096];
 
+       sprintf(buf, "T=%08x ", tsrm_thread_id());
+       OutputDebugString(buf);
+       
+       va_start(ap, fmt);
+       vsnprintf(buf, sizeof(buf), fmt, ap);
 
+       OutputDebugString(buf);
+       
+       va_end(ap);
+}
+/* }}} */
 /* {{{ scriptstate_to_string */
 static const char *scriptstate_to_string(SCRIPTSTATE ss)
 {
@@ -124,25 +83,6 @@ static const char *scriptstate_to_string(SCRIPTSTATE ss)
        }
 }
 /* }}} */
-
-/* {{{ trace */
-static inline void trace(char *fmt, ...)
-{
-       va_list ap;
-       char buf[4096];
-
-       sprintf(buf, "T=%08x ", tsrm_thread_id());
-       OutputDebugString(buf);
-       
-       va_start(ap, fmt);
-       vsnprintf(buf, sizeof(buf), fmt, ap);
-
-       OutputDebugString(buf);
-       
-       va_end(ap);
-}
-/* }}} */
-
 /* {{{ TWideString */
 /* This class helps manipulate strings from OLE.
  * It does not use emalloc, so it is better suited for passing pointers
@@ -226,6 +166,113 @@ class TWideString {
 };
 /* }}} */
 
+/* {{{ code fragment structures */
+enum fragtype {
+       FRAG_MAIN,
+       FRAG_SCRIPTLET,
+       FRAG_PROCEDURE
+};
+
+typedef struct {
+       enum fragtype fragtype;
+       zend_op_array *opcodes;
+       char *code;
+       int persistent; /* should be retained for Clone */
+       int executed;   /* for "main" */
+       char *functionname;
+       unsigned int codelen;
+       unsigned int starting_line;
+       TPHPScriptingEngine *engine;
+       void *ptr;
+} code_frag;
+
+#define FRAG_CREATE_FUNC       (char*)-1
+static code_frag *compile_code_fragment(
+               enum fragtype fragtype,
+               char *functionname,
+               LPCOLESTR code,
+               ULONG starting_line,
+               EXCEPINFO *excepinfo,
+               TPHPScriptingEngine *engine
+               TSRMLS_DC);
+
+static int execute_code_fragment(code_frag *frag,
+               VARIANT *varResult,
+               EXCEPINFO *excepinfo
+               TSRMLS_DC);
+static void free_code_fragment(code_frag *frag);
+static code_frag *clone_code_fragment(code_frag *frag, TPHPScriptingEngine *engine TSRMLS_DC);
+
+/* }}} */
+
+/* Magic for handling threading correctly */
+static inline HRESULT SEND_THREAD_MESSAGE(TPHPScriptingEngine *engine, LONG msg, WPARAM wparam, LPARAM lparam TSRMLS_DC)
+{
+       if (engine->m_enginethread == 0)
+               return E_UNEXPECTED;
+       if (tsrm_thread_id() == (engine)->m_enginethread) 
+               return (engine)->engine_thread_handler((msg), (wparam), (lparam), NULL TSRMLS_CC);
+       return (engine)->SendThreadMessage((msg), (wparam), (lparam));
+}
+
+/* These functions do some magic so that interfaces can be
+ * used across threads without worrying about marshalling
+ * or not marshalling, as appropriate.
+ * Win95 without DCOM 1.1, and NT SP 2 or lower do not have
+ * the GIT; so we emulate the GIT using other means.
+ * If you trace problems back to this code, installing the relevant
+ * SP should solve them.
+ * */
+static inline HRESULT GIT_get(DWORD cookie, REFIID riid, void **obj)
+{
+       IGlobalInterfaceTable *git;
+       HRESULT ret;
+       
+       if (SUCCEEDED(CoCreateInstance(CLSID_StdGlobalInterfaceTable, NULL,
+                                       CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable,
+                                       (void**)&git))) {
+               
+               ret = git->GetInterfaceFromGlobal(cookie, riid, obj);
+               git->Release();
+               return ret;
+       }
+       return CoGetInterfaceAndReleaseStream((LPSTREAM)cookie, riid, obj);
+}
+
+static inline HRESULT GIT_put(IUnknown *unk, REFIID riid, DWORD *cookie)
+{
+       IGlobalInterfaceTable *git;
+       HRESULT ret;
+       
+       if (SUCCEEDED(CoCreateInstance(CLSID_StdGlobalInterfaceTable, NULL,
+                                       CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable,
+                                       (void**)&git))) {
+               
+               ret = git->RegisterInterfaceInGlobal(unk, riid, cookie);
+               git->Release();
+               return ret;
+       }
+       return CoMarshalInterThreadInterfaceInStream(riid, unk, (LPSTREAM*)cookie);
+}
+
+static inline HRESULT GIT_revoke(DWORD cookie, IUnknown *unk)
+{
+       IGlobalInterfaceTable *git;
+       HRESULT ret;
+       
+       if (SUCCEEDED(CoCreateInstance(CLSID_StdGlobalInterfaceTable, NULL,
+                                       CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable,
+                                       (void**)&git))) {
+               
+               ret = git->RevokeInterfaceFromGlobal(cookie);
+               git->Release();
+       }
+       /* Kill remote clients */
+       return CoDisconnectObject(unk, 0);
+}
+
+
+
 /* {{{ A generic stupid IDispatch implementation */
 class IDispatchImpl:
        public IDispatch
@@ -325,6 +372,7 @@ public:
        code_frag               *m_frag;
        DWORD                   m_procflags;
        TPHPScriptingEngine *m_engine;
+       DWORD                   m_gitcookie;
 
        STDMETHODIMP Invoke( DISPID  dispIdMember, REFIID  riid, LCID  lcid, WORD  wFlags,
                DISPPARAMS FAR*  pDispParams, VARIANT FAR*  pVarResult, EXCEPINFO FAR*  pExcepInfo,
@@ -340,6 +388,7 @@ public:
        }
        ScriptProcedureDispatch() {
                m_refcount = 1;
+               GIT_put((IDispatch*)this, IID_IDispatch, &m_gitcookie);
        }
 };
 /* }}} */
@@ -433,7 +482,7 @@ static void free_code_fragment(code_frag *frag)
                        if (frag->ptr) {
                                ScriptProcedureDispatch *disp = (ScriptProcedureDispatch*)frag->ptr;
                                disp->Release();
-                               CoDisconnectObject((IUnknown*)disp, 0);
+                               GIT_revoke(disp->m_gitcookie, (IDispatch*)disp);
                                frag->ptr = NULL;
                        }
                        break;
@@ -599,6 +648,29 @@ TPHPScriptingEngine::TPHPScriptingEngine()
        CloseHandle(m_engine_thread_handle);
 }
 
+void activescript_run_ticks(int count)
+{
+       MSG msg;
+       TSRMLS_FETCH();
+       TPHPScriptingEngine *engine;
+       
+       trace("ticking %d\n", count);
+       
+       engine = (TPHPScriptingEngine*)SG(server_context);
+
+/*     PostThreadMessage(engine->m_enginethread, PHPSE_DUMMY_TICK, 0, 0); */
+       
+       while(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
+               if (msg.hwnd) {
+                       PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
+                       TranslateMessage(&msg);
+                       DispatchMessage(&msg);
+               } else {
+                       break;
+               }
+       }
+}
+
 /* Synchronize with the engine thread */
 HRESULT TPHPScriptingEngine::SendThreadMessage(LONG msg, WPARAM wparam, LPARAM lparam)
 {
@@ -635,6 +707,7 @@ HRESULT TPHPScriptingEngine::SendThreadMessage(LONG msg, WPARAM wparam, LPARAM l
                        MSG msg;
                        while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
                                //trace("dispatching message while waiting\n"); 
+                               TranslateMessage(&msg);
                                DispatchMessage(&msg);
                        }
                } else if (result == WAIT_TIMEOUT) {
@@ -786,6 +859,8 @@ HRESULT TPHPScriptingEngine::engine_thread_handler(LONG msg, WPARAM wparam, LPAR
 
                                php_request_startup(TSRMLS_C);
                                PG(during_request_startup) = 0;
+                               trace("\n\n     *** ticks func at %08x %08x ***\n\n\n", activescript_run_ticks, &activescript_run_ticks);
+//                             php_add_tick_function(activescript_run_ticks);
 
                        }
                        break;
@@ -917,44 +992,32 @@ HRESULT TPHPScriptingEngine::engine_thread_handler(LONG msg, WPARAM wparam, LPAR
                        {
                                struct php_active_script_get_dispatch_info *info = (struct php_active_script_get_dispatch_info *)lParam;
                                IDispatch *disp = NULL;
-                               char *itemname;
-                               unsigned int itemlen;
 
                                if (info->pstrItemName != NULL) {
                                        zval **tmp;
-
-                                       itemname = php_OLECHAR_to_char((OLECHAR*)info->pstrItemName, &itemlen, CP_ACP TSRMLS_CC);
-
+                                       /* use this rather than php_OLECHAR_to_char because we want to avoid emalloc here */
+                                       TWideString itemname(info->pstrItemName);
+                                       
                                        /* Get that item from the global namespace.
                                         * If it is an object, export it as a dispatchable object.
                                         * */
 
-                                       if (zend_hash_find(&EG(symbol_table), itemname, itemlen+1, (void**)&tmp) == SUCCESS) {
+                                       if (zend_hash_find(&EG(symbol_table), itemname.ansi_string(),
+                                                               itemname.ansi_len() + 1, (void**)&tmp) == SUCCESS) {
                                                if (Z_TYPE_PP(tmp) == IS_OBJECT) {
+                                                       /* FIXME: if this causes an allocation (emalloc) and we are
+                                                        * not in the engine thread, things could get ugly!!! */
                                                        disp = php_COM_export_object(*tmp TSRMLS_CC);
                                                }
                                        }
-                                       trace("%08x: GetScriptDispatch(%s --> %08x)\n", this, itemname, disp);
-
-                                       efree(itemname);
 
                                } else {
-#if 0
-                                       zval *obj;
-
-                                       MAKE_STD_ZVAL(obj);
-                                       object_init(obj);
-                                       disp = php_COM_export_object(obj TSRMLS_CC);
-#else
-
+                                       /* This object represents PHP global namespace */
                                        disp = (IDispatch*) new ScriptDispatch;
-#endif
-                                       trace("%08x: GetScriptDispatch(NULL --> %08x)\n", this, disp);
                                }
 
                                if (disp) {
-                                       trace("--- Marshaling to stream\n");
-                                       ret = CoMarshalInterThreadInterfaceInStream(IID_IDispatch, disp, &info->dispatch);
+                                       ret = GIT_put(disp, IID_IDispatch, &info->dispatch);
                                        disp->Release();
                                } else {
                                        ret = S_FALSE;
@@ -972,22 +1035,20 @@ HRESULT TPHPScriptingEngine::engine_thread_handler(LONG msg, WPARAM wparam, LPAR
                                TWideString name(info->pstrName);
                                IDispatch *disp;
                                
-                               if (SUCCEEDED(CoGetInterfaceAndReleaseStream(info->marshal, IID_IDispatch, (void**)&disp))) 
+                               if (SUCCEEDED(GIT_get(info->marshal, IID_IDispatch, (void**)&disp))) 
                                        add_to_global_namespace(disp, info->dwFlags, name.ansi_string() TSRMLS_CC);
 
                        }
                        break;
                case PHPSE_SET_SITE:
                        {
-                               LPSTREAM stream = (LPSTREAM)lParam;
-
                                if (m_pass_eng) {
                                        m_pass_eng->Release();
                                        m_pass_eng = NULL;
                                }
 
-                               if (stream)
-                                       CoGetInterfaceAndReleaseStream(stream, IID_IActiveScriptSite, (void**)&m_pass_eng);
+                               if (lParam)
+                                       GIT_get(lParam, IID_IActiveScriptSite, (void**)&m_pass_eng);
 
                                trace("%08x: site (engine-side) is now %08x (base=%08x)\n", this, m_pass_eng, m_pass);
 
@@ -1010,15 +1071,14 @@ HRESULT TPHPScriptingEngine::engine_thread_handler(LONG msg, WPARAM wparam, LPAR
                                 * execute the opcodes */
                                struct php_active_script_parse_proc_info *info = (struct php_active_script_parse_proc_info*)lParam;
                                TWideString
-                                       code(info->pstrCode),
-                               formal_params(info->pstrFormalParams),
-                               procedure_name(info->pstrProcedureName),
-                               item_name(info->pstrItemName),
-                               delimiter(info->pstrDelimiter);
+                                       formal_params(info->pstrFormalParams),
+                                       procedure_name(info->pstrProcedureName),
+                                       item_name(info->pstrItemName),
+                                       delimiter(info->pstrDelimiter);
 
-                               trace("%08x: ParseProc:\n state=%s\ncode=%s\n params=%s\nproc=%s\nitem=%s\n delim=%s\n line=%d\n",
+                               trace("%08x: ParseProc:\n state=%s\nparams=%s\nproc=%s\nitem=%s\n delim=%s\n line=%d\n",
                                                this, scriptstate_to_string(m_scriptstate),
-                                               code.safe_ansi_string(), formal_params.ansi_string(), procedure_name.ansi_string(),
+                                               formal_params.ansi_string(), procedure_name.ansi_string(),
                                                item_name.safe_ansi_string(), delimiter.safe_ansi_string(),
                                                info->ulStartingLineNumber);
 
@@ -1039,17 +1099,12 @@ HRESULT TPHPScriptingEngine::engine_thread_handler(LONG msg, WPARAM wparam, LPAR
 
                                        ScriptProcedureDispatch *disp = new ScriptProcedureDispatch;
 
-                                       disp->AddRef();
                                        disp->m_frag = frag;
                                        disp->m_procflags = info->dwFlags;
                                        disp->m_engine = this;
                                        frag->ptr = disp;
+                                       info->dispcookie = disp->m_gitcookie;
 
-                                       *info->ppdisp = disp;
-                                       /*
-                                       ret = CoMarshalInterThreadInterfaceInStream(IID_IDispatch, disp, &info->disp);
-                                       disp->Release();
-                                       */
                                } else {
                                        ret = DISP_E_EXCEPTION;
                                }
@@ -1147,8 +1202,11 @@ void TPHPScriptingEngine::engine_thread_func(void)
 
                                        if (msg.message == WM_QUIT) {
                                                terminated = 1;
-                                       } else {
+                                       } else if (msg.hwnd) {
+                                               TranslateMessage(&msg);
+                                               DispatchMessage(&msg);
 
+                                       } else {
                                                handled = 1;
                                                m_sync_thread_ret = engine_thread_handler(msg.message, msg.wParam, msg.lParam, &handled TSRMLS_CC);
                                                if (handled)
@@ -1354,9 +1412,9 @@ STDMETHODIMP TPHPScriptingEngine::SetScriptSite(IActiveScriptSite *pass)
        if (m_pass) {
                m_pass->AddRef();
 
-               LPSTREAM stream;
-               if (SUCCEEDED(CoMarshalInterThreadInterfaceInStream(IID_IActiveScriptSite, m_pass, &stream)))
-                       SEND_THREAD_MESSAGE(this, PHPSE_SET_SITE, 0, (LPARAM)stream TSRMLS_CC);
+               DWORD cookie;
+               if (SUCCEEDED(GIT_put(m_pass, IID_IActiveScriptSite, &cookie)))
+                       SEND_THREAD_MESSAGE(this, PHPSE_SET_SITE, 0, cookie TSRMLS_CC);
                
                if (m_scriptstate == SCRIPTSTATE_UNINITIALIZED)
                        SEND_THREAD_MESSAGE(this, PHPSE_STATE_CHANGE, 0, SCRIPTSTATE_INITIALIZED TSRMLS_CC);
@@ -1424,7 +1482,7 @@ STDMETHODIMP TPHPScriptingEngine::AddNamedItem(LPCOLESTR pstrName, DWORD dwFlags
        info.dwFlags = dwFlags;
 
        m_pass->GetItemInfo(pstrName, SCRIPTINFO_IUNKNOWN, &info.punk, NULL);
-       if (SUCCEEDED(CoMarshalInterThreadInterfaceInStream(IID_IDispatch, info.punk, &info.marshal))) {
+       if (SUCCEEDED(GIT_put(info.punk, IID_IDispatch, &info.marshal))) {
                SEND_THREAD_MESSAGE(this, PHPSE_ADD_NAMED_ITEM, 0, (LPARAM)&info TSRMLS_CC);
        }
        info.punk->Release();
@@ -1485,7 +1543,7 @@ STDMETHODIMP TPHPScriptingEngine::GetScriptDispatch(
        }
 
        if (S_OK == engine_thread_handler(PHPSE_GET_DISPATCH, 0, (LPARAM)&info, NULL TSRMLS_CC)) {
-               CoGetInterfaceAndReleaseStream(info.dispatch, IID_IDispatch, (void**)ppdisp);
+               GIT_get(info.dispatch, IID_IDispatch, (void**)ppdisp);
        }
        
        if (*ppdisp) {
@@ -1670,16 +1728,12 @@ STDMETHODIMP TPHPScriptingEngine::ParseProcedureText(
        info.dwSourceContextCookie = dwSourceContextCookie;
        info.ulStartingLineNumber = ulStartingLineNumber;
        info.dwFlags = dwFlags;
-       info.ppdisp = ppdisp;
 
        ret = SEND_THREAD_MESSAGE(this, PHPSE_PARSE_PROC, 0, (LPARAM)&info TSRMLS_CC);
 
-       /*
-       if (ret == S_OK) {
-               ret = CoGetInterfaceAndReleaseStream(info.disp, IID_IDispatch, (void**)ppdisp);
-
-       }
-       */
+       if (ret == S_OK)
+               ret = GIT_get(info.dispcookie, IID_IDispatch, (void**)ppdisp);
+       
        trace("ParseProc: ret=%08x disp=%08x\n", ret, *ppdisp);
        return ret;
 }