diff options
Diffstat (limited to 'sapi/activescript/scriptengine.cpp')
| -rw-r--r-- | sapi/activescript/scriptengine.cpp | 310 | 
1 files changed, 182 insertions, 128 deletions
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 <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;  }  | 
