void *StartThreadSpidermonkey(void *pData) {// begin StartThreadSpidermonkey pthread_mutex_lock(&g_pSpiderMonkeyMutex); /* The following mailling list post describes how to CORRECTLY use the threading API support with Spidermonkey "Thread from SpiderMonkey newsgroup" http://archive.gingerall.cz/archives/public/sablot2004/msg00117.html */ // Notify the Spidermonkey that we'll be processing in a thread #ifdef ADM_JS_THREADSAFE JS_SetContextThread(g_pCx); JS_BeginRequest(g_pCx); #endif bool ret = false; const char *pScriptFile = static_cast<const char *>(pData); ret = parseECMAScript(pScriptFile); if(ret == false) { if( actual_workbench_file ) ADM_dealloc(actual_workbench_file); actual_workbench_file = ADM_strdup(pScriptFile); } // Notify Spidermonkey that our thread processing has finished #ifdef ADM_JS_THREADSAFE JS_EndRequest(g_pCx); JS_ClearContextThread(g_pCx); #endif pthread_mutex_unlock(&g_pSpiderMonkeyMutex); return NULL; }// end StartThreadSpidermonkey
bool ControllerListener::frame() { jsval ret = JSVAL_VOID; JSBool res; JS_SetContextThread(jsContext); JS_BeginRequest(jsContext); if (!frameFunc) { res = JS_GetProperty(jsContext, jsObject, "frame", &frameFunc); if(!res || JSVAL_IS_VOID(frameFunc)) { error("method frame not found in TriggerController"); JS_ClearContextThread(jsContext); JS_EndRequest(jsContext); return false; } } res = JS_CallFunctionValue(jsContext, jsObject, frameFunc, 0, NULL, &ret); JS_EndRequest(jsContext); JS_ClearContextThread(jsContext); if (res == JS_FALSE) { error("trigger call frame() failed, deactivate ctrl"); //active = false; return false; } return true; }
int JsParser::parse(const char *command) { func("%u:%s:%s",__LINE__,__FILE__,__FUNCTION__); int eval_res; jsval res; JSString *str; if(!command) { /* true paranoia */ warning("NULL command passed to javascript parser"); return 0; } func("JS parse: %s", command); JsExecutionContext *new_script = new JsExecutionContext(this); JS_SetContextThread(new_script->cx); JS_BeginRequest(new_script->cx); eval_res = evaluate(new_script->cx, new_script->obj, (const char*)"parsed command", command, strlen(command)); JS_EndRequest(new_script->cx); JS_ClearContextThread(new_script->cx); if (eval_res) runtimes.append(new_script); else delete new_script; func("JS parse result: %i", eval_res); return eval_res; }
/* less bloat but this only works with 4 byte argv values */ bool ControllerListener::call(const char *funcname, int argc, jsval *argv) { jsval fval = JSVAL_VOID; jsval ret = JSVAL_VOID; JSBool res; func("calling js %s.%s()", name, funcname); JS_SetContextThread(jsContext); JS_BeginRequest(jsContext); res = JS_GetProperty(jsContext, jsObject, funcname, &fval); if(!res || JSVAL_IS_VOID(fval)) { // using func() instead of error() because this is not a real error condition. // controller could ask for unregistered functions ... // for instance in the case of a keyboardcontroller which propagates keystrokes // for unregistered keys func("method %s not found in %s controller", funcname, name); JS_EndRequest(jsContext); JS_ClearContextThread(jsContext); return(false); } res = JS_CallFunctionValue(jsContext, jsObject, fval, argc, argv, &ret); JS_EndRequest(jsContext); JS_ClearContextThread(jsContext); if(res == JS_FALSE) { error("%s : failed call", __PRETTY_FUNCTION__); return(false); } return(true); }
void SpidermonkeyDestroy() {// begin SpidermonkeyDestroy #ifdef ADM_JS_THREADSAFE JS_SetContextThread(g_pCx); #endif JS_DestroyContext(g_pCx); JS_DestroyRuntime(g_pRt); }// end SpidermonkeyDestroy
void SG_jscore__new_context(SG_context * pCtx, JSContext ** pp_cx, JSObject ** pp_glob, const SG_vhash * pServerConfig) { JSContext * cx = NULL; JSObject * glob = NULL; SG_ASSERT(pCtx!=NULL); SG_NULLARGCHECK_RETURN(pp_cx); if(gpJSCoreGlobalState==NULL) SG_ERR_THROW2_RETURN(SG_ERR_UNINITIALIZED, (pCtx, "jscore has not been initialized")); if (gpJSCoreGlobalState->cb) JS_SetContextCallback(gpJSCoreGlobalState->rt, gpJSCoreGlobalState->cb); cx = JS_NewContext(gpJSCoreGlobalState->rt, 8192); if(cx==NULL) SG_ERR_THROW2_RETURN(SG_ERR_MALLOCFAILED, (pCtx, "Failed to allocate new JS context")); (void)JS_SetContextThread(cx); JS_BeginRequest(cx); JS_SetOptions(cx, JSOPTION_VAROBJFIX); JS_SetVersion(cx, JSVERSION_LATEST); JS_SetContextPrivate(cx, pCtx); glob = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL); if(glob==NULL) SG_ERR_THROW2(SG_ERR_JS, (pCtx, "Failed to create JavaScript global object for new JSContext.")); if(!JS_InitStandardClasses(cx, glob)) SG_ERR_THROW2(SG_ERR_JS, (pCtx, "JS_InitStandardClasses() failed.")); if (gpJSCoreGlobalState->shell_functions) if (!JS_DefineFunctions(cx, glob, gpJSCoreGlobalState->shell_functions)) SG_ERR_THROW2(SG_ERR_JS, (pCtx, "Failed to install shell functions")); SG_jsglue__set_sg_context(pCtx, cx); SG_ERR_CHECK( SG_jsglue__install_scripting_api(pCtx, cx, glob) ); SG_ERR_CHECK( SG_zing_jsglue__install_scripting_api(pCtx, cx, glob) ); if (! gpJSCoreGlobalState->bSkipModules) { _sg_jscore__install_modules(pCtx, cx, glob, pServerConfig); SG_ERR_CHECK_CURRENT_DISREGARD(SG_ERR_NOTAFILE); } *pp_cx = cx; *pp_glob = glob; return; fail: if (cx) { JS_EndRequest(cx); JS_DestroyContext(cx); } }
XPCJSContextStack::~XPCJSContextStack() { if(mOwnSafeJSContext) { JS_SetContextThread(mOwnSafeJSContext); JS_DestroyContext(mOwnSafeJSContext); mOwnSafeJSContext = nsnull; } }
RuntimeContext::~RuntimeContext() { JS_SetContextThread(_context); JS_ClearNewbornRoots(_context); JS_ClearRegExpStatics(_context); JS_ClearPendingException(_context); JS_MaybeGC(_context); JS_DestroyContext(_context); }
JsExecutionContext::~JsExecutionContext() { JS_SetContextThread(cx); JS_GC(cx); JS_BeginRequest(cx); JS_ClearScope(cx, obj); JS_EndRequest(cx); JS_ClearContextThread(cx); JS_DestroyContext(cx); JS_DestroyRuntime(rt); }
bool __fastcall GameEventCallback(Script* script, void* argv, uint argc) { if(script->IsRunning() && script->IsListenerRegistered("gamemsg")) { AutoRoot** argv = new AutoRoot*[1]; JS_SetContextThread(ScriptEngine::GetGlobalContext()); argv[0] = new AutoRoot(STRING_TO_JSVAL(JS_NewStringCopyZ(ScriptEngine::GetGlobalContext(), (char*)argv))); JS_ClearContextThread(ScriptEngine::GetGlobalContext()); script->ExecEventAsync("gamemsg", 1, argv); } return true; }
void SG_jscontext__acquire(SG_context * pCtx, SG_jscontext ** ppJs) { SG_ASSERT(pCtx!=NULL); SG_NULLARGCHECK_RETURN(ppJs); if(gpJSContextPoolGlobalState->ssjsMutable) { _sg_jscontext__create(pCtx, ppJs); return; } SG_ERR_CHECK_RETURN( SG_mutex__lock(pCtx, &gpJSContextPoolGlobalState->lock) ); if(gpJSContextPoolGlobalState->pFirstAvailableContext!=NULL) { SG_jscontext * pJs = gpJSContextPoolGlobalState->pFirstAvailableContext; gpJSContextPoolGlobalState->pFirstAvailableContext = pJs->pNextAvailableContext; pJs->pNextAvailableContext = NULL; ++gpJSContextPoolGlobalState->numContextsCheckedOut; SG_ERR_CHECK_RETURN( SG_mutex__unlock(pCtx, &gpJSContextPoolGlobalState->lock) ); SG_httprequestprofiler__start(SG_HTTPREQUESTPROFILER_CATEGORY__JSREQUEST_TOGGLING); (void)JS_SetContextThread(pJs->cx); JS_BeginRequest(pJs->cx); pJs->isInARequest = SG_TRUE; SG_httprequestprofiler__stop(); JS_SetContextPrivate(pJs->cx, pCtx); *ppJs = pJs; } else { ++gpJSContextPoolGlobalState->numContextsCheckedOut; SG_ERR_CHECK_RETURN( SG_mutex__unlock(pCtx, &gpJSContextPoolGlobalState->lock) ); _sg_jscontext__create(pCtx, ppJs); if(SG_context__has_err(pCtx) || *ppJs==NULL) { /* Use the version of the mutex routines that doesn't touch pCtx, because we're already in an error state. */ SG_mutex__lock__bare(&gpJSContextPoolGlobalState->lock); --gpJSContextPoolGlobalState->numContextsCheckedOut; SG_mutex__unlock__bare(&gpJSContextPoolGlobalState->lock); } } }
bool __fastcall ChatEventCallback(Script* script, void* argv, uint argc) { ChatEventHelper* helper = (ChatEventHelper*)argv; if(script->IsRunning() && script->IsListenerRegistered(helper->event)) { AutoRoot** argv = new AutoRoot*[2]; JS_SetContextThread(ScriptEngine::GetGlobalContext()); argv[0] = new AutoRoot(STRING_TO_JSVAL(JS_NewStringCopyZ(ScriptEngine::GetGlobalContext(), helper->nick))); argv[1] = new AutoRoot(STRING_TO_JSVAL(JS_NewStringCopyZ(ScriptEngine::GetGlobalContext(), helper->msg))); JS_ClearContextThread(ScriptEngine::GetGlobalContext()); script->ExecEventAsync(helper->event, 2, argv); } return true; }
bool __fastcall CopyDataCallback(Script* script, void* argv, uint argc) { CopyDataHelper* helper = (CopyDataHelper*)argv; if(script->IsRunning() && script->IsListenerRegistered("copydata")) { AutoRoot** argv = new AutoRoot*[2]; JS_SetContextThread(ScriptEngine::GetGlobalContext()); argv[0] = new AutoRoot(); JS_NewNumberValue(ScriptEngine::GetGlobalContext(), helper->mode, argv[0]->value()); argv[1] = new AutoRoot(STRING_TO_JSVAL(JS_NewStringCopyZ(ScriptEngine::GetGlobalContext(), helper->msg))); JS_ClearContextThread(ScriptEngine::GetGlobalContext()); script->ExecEventAsync("copydata", 2, argv); } return true; }
void SG_jscontextpool__teardown(SG_context * pCtx) { if(gpJSContextPoolGlobalState!=NULL) { SG_ERR_CHECK_RETURN( SG_mutex__lock(pCtx, &gpJSContextPoolGlobalState->lock) ); // Wait until all outstanding SG_jscontexts have been released. Don't try to terminate // early, otherwise we have a race condition on our hands: If the outstanding SG_jscontext // tries to perform any JavaScript operations before the app terminates, but after we have // called JS_Shutdown(), we'll end up crashing on exit. This of course is worse than // making the user hit Ctrl-C again to do a hard shutdown if it's taking too long. if(gpJSContextPoolGlobalState->numContextsCheckedOut > 0) { SG_ERR_IGNORE( SG_log__report_warning(pCtx, "Waiting on %d SG_jscontexts that are still in use.", gpJSContextPoolGlobalState->numContextsCheckedOut) ); while(gpJSContextPoolGlobalState->numContextsCheckedOut > 0) { SG_ERR_CHECK_RETURN( SG_mutex__unlock(pCtx, &gpJSContextPoolGlobalState->lock) ); SG_sleep_ms(10); SG_ERR_CHECK_RETURN( SG_mutex__lock(pCtx, &gpJSContextPoolGlobalState->lock) ); } } SG_ERR_CHECK_RETURN( SG_mutex__unlock(pCtx, &gpJSContextPoolGlobalState->lock) ); SG_mutex__destroy(&gpJSContextPoolGlobalState->lock); while(gpJSContextPoolGlobalState->pFirstAvailableContext!=NULL) { SG_jscontext * pJs = gpJSContextPoolGlobalState->pFirstAvailableContext; gpJSContextPoolGlobalState->pFirstAvailableContext = pJs->pNextAvailableContext; (void)JS_SetContextThread(pJs->cx); JS_BeginRequest(pJs->cx); JS_SetContextPrivate(pJs->cx, pCtx); JS_DestroyContextNoGC(pJs->cx); if(SG_context__has_err(pCtx)) // An error was produced during GC... { SG_log__report_error__current_error(pCtx); SG_context__err_reset(pCtx); } SG_NULLFREE(pCtx, pJs); } SG_VHASH_NULLFREE(pCtx, gpJSContextPoolGlobalState->pServerConfig); SG_NULLFREE(pCtx, gpJSContextPoolGlobalState); } }
/* return lines read, or 0 on error */ int JsParser::open(const char* script_file) { JsExecutionContext *new_script = new JsExecutionContext(this); JS_SetContextThread(new_script->cx); JS_BeginRequest(new_script->cx); int ret = open(new_script->cx, new_script->obj, script_file); JS_EndRequest(new_script->cx); JS_ClearContextThread(new_script->cx); if (ret) { new_script->set_name(script_file); runtimes.append(new_script); } else { delete new_script; } return ret; }
bool __fastcall ItemEventCallback(Script* script, void* argv, uint argc) { ItemEventHelper* helper = (ItemEventHelper*)argv; if(script->IsRunning() && script->IsListenerRegistered("itemaction")) { AutoRoot** argv = new AutoRoot*[4]; JS_SetContextThread(ScriptEngine::GetGlobalContext()); argv[0] = new AutoRoot(); argv[1] = new AutoRoot(); JS_NewNumberValue(ScriptEngine::GetGlobalContext(), helper->id, argv[0]->value()); JS_NewNumberValue(ScriptEngine::GetGlobalContext(), helper->mode, argv[1]->value()); argv[2] = new AutoRoot(STRING_TO_JSVAL(JS_NewStringCopyZ(ScriptEngine::GetGlobalContext(), helper->code))); argv[3] = new AutoRoot(BOOLEAN_TO_JSVAL(helper->global)); JS_ClearContextThread(ScriptEngine::GetGlobalContext()); script->ExecEventAsync("itemaction", 4, argv); } return true; }
bool __fastcall GameActionEventCallback(Script* script, void* argv, uint argc) { GameActionEventHelper* helper = (GameActionEventHelper*)argv; if(script->IsRunning() && script->IsListenerRegistered("gameevent")) { AutoRoot** argv = new AutoRoot*[5]; JS_SetContextThread(ScriptEngine::GetGlobalContext()); argv[0] = new AutoRoot(); argv[1] = new AutoRoot(); argv[2] = new AutoRoot(); JS_NewNumberValue(ScriptEngine::GetGlobalContext(), helper->mode, argv[0]->value()); JS_NewNumberValue(ScriptEngine::GetGlobalContext(), helper->param1, argv[1]->value()); JS_NewNumberValue(ScriptEngine::GetGlobalContext(), helper->param2, argv[2]->value()); argv[3] = new AutoRoot(STRING_TO_JSVAL(JS_NewStringCopyZ(ScriptEngine::GetGlobalContext(), helper->name1))); argv[4] = new AutoRoot(STRING_TO_JSVAL(JS_NewStringCopyZ(ScriptEngine::GetGlobalContext(), helper->name2))); JS_ClearContextThread(ScriptEngine::GetGlobalContext()); script->ExecEventAsync("gameevent", 5, argv); } return true; }
/* JSCall function by name, cvalues will be converted * * deactivates controller if any script errors! * * format values: * case 'b': BOOLEAN_TO_JSVAL((JSBool) va_arg(ap, int)); * case 'c': INT_TO_JSVAL((uint16) va_arg(ap, unsigned int)); * case 'i': * case 'j': js_NewNumberValue(cx, (jsdouble) va_arg(ap, int32), sp) * case 'u': js_NewNumberValue(cx, (jsdouble) va_arg(ap, uint32), sp) * case 'd': * case 'I': js_NewDoubleValue(cx, va_arg(ap, jsdouble), sp) * case 's': JS_NewStringCopyZ(cx, va_arg(ap, char *)) * case 'W': JS_NewUCStringCopyZ(cx, va_arg(ap, jschar *)) * case 'S': va_arg(ap, JSString *) * case 'o': OBJECT_TO_JSVAL(va_arg(ap, JSObject *) * case 'f': * fun = va_arg(ap, JSFunction *); * fun ? OBJECT_TO_JSVAL(fun->object) : JSVAL_NULL; * case 'v': va_arg(ap, jsval); */ bool ControllerListener::call(const char *funcname, int argc, const char *format, ...) { va_list ap; jsval fval = JSVAL_VOID; jsval ret = JSVAL_VOID; func("%s try calling method %s.%s(argc:%i)", __func__, name, funcname, argc); JS_SetContextThread(jsContext); JS_BeginRequest(jsContext); int res = JS_GetProperty(jsContext, jsObject, funcname, &fval); if(JSVAL_IS_VOID(fval)) { warning("method unresolved by JS_GetProperty"); } else { jsval *argv; void *markp; va_start(ap, format); argv = JS_PushArgumentsVA(jsContext, &markp, format, ap); va_end(ap); res = JS_CallFunctionValue(jsContext, jsObject, fval, argc, argv, &ret); JS_PopArguments(jsContext, &markp); if (res) { if(!JSVAL_IS_VOID(ret)) { JSBool ok; JS_ValueToBoolean(jsContext, ret, &ok); if (ok) // JSfunc returned 'true', so event is done { JS_EndRequest(jsContext); JS_ClearContextThread(jsContext); return true; } } } } JS_EndRequest(jsContext); JS_ClearContextThread(jsContext); return false; // no callback, redo on next controller }
int Controller::JSCall(const char *funcname, int argc, const char *format, ...) { int res; jsval *argv; va_list args; ControllerListener *listener = listeners.begin(); va_start(args, format); va_end(args); while (listener) { void *markp = NULL; JS_SetContextThread(listener->context()); JS_BeginRequest(listener->context()); argv = JS_PushArgumentsVA(listener->context(), &markp, format, args); JS_EndRequest(listener->context()); JS_ClearContextThread(listener->context()); // TODO - unregister listener if returns false if (listener->call(funcname, argc, argv)) res++; listener = (ControllerListener *)listener->next; } return res; }
static void js_fini(void) { js_plugin_t *jsp, *n; JSContext *cx = js_global_cx; prop_courier_destroy(js_global_pc); JS_SetContextThread(cx); JS_BeginRequest(cx); for(jsp = LIST_FIRST(&js_plugins); jsp != NULL; jsp = n) { n = LIST_NEXT(jsp, jsp_link); js_plugin_unload0(cx, jsp); } JS_RemoveRoot(cx, &showtimeobj); JS_EndRequest(cx); JS_GC(cx); JS_DestroyContext(cx); JS_DestroyRuntime(runtime); JS_ShutDown(); }
inline void begin_request(spidermonkey_vm *vm) { JS_SetContextThread(vm->context); JS_BeginRequest(vm->context); }
void sm_stop(spidermonkey_vm *vm) { JS_SetContextThread(vm->context); JS_DestroyContext(vm->context); JS_DestroyRuntime(vm->runtime); driver_free(vm); }
void JsExecutionContext::gc() { JS_SetContextThread(cx); JS_MaybeGC(cx); JS_ClearContextThread(cx); }
bool Engine::executeFile(FILE *file,HttpServerRequest &httpRequest,HttpServerResponse &httpResponse) { JSContext *cx = NULL; JSObject *obj = NULL; m_mutex.acquire_write(); // pop any available context if ( !m_contexts.empty() ) { cx = m_contexts.top(); m_contexts.pop(); } m_mutex.release(); if ( cx==NULL ) { // create new context cx = JS_NewContext(m_runtime,8192); if ( cx==NULL ) { LogManager::getInstance()->warning(LOGGER_CLASSNAME,"Could not create context. Engine is unavailable."); return false; } JS_SetErrorReporter(cx,reportError); if ( LogManager::getInstance()->isDebug() ) { LogManager::getInstance()->debug(LOGGER_CLASSNAME,"Created new context"); } } bool result = false; // begin request (requires js_threadsafe compilation) JS_SetContextThread(cx); JS_BeginRequest(cx); // create global object obj = JS_NewObject(cx,&globalClass,0,0); if ( obj==NULL ) { LogManager::getInstance()->warning(LOGGER_CLASSNAME,"Could not create global object"); } else { // initialize standard classes on global object if ( JS_InitStandardClasses(cx,obj)==JS_FALSE ) { LogManager::getInstance()->warning(LOGGER_CLASSNAME,"Could not init standard classes"); } else { // initialize custom classes on global object if ( !initCustomClasses(cx,obj) ) { LogManager::getInstance()->warning(LOGGER_CLASSNAME,"Could not init custom classes"); } else { // create predefined objects on global object createPredefinedObjects(cx,obj,httpRequest); // create context private ContextPrivate *cxPrivate = new ContextPrivate(this,httpRequest,httpResponse); JS_SetContextPrivate(cx,cxPrivate); // execute script in the context result = executeFile(file,cx,obj); // cleanup predefined objects on context object // note: this one might not be needed, remove later if ok cleanupPredefinedObjects(cx,obj); delete cxPrivate; } } } JS_GC(cx); // force garbage collection // end request (requires js_threadsafe) JS_EndRequest(cx); JS_ClearContextThread(cx); // return context to js engine m_mutex.acquire_write(); m_contexts.push(cx); m_mutex.release(); return result; }
static void js_global_pc_prologue(void) { JS_SetContextThread(js_global_cx); }