Changeset 14637 for trunk/FACT++


Ignore:
Timestamp:
11/17/12 14:36:27 (12 years ago)
Author:
tbretz
Message:
Re-did (once more) the exception handling and script termination to allow to cancel a timeout thread properly. Added dim.kill to do that.
Location:
trunk/FACT++/src
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/FACT++/src/InterpreterV8.cc

    r14634 r14637  
    8484// ==========================================================================
    8585
    86 void InterpreterV8::Terminate()
    87 {
    88     if (!Locker::IsLocked())
    89         JsException("***** InterprterV8::Terminate call not locked *****");
    90 
    91     for (auto it=fThreadIds.begin(); it!=fThreadIds.end(); it++)
    92         V8::TerminateExecution(*it);
    93     fThreadIds.clear();
    94 
    95     if (fThreadId>=0)
    96     {
    97         V8::TerminateExecution(fThreadId);
    98         fThreadId = -1;
    99     }
    100 }
    101 
    10286Handle<Value> InterpreterV8::FuncExit(const Arguments &)
    10387{
    104     Terminate();
    105     return ThrowException(String::New("exit"));
     88    V8::TerminateExecution(fThreadId);
     89    return Undefined();
    10690}
    10791
     
    135119}
    136120
    137 void InterpreterV8::ThreadTimeout(Persistent<Function> func, uint32_t ms)
     121void InterpreterV8::ThreadTimeout(int &id, Persistent<Function> func, uint32_t ms)
    138122{
    139123    const Locker lock;
    140124
    141125    if (fThreadId<0)
     126    {
     127        id = -1;
    142128        return;
    143 
    144     const int id = V8::GetCurrentThreadId();
     129    }
     130
     131    id = V8::GetCurrentThreadId();
    145132    fThreadIds.insert(id);
    146133
     
    161148    fThreadIds.erase(id);
    162149
    163     if (!exception.HasCaught())
    164         return;
    165 
    166     ReportException(&exception);
    167     Terminate();
     150    if (!HandleException(exception, "dim.timeout"))
     151        V8::TerminateExecution(fThreadId);
    168152}
    169153
     
    190174    const uint32_t ms = args[0]->Uint32Value();
    191175
    192     fTimeout.push_back(thread(bind(&InterpreterV8::ThreadTimeout, this, func, ms)));
    193     return Undefined();
     176    int id=-2;
     177    fTimeout.push_back(thread(bind(&InterpreterV8::ThreadTimeout, this, ref(id), func, ms)));
     178    {
     179        const Unlocker unlock;
     180        while (id==-2)
     181            usleep(1);
     182    }
     183
     184    return Integer::New(id);
     185}
     186
     187Handle<Value> InterpreterV8::FuncKill(const Arguments& args)
     188{
     189    for (int i=0; i<args.Length(); i++)
     190        if (!args[i]->IsInt32())
     191            return ThrowException(String::New("All arguments must be int32."));
     192
     193    uint32_t cnt = 0;
     194
     195    for (int i=0; i<args.Length(); i++)
     196    {
     197        V8::TerminateExecution(args[i]->Int32Value());
     198        cnt += fThreadIds.erase(args[i]->Int32Value());
     199    }
     200
     201    return Integer::New(cnt);
    194202}
    195203
     
    9951003    const HandleScope handle_scope;
    9961004
    997     Persistent<Object> obj = it->second;
     1005    Handle<Object> obj = it->second;
    9981006
    9991007    obj->CreationContext()->Enter();
     
    10241032    fThreadIds.erase(id);
    10251033
    1026     if (exception.HasCaught())
    1027         ReportException(&exception);
     1034    if (!HandleException(exception, "Service.onchange"))
     1035        V8::TerminateExecution(fThreadId);
     1036    //Terminate();
    10281037
    10291038    if (ret->IsNativeError())
     1039    {
    10301040        JsException(service+".onchange callback - "+*String::Utf8Value(ret));
    1031 
    1032     if (ret->IsUndefined() || ret->IsNativeError() || exception.HasCaught())
    1033         Terminate();
     1041        V8::TerminateExecution(fThreadId);
     1042//Terminate();
     1043    }
     1044
     1045    //if (ret->IsUndefined() || ret->IsNativeError()/* || exception.HasCaught()*/)
    10341046}
    10351047
     
    10971109    fThreadIds.erase(id);
    10981110
    1099     if (!exception.HasCaught())
    1100         return;
    1101 
    1102     ReportException(&exception);
    1103     Terminate();
     1111    if (!HandleException(exception, "dim.onchange"))
     1112        V8::TerminateExecution(fThreadId);
     1113    //Terminate();
    11041114}
    11051115
     
    14401450// ==========================================================================
    14411451
    1442 bool InterpreterV8::ReportException(TryCatch* try_catch)
    1443 {
    1444     if (!try_catch->CanContinue())
    1445         return false;
     1452bool InterpreterV8::HandleException(TryCatch& try_catch, const char *where)
     1453{
     1454    if (!try_catch.HasCaught() || !try_catch.CanContinue())
     1455        return true;
    14461456
    14471457    const HandleScope handle_scope;
    14481458
    1449     const String::Utf8Value exception(try_catch->Exception());
    1450 
    1451     if (*exception && string(*exception)=="exit")
     1459    Handle<Value> except = try_catch.Exception();
     1460    if (except.IsEmpty() || except->IsNull())
    14521461        return true;
    1453     if (*exception && string(*exception)=="null")
    1454         return false;
    1455 
    1456     const Handle<Message> message = try_catch->Message();
     1462
     1463    const String::Utf8Value exception(except);
     1464
     1465    const Handle<Message> message = try_catch.Message();
    14571466    if (message.IsEmpty())
    14581467        return false;
     
    14651474        const String::Utf8Value filename(message->GetScriptResourceName());
    14661475
    1467         if (*filename)
    1468             out << *filename << ": ";
    1469         out << "l." << message->GetLineNumber();
     1476        out << *filename;
     1477        if (message->GetLineNumber()>0)
     1478            out << ": l." << message->GetLineNumber();
    14701479        if (*exception)
    14711480            out << ": ";
    14721481    }
    14731482
    1474     // -------------- SKIP if 'internal' and 'Error' ---------------
    14751483    if (*exception)
    14761484        out << *exception;
     1485
     1486    out << " [" << where << "]";
    14771487
    14781488    JsException(out.str());
     
    14821492    if (*sourceline)
    14831493        JsException(*sourceline);
    1484     // -------------- SKIP if 'internal' and 'Error: ' ---------------
    14851494
    14861495    // Print wavy underline (GetUnderline is deprecated).
     
    14951504    JsException(out.str());
    14961505
    1497     const String::Utf8Value stack_trace(try_catch->StackTrace());
     1506    const String::Utf8Value stack_trace(try_catch.StackTrace());
    14981507    if (stack_trace.length()<=0)
    14991508        return false;
     
    15471556        JsSetState(3);
    15481557
     1558    TryCatch exception;
     1559
    15491560    const Handle<Value> result = script->Run();
    1550     if (result.IsEmpty())
    1551         return Handle<Value>();
     1561
     1562    if (exception.HasCaught())
     1563    {
     1564        if (file=="internal")
     1565            return exception.ReThrow();
     1566
     1567        HandleException(exception, "code");
     1568        return Undefined();
     1569    }
    15521570
    15531571    // If all went well and the result wasn't undefined then print
    15541572    // the returned value.
    1555     if (!result->IsUndefined())
     1573    if (!result.IsEmpty() && result->IsUndefined())
    15561574        JsResult(*String::Utf8Value(result));
    15571575
     
    15961614
    15971615
    1598 void InterpreterV8::AddFormatToGlobal() const
     1616void InterpreterV8::AddFormatToGlobal()// const
    15991617{
    16001618    const string code =
     
    16511669        "}"*/;
    16521670
     1671    // ExcuteInternal does not work properly here...
     1672    // If suring compilation an exception is thrown, it will not work
    16531673    Handle<Script> script = Script::New(String::New(code.c_str()), String::New("internal"));
    16541674    if (!script.IsEmpty())
     
    16831703    dim->Set(String::New("sleep"),     FunctionTemplate::New(WrapSleep),     ReadOnly);
    16841704    dim->Set(String::New("timeout"),   FunctionTemplate::New(WrapTimeout),   ReadOnly);
     1705    dim->Set(String::New("kill"),      FunctionTemplate::New(WrapKill),      ReadOnly);
    16851706    dim->Set(String::New("subscribe"), FunctionTemplate::New(WrapSubscribe), ReadOnly);
    16861707    dim->Set(String::New("file"),      FunctionTemplate::New(WrapFile),      ReadOnly);
     1708
     1709    // timeout   -> Thread  - class?
     1710    // subscribe -> Service - class?
     1711    // file      -> File    - class?
     1712    // new class State ?
     1713    // newState -> return State?
     1714    // setState -> return State?
     1715    // getState -> return State?
    16871716
    16881717    Handle<ObjectTemplate> onchange = ObjectTemplate::New();
     
    17281757    }
    17291758
     1759    // Switch off eval(). It is not possible to track it's exceptions.
     1760    context->AllowCodeGenerationFromStrings(false);
     1761
    17301762    Context::Scope scope(context);
    17311763
     
    17381770    //V8::ResumeProfiler();
    17391771
     1772    bool rc;
     1773
     1774    TryCatch exception;
     1775
    17401776    AddFormatToGlobal();
    17411777
    1742     JsStart(filename);
    1743 
    1744     //context->Enter();
    1745 
    1746     TryCatch exception;
    1747 
    1748     Locker::StartPreemption(10);
    1749     bool rc = ExecuteFile(filename, true);
    1750 
    1751     Locker::StopPreemption();
    1752 
    1753     Terminate();
    1754 
    1755     if (exception.HasCaught())
    1756         rc = ReportException(&exception);
     1778    if (!exception.HasCaught())
     1779    {
     1780        JsStart(filename);
     1781
     1782        Locker::StartPreemption(10);
     1783
     1784        rc = ExecuteFile(filename, true);
     1785
     1786        Locker::StopPreemption();
     1787
     1788        // Stop all other threads
     1789        for (auto it=fThreadIds.begin(); it!=fThreadIds.end(); it++)
     1790            V8::TerminateExecution(*it);
     1791        fThreadIds.clear();
     1792    }
     1793
     1794    // Handle an exception
     1795    rc = HandleException(exception, "main");
    17571796
    17581797    // IsProfilerPaused()
     
    17731812    //context->Exit();
    17741813
    1775     // Thre threads are started already and wait to get the lock
    1776     // So we have to unlock (manual preemtion) so they they get
    1777     // the signal to terminate. After they are all successfully
    1778     // terminated, just to be sure... we lock again
     1814    // The threads are started already and wait to get the lock
     1815    // So we have to unlock (manual preemtion) so that they get
     1816    // the signal to terminate.
    17791817    {
    17801818        const Unlocker unlock;
     
    18141852{
    18151853    Locker locker;
    1816     This->Terminate();
     1854    V8::TerminateExecution(This->fThreadId);
     1855    //This->Terminate();
    18171856}
    18181857
  • trunk/FACT++/src/InterpreterV8.h

    r14636 r14637  
    5050
    5151#ifdef HAVE_V8
    52     void Terminate();
    53 
    54     bool ReportException(v8::TryCatch* try_catch);
     52    bool HandleException(v8::TryCatch &try_catch, const char *where);
    5553    bool ExecuteFile(const std::string &name, bool main=false);
    5654    v8::Handle<v8::Value> ExecuteCode(const std::string &code, const std::string &file="internal", bool main=false);
    5755    v8::Handle<v8::Value> ExecuteInternal(const std::string &code);
    5856
    59     void ThreadTimeout(v8::Persistent<v8::Function> func, uint32_t ms);
     57    void ThreadTimeout(int &id, v8::Persistent<v8::Function> func, uint32_t ms);
    6058
    6159    v8::Handle<v8::Value> FuncWait(const v8::Arguments& args);
     
    6361    v8::Handle<v8::Value> FuncSleep(const v8::Arguments& args);
    6462    v8::Handle<v8::Value> FuncTimeout(const v8::Arguments& args);
     63    v8::Handle<v8::Value> FuncKill(const v8::Arguments& args);
    6564    v8::Handle<v8::Value> FuncPrint(const v8::Arguments& args);
    6665    v8::Handle<v8::Value> FuncAlarm(const v8::Arguments& args);
     
    108107    static v8::Handle<v8::Value> WrapSleep(const v8::Arguments &args)    { if (This) return This->FuncSleep(args);    else return v8::Undefined(); }
    109108    static v8::Handle<v8::Value> WrapTimeout(const v8::Arguments &args)  { if (This) return This->FuncTimeout(args);  else return v8::Undefined(); }
     109    static v8::Handle<v8::Value> WrapKill(const v8::Arguments &args)     { if (This) return This->FuncKill(args);     else return v8::Undefined(); }
    110110    static v8::Handle<v8::Value> WrapExit(const v8::Arguments &args)     { if (This) return This->FuncExit(args);     else return v8::Undefined(); }
    111111    static v8::Handle<v8::Value> WrapState(const v8::Arguments &args)    { if (This) return This->FuncState(args);    else return v8::Undefined(); }
     
    178178    void JsHandleState(const std::string &, const State &);
    179179
    180     void AddFormatToGlobal() const;
     180    void AddFormatToGlobal();
    181181
    182182    bool JsRun(const std::string &, const std::map<std::string,std::string> & = std::map<std::string,std::string>());
Note: See TracChangeset for help on using the changeset viewer.