FS-11194: [mod_v8] Implement JavaScript Process Status with Heap statistics.

This commit is contained in:
Andrey Volk 2018-07-24 14:01:55 +03:00
parent fc139b7068
commit 27669eda04
6 changed files with 362 additions and 27 deletions

View File

@ -63,6 +63,8 @@ public:
JS_FUNCTION_DEF_STATIC(FetchURL);
JS_FUNCTION_DEF_STATIC(FetchURLHash);
JS_FUNCTION_DEF_STATIC(FetchURLFile);
JS_FUNCTION_DEF_STATIC(Version);
JS_FUNCTION_DEF_STATIC(Id);
};
#endif /* FS_GLOBAL_H */

View File

@ -332,7 +332,6 @@ public:
static void Dispose(); /* Deinitialize the V8 engine */
static void Include(const v8::FunctionCallbackInfo<v8::Value>& args); /* Adds functionality to include another JavaScript from the running script */
static void Version(const v8::FunctionCallbackInfo<v8::Value>& args); /* Internal Version function accessable from JS - used to get the current V( version */
static const std::string GetExceptionInfo(v8::Isolate* isolate, v8::TryCatch* try_catch); /* Get the exception information from a V8 TryCatch instance */
const std::vector<const js_class_definition_t *>& GetExtenderClasses() const;/* Returns the list of class definitions */
@ -355,7 +354,7 @@ public:
int GetForcedTerminationLineNumber(void);
/* Method to force termination of a script */
static void ExitScript(v8::Isolate *isolate, const char *msg);
static void ExitScript(v8::Isolate *isolate, const char *msg, bool jskill = false);
/* Get the filename and line number of the current JS stack */
static char *GetStackInfo(v8::Isolate *isolate, int *lineNumber);

View File

@ -125,6 +125,8 @@ typedef struct {
v8::Platform *v8platform;
switch_hash_t *compiled_script_hash;
switch_mutex_t *compiled_script_hash_mutex;
map<string, Isolate *> *task_manager;
switch_mutex_t *task_manager_mutex;
char *script_caching;
switch_time_t cache_expires_seconds;
bool performance_monitor;
@ -607,7 +609,7 @@ static int v8_parse_and_execute(switch_core_session_t *session, const char *inpu
JSMain *js;
Isolate *isolate;
char *arg, *argv[512];
int argc = 0, x = 0, y = 0;
int argc = 0;
unsigned int flags = 0;
char *path = NULL;
string result_string;
@ -642,7 +644,26 @@ static int v8_parse_and_execute(switch_core_session_t *session, const char *inpu
HandleScope scope(isolate);
// Store our object internally
isolate->SetData(0, js);
isolate->SetData(ISOLATE_DATA_OBJECT, js);
// Set isolate related data.
switch_uuid_t task_id;
switch_uuid_get(&task_id);
char str_task_id[SWITCH_UUID_FORMATTED_LENGTH + 1];
switch_uuid_format(str_task_id, &task_id);
js_isolate_private_data_t *private_data = new js_isolate_private_data_t();
private_data->str_task_id = str_task_id;
private_data->input_code = input_code;
private_data->start_time = switch_time_now();
// Store private data internally
isolate->SetData(ISOLATE_DATA_PRIVATE, private_data);
// Add isolate to the task manager
switch_mutex_lock(globals.task_manager_mutex);
(*globals.task_manager)[str_task_id] = isolate;
switch_mutex_unlock(globals.task_manager_mutex);
// New global template
Handle<ObjectTemplate> global = ObjectTemplate::New(isolate);
@ -650,9 +671,6 @@ static int v8_parse_and_execute(switch_core_session_t *session, const char *inpu
if (global.IsEmpty()) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to create JS global object template\n");
} else {
/* Function to print current V8 version */
global->Set(String::NewFromUtf8(isolate, "version"), FunctionTemplate::New(isolate, JSMain::Version));
/* Add all global functions */
for (size_t i = 0; i < js->GetExtenderFunctions().size(); i++) {
js_function_t *proc = js->GetExtenderFunctions()[i];
@ -670,7 +688,7 @@ static int v8_parse_and_execute(switch_core_session_t *session, const char *inpu
#ifdef V8_ENABLE_DEBUGGING
Persistent<Context> *debug_context = new Persistent<Context>();
isolate->SetData(1, debug_context);
isolate->SetData(ISOLATE_DATA_DEBUG, debug_context);
debug_context->Reset(isolate, context);
//v8::Locker lck(isolate);
@ -749,7 +767,7 @@ static int v8_parse_and_execute(switch_core_session_t *session, const char *inpu
// Add arguments before running script.
Local<Array> arguments = Array::New(isolate, argc);
for (y = 0; y < argc; y++) {
for (int y = 0; y < argc; y++) {
arguments->Set(Integer::New(isolate, y), String::NewFromUtf8(isolate, argv[y]));
}
context->Global()->Set(String::NewFromUtf8(isolate, "argv"), arguments);
@ -786,11 +804,11 @@ static int v8_parse_and_execute(switch_core_session_t *session, const char *inpu
if (!script_data) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No script to execute!\n");
} else {
/* Store our base directoy in variable 'scriptPath' */
char *path = v8_get_script_path(script_file);
if (path) {
context->Global()->Set(String::NewFromUtf8(isolate, "scriptPath"), String::NewFromUtf8(isolate, path));
free(path);
/* Store our base directory in variable 'scriptPath' */
char *scriptPath = v8_get_script_path(script_file);
if (scriptPath) {
context->Global()->Set(String::NewFromUtf8(isolate, "scriptPath"), String::NewFromUtf8(isolate, scriptPath));
switch_safe_free(scriptPath);
}
TryCatch try_catch(isolate);
@ -818,10 +836,10 @@ static int v8_parse_and_execute(switch_core_session_t *session, const char *inpu
#endif
#if defined(V8_MAJOR_VERSION) && V8_MAJOR_VERSION >=5
Handle<Value> result;
Handle<Value> script_result;
if (!v8_script.IsEmpty()) {
result = v8_script.ToLocalChecked()->Run();
script_result = v8_script.ToLocalChecked()->Run();
}
switch_mutex_lock(globals.mutex);
@ -842,9 +860,9 @@ static int v8_parse_and_execute(switch_core_session_t *session, const char *inpu
switch_log_printf(SWITCH_CHANNEL_ID_LOG, js->GetForcedTerminationScriptFile(), modname, js->GetForcedTerminationLineNumber(), NULL, SWITCH_LOG_NOTICE, "Script exited with info [%s]\n", js->GetForcedTerminationMessage());
}
if (!result.IsEmpty()) {
if (!script_result.IsEmpty()) {
// Return result as string
String::Utf8Value ascii(result);
String::Utf8Value ascii(script_result);
if (*ascii) {
res = *ascii;
}
@ -868,7 +886,7 @@ static int v8_parse_and_execute(switch_core_session_t *session, const char *inpu
#endif
}
#ifdef V8_ENABLE_DEBUGGING
isolate->SetData(1, NULL);
isolate->SetData(ISOLATE_DATA_DEBUG, NULL);
if (debug_listen_port > 0) {
Debug::DisableAgent();
}
@ -877,7 +895,16 @@ static int v8_parse_and_execute(switch_core_session_t *session, const char *inpu
#endif
}
}
isolate->SetData(0, NULL);
// Remove isolate from the task manager
switch_mutex_lock(globals.task_manager_mutex);
globals.task_manager->erase(str_task_id);
switch_mutex_unlock(globals.task_manager_mutex);
isolate->SetData(ISOLATE_DATA_PRIVATE, NULL);
isolate->SetData(ISOLATE_DATA_OBJECT, NULL);
delete private_data;
}
#ifdef V8_FORCE_GC_AFTER_EXECUTION
@ -1178,6 +1205,279 @@ SWITCH_STANDARD_API(jsmon_function)
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(kill_function)
{
if (!zstr(cmd)) {
switch_mutex_lock(globals.task_manager_mutex);
auto isolate_it = globals.task_manager->find(cmd);
if (isolate_it != globals.task_manager->end()) {
Isolate * isolate = isolate_it->second;
JSMain *js = JSMain::GetScriptInstanceFromIsolate(isolate);
if (js)
js->ExitScript(isolate, "Script termination requested by jskill API.", true);
}
switch_mutex_unlock(globals.task_manager_mutex);
stream->write_function(stream, "+OK\n");
}
else {
stream->write_function(stream, "false");
}
return SWITCH_STATUS_SUCCESS;
}
inline static void stream_write_safe_d(switch_stream_handle_t *stream, const char *str) {
if (!str) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
stream->write_function(stream, "-ERR Memory Error!\n");
}
else {
stream->write_function(stream, "%s", str);
}
}
#define stream_write_safe(output_text) stream_write_safe_d(stream, output_text)
SWITCH_STANDARD_API(process_status_function)
{
char *mydata = NULL, *argv[3] = { 0 };
char *as = NULL, *output_text = NULL, *delim = ",";
cJSON *json = NULL, *row;
switch_xml_t xml = NULL, xml_row, xml_field;
int rows = 0, f_off = 0, count = 0;
char tmp_str[50];
std::vector<js_isolate_private_data_t> tasks;
if (cmd && *cmd && (mydata = strdup(cmd))) {
switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
if (argv[1] && !strcasecmp(argv[0], "as")) {
as = argv[1];
if (!strcasecmp(as, "csv")) {
if (argv[2]) delim = argv[2];
}
}
}
if (!as) {
as = "plain";
}
if (!strcasecmp(as, "json")) {
if (!(json = cJSON_CreateArray())) {
goto end;
}
} else if (!strcasecmp(as, "xml")) {
if (!(xml = switch_xml_new("result"))) {
goto end;
}
} else if (!strcasecmp(as, "delim") || !strcasecmp(as, "csv")) {
stream->write_function(stream, "%s%s", "task_id", delim);
stream->write_function(stream, "%s%s", "input_code", delim);
stream->write_function(stream, "%s%s", "execution_time", delim);
stream->write_function(stream, "%s%s", "total_physical_size", delim);
stream->write_function(stream, "%s%s", "total_heap_size_executable", delim);
stream->write_function(stream, "%s%s", "total_heap_size", delim);
stream->write_function(stream, "%s%s", "used_heap_size", delim);
stream->write_function(stream, "%s%s", "heap_size_limit", delim);
stream->write_function(stream, "%s%s", "malloced_memory", delim);
stream->write_function(stream, "%s%s", "peak_malloced_memory", "\n");
} else {
stream->write_function(stream, "JavaScript process status.\n");
}
switch_mutex_lock(globals.task_manager_mutex);
for (auto isolate_pair : *globals.task_manager) {
Isolate *isolate = isolate_pair.second;
js_isolate_private_data_t *isolate_private_data = (js_isolate_private_data_t*)isolate->GetData(ISOLATE_DATA_PRIVATE);
js_isolate_private_data_t private_data = *isolate_private_data;
isolate->GetHeapStatistics(&private_data.stats);
tasks.push_back(private_data);
}
switch_mutex_unlock(globals.task_manager_mutex);
for (auto isolate_private_data : tasks) {
count++;
js_isolate_private_data_t *private_data = (js_isolate_private_data_t *)&(isolate_private_data);
switch_time_t end = switch_time_now();
unsigned int delay = (end - private_data->start_time) / 1000;
if (!strcasecmp(as, "plain")) {
stream->write_function(stream, "\nTask id: %s\n", private_data->str_task_id.c_str());
stream->write_function(stream, "input_code: %s\n", (private_data->input_code[0] == '~' ? "inline" : private_data->input_code.c_str()));
stream->write_function(stream, "execution_time: %u ms\n", delay);
stream->write_function(stream, "total_physical_size: %u\n", private_data->stats.total_physical_size());
stream->write_function(stream, "total_heap_size_executable: %u\n", private_data->stats.total_heap_size_executable());
stream->write_function(stream, "total_heap_size: %u\n", private_data->stats.total_heap_size());
stream->write_function(stream, "used_heap_size: %u\n", private_data->stats.used_heap_size());
stream->write_function(stream, "heap_size_limit: %u\n", private_data->stats.heap_size_limit());
stream->write_function(stream, "malloced_memory: %u\n", private_data->stats.malloced_memory());
stream->write_function(stream, "peak_malloced_memory: %u\n", private_data->stats.peak_malloced_memory());
} else if (!strcasecmp(as, "json")) {
if (!(row = cJSON_CreateObject())) {
goto end;
}
cJSON_AddItemToArray(json, row);
cJSON_AddItemToObject(row, "task_id", cJSON_CreateString(private_data->str_task_id.c_str()));
cJSON_AddItemToObject(row, "input_code", cJSON_CreateString((private_data->input_code[0] == '~' ? "inline" : private_data->input_code.c_str())));
cJSON_AddItemToObject(row, "execution_time", cJSON_CreateNumber(delay));
cJSON_AddItemToObject(row, "total_physical_size", cJSON_CreateNumber(private_data->stats.total_physical_size()));
cJSON_AddItemToObject(row, "total_heap_size_executable", cJSON_CreateNumber(private_data->stats.total_heap_size_executable()));
cJSON_AddItemToObject(row, "total_heap_size", cJSON_CreateNumber(private_data->stats.total_heap_size()));
cJSON_AddItemToObject(row, "used_heap_size", cJSON_CreateNumber(private_data->stats.used_heap_size()));
cJSON_AddItemToObject(row, "heap_size_limit", cJSON_CreateNumber(private_data->stats.heap_size_limit()));
cJSON_AddItemToObject(row, "malloced_memory", cJSON_CreateNumber(private_data->stats.malloced_memory()));
cJSON_AddItemToObject(row, "peak_malloced_memory", cJSON_CreateNumber(private_data->stats.peak_malloced_memory()));
} else if (!strcasecmp(as, "delim") || !strcasecmp(as, "csv")) {
stream->write_function(stream, "%s%s", private_data->str_task_id.c_str(), delim);
stream->write_function(stream, "%s%s", (private_data->input_code[0] == '~' ? "inline" : private_data->input_code.c_str()), delim);
switch_snprintf(tmp_str, sizeof(tmp_str), "%u", delay);
stream->write_function(stream, "%s%s", tmp_str, delim);
switch_snprintf(tmp_str, sizeof(tmp_str), "%u", private_data->stats.total_physical_size());
stream->write_function(stream, "%s%s", tmp_str, delim);
switch_snprintf(tmp_str, sizeof(tmp_str), "%u", private_data->stats.total_heap_size_executable());
stream->write_function(stream, "%s%s", tmp_str, delim);
switch_snprintf(tmp_str, sizeof(tmp_str), "%u", private_data->stats.total_heap_size());
stream->write_function(stream, "%s%s", tmp_str, delim);
switch_snprintf(tmp_str, sizeof(tmp_str), "%u", private_data->stats.used_heap_size());
stream->write_function(stream, "%s%s", tmp_str, delim);
switch_snprintf(tmp_str, sizeof(tmp_str), "%u", private_data->stats.heap_size_limit());
stream->write_function(stream, "%s%s", tmp_str, delim);
switch_snprintf(tmp_str, sizeof(tmp_str), "%u", private_data->stats.malloced_memory());
stream->write_function(stream, "%s%s", tmp_str, delim);
switch_snprintf(tmp_str, sizeof(tmp_str), "%u", private_data->stats.peak_malloced_memory());
stream->write_function(stream, "%s%s", tmp_str, "\n");
} else if (!strcasecmp(as, "xml")) {
if (!(xml_row = switch_xml_add_child_d(xml, "row", rows++))) {
goto end;
}
switch_snprintf(tmp_str, sizeof(tmp_str), "%d", rows);
switch_xml_set_attr(switch_xml_set_flag(xml_row, SWITCH_XML_DUP), strdup("row_id"), strdup(tmp_str));
if (!(xml_field = switch_xml_add_child_d(xml_row, "task_id", f_off++))) {
goto end;
}
switch_xml_set_txt_d(xml_field, private_data->str_task_id.c_str());
if (!(xml_field = switch_xml_add_child_d(xml_row, "input_code", f_off++))) {
goto end;
}
switch_xml_set_txt_d(xml_field, (private_data->input_code[0] == '~' ? "inline" : private_data->input_code.c_str()));
if (!(xml_field = switch_xml_add_child_d(xml_row, "execution_time", f_off++))) {
goto end;
}
switch_snprintf(tmp_str, sizeof(tmp_str), "%u", delay);
switch_xml_set_txt_d(xml_field, tmp_str);
if (!(xml_field = switch_xml_add_child_d(xml_row, "total_physical_size", f_off++))) {
goto end;
}
switch_snprintf(tmp_str, sizeof(tmp_str), "%u", private_data->stats.total_physical_size());
switch_xml_set_txt_d(xml_field, tmp_str);
if (!(xml_field = switch_xml_add_child_d(xml_row, "total_heap_size_executable", f_off++))) {
goto end;
}
switch_snprintf(tmp_str, sizeof(tmp_str), "%u", private_data->stats.total_heap_size_executable());
switch_xml_set_txt_d(xml_field, tmp_str);
if (!(xml_field = switch_xml_add_child_d(xml_row, "total_heap_size", f_off++))) {
goto end;
}
switch_snprintf(tmp_str, sizeof(tmp_str), "%u", private_data->stats.total_heap_size());
switch_xml_set_txt_d(xml_field, tmp_str);
if (!(xml_field = switch_xml_add_child_d(xml_row, "used_heap_size", f_off++))) {
goto end;
}
switch_snprintf(tmp_str, sizeof(tmp_str), "%u", private_data->stats.used_heap_size());
switch_xml_set_txt_d(xml_field, tmp_str);
if (!(xml_field = switch_xml_add_child_d(xml_row, "heap_size_limit", f_off++))) {
goto end;
}
switch_snprintf(tmp_str, sizeof(tmp_str), "%u", private_data->stats.heap_size_limit());
switch_xml_set_txt_d(xml_field, tmp_str);
if (!(xml_field = switch_xml_add_child_d(xml_row, "malloced_memory", f_off++))) {
goto end;
}
switch_snprintf(tmp_str, sizeof(tmp_str), "%u", private_data->stats.malloced_memory());
switch_xml_set_txt_d(xml_field, tmp_str);
if (!(xml_field = switch_xml_add_child_d(xml_row, "peak_malloced_memory", f_off++))) {
goto end;
}
switch_snprintf(tmp_str, sizeof(tmp_str), "%u", private_data->stats.peak_malloced_memory());
switch_xml_set_txt_d(xml_field, tmp_str);
}
}
if (!strcasecmp(as, "json")) {
cJSON *result;
if (!(result = cJSON_CreateObject())) {
stream->write_function(stream, "-ERR Error creating json object!\n");
goto end;
}
else {
cJSON_AddItemToObject(result, "row_count", cJSON_CreateNumber(count));
cJSON_AddItemToObject(result, "rows", json);
output_text = cJSON_PrintUnformatted(result);
json = result;
}
stream_write_safe(output_text);
} else if (!strcasecmp(as, "xml")) {
switch_snprintf(tmp_str, sizeof(tmp_str), "%u", count);
switch_xml_set_attr(switch_xml_set_flag(xml, SWITCH_XML_DUP), strdup("row_count"), strdup(tmp_str));
output_text = switch_xml_toxml(xml, SWITCH_FALSE);
stream_write_safe(output_text);
} else if (!strcasecmp(as, "delim") || !strcasecmp(as, "csv")) {
stream->write_function(stream, "%s%u total.%s", "\n", count, "\n");
}
end:
switch_xml_free(xml);
cJSON_Delete(json);
switch_safe_free(output_text);
switch_safe_free(mydata);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_MODULE_LOAD_FUNCTION(mod_v8_load)
{
switch_application_interface_t *app_interface;
@ -1193,12 +1493,15 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_v8_load)
#if defined(V8_MAJOR_VERSION) && V8_MAJOR_VERSION >=5
switch_mutex_init(&globals.compiled_script_hash_mutex, SWITCH_MUTEX_NESTED, globals.pool);
switch_mutex_init(&globals.task_manager_mutex, SWITCH_MUTEX_NESTED, globals.pool);
switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, globals.pool);
#endif
switch_mutex_init(&globals.event_mutex, SWITCH_MUTEX_NESTED, globals.pool);
globals.event_handlers = new set<FSEventHandler *>();
if (load_modules() != SWITCH_STATUS_SUCCESS) {
delete globals.event_handlers;
switch_event_unbind(&globals.event_node);
return SWITCH_STATUS_FALSE;
}
@ -1211,6 +1514,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_v8_load)
JSMain::Initialize(&globals.v8platform);
switch_core_hash_init(&globals.compiled_script_hash);
globals.task_manager = new map<string, Isolate *>();
#else
JSMain::Initialize();
#endif
@ -1234,6 +1538,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_v8_load)
SWITCH_ADD_API(jsrun_interface, "jsrun", "run a script", launch_async, "jsrun <script> [additional_vars [...]]");
SWITCH_ADD_API(jsapi_interface, "jsapi", "execute an api call", jsapi_function, "jsapi <script> [additional_vars [...]]");
SWITCH_ADD_API(jsmon_interface, "jsmon", "toggle performance monitor", jsmon_function, "jsmon on|off");
SWITCH_ADD_API(jsrun_interface, "jsps", "process status", process_status_function, "jsps [as plain|json|xml|delim|csv [<delimeter>]]");
SWITCH_ADD_API(jsrun_interface, "jskill", "kill a task", kill_function, "jskill <task_id>");
SWITCH_ADD_APP(app_interface, "javascript", "Launch JS ivr", "Run a javascript ivr on a channel", v8_dp_function, "<script> [additional_vars [...]]", SAF_SUPPORT_NOMEDIA);
SWITCH_ADD_CHAT_APP(chat_app_interface, "javascript", "execute a js script", "execute a js script", v8_chat_function, "<script>", SCAF_NONE);
@ -1257,6 +1563,8 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_v8_shutdown)
switch_core_hash_destroy(&globals.compiled_script_hash);
switch_mutex_destroy(globals.compiled_script_hash_mutex);
switch_mutex_destroy(globals.task_manager_mutex);
delete globals.task_manager;
switch_mutex_destroy(globals.mutex);
#endif

View File

@ -83,6 +83,19 @@ typedef struct {
}
v8_event_t;
#define ISOLATE_DATA_OBJECT 0
#define ISOLATE_DATA_DEBUG 1
#define ISOLATE_DATA_PRIVATE 2
/* Isolate Private Data */
typedef struct {
std::string str_task_id; /* JavaScript task id */
std::string input_code; /* Path to JavaScript source */
switch_time_t start_time; /* Script start_time */
v8::HeapStatistics stats;
} js_isolate_private_data_t;
SWITCH_END_EXTERN_C
void v8_add_event_handler(void *event_handler);

View File

@ -748,6 +748,19 @@ JS_GLOBAL_FUNCTION_IMPL_STATIC(FileDelete)
info.GetIsolate()->ThrowException(String::NewFromUtf8(info.GetIsolate(), "Invalid arguments"));
}
/* Internal Version function accessable from JS - used to get the current V8 version */
JS_GLOBAL_FUNCTION_IMPL_STATIC(Version)
{
info.GetReturnValue().Set(String::NewFromUtf8(info.GetIsolate(), V8::GetVersion()));
}
/* TaskId assigned to the script - used to manage the task */
JS_GLOBAL_FUNCTION_IMPL_STATIC(Id)
{
js_isolate_private_data_t *private_data = (js_isolate_private_data_t*)info.GetIsolate()->GetData(ISOLATE_DATA_PRIVATE);
info.GetReturnValue().Set(String::NewFromUtf8(info.GetIsolate(), private_data->str_task_id.c_str()));
}
static const js_function_t fs_proc[] = {
{"console_log", FSGlobal::Log}, // Deprecated
{"consoleLog", FSGlobal::Log},
@ -770,6 +783,8 @@ static const js_function_t fs_proc[] = {
{"fetchUrl", FSGlobal::FetchURL},
{"fetchUrlHash", FSGlobal::FetchURLHash},
{"fetchUrlFile", FSGlobal::FetchURLFile},
{"id", FSGlobal::Id },
{"version", FSGlobal::Version},
{0}
};

View File

@ -264,11 +264,6 @@ void JSMain::Log(const v8::FunctionCallbackInfo<Value>& args)
args.GetReturnValue().Set(Undefined(args.GetIsolate()));
}
void JSMain::Version(const v8::FunctionCallbackInfo<Value>& args)
{
args.GetReturnValue().Set(String::NewFromUtf8(args.GetIsolate(), V8::GetVersion()));
}
const string JSMain::ExecuteScript(const string& filename, bool *resultIsError)
{
// Get the file and load into a string.
@ -553,7 +548,7 @@ int JSMain::GetForcedTerminationLineNumber(void)
return forcedTerminationLineNumber;
}
void JSMain::ExitScript(Isolate *isolate, const char *msg)
void JSMain::ExitScript(Isolate *isolate, const char *msg, bool jskill)
{
if (!isolate) {
return;
@ -580,7 +575,10 @@ void JSMain::ExitScript(Isolate *isolate, const char *msg)
js_strdup(js->forcedTerminationMessage, msg);
}
js->forcedTerminationScriptFile = GetStackInfo(isolate, &js->forcedTerminationLineNumber);
/* When forcefully killed, don't call GetStackInfo() because isolate is locked by another thread */
if (!jskill) {
js->forcedTerminationScriptFile = GetStackInfo(isolate, &js->forcedTerminationLineNumber);
}
}
isolate->TerminateExecution();