github.com/igggame/nebulas-go@v2.1.0+incompatible/nf/nvm/v8/thread_engine.cc (about) 1 // Copyright (C) 2017 go-nebulas authors 2 // 3 // This file is part of the go-nebulas library. 4 // 5 // the go-nebulas library is free software: you can redistribute it and/or 6 // modify it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // the go-nebulas library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with the go-nebulas library. If not, see 17 // <http://www.gnu.org/licenses/>. 18 // 19 20 #include "engine.h" 21 #include "engine_int.h" 22 #include "lib/tracing.h" 23 #include "lib/typescript.h" 24 #include "lib/logger.h" 25 #include "lib/nvm_error.h" 26 27 #include <assert.h> 28 #include <string.h> 29 #include <stdio.h> 30 // #include <stdlib.h> 31 #include <stdlib.h> 32 #include <thread> 33 #include <sys/time.h> 34 #include <unistd.h> 35 #define MicroSecondDiff(newtv, oldtv) (1000000 * (unsigned long long)((newtv).tv_sec - (oldtv).tv_sec) + (newtv).tv_usec - (oldtv).tv_usec) //微秒 36 #define CodeExecuteErr 1 37 #define CodeExecuteInnerNvmErr 2 38 #define CodeTimeOut 3 39 40 void SetRunScriptArgs(v8ThreadContext *ctx, V8Engine *e, int opt, const char *source, int line_offset, int allow_usage) { 41 ctx->e = e; 42 ctx->input.source = source; 43 ctx->input.opt = (OptType)opt; 44 ctx->input.allow_usage = allow_usage; 45 ctx->input.line_offset = line_offset; 46 } 47 48 char *InjectTracingInstructionsThread(V8Engine *e, const char *source, 49 int *source_line_offset, 50 int allow_usage) { 51 v8ThreadContext ctx; 52 memset(&ctx, 0x00, sizeof(ctx)); 53 SetRunScriptArgs(&ctx, e, INSTRUCTION, source, *source_line_offset, allow_usage); 54 bool btn = CreateScriptThread(&ctx); 55 if (btn == false) { 56 LogErrorf("Failed to create script thread"); 57 return NULL; 58 } 59 *source_line_offset = ctx.output.line_offset; 60 return ctx.output.result; 61 } 62 63 char *TranspileTypeScriptModuleThread(V8Engine *e, const char *source, 64 int *source_line_offset) { 65 v8ThreadContext ctx; 66 memset(&ctx, 0x00, sizeof(ctx)); 67 SetRunScriptArgs(&ctx, e, INSTRUCTIONTS, source, *source_line_offset, 1); 68 bool btn = CreateScriptThread(&ctx); 69 if (btn == false) { 70 return NULL; 71 } 72 *source_line_offset = ctx.output.line_offset; 73 return ctx.output.result; 74 } 75 int RunScriptSourceThread(char **result, V8Engine *e, const char *source, 76 int source_line_offset, uintptr_t lcs_handler, 77 uintptr_t gcs_handler) { 78 v8ThreadContext ctx; 79 memset(&ctx, 0x00, sizeof(ctx)); 80 SetRunScriptArgs(&ctx, e, RUNSCRIPT, source, source_line_offset, 1); 81 ctx.input.lcs = lcs_handler; 82 ctx.input.gcs = gcs_handler; 83 84 bool btn = CreateScriptThread(&ctx); 85 if (btn == false) { 86 return NVM_UNEXPECTED_ERR; 87 } 88 89 *result = ctx.output.result; 90 return ctx.output.ret; 91 } 92 93 void *ExecuteThread(void *args) { 94 v8ThreadContext *ctx = (v8ThreadContext*)args; 95 if (ctx->input.opt == INSTRUCTION) { 96 TracingContext tContext; 97 tContext.source_line_offset = 0; 98 tContext.tracable_source = NULL; 99 tContext.strictDisallowUsage = ctx->input.allow_usage; 100 101 Execute(NULL, ctx->e, ctx->input.source, 0, 0L, 0L, InjectTracingInstructionDelegate, 102 (void *)&tContext); 103 104 ctx->output.line_offset = tContext.source_line_offset; 105 ctx->output.result = static_cast<char *>(tContext.tracable_source); 106 } else if (ctx->input.opt == INSTRUCTIONTS) { 107 TypeScriptContext tContext; 108 tContext.source_line_offset = 0; 109 tContext.js_source = NULL; 110 111 Execute(NULL, ctx->e, ctx->input.source, 0, 0L, 0L, TypeScriptTranspileDelegate, 112 (void *)&tContext); 113 114 ctx->output.line_offset = tContext.source_line_offset; 115 ctx->output.result = static_cast<char *>(tContext.js_source); 116 } else { 117 ctx->output.ret = Execute(&ctx->output.result, ctx->e, ctx->input.source, ctx->input.line_offset, (void *)ctx->input.lcs, 118 (void *)ctx->input.gcs, ExecuteSourceDataDelegate, NULL); 119 // printf("iRtn:%d--result:%s\n", ctx->output.ret, ctx->output.result); 120 } 121 122 ctx->is_finished = true; 123 return 0x00; 124 } 125 // return : success return true. if hava err ,then return false. and not need to free heap 126 // if gettimeofday hava err ,There is a risk of an infinite loop 127 bool CreateScriptThread(v8ThreadContext *ctx) { 128 pthread_t thread; 129 pthread_attr_t attribute; 130 pthread_attr_init(&attribute); 131 pthread_attr_setstacksize(&attribute, 2 * 1024 * 1024); 132 pthread_attr_setdetachstate (&attribute, PTHREAD_CREATE_DETACHED); 133 struct timeval tcBegin, tcEnd; 134 int rtn = gettimeofday(&tcBegin, NULL); 135 if (rtn != 0) { 136 LogErrorf("CreateScriptThread get start time err:%d\n", rtn); 137 return false; 138 } 139 rtn = pthread_create(&thread, &attribute, ExecuteThread, (void *)ctx); 140 if (rtn != 0) { 141 LogErrorf("CreateScriptThread pthread_create err:%d\n", rtn); 142 return false; 143 } 144 145 int timeout = ctx->e->timeout; 146 bool is_kill = false; 147 //thread safe 148 while(1) { 149 if (ctx->is_finished == true) { 150 if (is_kill == true) { 151 ctx->output.ret = NVM_EXE_TIMEOUT_ERR; 152 // ctx->output.ret = CodeTimeOut; 153 } 154 else if (ctx->e->is_inner_nvm_error_happen == 1) { 155 ctx->output.ret = NVM_INNER_EXE_ERR; 156 } 157 break; 158 } else { 159 usleep(10); //10 micro second loop .epoll_wait optimize 160 rtn = gettimeofday(&tcEnd, NULL); 161 if (rtn) { 162 LogErrorf("CreateScriptThread get end time err:%d\n", rtn); 163 continue; 164 } 165 int diff = MicroSecondDiff(tcEnd, tcBegin); 166 167 if (diff >= timeout && is_kill == false) { 168 LogErrorf("CreateScriptThread timeout timeout:%d diff:%d\n", timeout, diff); 169 TerminateExecution(ctx->e); 170 is_kill = true; 171 } 172 } 173 } 174 return true; 175 }