Sfoglia il codice sorgente

Start to add support for OS threads using slave vms

mingodad 9 anni fa
parent
commit
954642c384

+ 8 - 0
SquiLu-ext/mongoose.c

@@ -1111,6 +1111,10 @@ static int pthread_mutex_lock(pthread_mutex_t *mutex) {
   return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
   return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
 }
 }
 
 
+static int pthread_mutex_trylock(pthread_mutex_t *mutex) {
+  return WaitForSingleObject(*mutex, 0) == WAIT_OBJECT_0? 0 : -1;
+}
+
 static int pthread_mutex_unlock(pthread_mutex_t *mutex) {
 static int pthread_mutex_unlock(pthread_mutex_t *mutex) {
   return ReleaseMutex(*mutex) == 0 ? -1 : 0;
   return ReleaseMutex(*mutex) == 0 ? -1 : 0;
 }
 }
@@ -5495,6 +5499,10 @@ int mg_thread_mutex_lock(mg_thread_mutex_t *mutex){
     return pthread_mutex_lock(mutex);
     return pthread_mutex_lock(mutex);
 }
 }
 
 
+int mg_thread_mutex_trylock(mg_thread_mutex_t *mutex){
+    return pthread_mutex_trylock(mutex);
+}
+
 int mg_thread_mutex_unlock(mg_thread_mutex_t *mutex){
 int mg_thread_mutex_unlock(mg_thread_mutex_t *mutex){
     return pthread_mutex_unlock(mutex);
     return pthread_mutex_unlock(mutex);
 }
 }

+ 1 - 0
SquiLu-ext/mongoose.h

@@ -399,6 +399,7 @@ mg_thread_t mg_thread_self(void);
 int mg_thread_mutex_init(mg_thread_mutex_t *mutex, const mg_thread_mutexattr_t *attr);
 int mg_thread_mutex_init(mg_thread_mutex_t *mutex, const mg_thread_mutexattr_t *attr);
 int mg_thread_mutex_destroy(mg_thread_mutex_t *mutex);
 int mg_thread_mutex_destroy(mg_thread_mutex_t *mutex);
 int mg_thread_mutex_lock(mg_thread_mutex_t *mutex);
 int mg_thread_mutex_lock(mg_thread_mutex_t *mutex);
+int mg_thread_mutex_trylock(mg_thread_mutex_t *mutex);
 int mg_thread_mutex_unlock(mg_thread_mutex_t *mutex);
 int mg_thread_mutex_unlock(mg_thread_mutex_t *mutex);
 int mg_thread_cond_init(mg_thread_cond_t *cv, const mg_thread_condattr_t *attr);
 int mg_thread_cond_init(mg_thread_cond_t *cv, const mg_thread_condattr_t *attr);
 int mg_thread_cond_wait(mg_thread_cond_t *cv, mg_thread_mutex_t *mutex);
 int mg_thread_cond_wait(mg_thread_cond_t *cv, mg_thread_mutex_t *mutex);

+ 390 - 57
SquiLu-ext/sq_slave_vm.cpp

@@ -14,6 +14,10 @@
 #include <sqstdmath.h>
 #include <sqstdmath.h>
 #include <sqstdstring.h>
 #include <sqstdstring.h>
 
 
+#ifdef SLAVE_VM_WITH_OS_THREADS
+#include "mongoose.h"
+#endif // SLAVE_VM_WITH_OS_THREADS
+
 /*
 /*
 ** Copies values from State src to State dst.
 ** Copies values from State src to State dst.
 */
 */
@@ -99,33 +103,114 @@ static SQRESULT copy_values_between_vms (HSQUIRRELVM dst, HSQUIRRELVM src, int a
     return SQ_OK;
     return SQ_OK;
 }
 }
 
 
+struct SlaveVM_st {
+    HSQUIRRELVM v;
+    HSQUIRRELVM master_vm;
+#ifdef SLAVE_VM_WITH_OS_THREADS
+    mg_thread_mutex_t mutex;
+    mg_thread_cond_t cond_var;
+    mg_thread_t thread_id;
+    int slave_state, master_state;
+    bool isRunningAsThread;
+#endif // SLAVE_VM_WITH_OS_THREADS
+};
 
 
 static const SQChar sq_slave_vm_TAG[] = _SC("SlaveVM");
 static const SQChar sq_slave_vm_TAG[] = _SC("SlaveVM");
 
 
-static SQRESULT get_slave_vm_instance(HSQUIRRELVM v, SQInteger idx, HSQUIRRELVM *vm)
+static SQRESULT get_slave_vm_instance(HSQUIRRELVM v, SQInteger idx, SlaveVM_st **svm_st)
 {
 {
-    if(sq_getinstanceup(v, idx, (SQUserPointer*)vm, (void*)sq_slave_vm_TAG) != SQ_OK) return SQ_ERROR;
-    if(!vm) return sq_throwerror(v, _SC("slave vm already closed"));
+    if(sq_getinstanceup(v, idx, (SQUserPointer*)svm_st, (void*)sq_slave_vm_TAG) != SQ_OK) return SQ_ERROR;
+    if(!*svm_st) return sq_throwerror(v, _SC("slave vm already closed"));
     return SQ_OK;
     return SQ_OK;
 }
 }
 
 
 #define GET_sq_slave_vm_INSTANCE(v, idx) \
 #define GET_sq_slave_vm_INSTANCE(v, idx) \
-    HSQUIRRELVM self=NULL; if(get_slave_vm_instance(v, idx, &self) != SQ_OK) return SQ_ERROR;
+    SlaveVM_st *self=NULL; HSQUIRRELVM svm; \
+    if(get_slave_vm_instance(v, idx, &self) != SQ_OK) return SQ_ERROR; \
+    svm = self->v;
 
 
 static SQRESULT sq_slave_vm__tostring (HSQUIRRELVM v)
 static SQRESULT sq_slave_vm__tostring (HSQUIRRELVM v)
 {
 {
     GET_sq_slave_vm_INSTANCE(v, 1);
     GET_sq_slave_vm_INSTANCE(v, 1);
-    sq_pushfstring (v, _SC("Squirrel vm (%p)"), self);
+    sq_pushfstring (v, _SC("Squirrel vm (%p)"), svm);
     return 1;
     return 1;
 }
 }
 
 
+#ifdef SLAVE_VM_WITH_OS_THREADS
+static int releaseSlaveThread(SlaveVM_st *self)
+{
+    if(self->isRunningAsThread)
+    {
+        mg_thread_cond_destroy(&self->cond_var);
+        mg_thread_mutex_destroy(&self->mutex);
+    }
+    return 0;
+}
+#endif // SLAVE_VM_WITH_OS_THREADS
+
 static SQRESULT sq_slave_vm_release_hook(SQUserPointer p, SQInteger size, void */*ep*/)
 static SQRESULT sq_slave_vm_release_hook(SQUserPointer p, SQInteger size, void */*ep*/)
 {
 {
-    HSQUIRRELVM self = (HSQUIRRELVM)p;
-    if(self) sq_close(self);
+    SlaveVM_st *self = (SlaveVM_st*)p;
+    if(self && self->v)
+    {
+#ifdef SLAVE_VM_WITH_OS_THREADS
+        releaseSlaveThread(self);
+#endif // SLAVE_VM_WITH_OS_THREADS
+        sq_close(self->v);
+        self->v = NULL;
+        sq_free(self, sizeof(*self));
+    }
     return 0;
     return 0;
 }
 }
 
 
+#ifdef SLAVE_VM_WITH_OS_THREADS
+
+#define SQ_getforeignptr_slave(v) \
+    SlaveVM_st *self = (SlaveVM_st*)sq_getforeignptr(v);\
+    if(!self) return sq_throwerror(v, _SC("No slavevm foreignptr found"));
+
+static SQRESULT sq_vm_thread_lock(HSQUIRRELVM v)
+{
+    SQ_getforeignptr_slave(v);
+    sq_pushinteger(v, mg_thread_mutex_lock(&self->mutex));
+    return 1;
+}
+
+/*
+static SQRESULT sq_vm_thread_unlock(HSQUIRRELVM v)
+{
+    SQ_getforeignptr_slave(v);
+    sq_pushinteger(v, mg_thread_mutex_unlock(&self->mutex));
+    return 1;
+}
+*/
+
+static SQRESULT sq_vm_thread_cond_wait(HSQUIRRELVM v)
+{
+    SQ_getforeignptr_slave(v);
+    sq_pushinteger(v, mg_thread_cond_wait(&self->cond_var, &self->mutex));
+    return 1;
+}
+
+static SQRESULT sq_vm_thread_master_state(HSQUIRRELVM v)
+{
+    SQ_getforeignptr_slave(v);
+    sq_pushinteger(v, self->master_state);
+    return 1;
+}
+
+static SQRESULT sq_vm_thread_slave_state(HSQUIRRELVM v)
+{
+    SQ_FUNC_VARS(v);
+    SQ_getforeignptr_slave(v);
+    SQ_OPT_INTEGER(v, 2, state, 0);
+    sq_pushinteger(v, self->slave_state);
+    if(sq_gettop(v) > 1) self->slave_state = state;
+    return 1;
+}
+#endif // SLAVE_VM_WITH_OS_THREADS
+
+
 /*
 /*
 ** Creates a new SQuirrel vm.
 ** Creates a new SQuirrel vm.
 */
 */
@@ -134,6 +219,7 @@ static SQRESULT sq_slave_vm_constructor (HSQUIRRELVM v)
     SQ_FUNC_VARS(v);
     SQ_FUNC_VARS(v);
     SQ_OPT_INTEGER(v, 2, stack_size, 1024);
     SQ_OPT_INTEGER(v, 2, stack_size, 1024);
     SQ_OPT_BOOL(v, 3, with_libraries, false);
     SQ_OPT_BOOL(v, 3, with_libraries, false);
+    SQ_OPT_BOOL(v, 4, run_as_thread, false);
     HSQUIRRELVM self = sq_open(stack_size);
     HSQUIRRELVM self = sq_open(stack_size);
 
 
     /* Initialize environment */
     /* Initialize environment */
@@ -152,16 +238,54 @@ static SQRESULT sq_slave_vm_constructor (HSQUIRRELVM v)
         sq_poptop(self); //remove root table
         sq_poptop(self); //remove root table
     }
     }
 
 
-    sq_setinstanceup(v, 1, self);
+    SlaveVM_st *svm_st = (SlaveVM_st *)sq_malloc(sizeof(SlaveVM_st));
+    memset(svm_st, 0, sizeof(*svm_st));
+#ifdef SLAVE_VM_WITH_OS_THREADS
+    sq_setforeignptr(self, svm_st);
+    if(run_as_thread)
+    {
+        svm_st->isRunningAsThread = true;
+        svm_st->master_vm = v;
+        mg_thread_mutex_init(&svm_st->mutex, NULL);
+        mg_thread_cond_init(&svm_st->cond_var, NULL);
+
+        sq_pushroottable(self);
+        //sq_insertfunc(self, _SC("slavevm_thread_lock"), sq_vm_thread_lock, 1, _SC("."), SQFalse);
+        //sq_insertfunc(self, _SC("slavevm_unlock"), sq_vm_thread_unlock, 1, _SC("."), SQFalse);
+        sq_insertfunc(self, _SC("slavevm_thread_cond_wait"), sq_vm_thread_cond_wait, 1, _SC("."), SQFalse);
+        sq_insertfunc(self, _SC("slavevm_thread_master_state"), sq_vm_thread_master_state, 1, _SC("."), SQFalse);
+        sq_insertfunc(self, _SC("slavevm_thread_slave_state"), sq_vm_thread_slave_state, -1, _SC(".i"), SQFalse);
+        sq_poptop(self); //remove root table
+    }
+#endif // SLAVE_VM_WITH_OS_THREADS
+    svm_st->v = self;
+    svm_st->master_vm = v;
+
+    sq_setinstanceup(v, 1, svm_st);
     sq_setreleasehook(v, 1, sq_slave_vm_release_hook);
     sq_setreleasehook(v, 1, sq_slave_vm_release_hook);
 
 
     return 1;
     return 1;
 }
 }
 
 
+#ifdef SLAVE_VM_WITH_OS_THREADS
+static SQRESULT checkTryLock(HSQUIRRELVM v, SlaveVM_st *self)
+{
+    if(self->isRunningAsThread && mg_thread_mutex_trylock(&self->mutex))
+    {
+        return sq_throwerror(v, _SC("Could not aquire slave lock"));
+    }
+    return SQ_OK;
+}
+#endif // SLAVE_VM_WITH_OS_THREADS
+
 static SQRESULT sq_slave_vm_close(HSQUIRRELVM v)
 static SQRESULT sq_slave_vm_close(HSQUIRRELVM v)
 {
 {
     GET_sq_slave_vm_INSTANCE(v, 1);
     GET_sq_slave_vm_INSTANCE(v, 1);
-    sq_close(self);
+#ifdef SLAVE_VM_WITH_OS_THREADS
+    if(checkTryLock(v, self)) return SQ_ERROR;
+    releaseSlaveThread(self);
+#endif // SLAVE_VM_WITH_OS_THREADS
+    sq_close(svm);
     sq_setinstanceup(v, 1, 0); //next calls will fail with "vm is closed"
     sq_setinstanceup(v, 1, 0); //next calls will fail with "vm is closed"
     return 0;
     return 0;
 }
 }
@@ -172,33 +296,36 @@ static SQRESULT sq_slave_vm_call(HSQUIRRELVM v)
     GET_sq_slave_vm_INSTANCE(v, 1);
     GET_sq_slave_vm_INSTANCE(v, 1);
     SQ_GET_BOOL(v, 2, has_ret_val);
     SQ_GET_BOOL(v, 2, has_ret_val);
     SQ_GET_STRING(v, 3, func_name);
     SQ_GET_STRING(v, 3, func_name);
-    SQInteger top = sq_gettop(self);
+#ifdef SLAVE_VM_WITH_OS_THREADS
+    if(checkTryLock(v, self)) return SQ_ERROR;
+#endif // SLAVE_VM_WITH_OS_THREADS
+    SQInteger top = sq_gettop(svm);
     SQRESULT result = SQ_ERROR;
     SQRESULT result = SQ_ERROR;
-    sq_pushroottable(self);
-    sq_pushstring(self, func_name, func_name_size);
-    if(sq_get(self, -2) == SQ_OK)
+    sq_pushroottable(svm);
+    sq_pushstring(svm, func_name, func_name_size);
+    if(sq_get(svm, -2) == SQ_OK)
     {
     {
-        switch(sq_gettype(self, -1))
+        switch(sq_gettype(svm, -1))
         {
         {
         case OT_CLOSURE:
         case OT_CLOSURE:
         case OT_NATIVECLOSURE:
         case OT_NATIVECLOSURE:
         case OT_CLASS:
         case OT_CLASS:
         {
         {
-            sq_pushroottable(self);
+            sq_pushroottable(svm);
             int argc = sq_gettop(v) - 3;
             int argc = sq_gettop(v) - 3;
-            if(argc && copy_values_between_vms(self, v, argc, 4) != SQ_OK)
+            if(argc && copy_values_between_vms(svm, v, argc, 4) != SQ_OK)
             {
             {
-                sq_throwerror(v, sq_getlasterror_str(self));
+                result = sq_throwerror(v, sq_getlasterror_str(svm));
                 goto cleanup;
                 goto cleanup;
             }
             }
-            if(sq_call(self, argc+1, has_ret_val, SQFalse) != SQ_OK)
+            if(sq_call(svm, argc+1, has_ret_val, SQFalse) != SQ_OK)
             {
             {
-                sq_throwerror(v, sq_getlasterror_str(self));
+                result = sq_throwerror(v, sq_getlasterror_str(svm));
                 goto cleanup;
                 goto cleanup;
             }
             }
             if(has_ret_val)
             if(has_ret_val)
             {
             {
-                if(copy_values_between_vms(v, self, 1, sq_gettop(self)) == SQ_OK) result = 1;
+                if(copy_values_between_vms(v, svm, 1, sq_gettop(svm)) == SQ_OK) result = 1;
             }
             }
             else result = SQ_OK;
             else result = SQ_OK;
         }
         }
@@ -206,50 +333,65 @@ static SQRESULT sq_slave_vm_call(HSQUIRRELVM v)
     }
     }
     else
     else
     {
     {
-        sq_throwerror(v, sq_getlasterror_str(self));
+        result = sq_throwerror(v, sq_getlasterror_str(svm));
     }
     }
 cleanup:
 cleanup:
-    sq_settop(self, top);
+    sq_settop(svm, top);
+#ifdef SLAVE_VM_WITH_OS_THREADS
+    if(self->isRunningAsThread) mg_thread_mutex_unlock(&self->mutex);
+#endif // SLAVE_VM_WITH_OS_THREADS
     return result;
     return result;
 }
 }
 
 
 static SQRESULT sq_slave_vm_set(HSQUIRRELVM v)
 static SQRESULT sq_slave_vm_set(HSQUIRRELVM v)
 {
 {
     GET_sq_slave_vm_INSTANCE(v, 1);
     GET_sq_slave_vm_INSTANCE(v, 1);
-    SQInteger top = sq_gettop(self);
+#ifdef SLAVE_VM_WITH_OS_THREADS
+    if(checkTryLock(v, self)) return SQ_ERROR;
+#endif // SLAVE_VM_WITH_OS_THREADS
+    SQInteger top = sq_gettop(svm);
     SQRESULT result;
     SQRESULT result;
-    sq_pushroottable(self);
-    if(copy_values_between_vms(self, v, 1, 2) == SQ_OK
-            && copy_values_between_vms(self, v, 1, 3) == SQ_OK)
+    sq_pushroottable(svm);
+    if(copy_values_between_vms(svm, v, 1, 2) == SQ_OK
+            && copy_values_between_vms(svm, v, 1, 3) == SQ_OK)
     {
     {
-        result = sq_newslot(self, -3, SQFalse);
-        if(result == SQ_ERROR) sq_throwerror(v, sq_getlasterror_str(self));
+        result = sq_newslot(svm, -3, SQFalse);
+        if(result == SQ_ERROR) sq_throwerror(v, sq_getlasterror_str(svm));
     }
     }
     else result = SQ_ERROR;
     else result = SQ_ERROR;
-    sq_settop(self, top);
+    sq_settop(svm, top);
+#ifdef SLAVE_VM_WITH_OS_THREADS
+    if(self->isRunningAsThread) mg_thread_mutex_unlock(&self->mutex);
+#endif // SLAVE_VM_WITH_OS_THREADS
     return result;
     return result;
 }
 }
 
 
 static SQRESULT sq_slave_vm_get(HSQUIRRELVM v)
 static SQRESULT sq_slave_vm_get(HSQUIRRELVM v)
 {
 {
     GET_sq_slave_vm_INSTANCE(v, 1);
     GET_sq_slave_vm_INSTANCE(v, 1);
-    SQInteger top = sq_gettop(self);
+#ifdef SLAVE_VM_WITH_OS_THREADS
+    if(checkTryLock(v, self)) return SQ_ERROR;
+#endif // SLAVE_VM_WITH_OS_THREADS
+    SQInteger top = sq_gettop(svm);
     SQRESULT result = SQ_ERROR;
     SQRESULT result = SQ_ERROR;
-    sq_pushroottable(self);
-    if(copy_values_between_vms(self, v, 1, 2) == SQ_OK)
+    sq_pushroottable(svm);
+    if(copy_values_between_vms(svm, v, 1, 2) == SQ_OK)
     {
     {
-        if(sq_get(self, -2) == SQ_OK
-                && copy_values_between_vms(v, self, 1, sq_gettop(self)) == SQ_OK)
+        if(sq_get(svm, -2) == SQ_OK
+                && copy_values_between_vms(v, svm, 1, sq_gettop(svm)) == SQ_OK)
         {
         {
             result = 1;
             result = 1;
         }
         }
         else
         else
         {
         {
             if(sq_gettop(v) == 3) result = 1; //we have a default value
             if(sq_gettop(v) == 3) result = 1; //we have a default value
-            else sq_throwerror(v, sq_getlasterror_str(self));
+            else sq_throwerror(v, sq_getlasterror_str(svm));
         }
         }
     }
     }
-    sq_settop(self, top);
+    sq_settop(svm, top);
+#ifdef SLAVE_VM_WITH_OS_THREADS
+    if(self->isRunningAsThread) mg_thread_mutex_unlock(&self->mutex);
+#endif // SLAVE_VM_WITH_OS_THREADS
     return result;
     return result;
 }
 }
 
 
@@ -261,19 +403,25 @@ static SQRESULT sq_slave_vm_dofile(HSQUIRRELVM v)
     SQ_OPT_BOOL(v, 3, retval, false);
     SQ_OPT_BOOL(v, 3, retval, false);
     SQ_OPT_BOOL(v, 4, printerror, false);
     SQ_OPT_BOOL(v, 4, printerror, false);
     SQ_OPT_BOOL(v, 5, show_warnings, false);
     SQ_OPT_BOOL(v, 5, show_warnings, false);
-    SQInteger top = sq_gettop(self);
+#ifdef SLAVE_VM_WITH_OS_THREADS
+    if(checkTryLock(v, self)) return SQ_ERROR;
+#endif // SLAVE_VM_WITH_OS_THREADS
+    SQInteger top = sq_gettop(svm);
     SQRESULT result = SQ_ERROR;
     SQRESULT result = SQ_ERROR;
-    sq_pushroottable(self); //important always push the root table, because sqstd_dofile will try to do a sq_push(v, -2)
-    if(sqstd_dofile(self, file_name, retval, printerror, show_warnings) >= 0)
+    sq_pushroottable(svm); //important always push the root table, because sqstd_dofile will try to do a sq_push(v, -2)
+    if(sqstd_dofile(svm, file_name, retval, printerror, show_warnings) >= 0)
     {
     {
         if(retval)
         if(retval)
         {
         {
-            if(copy_values_between_vms(v, self, 1, sq_gettop(self)) == SQ_OK) result = 1;
+            if(copy_values_between_vms(v, svm, 1, sq_gettop(svm)) == SQ_OK) result = 1;
         }
         }
         else result = SQ_OK;
         else result = SQ_OK;
     }
     }
-    else sq_throwerror(v, sq_getlasterror_str(self));
-    sq_settop(self, top);
+    else sq_throwerror(v, sq_getlasterror_str(svm));
+    sq_settop(svm, top);
+#ifdef SLAVE_VM_WITH_OS_THREADS
+    if(self->isRunningAsThread) mg_thread_mutex_unlock(&self->mutex);
+#endif // SLAVE_VM_WITH_OS_THREADS
     return result;
     return result;
 }
 }
 
 
@@ -285,15 +433,21 @@ static SQRESULT sq_slave_vm_loadfile(HSQUIRRELVM v)
     SQ_GET_STRING(v, 3, file_name);
     SQ_GET_STRING(v, 3, file_name);
     SQ_OPT_BOOL(v, 4, printerror, false);
     SQ_OPT_BOOL(v, 4, printerror, false);
     SQ_OPT_BOOL(v, 5, show_warnings, false);
     SQ_OPT_BOOL(v, 5, show_warnings, false);
-    SQInteger top = sq_gettop(self);
+#ifdef SLAVE_VM_WITH_OS_THREADS
+    if(checkTryLock(v, self)) return SQ_ERROR;
+#endif // SLAVE_VM_WITH_OS_THREADS
+    SQInteger top = sq_gettop(svm);
     SQRESULT result = SQ_ERROR;
     SQRESULT result = SQ_ERROR;
-    sq_pushroottable(self);
-    sq_pushstring(self, func_name, func_name_size);
-    if(sqstd_loadfile(self, file_name, printerror, show_warnings) >= 0)
+    sq_pushroottable(svm);
+    sq_pushstring(svm, func_name, func_name_size);
+    if(sqstd_loadfile(svm, file_name, printerror, show_warnings) >= 0)
     {
     {
-        result = sq_newslot(self, -3, SQFalse);
+        result = sq_newslot(svm, -3, SQFalse);
     }
     }
-    sq_settop(self, top);
+    sq_settop(svm, top);
+#ifdef SLAVE_VM_WITH_OS_THREADS
+    if(self->isRunningAsThread) mg_thread_mutex_unlock(&self->mutex);
+#endif // SLAVE_VM_WITH_OS_THREADS
     return result;
     return result;
 }
 }
 
 
@@ -306,27 +460,195 @@ static SQRESULT sq_slave_vm_compilestring(HSQUIRRELVM v)
     SQ_OPT_BOOL(v, 4, printerror, false);
     SQ_OPT_BOOL(v, 4, printerror, false);
     SQ_OPT_BOOL(v, 5, show_warnings, false);
     SQ_OPT_BOOL(v, 5, show_warnings, false);
     SQ_OPT_INTEGER(v, 6, max_nested_includes, 0);
     SQ_OPT_INTEGER(v, 6, max_nested_includes, 0);
-    SQInteger top = sq_gettop(self);
+#ifdef SLAVE_VM_WITH_OS_THREADS
+    if(checkTryLock(v, self)) return SQ_ERROR;
+#endif // SLAVE_VM_WITH_OS_THREADS
+    SQInteger top = sq_gettop(svm);
     SQRESULT result = SQ_ERROR;
     SQRESULT result = SQ_ERROR;
-    sq_pushroottable(self);
-    sq_pushstring(self, func_name, func_name_size);
-    if(sq_compilebuffer(self, str_script, str_script_size, func_name, printerror, show_warnings, max_nested_includes) >= 0)
+    sq_pushroottable(svm);
+    sq_pushstring(svm, func_name, func_name_size);
+    if(sq_compilebuffer(svm, str_script, str_script_size, func_name, printerror, show_warnings, max_nested_includes) >= 0)
     {
     {
-        result = sq_newslot(self, -3, SQFalse);
+        result = sq_newslot(svm, -3, SQFalse);
     }
     }
     else
     else
     {
     {
-        const SQChar *last_error = sq_getlasterror_str(self);
+        const SQChar *last_error = sq_getlasterror_str(svm);
         if(last_error) {
         if(last_error) {
             SQInteger line, column;
             SQInteger line, column;
-            sq_getlasterror_line_col(self, &line, &column);
+            sq_getlasterror_line_col(svm, &line, &column);
             result = sq_throwerror(v, _SC("compilestring %s %d:%d: %s"), func_name, line, column, last_error);
             result = sq_throwerror(v, _SC("compilestring %s %d:%d: %s"), func_name, line, column, last_error);
         }
         }
     }
     }
-    sq_settop(self, top);
+    sq_settop(svm, top);
+#ifdef SLAVE_VM_WITH_OS_THREADS
+    if(self->isRunningAsThread) mg_thread_mutex_unlock(&self->mutex);
+#endif // SLAVE_VM_WITH_OS_THREADS
+    return result;
+}
+
+extern SQInteger _g_io_dostring(HSQUIRRELVM v);
+
+static SQRESULT sq_slave_vm_dostring(HSQUIRRELVM v)
+{
+    SQ_FUNC_VARS(v);
+    GET_sq_slave_vm_INSTANCE(v, 1);
+    SQ_GET_STRING(v, 2, str);
+    SQ_OPT_BOOL(v, 3, retval, false);
+#ifdef SLAVE_VM_WITH_OS_THREADS
+    if(checkTryLock(v, self)) return SQ_ERROR;
+#endif // SLAVE_VM_WITH_OS_THREADS
+    SQInteger top = sq_gettop(svm);
+    sq_pushroottable(svm); //important always push the root table, because sqstd_dofile will try to do a sq_push(v, -2)
+    sq_pushstring(svm, str, str_size);
+    sq_pushbool(svm, retval);
+    SQRESULT result = _g_io_dostring(svm);
+    if(result == SQ_ERROR) sq_settop(svm, top);
+#ifdef SLAVE_VM_WITH_OS_THREADS
+    if(self->isRunningAsThread) mg_thread_mutex_unlock(&self->mutex);
+#endif // SLAVE_VM_WITH_OS_THREADS
     return result;
     return result;
 }
 }
 
 
+static SQRESULT sq_slave_vm_is_thread_idle(HSQUIRRELVM v)
+{
+#ifdef SLAVE_VM_WITH_OS_THREADS
+    GET_sq_slave_vm_INSTANCE(v, 1);
+    int rc = mg_thread_mutex_trylock(&self->mutex) == 0;
+    if(rc) mg_thread_mutex_unlock(&self->mutex);
+    sq_pushbool(v, rc);
+#else
+    sq_pushbool(v, SQTrue);
+#endif
+    return 1;
+}
+
+static SQRESULT sq_slave_vm_is_runing_as_thread(HSQUIRRELVM v)
+{
+#ifdef SLAVE_VM_WITH_OS_THREADS
+    GET_sq_slave_vm_INSTANCE(v, 1);
+    sq_pushbool(v, self->isRunningAsThread);
+#else
+    sq_pushbool(v, SQFalse);
+#endif
+    return 1;
+}
+
+#ifdef SLAVE_VM_WITH_OS_THREADS
+
+#define check_run_as_thread(v) \
+    if(!self->isRunningAsThread) return sq_throwerror(v, _SC("Slave VM not running as thread"))
+
+static void *slaveThreadTask(void *p)
+{
+    SlaveVM_st *self = (SlaveVM_st*)p;
+    self->thread_id = mg_thread_self();
+    HSQUIRRELVM svm = self->v;
+    int rc;
+    SQInteger top, argc;
+    rc = sq_getinteger(svm, -1, &top) == SQ_OK;
+    if(rc)
+    {
+        rc = sq_getinteger(svm, -2, &argc) == SQ_OK;
+        if(rc)
+        {
+            sq_pop(svm, 2); //remove top & argc
+            rc = sq_call(svm, argc+1, SQFalse, SQFalse);
+        }
+        sq_settop(svm, top);
+    }
+    rc = mg_thread_mutex_unlock(&self->mutex);
+    self->thread_id = 0;
+    //printf("%d:%d:%s\n", __LINE__, rc, __FILE__);
+    return NULL;
+}
+
+extern int sq_system_sleep(int n);
+
+static SQRESULT sq_slave_vm_thread_run(HSQUIRRELVM v)
+{
+    GET_sq_slave_vm_INSTANCE(v, 1);
+    check_run_as_thread(v);
+
+    int rc;
+    const SQChar *func_name;
+    SQInteger func_name_size;
+    if(self->thread_id) return sq_throwerror(v, _SC("slavevm already running in a thread"));
+    SQInteger top = sq_gettop(svm);
+    rc = mg_thread_mutex_trylock(&self->mutex) == 0;
+    if(rc)
+    {
+        sq_getstr_and_size(v, 2, &func_name, &func_name_size);
+        sq_pushstring(svm, func_name, func_name_size);
+        sq_getonroottable(svm);
+        //printf("%d:%s\n", __LINE__, __FILE__);
+        rc = (sq_gettype(svm, -1) == OT_CLOSURE);
+        if( rc )
+        {
+            //printf("%d:%s\n", __LINE__, __FILE__);
+            sq_pushroottable(svm);
+            int argc = sq_gettop(v) - 2;
+            rc = ( (argc == 0) || (copy_values_between_vms(svm, v, argc, 3) == SQ_OK));
+            if(rc)
+            {
+                sq_pushinteger(svm, argc);
+                sq_pushinteger(svm, top);
+                rc = mg_start_thread(slaveThreadTask, self) == 0;
+                if(rc) goto done;
+            }
+            //printf("%d:%d:%s\n", __LINE__, rc, __FILE__);
+        }
+        sq_settop(svm, top); //something went wrong reset slave stack
+    }
+done:
+    sq_pushbool(v, rc);
+    return 1;
+}
+
+static SQRESULT sq_slave_vm_thread_trylock(HSQUIRRELVM v)
+{
+    GET_sq_slave_vm_INSTANCE(v, 1);
+    check_run_as_thread(v);
+    sq_pushinteger(v, mg_thread_mutex_trylock(&self->mutex));
+    return 1;
+}
+
+static SQRESULT sq_slave_vm_thread_unlock(HSQUIRRELVM v)
+{
+    GET_sq_slave_vm_INSTANCE(v, 1);
+    check_run_as_thread(v);
+    sq_pushinteger(v, mg_thread_mutex_unlock(&self->mutex));
+    return 1;
+}
+
+static SQRESULT sq_slave_vm_thread_cond_signal(HSQUIRRELVM v)
+{
+    GET_sq_slave_vm_INSTANCE(v, 1);
+    check_run_as_thread(v);
+    sq_pushinteger(v, mg_thread_cond_signal(&self->cond_var));
+    return 1;
+}
+
+static SQRESULT sq_slave_vm_thread_master_state(HSQUIRRELVM v)
+{
+    SQ_FUNC_VARS(v);
+    GET_sq_slave_vm_INSTANCE(v, 1);
+    check_run_as_thread(v);
+    SQ_OPT_INTEGER(v, 2, state, 0);
+    sq_pushinteger(v, self->master_state);
+    if(sq_gettop(v) > 1) self->master_state = state;
+    return 1;
+}
+
+static SQRESULT sq_slave_vm_thread_slave_state(HSQUIRRELVM v)
+{
+    GET_sq_slave_vm_INSTANCE(v, 1);
+    check_run_as_thread(v);
+    sq_pushinteger(v, self->slave_state);
+    return 1;
+}
+#endif // SLAVE_VM_WITH_OS_THREADS
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
 #endif
 #endif
@@ -337,7 +659,7 @@ extern "C" {
         sq_pushstring(v,sq_slave_vm_TAG, -1);
         sq_pushstring(v,sq_slave_vm_TAG, -1);
         sq_newclass(v, SQFalse);
         sq_newclass(v, SQFalse);
         sq_settypetag(v,-1,(void*)sq_slave_vm_TAG);
         sq_settypetag(v,-1,(void*)sq_slave_vm_TAG);
-        sq_insertfunc(v, _SC("constructor"), sq_slave_vm_constructor, -1, _SC("xib"), SQFalse);
+        sq_insertfunc(v, _SC("constructor"), sq_slave_vm_constructor, -1, _SC("xibb"), SQFalse);
         sq_insertfunc(v, _SC("_tostring"), sq_slave_vm__tostring, 1, _SC("x"), SQFalse);
         sq_insertfunc(v, _SC("_tostring"), sq_slave_vm__tostring, 1, _SC("x"), SQFalse);
         sq_insertfunc(v, _SC("close"), sq_slave_vm_close, 1, _SC("x"), SQFalse);
         sq_insertfunc(v, _SC("close"), sq_slave_vm_close, 1, _SC("x"), SQFalse);
         sq_insertfunc(v, _SC("set"), sq_slave_vm_set, 3, get_set_validation_mask, SQFalse);
         sq_insertfunc(v, _SC("set"), sq_slave_vm_set, 3, get_set_validation_mask, SQFalse);
@@ -346,8 +668,19 @@ extern "C" {
         sq_insertfunc(v, _SC("_get"), sq_slave_vm_get, -2, get_set_validation_mask, SQFalse);
         sq_insertfunc(v, _SC("_get"), sq_slave_vm_get, -2, get_set_validation_mask, SQFalse);
         sq_insertfunc(v, _SC("dofile"), sq_slave_vm_dofile, -2, _SC("xsbbb"), SQFalse);
         sq_insertfunc(v, _SC("dofile"), sq_slave_vm_dofile, -2, _SC("xsbbb"), SQFalse);
         sq_insertfunc(v, _SC("loadfile"), sq_slave_vm_loadfile, -3, _SC("xssbb"), SQFalse);
         sq_insertfunc(v, _SC("loadfile"), sq_slave_vm_loadfile, -3, _SC("xssbb"), SQFalse);
+        sq_insertfunc(v, _SC("dostring"), sq_slave_vm_dostring, -2, _SC("xsb"), SQFalse);
         sq_insertfunc(v, _SC("compilestring"), sq_slave_vm_compilestring, -3, _SC("xssbbi"), SQFalse);
         sq_insertfunc(v, _SC("compilestring"), sq_slave_vm_compilestring, -3, _SC("xssbbi"), SQFalse);
         sq_insertfunc(v, _SC("call"), sq_slave_vm_call, -3, _SC("xbs"), SQFalse);
         sq_insertfunc(v, _SC("call"), sq_slave_vm_call, -3, _SC("xbs"), SQFalse);
+        sq_insertfunc(v, _SC("is_thread_idle"), sq_slave_vm_is_thread_idle, 1, _SC("x"), SQFalse);
+        sq_insertfunc(v, _SC("is_runing_as_thread"), sq_slave_vm_is_runing_as_thread, 1, _SC("x"), SQFalse);
+#ifdef SLAVE_VM_WITH_OS_THREADS
+        sq_insertfunc(v, _SC("thread_run"), sq_slave_vm_thread_run, -2, _SC("xs"), SQFalse);
+        sq_insertfunc(v, _SC("thread_trylock"), sq_slave_vm_thread_trylock, 1, _SC("x"), SQFalse);
+        sq_insertfunc(v, _SC("thread_unlock"), sq_slave_vm_thread_unlock, 1, _SC("x"), SQFalse);
+        sq_insertfunc(v, _SC("thread_cond_signal"), sq_slave_vm_thread_cond_signal, 1, _SC("x"), SQFalse);
+        sq_insertfunc(v, _SC("thread_master_state"), sq_slave_vm_thread_master_state, -1, _SC("xi"), SQFalse);
+        sq_insertfunc(v, _SC("thread_slave_state"), sq_slave_vm_thread_slave_state, 1, _SC("x"), SQFalse);
+#endif // SLAVE_VM_WITH_OS_THREADS
 
 
         sq_newslot(v,-3,SQTrue); //push sq_slave_vm class
         sq_newslot(v,-3,SQTrue); //push sq_slave_vm class
         return 0;
         return 0;

+ 56 - 1
SquiLu/samples/test-slave-vm.nut

@@ -1,7 +1,62 @@
+local svm = SlaveVM(1024, true, true);
+
+print(svm);
+print(svm.is_thread_idle(), svm.is_runing_as_thread());
+
+if(svm.is_runing_as_thread())
+{
+	auto slave_code = [==[
+auto count = 0;
+
+function getCount(){return count;}
+
+function slaveThreadTask(max_loop)
+{
+	print("==========", max_loop);
+	//foreach(k,v in getroottable()) print(k,v);
+	//print("slavevm_thread_lock", slavevm_thread_lock());
+	
+	for(auto i=0; i < max_loop; ++i)
+	{
+		count += max_loop;
+		print("count", count);
+		print("slavevm_thread_slave_state", slavevm_thread_slave_state(count));
+		print("slavevm_thread_cond_wait", slavevm_thread_cond_wait());
+		//print("slavevm_thread_lock", slavevm_thread_lock());
+	}
+}
+
+]==];
+
+	//local slave_func = "svm_code";
+	//svm.compilestring(slave_func, slave_code);
+	//svm.call(false, slave_func);
+	svm.dostring(slave_code);
+
+	svm.thread_run("slaveThreadTask", 5);
+
+	for(auto i=0; i < 10; ++i)
+	{
+		do {
+			os.sleep(1000);
+			print(i);
+			if(svm.is_thread_idle())
+			{
+				print("==thread_slave_state", svm.thread_slave_state());
+				print("==thread_cond_signal", svm.thread_cond_signal());
+				break;
+			}
+		} while(!svm.is_thread_idle());
+		
+	}
+}
+
 local vm = SlaveVM();
 local vm = SlaveVM();
 vm.set("_slave_", true);
 vm.set("_slave_", true);
 
 
 print(vm);
 print(vm);
+print(vm.is_thread_idle(), vm.is_runing_as_thread());
+
 print(vm.get("_version_"));
 print(vm.get("_version_"));
 vm.set("dad", "Domingo");
 vm.set("dad", "Domingo");
 print(vm.get("dad"));
 print(vm.get("dad"));
@@ -29,7 +84,7 @@ local ar = "1,2,3,4,5".split(',');
 print("1,2,3,4,5".split(','));
 print("1,2,3,4,5".split(','));
 
 
 local globals = getroottable();
 local globals = getroottable();
-if(!globals.get("_slave_", false)){
+if(!table_get(globals, "_slave_", false)){
 	print("I'm not a slave !");
 	print("I'm not a slave !");
 	//vm.dofile("test-slave-vm.nut");
 	//vm.dofile("test-slave-vm.nut");
 	//vm.dofile("loops.nut");
 	//vm.dofile("loops.nut");

+ 157 - 153
SquiLu/sqstdlib/sqstdsystem.cpp

@@ -1,39 +1,39 @@
-/* see copyright notice in squirrel.h */
+/* see copyright notice in squirrel.h */
 #include <squirrel.h>
 #include <squirrel.h>
 #include <string.h>
 #include <string.h>
-#include "sqstdblobimpl.h"
-#include <time.h>
-#include <stdlib.h>
+#include "sqstdblobimpl.h"
+#include <time.h>
+#include <stdlib.h>
 #include <stdio.h>
 #include <stdio.h>
 #ifdef _WIN32_WCE
 #ifdef _WIN32_WCE
 #include "celibc.h"
 #include "celibc.h"
 #else
 #else
 #include <signal.h>
 #include <signal.h>
-#endif
+#endif
 #include <sqstdsystem.h>
 #include <sqstdsystem.h>
 
 
 #ifdef _WIN32
 #ifdef _WIN32
 #include <windows.h>
 #include <windows.h>
 #else
 #else
 #include <unistd.h>
 #include <unistd.h>
-#endif
-
-#ifdef SQUNICODE
-#include <wchar.h>
-#define scgetenv _wgetenv
-#define scsystem _wsystem
-#define scasctime _wasctime
-#define scstrftime _wstrftime
-#define scremove _wremove
-#define screname _wrename
-#else
-#define scgetenv getenv
-#define scsystem system
-#define scasctime asctime
-#define scstrftime strftime
-#define scremove remove
-#define screname rename
-#endif
+#endif
+
+#ifdef SQUNICODE
+#include <wchar.h>
+#define scgetenv _wgetenv
+#define scsystem _wsystem
+#define scasctime _wasctime
+#define scstrftime _wstrftime
+#define scremove _wremove
+#define screname _wrename
+#else
+#define scgetenv getenv
+#define scsystem system
+#define scasctime asctime
+#define scstrftime strftime
+#define scremove remove
+#define screname rename
+#endif
 
 
 SQ_OPT_STRING_STRLEN();
 SQ_OPT_STRING_STRLEN();
 
 
@@ -45,11 +45,11 @@ SQ_OPT_STRING_STRLEN();
 #include <uuid/uuid.h>
 #include <uuid/uuid.h>
 #endif
 #endif
 
 
-static SQRESULT _system_getuuid(HSQUIRRELVM v)
-{
+static SQRESULT _system_getuuid(HSQUIRRELVM v)
+{
     char s[64];
     char s[64];
 #ifdef _WIN32
 #ifdef _WIN32
-    UUID uuid;
+    UUID uuid;
     UuidCreate ( &uuid );
     UuidCreate ( &uuid );
 
 
     UuidToStringA ( &uuid, (unsigned char**)&s );
     UuidToStringA ( &uuid, (unsigned char**)&s );
@@ -62,44 +62,44 @@ static SQRESULT _system_getuuid(HSQUIRRELVM v)
     uuid_generate_random ( uuid );
     uuid_generate_random ( uuid );
     uuid_unparse ( uuid, s );
     uuid_unparse ( uuid, s );
     sq_pushstring(v,s,-1);
     sq_pushstring(v,s,-1);
-#endif
-	return 1;
-}
-#endif
-static SQRESULT _system_getenv(HSQUIRRELVM v)
-{
-	const SQChar *s;
-	if(SQ_SUCCEEDED(sq_getstring(v,2,&s))){
-        sq_pushstring(v,scgetenv(s),-1);
-		return 1;
-	}
-	return 0;
-}
-
-static SQRESULT _system_system(HSQUIRRELVM v)
-{
-	const SQChar *s;
-	if(SQ_SUCCEEDED(sq_getstring(v,2,&s))){
-		sq_pushinteger(v,scsystem(s));
-		return 1;
-	}
-	return sq_throwerror(v,_SC("wrong param"));
-}
-
-
-static SQRESULT _system_clock(HSQUIRRELVM v)
-{
-	sq_pushfloat(v,((SQFloat)clock())/(SQFloat)CLOCKS_PER_SEC);
-	return 1;
-}
-
-/*
-static SQRESULT _system_time(HSQUIRRELVM v)
-{
-	time_t t;
-	time(&t);
-	sq_pushinteger(v,*((SQInteger *)&t));
-	return 1;
+#endif
+	return 1;
+}
+#endif
+static SQRESULT _system_getenv(HSQUIRRELVM v)
+{
+	const SQChar *s;
+	if(SQ_SUCCEEDED(sq_getstring(v,2,&s))){
+        sq_pushstring(v,scgetenv(s),-1);
+		return 1;
+	}
+	return 0;
+}
+
+static SQRESULT _system_system(HSQUIRRELVM v)
+{
+	const SQChar *s;
+	if(SQ_SUCCEEDED(sq_getstring(v,2,&s))){
+		sq_pushinteger(v,scsystem(s));
+		return 1;
+	}
+	return sq_throwerror(v,_SC("wrong param"));
+}
+
+
+static SQRESULT _system_clock(HSQUIRRELVM v)
+{
+	sq_pushfloat(v,((SQFloat)clock())/(SQFloat)CLOCKS_PER_SEC);
+	return 1;
+}
+
+/*
+static SQRESULT _system_time(HSQUIRRELVM v)
+{
+	time_t t;
+	time(&t);
+	sq_pushinteger(v,*((SQInteger *)&t));
+	return 1;
 }
 }
 */
 */
 
 
@@ -167,43 +167,43 @@ static SQRESULT _system_time(HSQUIRRELVM v) {
   else sq_pushinteger(v,(SQInteger)t);
   else sq_pushinteger(v,(SQInteger)t);
   return 1;
   return 1;
 }
 }
-
-
+
+
 static SQRESULT _system_difftime (HSQUIRRELVM v) {
 static SQRESULT _system_difftime (HSQUIRRELVM v) {
     SQ_FUNC_VARS(v);
     SQ_FUNC_VARS(v);
     SQ_GET_FLOAT(v, 2, t1);
     SQ_GET_FLOAT(v, 2, t1);
     SQ_OPT_FLOAT(v, 3, t2, 0);
     SQ_OPT_FLOAT(v, 3, t2, 0);
     sq_pushfloat(v, difftime( (time_t)t1, (time_t)t2));
     sq_pushfloat(v, difftime( (time_t)t1, (time_t)t2));
   return 1;
   return 1;
-}
-
-static SQRESULT _system_remove(HSQUIRRELVM v)
-{
-	const SQChar *s;
-	sq_getstring(v,2,&s);
-	if(scremove(s)==-1)
-		return sq_throwerror(v,_SC("remove() failed"));
-	return 0;
-}
-
-static SQRESULT _system_rename(HSQUIRRELVM v)
-{
-	const SQChar *oldn,*newn;
-	sq_getstring(v,2,&oldn);
-	sq_getstring(v,3,&newn);
-	if(screname(oldn,newn)==-1)
-		return sq_throwerror(v,_SC("rename() failed"));
-	return 0;
-}
-
-static void _set_integer_slot(HSQUIRRELVM v,const SQChar *name,SQInteger val)
-{
-	sq_pushstring(v,name,-1);
-	sq_pushinteger(v,val);
-	sq_rawset(v,-3);
-}
-
-static SQRESULT _system_date(HSQUIRRELVM v)
+}
+
+static SQRESULT _system_remove(HSQUIRRELVM v)
+{
+	const SQChar *s;
+	sq_getstring(v,2,&s);
+	if(scremove(s)==-1)
+		return sq_throwerror(v,_SC("remove() failed"));
+	return 0;
+}
+
+static SQRESULT _system_rename(HSQUIRRELVM v)
+{
+	const SQChar *oldn,*newn;
+	sq_getstring(v,2,&oldn);
+	sq_getstring(v,3,&newn);
+	if(screname(oldn,newn)==-1)
+		return sq_throwerror(v,_SC("rename() failed"));
+	return 0;
+}
+
+static void _set_integer_slot(HSQUIRRELVM v,const SQChar *name,SQInteger val)
+{
+	sq_pushstring(v,name,-1);
+	sq_pushinteger(v,val);
+	sq_rawset(v,-3);
+}
+
+static SQRESULT _system_date(HSQUIRRELVM v)
 {
 {
     SQ_FUNC_VARS(v);
     SQ_FUNC_VARS(v);
     const SQChar *arg_format;
     const SQChar *arg_format;
@@ -230,7 +230,7 @@ static SQRESULT _system_date(HSQUIRRELVM v)
         arg_format = _SC("%c");
         arg_format = _SC("%c");
         arg_time = time(NULL);
         arg_time = time(NULL);
     }
     }
-	time_t t = (time_t)arg_time;
+	time_t t = (time_t)arg_time;
 
 
     struct tm *stm;
     struct tm *stm;
 #ifdef SQ_USE_LOCALTIME_R
 #ifdef SQ_USE_LOCALTIME_R
@@ -251,14 +251,14 @@ static SQRESULT _system_date(HSQUIRRELVM v)
     if (stm == NULL)  /* invalid date? */
     if (stm == NULL)  /* invalid date? */
         sq_pushnull(v);
         sq_pushnull(v);
     else if (scstrcmp(arg_format, _SC("*t")) == 0) {
     else if (scstrcmp(arg_format, _SC("*t")) == 0) {
-        sq_newtableex(v, 9); /* 9 = number of fields */
-        _set_integer_slot(v, _SC("sec"), stm->tm_sec);
-        _set_integer_slot(v, _SC("min"), stm->tm_min);
-        _set_integer_slot(v, _SC("hour"), stm->tm_hour);
-        _set_integer_slot(v, _SC("day"), stm->tm_mday);
-        _set_integer_slot(v, _SC("month"), stm->tm_mon);
-        _set_integer_slot(v, _SC("year"), stm->tm_year+1900);
-        _set_integer_slot(v, _SC("wday"), stm->tm_wday);
+        sq_newtableex(v, 9); /* 9 = number of fields */
+        _set_integer_slot(v, _SC("sec"), stm->tm_sec);
+        _set_integer_slot(v, _SC("min"), stm->tm_min);
+        _set_integer_slot(v, _SC("hour"), stm->tm_hour);
+        _set_integer_slot(v, _SC("day"), stm->tm_mday);
+        _set_integer_slot(v, _SC("month"), stm->tm_mon);
+        _set_integer_slot(v, _SC("year"), stm->tm_year+1900);
+        _set_integer_slot(v, _SC("wday"), stm->tm_wday);
         _set_integer_slot(v, _SC("yday"), stm->tm_yday);
         _set_integer_slot(v, _SC("yday"), stm->tm_yday);
         sq_pushliteral(v, _SC("isdst"));
         sq_pushliteral(v, _SC("isdst"));
         sq_pushbool(v, stm->tm_isdst);
         sq_pushbool(v, stm->tm_isdst);
@@ -281,9 +281,9 @@ static SQRESULT _system_date(HSQUIRRELVM v)
         }
         }
         sq_pushstring(v, (const SQChar*)b.GetBuf(), b.Len());
         sq_pushstring(v, (const SQChar*)b.GetBuf(), b.Len());
     }
     }
-    return 1;
+    return 1;
 }
 }
-
+
 static SQRESULT _system_exit (HSQUIRRELVM v) {
 static SQRESULT _system_exit (HSQUIRRELVM v) {
   SQRESULT status = 0;
   SQRESULT status = 0;
   SQ_FUNC_VARS(v);
   SQ_FUNC_VARS(v);
@@ -348,19 +348,23 @@ static SQRESULT _system_setlocale (HSQUIRRELVM v) {
   return 0;
   return 0;
 #endif
 #endif
 }
 }
-
+
 /*-------------------------------------------------------------------------*\
 /*-------------------------------------------------------------------------*\
 * Sleep for n miliseconds.
 * Sleep for n miliseconds.
 \*-------------------------------------------------------------------------*/
 \*-------------------------------------------------------------------------*/
-static SQRESULT  _system_sleep(HSQUIRRELVM v)
+int sq_system_sleep(int n)
 {
 {
-    SQ_FUNC_VARS_NO_TOP(v);
-    SQ_GET_INTEGER(v, 2, n);
 #ifdef _WIN32
 #ifdef _WIN32
-    Sleep((int)n);
+    return Sleep(n);
 #else
 #else
-    usleep((n)*1000);
+    return usleep((n)*1000);
 #endif
 #endif
+}
+static SQRESULT  _system_sleep(HSQUIRRELVM v)
+{
+    SQ_FUNC_VARS_NO_TOP(v);
+    SQ_GET_INTEGER(v, 2, n);
+    sq_system_sleep(n);
     return 0;
     return 0;
 }
 }
 
 
@@ -626,56 +630,56 @@ static SQRESULT _system_raise(HSQUIRRELVM v)
     return sig;
     return sig;
 }
 }
 #endif
 #endif
-
-#define _DECL_FUNC(name,nparams,pmask) {_SC(#name),_system_##name,nparams,pmask}
+
+#define _DECL_FUNC(name,nparams,pmask) {_SC(#name),_system_##name,nparams,pmask}
 static SQRegFunction systemlib_funcs[]={
 static SQRegFunction systemlib_funcs[]={
-	_DECL_FUNC(getenv,2,_SC(".s")),
-	_DECL_FUNC(system,2,_SC(".s")),
-	_DECL_FUNC(clock,0,NULL),
-	_DECL_FUNC(remove,2,_SC(".s")),
-	_DECL_FUNC(rename,3,_SC(".ss")),
-	_DECL_FUNC(date,-1,_SC(". s|n")),
-	_DECL_FUNC(tmpname,1,_SC(".")),
-	_DECL_FUNC(setlocale,-1,_SC(".ss")),
+	_DECL_FUNC(getenv,2,_SC(".s")),
+	_DECL_FUNC(system,2,_SC(".s")),
+	_DECL_FUNC(clock,0,NULL),
+	_DECL_FUNC(remove,2,_SC(".s")),
+	_DECL_FUNC(rename,3,_SC(".ss")),
+	_DECL_FUNC(date,-1,_SC(". s|n")),
+	_DECL_FUNC(tmpname,1,_SC(".")),
+	_DECL_FUNC(setlocale,-1,_SC(".ss")),
 	_DECL_FUNC(time,-1,_SC(".t")),
 	_DECL_FUNC(time,-1,_SC(".t")),
-	_DECL_FUNC(difftime,-2,_SC(".nn")),
-	_DECL_FUNC(exit, -1,_SC(". b|i b")),
+	_DECL_FUNC(difftime,-2,_SC(".nn")),
+	_DECL_FUNC(exit, -1,_SC(". b|i b")),
 	_DECL_FUNC(sleep, 2,_SC(".i")),
 	_DECL_FUNC(sleep, 2,_SC(".i")),
-#ifdef WITH_UUID
+#ifdef WITH_UUID
 	_DECL_FUNC(getuuid, 0, NULL),
 	_DECL_FUNC(getuuid, 0, NULL),
-#endif
-#ifndef _WIN32_WCE
-	_DECL_FUNC(getmillicount,1,_SC(".")),
-	_DECL_FUNC(getmillispan,2,_SC(".i")),
+#endif
+#ifndef _WIN32_WCE
+	_DECL_FUNC(getmillicount,1,_SC(".")),
+	_DECL_FUNC(getmillispan,2,_SC(".i")),
 #endif
 #endif
 #ifdef USE_SIGNAL_HANDLER
 #ifdef USE_SIGNAL_HANDLER
-	_DECL_FUNC(set_signal_received,2,_SC(".i")),
-	_DECL_FUNC(get_signal_received,1,_SC(".")),
-	_DECL_FUNC(signal,2,_SC(". i|s")),
+	_DECL_FUNC(set_signal_received,2,_SC(".i")),
+	_DECL_FUNC(get_signal_received,1,_SC(".")),
+	_DECL_FUNC(signal,2,_SC(". i|s")),
 	_DECL_FUNC(raise,2,_SC(". i|s")),
 	_DECL_FUNC(raise,2,_SC(". i|s")),
 	_DECL_FUNC(signal_str2int,2,_SC(".s")),
 	_DECL_FUNC(signal_str2int,2,_SC(".s")),
 	_DECL_FUNC(signal_int2str,2,_SC(".i")),
 	_DECL_FUNC(signal_int2str,2,_SC(".i")),
-#endif
-	{NULL,(SQFUNCTION)0,0,NULL}
-};
-#undef _DECL_FUNC
-
-SQInteger sqstd_register_systemlib(HSQUIRRELVM v)
-{
+#endif
+	{NULL,(SQFUNCTION)0,0,NULL}
+};
+#undef _DECL_FUNC
+
+SQInteger sqstd_register_systemlib(HSQUIRRELVM v)
+{
     sq_pushstring(v,_SC("os"),-1);
     sq_pushstring(v,_SC("os"),-1);
     sq_newtable(v);
     sq_newtable(v);
 
 
-	SQInteger i=0;
-	while(systemlib_funcs[i].name!=0)
-	{
-		sq_pushstring(v,systemlib_funcs[i].name,-1);
-		sq_newclosure(v,systemlib_funcs[i].f,0);
-		sq_setparamscheck(v,systemlib_funcs[i].nparamscheck,systemlib_funcs[i].typemask);
-		sq_setnativeclosurename(v,-1,systemlib_funcs[i].name);
-		sq_newslot(v,-3,SQFalse);
-		i++;
-	}
-
-	sq_newslot(v,-3,SQTrue); //insert os
-	return 1;
-}
+	SQInteger i=0;
+	while(systemlib_funcs[i].name!=0)
+	{
+		sq_pushstring(v,systemlib_funcs[i].name,-1);
+		sq_newclosure(v,systemlib_funcs[i].f,0);
+		sq_setparamscheck(v,systemlib_funcs[i].nparamscheck,systemlib_funcs[i].typemask);
+		sq_setnativeclosurename(v,-1,systemlib_funcs[i].name);
+		sq_newslot(v,-3,SQFalse);
+		i++;
+	}
+
+	sq_newslot(v,-3,SQTrue); //insert os
+	return 1;
+}

+ 4 - 1
SquiLu/squilu.cbp

@@ -1181,6 +1181,8 @@
 			<Add option="-DWITH_LIBCLANG=1" />
 			<Add option="-DWITH_LIBCLANG=1" />
 			<Add option="-DWITH_MPDECIMAL=1" />
 			<Add option="-DWITH_MPDECIMAL=1" />
 			<Add option="-DSQ_USE_EASYCURL=1" />
 			<Add option="-DSQ_USE_EASYCURL=1" />
+			<Add option="-DOS_POSIX=1" />
+			<Add option="-DSLAVE_VM_WITH_OS_THREADS=1" />
 			<Add directory="include" />
 			<Add directory="include" />
 			<Add directory="sqstdlib" />
 			<Add directory="sqstdlib" />
 			<Add directory="../myaxtls" />
 			<Add directory="../myaxtls" />
@@ -1807,7 +1809,7 @@
 			<Option target="Release FLTK 64bits Code Size" />
 			<Option target="Release FLTK 64bits Code Size" />
 			<Option target="GCC 6.1 Release 64bits" />
 			<Option target="GCC 6.1 Release 64bits" />
 		</Unit>
 		</Unit>
-		<Unit filename="../SquiLu-ext/sq_fs.c">
+		<Unit filename="../SquiLu-ext/sq_fs.cpp">
 			<Option compilerVar="CC" />
 			<Option compilerVar="CC" />
 			<Option target="Debug" />
 			<Option target="Debug" />
 			<Option target="Release" />
 			<Option target="Release" />
@@ -2524,6 +2526,7 @@
 		<Unit filename="sqstdlib/sqstdaux.cpp" />
 		<Unit filename="sqstdlib/sqstdaux.cpp" />
 		<Unit filename="sqstdlib/sqstdblob.cpp" />
 		<Unit filename="sqstdlib/sqstdblob.cpp" />
 		<Unit filename="sqstdlib/sqstdblobimpl.h" />
 		<Unit filename="sqstdlib/sqstdblobimpl.h" />
+		<Unit filename="sqstdlib/sqstdfile.h" />
 		<Unit filename="sqstdlib/sqstdio.cpp" />
 		<Unit filename="sqstdlib/sqstdio.cpp" />
 		<Unit filename="sqstdlib/sqstdmath.cpp" />
 		<Unit filename="sqstdlib/sqstdmath.cpp" />
 		<Unit filename="sqstdlib/sqstdrex.cpp" />
 		<Unit filename="sqstdlib/sqstdrex.cpp" />