From: Wez Furlong Date: Mon, 20 May 2002 22:22:57 +0000 (+0000) Subject: Use the GIT for inter-thread marshalling. X-Git-Tag: RELEASE_0_10~76 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3fca69809d4778982180a7a9171288bac1ff6e2b;p=php Use the GIT for inter-thread marshalling. --- diff --git a/sapi/activescript/php4activescript.h b/sapi/activescript/php4activescript.h index 423958fba0..2473a9c425 100644 --- a/sapi/activescript/php4activescript.h +++ b/sapi/activescript/php4activescript.h @@ -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); - diff --git a/sapi/activescript/php4as_scriptengine.h b/sapi/activescript/php4as_scriptengine.h index 1d2314b5e2..a996b24138 100644 --- a/sapi/activescript/php4as_scriptengine.h +++ b/sapi/activescript/php4as_scriptengine.h @@ -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 { diff --git a/sapi/activescript/scriptengine.cpp b/sapi/activescript/scriptengine.cpp index 8e1f92baaf..da4f51baa5 100644 --- a/sapi/activescript/scriptengine.cpp +++ b/sapi/activescript/scriptengine.cpp @@ -27,17 +27,6 @@ * 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 -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; }