Changeset 14598 for trunk/FACT++


Ignore:
Timestamp:
11/10/12 12:16:14 (12 years ago)
Author:
tbretz
Message:
Instead of catching exception everywhere to check for termination of othr threads, handles are checked for validity; added new threads as 'timeout' threads; keep th global context and enter it is other threads; kep a list of threads and terminate them, too, if program is exited or an exception is thrown.
Location:
trunk/FACT++/src
Files:
2 edited

Legend:

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

    r14591 r14598  
    11#include "InterpreterV8.h"
     2
     3#ifdef HAVE_V8
     4
     5#include <fstream>
     6#include <sstream>
     7#include <iomanip>
     8
     9#include <boost/tokenizer.hpp>
    210
    311#ifdef HAVE_NOVA
     
    1018#endif
    1119
    12 #include <boost/tokenizer.hpp>
    13 
    14 InterpreterV8 *InterpreterV8::This = 0;
    15 
    16 #ifdef HAVE_V8
    17 
    1820#include <v8.h>
    19 #include <fstream>
    20 #include <sstream>
    21 #include <iomanip>
    2221
    2322using namespace std;
     
    2928// ==========================================================================
    3029
     30void InterpreterV8::Terminate()
     31{
     32    for (auto it=fThreadIds.begin(); it!=fThreadIds.end(); it++)
     33        V8::TerminateExecution(*it);
     34    fThreadIds.clear();
     35
     36    if (fThreadId>=0)
     37        V8::TerminateExecution(fThreadId);
     38}
     39
    3140Handle<Value> InterpreterV8::FuncExit(const Arguments &)
    3241{
    33     V8::TerminateExecution(fThreadId);
     42    Terminate();
    3443    return ThrowException(String::New("exit"));
    35 /*
    36     if (args.Length()!=1)
    37         return ThrowException(String::New("Number of arguments must be exactly 1."));
    38 
    39     if (!args[0]->IsUint32())
    40         return ThrowException(String::New("Argument 1 must be an uint32."));
    41 
    42     const HandleScope handle_scope;
    43 
    44     JsSleep(args[0]->Int32Value());
    45 */
    46     return Undefined();
    47 }
    48 
     44}
    4945
    5046Handle<Value> InterpreterV8::FuncSleep(const Arguments& args)
     
    7773
    7874    const Handle<Script> script = Script::Compile(String::New(code.c_str()));
     75    if (script.IsEmpty())
     76        return Undefined();
    7977
    8078    return handle_scope.Close(script->Run());
     
    8280    //JsSleep(args[0]->Int32Value());
    8381    //return Undefined();
     82}
     83
     84void InterpreterV8::ThreadTimeout(Persistent<Function> func, uint32_t ms)
     85{
     86    if (fThreadId<0)
     87        return;
     88
     89    Locker lock;
     90
     91    const HandleScope handle_scope;
     92
     93    fGlobalContext->Enter();
     94
     95    const int id = V8::GetCurrentThreadId();
     96    fThreadIds.insert(id);
     97
     98    TryCatch exception;
     99
     100    const Handle<Script> sleep = Script::Compile(String::New(("dim.sleep("+to_string(ms)+");").c_str()));
     101    if (!sleep.IsEmpty() && !sleep->Run().IsEmpty())
     102    {
     103        Handle<Value> args[] = {  };
     104        func->Call(func, 0, args);
     105    }
     106
     107    func.Dispose();
     108    fThreadIds.erase(id);
     109
     110    if (!exception.HasCaught())
     111        return;
     112
     113    ReportException(&exception);
     114    Terminate();
     115}
     116
     117Handle<Value> InterpreterV8::FuncTimeout(const Arguments& args)
     118{
     119    if (args.Length()!=2)
     120        return ThrowException(String::New("Number of arguments must be at least 1."));
     121
     122    if (args.Length()==0)
     123        return ThrowException(String::New("Number of arguments must be at least 1."));
     124
     125    if (!args[1]->IsFunction())
     126        return ThrowException(String::New("Argument 1 not a function."));
     127
     128    if (!args[0]->IsUint32())
     129        return ThrowException(String::New("Argument 0 not an uint32."));
     130
     131    Handle<Function> handle = Handle<Function>::Cast(args[1]);
     132
     133    Persistent<Function> func = Persistent<Function>::New(handle);
     134
     135    const uint32_t ms = args[0]->Uint32Value();
     136
     137    fTimeout.push_back(thread(bind(&InterpreterV8::ThreadTimeout, this, func, ms)));
     138    return Undefined();
    84139}
    85140
     
    173228
    174229    const Handle<Script> script = Script::Compile(String::New(code.c_str()));
    175     const Handle<Value>  result = script->Run();
     230    if (script.IsEmpty())
     231        return Undefined();
     232
     233    const Handle<Value> result = script->Run();
    176234
    177235    return exception.HasCaught() ? exception.ReThrow() : handle_scope.Close(result);
     
    210268    HandleScope handle_scope;
    211269
    212     // It is important to catch the exception thrown
    213     // by Date::New in case of thread termination!
    214     Local<Value> date;
    215     {
    216         TryCatch exception;
    217         date = Date::New(rc.time.JavaDate());
    218         if (exception.HasCaught())
    219             return exception.ReThrow();
    220     }
    221 
    222270    Handle<ObjectTemplate> obj = ObjectTemplate::New();
    223271    obj->Set(String::New("index"), rc.index<=-256?Undefined():Integer::New(rc.index),       ReadOnly);
    224272    obj->Set(String::New("name"),  rc.index<=-256?Undefined():String::New(rc.name.c_str()), ReadOnly);
    225     if (rc.index>-256)
     273
     274    const Local<Value> date = Date::New(rc.time.JavaDate());
     275    if (rc.index>-256 && !date.IsEmpty())
    226276        obj->Set(String::New("time"),  date);
     277
    227278    //obj->Set(String::New("toString"),  String::New(("[Object state "+string(*str)+":"+to_string(rc.index)+"]").c_str()));
    228279
     
    380431    HandleScope handle_scope;
    381432
    382     void *ptr = Handle<External>::Cast(args.This()->GetInternalField(0))->Value();
     433    void *ptr = External::Unwrap(args.This()->GetInternalField(0));
    383434    if (!ptr)
    384435        return handle_scope.Close(Boolean::New(false));
     
    402453    HandleScope handle_scope;
    403454
    404     void *ptr = Handle<External>::Cast(args.This()->GetInternalField(0))->Value();
     455    void *ptr = External::Unwrap(args.This()->GetInternalField(0));
    405456    if (!ptr)
    406457        return Undefined();
     
    419470
    420471        Handle<Array> ret = Array::New();
     472        if (ret.IsEmpty())
     473            return Undefined();
     474
    421475        ret->Set(String::New("table"), String::New(res.table()),   ReadOnly);
    422476        ret->Set(String::New("query"), String::New(query.c_str()), ReadOnly);
    423477
    424478        Handle<Array> cols = Array::New();
     479        if (cols.IsEmpty())
     480            return Undefined();
    425481
    426482        int irow=0;
     
    428484        {
    429485            Handle<Array> row = Array::New();
     486            if (row.IsEmpty())
     487                return Undefined();
    430488
    431489            const mysqlpp::FieldNames *list = it->field_list().list;
     
    518576                    // It is important to catch the exception thrown
    519577                    // by Date::New in case of thread termination!
    520                     TryCatch exception;
    521                     Local<Value> val = Date::New(date*1000);
    522                     if (exception.HasCaught())
    523                         return exception.ReThrow();
    524                     //if (V8::IsExecutionTerminating())
    525                     //    return Undefined();
     578                    const Local<Value> val = Date::New(date*1000);
     579                    if (val.IsEmpty())
     580                        return Undefined();
    526581
    527582                    row->Set(name, val, ReadOnly);
     
    570625
    571626        Handle<Object> obj = tem->NewInstance();
     627        if (obj.IsEmpty())
     628            return Undefined();
     629
    572630        obj->SetInternalField(0, External::New(db));
    573631
     
    640698Handle<Value> InterpreterV8::ConvertEvent(const EventImp *evt, uint64_t counter, const char *str)
    641699{
    642     Local<Value> date;
    643 
    644     // It is important to catch the exception thrown
    645     // by Date::New in case of thread termination!
    646     {
    647         TryCatch exception;
    648         date = Date::New(evt->GetJavaDate());
    649         if (exception.HasCaught())
    650             return exception.ReThrow();
    651     }
    652 
    653700    const vector<Description> vec = JsDescription(str);
    654701
    655702    Handle<Array> ret = Array::New();
     703    if (ret.IsEmpty())
     704        return Undefined();
     705
     706    const Local<Value> date = Date::New(evt->GetJavaDate());
     707    if (date.IsEmpty())
     708        return Undefined();
     709
    656710    ret->Set(String::New("name"),    String::New(str),             ReadOnly);
    657711    ret->Set(String::New("format"),  String::New(evt->GetFormat().c_str()), ReadOnly);
     
    660714    ret->Set(String::New("size"),    Integer::New(evt->GetSize()),  ReadOnly);
    661715    ret->Set(String::New("counter"), Integer::New(counter),         ReadOnly);
    662     ret->Set(String::New("time"),    date,                          ReadOnly);
     716    ret->Set(String::New("time"), date, ReadOnly);
    663717
    664718    // If no event was received (usually a disconnection event in
     
    681735
    682736    Handle<Array> obj = tok.size()>1 ? Array::New() : ret;
     737    if (obj.IsEmpty())
     738        return Undefined();
    683739
    684740    const char *ptr = evt->GetText();
     
    716772            {
    717773                Handle<Array> a = Array::New(cnt);
     774                if (a.IsEmpty())
     775                    return Undefined();
     776
    718777                for (uint32_t i=0; i<cnt; i++)
    719778                    a->Set(i, Convert(type, ptr));
     
    774833
    775834    const Handle<Script> sleep = Script::Compile(String::New("dim.sleep();"));
     835    if (sleep.IsEmpty())
     836        return Undefined();
    776837
    777838    const Handle<String> data  = String::New("data");
     
    841902    const HandleScope handle_scope;
    842903
     904    fGlobalContext->Enter();
     905
    843906    Handle<Object> obj = it->second;
    844     if (obj.IsEmpty())
     907    if (!obj.IsEmpty())
    845908        return;
    846909
    847910    const Handle<String> onchange = String::New("onchange");
    848     if (!obj->Has(onchange))
     911    if (obj->Has(onchange))
    849912        return;
    850913
    851914    const Handle<Value> val = obj->Get(onchange);
    852     if (!val->IsFunction())
     915    if (val->IsFunction())
    853916        return;
    854917
    855918    // -------------------------------------------------------------------
    856     // We are not in a context... we need to get into one for Array::New
    857 
    858     Persistent<Context> context = Context::New();
    859     if (context.IsEmpty())
    860         return;
    861 
    862     const Context::Scope scope(context);
    863 
    864     // -------------------------------------------------------------------
    865 
    866919    TryCatch exception;
     920
     921    const int id = V8::GetCurrentThreadId();
     922    fThreadIds.insert(id);
    867923
    868924    Handle<Value> ret = ConvertEvent(&evt, cnt, service.c_str());
     
    875931    }
    876932
     933    fThreadIds.erase(id);
     934
    877935    if (exception.HasCaught())
    878936        ReportException(&exception);
     
    881939        JsException(service+".onchange callback - "+*String::Utf8Value(ret));
    882940
    883     context.Dispose();
    884 
    885941    if (ret->IsUndefined() || ret->IsNativeError() || exception.HasCaught())
    886         V8::TerminateExecution(fThreadId);
     942        Terminate();
    887943}
    888944
     
    928984        return;
    929985
     986    fGlobalContext->Enter();
     987
    930988    // -------------------------------------------------------------------
    931     // We are not in a context... we need to get into one for Array::New
    932 
    933     Persistent<Context> context = Context::New();
    934     if (context.IsEmpty())
     989
     990    Handle<ObjectTemplate> obj = ObjectTemplate::New();
     991    obj->Set(String::New("index"),   state.index<=-256?Undefined():Integer::New(state.index),          ReadOnly);
     992    obj->Set(String::New("name"),    state.index<=-256?Undefined():String::New(state.name.c_str()),    ReadOnly);
     993    obj->Set(String::New("comment"), state.index<=-256?Undefined():String::New(state.comment.c_str()), ReadOnly);
     994    obj->Set(String::New("server"),  String::New(server.c_str()), ReadOnly);
     995
     996    const Local<Value> date = Date::New(state.time.JavaDate());
     997    if (state.index>-256 && !date.IsEmpty())
     998        obj->Set(String::New("time"), date);
     999
     1000    // -------------------------------------------------------------------
     1001
     1002    TryCatch exception;
     1003
     1004    const int id = V8::GetCurrentThreadId();
     1005    fThreadIds.insert(id);
     1006
     1007    Handle<Value> args[] = { obj->NewInstance() };
     1008    Handle<Function> fun = Handle<Function>::Cast(it->second);
     1009    fun->Call(fun, 1, args);
     1010
     1011    fThreadIds.erase(id);
     1012
     1013    if (!exception.HasCaught())
    9351014        return;
    9361015
    937     const Context::Scope scope(context);
    938 
    939     // -------------------------------------------------------------------
    940 
    941     TryCatch exception;
    942 
    943     // It is important to catch the exception thrown
    944     // by Date::New in case of thread termination!
    945     Local<Value> date = Date::New(state.time.JavaDate());
    946 
    947     if (!exception.HasCaught())
    948     {
    949         Handle<ObjectTemplate> obj = ObjectTemplate::New();
    950         obj->Set(String::New("index"),   state.index<=-256?Undefined():Integer::New(state.index),          ReadOnly);
    951         obj->Set(String::New("name"),    state.index<=-256?Undefined():String::New(state.name.c_str()),    ReadOnly);
    952         obj->Set(String::New("comment"), state.index<=-256?Undefined():String::New(state.comment.c_str()), ReadOnly);
    953         obj->Set(String::New("server"),  String::New(server.c_str()), ReadOnly);
    954         if (state.index>-256)
    955             obj->Set(String::New("time"), date);
    956 
    957         Handle<Value> args[] = { obj->NewInstance() };
    958 
    959         Handle<Function> fun = Handle<Function>::Cast(it->second);
    960         fun->Call(fun, 1, args);
    961     }
    962 
    963     if (exception.HasCaught())
    964         ReportException(&exception);
    965 
    966     context.Dispose();
    967 
    968     if (exception.HasCaught())
    969         V8::TerminateExecution(fThreadId);
     1016    ReportException(&exception);
     1017    Terminate();
    9701018}
    9711019
     
    10081056
    10091057    Handle<Object> obj = tem->NewInstance();
     1058    if (obj.IsEmpty())
     1059        return Undefined();
     1060
    10101061    obj->SetInternalField(0, External::New(ptr));
    10111062
     
    11581209        return ThrowException(String::New("zd and az must be finite."));
    11591210
    1160     // It is important to catch the exception thrown
    1161     // by Date::New in case of thread termination!
    1162     TryCatch exception;
    1163 
    11641211    const Local<Value> date =
    11651212        args.Length()==0 ? Date::New(Time().JavaDate()) : args[0];
    1166     if (exception.HasCaught())
    1167         return exception.ReThrow();
    1168 
    1169     const uint64_t v = uint64_t(args[0]->NumberValue());
     1213    if (date.IsEmpty())
     1214        return Undefined();
     1215
     1216    const uint64_t v = uint64_t(date->NumberValue());
    11701217    const Time utc(v/1000, v%1000);
    11711218
     
    11941241        return ThrowException(String::New("Ra and dec must be finite."));
    11951242
    1196     // It is important to catch the exception thrown
    1197     // by Date::New in case of thread termination!
    1198     TryCatch exception;
    1199 
    12001243    const Local<Value> date =
    12011244        args.Length()==0 ? Date::New(Time().JavaDate()) : args[0];
    1202     if (exception.HasCaught())
    1203         return exception.ReThrow();
    1204 
    1205     const uint64_t v = uint64_t(args[0]->NumberValue());
     1245    if (date.IsEmpty())
     1246        return Undefined();
     1247
     1248    const uint64_t v = uint64_t(date->NumberValue());
    12061249    const Time utc(v/1000, v%1000);
    12071250
     
    12301273        return ThrowException(String::New("ra and dec must be finite."));
    12311274
    1232     // It is important to catch the exception thrown
    1233     // by Date::New in case of thread termination!
    1234     TryCatch exception;
    1235 
    12361275    const Local<Value> date =
    12371276        args.Length()==0 ? Date::New(Time().JavaDate()) : args.This()->Get(String::New("time"));
    1238     if (exception.HasCaught())
    1239         return exception.ReThrow();
    1240 
    1241     const uint64_t v = uint64_t(args[0]->NumberValue());
     1277    if (date.IsEmpty())
     1278        return Undefined();
     1279
     1280    const uint64_t v = uint64_t(date->NumberValue());
    12421281    const Time utc(v/1000, v%1000);
    12431282
     
    12591298        return ThrowException(String::New("Moon constructor must not be called with more than one argument."));
    12601299
    1261     // It is important to catch the exception thrown
    1262     // by Date::New in case of thread termination!
    1263     TryCatch exception;
    1264 
    12651300    const Local<Value> date =
    12661301        args.Length()==0 ? Date::New(Time().JavaDate()) : args[0];
    1267     if (exception.HasCaught())
    1268         return exception.ReThrow();
    1269 
    1270     const uint64_t v = uint64_t(args[0]->NumberValue());
     1302    if (date.IsEmpty())
     1303        return Undefined();
     1304
     1305    const uint64_t v = uint64_t(date->NumberValue());
    12711306    const Time utc(v/1000, v%1000);
    12721307
     
    14671502    dim->Set(String::New("setState"),  FunctionTemplate::New(WrapSetState),  ReadOnly);
    14681503    dim->Set(String::New("sleep"),     FunctionTemplate::New(WrapSleep),     ReadOnly);
     1504    dim->Set(String::New("timeout"),   FunctionTemplate::New(WrapTimeout),   ReadOnly);
    14691505    dim->Set(String::New("subscribe"), FunctionTemplate::New(WrapSubscribe), ReadOnly);
    14701506    dim->Set(String::New("database"),  FunctionTemplate::New(WrapDatabase),  ReadOnly);
     
    14941530
    14951531    // Persistent
    1496     Persistent<Context> context = Context::New(NULL, global);
    1497     if (context.IsEmpty())
     1532    fGlobalContext = Context::New(NULL, global);
     1533    if (fGlobalContext.IsEmpty())
    14981534    {
    14991535        //printf("Error creating context\n");
     
    15011537    }
    15021538
    1503     Context::Scope scope(context);
     1539    Context::Scope scope(fGlobalContext);
    15041540
    15051541    Handle<Array> args = Array::New(map.size());
    15061542    for (auto it=map.begin(); it!=map.end(); it++)
    15071543        args->Set(String::New(it->first.c_str()), String::New(it->second.c_str()));
    1508     context->Global()->Set(String::New("$"),   args, ReadOnly);
    1509     context->Global()->Set(String::New("arg"), args, ReadOnly);
     1544    fGlobalContext->Global()->Set(String::New("$"),   args, ReadOnly);
     1545    fGlobalContext->Global()->Set(String::New("arg"), args, ReadOnly);
    15101546
    15111547    JsStart(filename);
     
    15141550    Locker::StartPreemption(10);
    15151551    const bool rc = ExecuteFile(filename);
     1552    Terminate();
    15161553
    15171554    // -----
     
    15301567    //context->Exit();
    15311568
     1569    // Thre threads are started already and wait to get the lock
     1570    // So we have to unlock (manual preemtion) so they they get
     1571    // the signal to terminate. After they are all successfully
     1572    // terminated, just to be sure... we lock again
     1573    Unlocker unlock;
     1574
     1575    for (auto it=fTimeout.begin(); it!=fTimeout.end(); it++)
     1576        it->join();
     1577    fTimeout.clear();
     1578
     1579    Locker lock2;
     1580
     1581    // Now we can dispose all persistent handles from state callbacks
    15321582    for (auto it=fStateCallbacks.begin(); it!=fStateCallbacks.end(); it++)
    15331583        it->second.Dispose();
    15341584    fStateCallbacks.clear();
    15351585
     1586    // Now we can dispose all persistent handles from reverse maps
    15361587    for (auto it=fReverseMap.begin(); it!=fReverseMap.end(); it++)
    15371588        it->second.Dispose();
    15381589    fReverseMap.clear();
    15391590
    1540     context.Dispose();
    1541 
    15421591#ifdef HAVE_SQL
     1592    // ...and close all database  handles
    15431593    for (auto it=fDatabases.begin(); it!=fDatabases.end(); it++)
    15441594        delete *it;
     
    15541604{
    15551605    Locker locker;
    1556 
    1557     //cout << "Terminate " << fThreadId << endl;
    1558     if (This->fThreadId>=0)
    1559         V8::TerminateExecution(This->fThreadId);
    1560     //cout << "Terminate " << fThreadId << endl;
    1561 
    1562     //Unlocker unlocker;
     1606    This->Terminate();
    15631607}
    15641608
    15651609#endif
    15661610
    1567 
    1568 
    1569 
    1570 
     1611InterpreterV8 *InterpreterV8::This = 0;
  • trunk/FACT++/src/InterpreterV8.h

    r14591 r14598  
    33
    44#include <map>
     5#include <set>
    56#include <list>
    67#include <string>
     8#include <thread>
    79
    810#ifdef HAVE_V8
     
    2325    // the thread forcefully from 'the outside'
    2426    int fThreadId;
     27    std::set<int> fThreadIds;
     28
     29    v8::Persistent<v8::Context> fGlobalContext;
    2530
    2631    // A loookup table which allows to indentify the
     
    3338    std::map<std::string, v8::Persistent<v8::Value>>  fStateCallbacks;
    3439
     40    // List of all timeout threads
     41    std::vector<std::thread> fTimeout;
     42
    3543#ifdef HAVE_SQL
    3644    std::list<Database*> fDatabases;
     
    3846
    3947#ifdef HAVE_V8
     48    void Terminate();
     49
    4050    bool ReportException(v8::TryCatch* try_catch);
    4151    bool ExecuteStringNT(const v8::Handle<v8::String> &code, const v8::Handle<v8::Value>  &file);
     
    4454    bool ExecuteFile(const std::string &name);
    4555
     56    void ThreadTimeout(v8::Persistent<v8::Function> func, uint32_t ms);
     57
    4658    v8::Handle<v8::Value> FuncWait(const v8::Arguments& args);
    4759    v8::Handle<v8::Value> FuncSend(const v8::Arguments& args);
    4860    v8::Handle<v8::Value> FuncSleep(const v8::Arguments& args);
     61    v8::Handle<v8::Value> FuncTimeout(const v8::Arguments& args);
    4962    v8::Handle<v8::Value> FuncPrint(const v8::Arguments& args);
    5063    v8::Handle<v8::Value> FuncAlarm(const v8::Arguments& args);
     
    89102    static v8::Handle<v8::Value> WrapSend(const v8::Arguments &args)     { if (This) return This->FuncSend(args);     else return v8::Undefined(); }
    90103    static v8::Handle<v8::Value> WrapSleep(const v8::Arguments &args)    { if (This) return This->FuncSleep(args);    else return v8::Undefined(); }
     104    static v8::Handle<v8::Value> WrapTimeout(const v8::Arguments &args)  { if (This) return This->FuncTimeout(args);  else return v8::Undefined(); }
    91105    static v8::Handle<v8::Value> WrapExit(const v8::Arguments &args)     { if (This) return This->FuncExit(args);     else return v8::Undefined(); }
    92106    static v8::Handle<v8::Value> WrapState(const v8::Arguments &args)    { if (This) return This->FuncState(args);    else return v8::Undefined(); }
Note: See TracChangeset for help on using the changeset viewer.