Index: trunk/FACT++/src/InterpreterV8.cc
===================================================================
--- trunk/FACT++/src/InterpreterV8.cc	(revision 14596)
+++ trunk/FACT++/src/InterpreterV8.cc	(revision 14598)
@@ -1,3 +1,11 @@
 #include "InterpreterV8.h"
+
+#ifdef HAVE_V8
+
+#include <fstream>
+#include <sstream>
+#include <iomanip>
+
+#include <boost/tokenizer.hpp>
 
 #ifdef HAVE_NOVA
@@ -10,14 +18,5 @@
 #endif
 
-#include <boost/tokenizer.hpp>
-
-InterpreterV8 *InterpreterV8::This = 0;
-
-#ifdef HAVE_V8
-
 #include <v8.h>
-#include <fstream>
-#include <sstream>
-#include <iomanip>
 
 using namespace std;
@@ -29,22 +28,19 @@
 // ==========================================================================
 
+void InterpreterV8::Terminate()
+{
+    for (auto it=fThreadIds.begin(); it!=fThreadIds.end(); it++)
+        V8::TerminateExecution(*it);
+    fThreadIds.clear();
+
+    if (fThreadId>=0)
+        V8::TerminateExecution(fThreadId);
+}
+
 Handle<Value> InterpreterV8::FuncExit(const Arguments &)
 {
-    V8::TerminateExecution(fThreadId);
+    Terminate();
     return ThrowException(String::New("exit"));
-/*
-    if (args.Length()!=1)
-        return ThrowException(String::New("Number of arguments must be exactly 1."));
-
-    if (!args[0]->IsUint32())
-        return ThrowException(String::New("Argument 1 must be an uint32."));
-
-    const HandleScope handle_scope;
-
-    JsSleep(args[0]->Int32Value());
-*/
-    return Undefined();
-}
-
+}
 
 Handle<Value> InterpreterV8::FuncSleep(const Arguments& args)
@@ -77,4 +73,6 @@
 
     const Handle<Script> script = Script::Compile(String::New(code.c_str()));
+    if (script.IsEmpty())
+        return Undefined();
 
     return handle_scope.Close(script->Run());
@@ -82,4 +80,61 @@
     //JsSleep(args[0]->Int32Value());
     //return Undefined();
+}
+
+void InterpreterV8::ThreadTimeout(Persistent<Function> func, uint32_t ms)
+{
+    if (fThreadId<0)
+        return;
+
+    Locker lock;
+
+    const HandleScope handle_scope;
+
+    fGlobalContext->Enter();
+
+    const int id = V8::GetCurrentThreadId();
+    fThreadIds.insert(id);
+
+    TryCatch exception;
+
+    const Handle<Script> sleep = Script::Compile(String::New(("dim.sleep("+to_string(ms)+");").c_str()));
+    if (!sleep.IsEmpty() && !sleep->Run().IsEmpty())
+    {
+        Handle<Value> args[] = {  };
+        func->Call(func, 0, args);
+    }
+
+    func.Dispose();
+    fThreadIds.erase(id);
+
+    if (!exception.HasCaught())
+        return;
+
+    ReportException(&exception);
+    Terminate();
+}
+
+Handle<Value> InterpreterV8::FuncTimeout(const Arguments& args)
+{
+    if (args.Length()!=2)
+        return ThrowException(String::New("Number of arguments must be at least 1."));
+
+    if (args.Length()==0)
+        return ThrowException(String::New("Number of arguments must be at least 1."));
+
+    if (!args[1]->IsFunction())
+        return ThrowException(String::New("Argument 1 not a function."));
+
+    if (!args[0]->IsUint32())
+        return ThrowException(String::New("Argument 0 not an uint32."));
+
+    Handle<Function> handle = Handle<Function>::Cast(args[1]);
+
+    Persistent<Function> func = Persistent<Function>::New(handle);
+
+    const uint32_t ms = args[0]->Uint32Value();
+
+    fTimeout.push_back(thread(bind(&InterpreterV8::ThreadTimeout, this, func, ms)));
+    return Undefined();
 }
 
@@ -173,5 +228,8 @@
 
     const Handle<Script> script = Script::Compile(String::New(code.c_str()));
-    const Handle<Value>  result = script->Run();
+    if (script.IsEmpty())
+        return Undefined();
+
+    const Handle<Value> result = script->Run();
 
     return exception.HasCaught() ? exception.ReThrow() : handle_scope.Close(result);
@@ -210,19 +268,12 @@
     HandleScope handle_scope;
 
-    // It is important to catch the exception thrown
-    // by Date::New in case of thread termination!
-    Local<Value> date;
-    {
-        TryCatch exception;
-        date = Date::New(rc.time.JavaDate());
-        if (exception.HasCaught())
-            return exception.ReThrow();
-    }
-
     Handle<ObjectTemplate> obj = ObjectTemplate::New();
     obj->Set(String::New("index"), rc.index<=-256?Undefined():Integer::New(rc.index),       ReadOnly);
     obj->Set(String::New("name"),  rc.index<=-256?Undefined():String::New(rc.name.c_str()), ReadOnly);
-    if (rc.index>-256)
+
+    const Local<Value> date = Date::New(rc.time.JavaDate());
+    if (rc.index>-256 && !date.IsEmpty())
         obj->Set(String::New("time"),  date);
+
     //obj->Set(String::New("toString"),  String::New(("[Object state "+string(*str)+":"+to_string(rc.index)+"]").c_str()));
 
@@ -380,5 +431,5 @@
     HandleScope handle_scope;
 
-    void *ptr = Handle<External>::Cast(args.This()->GetInternalField(0))->Value();
+    void *ptr = External::Unwrap(args.This()->GetInternalField(0));
     if (!ptr)
         return handle_scope.Close(Boolean::New(false));
@@ -402,5 +453,5 @@
     HandleScope handle_scope;
 
-    void *ptr = Handle<External>::Cast(args.This()->GetInternalField(0))->Value();
+    void *ptr = External::Unwrap(args.This()->GetInternalField(0));
     if (!ptr)
         return Undefined();
@@ -419,8 +470,13 @@
 
         Handle<Array> ret = Array::New();
+        if (ret.IsEmpty())
+            return Undefined();
+
         ret->Set(String::New("table"), String::New(res.table()),   ReadOnly);
         ret->Set(String::New("query"), String::New(query.c_str()), ReadOnly);
 
         Handle<Array> cols = Array::New();
+        if (cols.IsEmpty())
+            return Undefined();
 
         int irow=0;
@@ -428,4 +484,6 @@
         {
             Handle<Array> row = Array::New();
+            if (row.IsEmpty())
+                return Undefined();
 
             const mysqlpp::FieldNames *list = it->field_list().list;
@@ -518,10 +576,7 @@
                     // It is important to catch the exception thrown
                     // by Date::New in case of thread termination!
-                    TryCatch exception;
-                    Local<Value> val = Date::New(date*1000);
-                    if (exception.HasCaught())
-                        return exception.ReThrow();
-                    //if (V8::IsExecutionTerminating())
-                    //    return Undefined();
+                    const Local<Value> val = Date::New(date*1000);
+                    if (val.IsEmpty())
+                        return Undefined();
 
                     row->Set(name, val, ReadOnly);
@@ -570,4 +625,7 @@
 
         Handle<Object> obj = tem->NewInstance();
+        if (obj.IsEmpty())
+            return Undefined();
+
         obj->SetInternalField(0, External::New(db));
 
@@ -640,18 +698,14 @@
 Handle<Value> InterpreterV8::ConvertEvent(const EventImp *evt, uint64_t counter, const char *str)
 {
-    Local<Value> date;
-
-    // It is important to catch the exception thrown
-    // by Date::New in case of thread termination!
-    {
-        TryCatch exception;
-        date = Date::New(evt->GetJavaDate());
-        if (exception.HasCaught())
-            return exception.ReThrow();
-    }
-
     const vector<Description> vec = JsDescription(str);
 
     Handle<Array> ret = Array::New();
+    if (ret.IsEmpty())
+        return Undefined();
+
+    const Local<Value> date = Date::New(evt->GetJavaDate());
+    if (date.IsEmpty())
+        return Undefined();
+
     ret->Set(String::New("name"),    String::New(str),             ReadOnly);
     ret->Set(String::New("format"),  String::New(evt->GetFormat().c_str()), ReadOnly);
@@ -660,5 +714,5 @@
     ret->Set(String::New("size"),    Integer::New(evt->GetSize()),  ReadOnly);
     ret->Set(String::New("counter"), Integer::New(counter),         ReadOnly);
-    ret->Set(String::New("time"),    date,                          ReadOnly);
+    ret->Set(String::New("time"), date, ReadOnly);
 
     // If no event was received (usually a disconnection event in
@@ -681,4 +735,6 @@
 
     Handle<Array> obj = tok.size()>1 ? Array::New() : ret;
+    if (obj.IsEmpty())
+        return Undefined();
 
     const char *ptr = evt->GetText();
@@ -716,4 +772,7 @@
             {
                 Handle<Array> a = Array::New(cnt);
+                if (a.IsEmpty())
+                    return Undefined();
+
                 for (uint32_t i=0; i<cnt; i++)
                     a->Set(i, Convert(type, ptr));
@@ -774,4 +833,6 @@
 
     const Handle<Script> sleep = Script::Compile(String::New("dim.sleep();"));
+    if (sleep.IsEmpty())
+        return Undefined();
 
     const Handle<String> data  = String::New("data");
@@ -841,28 +902,23 @@
     const HandleScope handle_scope;
 
+    fGlobalContext->Enter();
+
     Handle<Object> obj = it->second;
-    if (obj.IsEmpty())
+    if (!obj.IsEmpty())
         return;
 
     const Handle<String> onchange = String::New("onchange");
-    if (!obj->Has(onchange))
+    if (obj->Has(onchange))
         return;
 
     const Handle<Value> val = obj->Get(onchange);
-    if (!val->IsFunction())
+    if (val->IsFunction())
         return;
 
     // -------------------------------------------------------------------
-    // We are not in a context... we need to get into one for Array::New
-
-    Persistent<Context> context = Context::New();
-    if (context.IsEmpty())
-        return;
-
-    const Context::Scope scope(context);
-
-    // -------------------------------------------------------------------
-
     TryCatch exception;
+
+    const int id = V8::GetCurrentThreadId();
+    fThreadIds.insert(id);
 
     Handle<Value> ret = ConvertEvent(&evt, cnt, service.c_str());
@@ -875,4 +931,6 @@
     }
 
+    fThreadIds.erase(id);
+
     if (exception.HasCaught())
         ReportException(&exception);
@@ -881,8 +939,6 @@
         JsException(service+".onchange callback - "+*String::Utf8Value(ret));
 
-    context.Dispose();
-
     if (ret->IsUndefined() || ret->IsNativeError() || exception.HasCaught())
-        V8::TerminateExecution(fThreadId);
+        Terminate();
 }
 
@@ -928,44 +984,36 @@
         return;
 
+    fGlobalContext->Enter();
+
     // -------------------------------------------------------------------
-    // We are not in a context... we need to get into one for Array::New
-
-    Persistent<Context> context = Context::New();
-    if (context.IsEmpty())
+
+    Handle<ObjectTemplate> obj = ObjectTemplate::New();
+    obj->Set(String::New("index"),   state.index<=-256?Undefined():Integer::New(state.index),          ReadOnly);
+    obj->Set(String::New("name"),    state.index<=-256?Undefined():String::New(state.name.c_str()),    ReadOnly);
+    obj->Set(String::New("comment"), state.index<=-256?Undefined():String::New(state.comment.c_str()), ReadOnly);
+    obj->Set(String::New("server"),  String::New(server.c_str()), ReadOnly);
+
+    const Local<Value> date = Date::New(state.time.JavaDate());
+    if (state.index>-256 && !date.IsEmpty())
+        obj->Set(String::New("time"), date);
+
+    // -------------------------------------------------------------------
+
+    TryCatch exception;
+
+    const int id = V8::GetCurrentThreadId();
+    fThreadIds.insert(id);
+
+    Handle<Value> args[] = { obj->NewInstance() };
+    Handle<Function> fun = Handle<Function>::Cast(it->second);
+    fun->Call(fun, 1, args);
+
+    fThreadIds.erase(id);
+
+    if (!exception.HasCaught())
         return;
 
-    const Context::Scope scope(context);
-
-    // -------------------------------------------------------------------
-
-    TryCatch exception;
-
-    // It is important to catch the exception thrown
-    // by Date::New in case of thread termination!
-    Local<Value> date = Date::New(state.time.JavaDate());
-
-    if (!exception.HasCaught())
-    {
-        Handle<ObjectTemplate> obj = ObjectTemplate::New();
-        obj->Set(String::New("index"),   state.index<=-256?Undefined():Integer::New(state.index),          ReadOnly);
-        obj->Set(String::New("name"),    state.index<=-256?Undefined():String::New(state.name.c_str()),    ReadOnly);
-        obj->Set(String::New("comment"), state.index<=-256?Undefined():String::New(state.comment.c_str()), ReadOnly);
-        obj->Set(String::New("server"),  String::New(server.c_str()), ReadOnly);
-        if (state.index>-256)
-            obj->Set(String::New("time"), date);
-
-        Handle<Value> args[] = { obj->NewInstance() };
-
-        Handle<Function> fun = Handle<Function>::Cast(it->second);
-        fun->Call(fun, 1, args);
-    }
-
-    if (exception.HasCaught())
-        ReportException(&exception);
-
-    context.Dispose();
-
-    if (exception.HasCaught())
-        V8::TerminateExecution(fThreadId);
+    ReportException(&exception);
+    Terminate();
 }
 
@@ -1008,4 +1056,7 @@
 
     Handle<Object> obj = tem->NewInstance();
+    if (obj.IsEmpty())
+        return Undefined();
+
     obj->SetInternalField(0, External::New(ptr));
 
@@ -1158,14 +1209,10 @@
         return ThrowException(String::New("zd and az must be finite."));
 
-    // It is important to catch the exception thrown
-    // by Date::New in case of thread termination!
-    TryCatch exception;
-
     const Local<Value> date =
         args.Length()==0 ? Date::New(Time().JavaDate()) : args[0];
-    if (exception.HasCaught())
-        return exception.ReThrow();
-
-    const uint64_t v = uint64_t(args[0]->NumberValue());
+    if (date.IsEmpty())
+        return Undefined();
+
+    const uint64_t v = uint64_t(date->NumberValue());
     const Time utc(v/1000, v%1000);
 
@@ -1194,14 +1241,10 @@
         return ThrowException(String::New("Ra and dec must be finite."));
 
-    // It is important to catch the exception thrown
-    // by Date::New in case of thread termination!
-    TryCatch exception;
-
     const Local<Value> date =
         args.Length()==0 ? Date::New(Time().JavaDate()) : args[0];
-    if (exception.HasCaught())
-        return exception.ReThrow();
-
-    const uint64_t v = uint64_t(args[0]->NumberValue());
+    if (date.IsEmpty())
+        return Undefined();
+
+    const uint64_t v = uint64_t(date->NumberValue());
     const Time utc(v/1000, v%1000);
 
@@ -1230,14 +1273,10 @@
         return ThrowException(String::New("ra and dec must be finite."));
 
-    // It is important to catch the exception thrown
-    // by Date::New in case of thread termination!
-    TryCatch exception;
-
     const Local<Value> date =
         args.Length()==0 ? Date::New(Time().JavaDate()) : args.This()->Get(String::New("time"));
-    if (exception.HasCaught())
-        return exception.ReThrow();
-
-    const uint64_t v = uint64_t(args[0]->NumberValue());
+    if (date.IsEmpty())
+        return Undefined();
+
+    const uint64_t v = uint64_t(date->NumberValue());
     const Time utc(v/1000, v%1000);
 
@@ -1259,14 +1298,10 @@
         return ThrowException(String::New("Moon constructor must not be called with more than one argument."));
 
-    // It is important to catch the exception thrown
-    // by Date::New in case of thread termination!
-    TryCatch exception;
-
     const Local<Value> date =
         args.Length()==0 ? Date::New(Time().JavaDate()) : args[0];
-    if (exception.HasCaught())
-        return exception.ReThrow();
-
-    const uint64_t v = uint64_t(args[0]->NumberValue());
+    if (date.IsEmpty())
+        return Undefined();
+
+    const uint64_t v = uint64_t(date->NumberValue());
     const Time utc(v/1000, v%1000);
 
@@ -1467,4 +1502,5 @@
     dim->Set(String::New("setState"),  FunctionTemplate::New(WrapSetState),  ReadOnly);
     dim->Set(String::New("sleep"),     FunctionTemplate::New(WrapSleep),     ReadOnly);
+    dim->Set(String::New("timeout"),   FunctionTemplate::New(WrapTimeout),   ReadOnly);
     dim->Set(String::New("subscribe"), FunctionTemplate::New(WrapSubscribe), ReadOnly);
     dim->Set(String::New("database"),  FunctionTemplate::New(WrapDatabase),  ReadOnly);
@@ -1494,6 +1530,6 @@
 
     // Persistent
-    Persistent<Context> context = Context::New(NULL, global);
-    if (context.IsEmpty())
+    fGlobalContext = Context::New(NULL, global);
+    if (fGlobalContext.IsEmpty())
     {
         //printf("Error creating context\n");
@@ -1501,11 +1537,11 @@
     }
 
-    Context::Scope scope(context);
+    Context::Scope scope(fGlobalContext);
 
     Handle<Array> args = Array::New(map.size());
     for (auto it=map.begin(); it!=map.end(); it++)
         args->Set(String::New(it->first.c_str()), String::New(it->second.c_str()));
-    context->Global()->Set(String::New("$"),   args, ReadOnly);
-    context->Global()->Set(String::New("arg"), args, ReadOnly);
+    fGlobalContext->Global()->Set(String::New("$"),   args, ReadOnly);
+    fGlobalContext->Global()->Set(String::New("arg"), args, ReadOnly);
 
     JsStart(filename);
@@ -1514,4 +1550,5 @@
     Locker::StartPreemption(10);
     const bool rc = ExecuteFile(filename);
+    Terminate();
 
     // -----
@@ -1530,15 +1567,28 @@
     //context->Exit();
 
+    // Thre threads are started already and wait to get the lock
+    // So we have to unlock (manual preemtion) so they they get
+    // the signal to terminate. After they are all successfully
+    // terminated, just to be sure... we lock again
+    Unlocker unlock;
+
+    for (auto it=fTimeout.begin(); it!=fTimeout.end(); it++)
+        it->join();
+    fTimeout.clear();
+
+    Locker lock2;
+
+    // Now we can dispose all persistent handles from state callbacks
     for (auto it=fStateCallbacks.begin(); it!=fStateCallbacks.end(); it++)
         it->second.Dispose();
     fStateCallbacks.clear();
 
+    // Now we can dispose all persistent handles from reverse maps
     for (auto it=fReverseMap.begin(); it!=fReverseMap.end(); it++)
         it->second.Dispose();
     fReverseMap.clear();
 
-    context.Dispose();
-
 #ifdef HAVE_SQL
+    // ...and close all database  handles
     for (auto it=fDatabases.begin(); it!=fDatabases.end(); it++)
         delete *it;
@@ -1554,17 +1604,8 @@
 {
     Locker locker;
-
-    //cout << "Terminate " << fThreadId << endl;
-    if (This->fThreadId>=0)
-        V8::TerminateExecution(This->fThreadId);
-    //cout << "Terminate " << fThreadId << endl;
-
-    //Unlocker unlocker;
+    This->Terminate();
 }
 
 #endif
 
-
-
-
-
+InterpreterV8 *InterpreterV8::This = 0;
Index: trunk/FACT++/src/InterpreterV8.h
===================================================================
--- trunk/FACT++/src/InterpreterV8.h	(revision 14596)
+++ trunk/FACT++/src/InterpreterV8.h	(revision 14598)
@@ -3,6 +3,8 @@
 
 #include <map>
+#include <set>
 #include <list>
 #include <string>
+#include <thread>
 
 #ifdef HAVE_V8
@@ -23,4 +25,7 @@
     // the thread forcefully from 'the outside'
     int fThreadId;
+    std::set<int> fThreadIds;
+
+    v8::Persistent<v8::Context> fGlobalContext;
 
     // A loookup table which allows to indentify the
@@ -33,4 +38,7 @@
     std::map<std::string, v8::Persistent<v8::Value>>  fStateCallbacks;
 
+    // List of all timeout threads
+    std::vector<std::thread> fTimeout;
+
 #ifdef HAVE_SQL
     std::list<Database*> fDatabases;
@@ -38,4 +46,6 @@
 
 #ifdef HAVE_V8
+    void Terminate();
+
     bool ReportException(v8::TryCatch* try_catch);
     bool ExecuteStringNT(const v8::Handle<v8::String> &code, const v8::Handle<v8::Value>  &file);
@@ -44,7 +54,10 @@
     bool ExecuteFile(const std::string &name);
 
+    void ThreadTimeout(v8::Persistent<v8::Function> func, uint32_t ms);
+
     v8::Handle<v8::Value> FuncWait(const v8::Arguments& args);
     v8::Handle<v8::Value> FuncSend(const v8::Arguments& args);
     v8::Handle<v8::Value> FuncSleep(const v8::Arguments& args);
+    v8::Handle<v8::Value> FuncTimeout(const v8::Arguments& args);
     v8::Handle<v8::Value> FuncPrint(const v8::Arguments& args);
     v8::Handle<v8::Value> FuncAlarm(const v8::Arguments& args);
@@ -89,4 +102,5 @@
     static v8::Handle<v8::Value> WrapSend(const v8::Arguments &args)     { if (This) return This->FuncSend(args);     else return v8::Undefined(); }
     static v8::Handle<v8::Value> WrapSleep(const v8::Arguments &args)    { if (This) return This->FuncSleep(args);    else return v8::Undefined(); }
+    static v8::Handle<v8::Value> WrapTimeout(const v8::Arguments &args)  { if (This) return This->FuncTimeout(args);  else return v8::Undefined(); }
     static v8::Handle<v8::Value> WrapExit(const v8::Arguments &args)     { if (This) return This->FuncExit(args);     else return v8::Undefined(); }
     static v8::Handle<v8::Value> WrapState(const v8::Arguments &args)    { if (This) return This->FuncState(args);    else return v8::Undefined(); }
