|
|
@@ -14,6 +14,10 @@
|
|
|
#include <sqstdmath.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.
|
|
|
*/
|
|
|
@@ -99,33 +103,114 @@ static SQRESULT copy_values_between_vms (HSQUIRRELVM dst, HSQUIRRELVM src, int a
|
|
|
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 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;
|
|
|
}
|
|
|
|
|
|
#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)
|
|
|
{
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
+#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*/)
|
|
|
{
|
|
|
- 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;
|
|
|
}
|
|
|
|
|
|
+#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.
|
|
|
*/
|
|
|
@@ -134,6 +219,7 @@ static SQRESULT sq_slave_vm_constructor (HSQUIRRELVM v)
|
|
|
SQ_FUNC_VARS(v);
|
|
|
SQ_OPT_INTEGER(v, 2, stack_size, 1024);
|
|
|
SQ_OPT_BOOL(v, 3, with_libraries, false);
|
|
|
+ SQ_OPT_BOOL(v, 4, run_as_thread, false);
|
|
|
HSQUIRRELVM self = sq_open(stack_size);
|
|
|
|
|
|
/* Initialize environment */
|
|
|
@@ -152,16 +238,54 @@ static SQRESULT sq_slave_vm_constructor (HSQUIRRELVM v)
|
|
|
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);
|
|
|
|
|
|
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)
|
|
|
{
|
|
|
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"
|
|
|
return 0;
|
|
|
}
|
|
|
@@ -172,33 +296,36 @@ static SQRESULT sq_slave_vm_call(HSQUIRRELVM v)
|
|
|
GET_sq_slave_vm_INSTANCE(v, 1);
|
|
|
SQ_GET_BOOL(v, 2, has_ret_val);
|
|
|
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;
|
|
|
- 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_NATIVECLOSURE:
|
|
|
case OT_CLASS:
|
|
|
{
|
|
|
- sq_pushroottable(self);
|
|
|
+ sq_pushroottable(svm);
|
|
|
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;
|
|
|
}
|
|
|
- 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;
|
|
|
}
|
|
|
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;
|
|
|
}
|
|
|
@@ -206,50 +333,65 @@ static SQRESULT sq_slave_vm_call(HSQUIRRELVM v)
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- sq_throwerror(v, sq_getlasterror_str(self));
|
|
|
+ result = sq_throwerror(v, sq_getlasterror_str(svm));
|
|
|
}
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
static SQRESULT sq_slave_vm_set(HSQUIRRELVM v)
|
|
|
{
|
|
|
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_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;
|
|
|
- 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;
|
|
|
}
|
|
|
|
|
|
static SQRESULT sq_slave_vm_get(HSQUIRRELVM v)
|
|
|
{
|
|
|
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;
|
|
|
- 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;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
@@ -261,19 +403,25 @@ static SQRESULT sq_slave_vm_dofile(HSQUIRRELVM v)
|
|
|
SQ_OPT_BOOL(v, 3, retval, false);
|
|
|
SQ_OPT_BOOL(v, 4, printerror, 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;
|
|
|
- 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(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 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;
|
|
|
}
|
|
|
|
|
|
@@ -285,15 +433,21 @@ static SQRESULT sq_slave_vm_loadfile(HSQUIRRELVM v)
|
|
|
SQ_GET_STRING(v, 3, file_name);
|
|
|
SQ_OPT_BOOL(v, 4, printerror, 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;
|
|
|
- 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;
|
|
|
}
|
|
|
|
|
|
@@ -306,27 +460,195 @@ static SQRESULT sq_slave_vm_compilestring(HSQUIRRELVM v)
|
|
|
SQ_OPT_BOOL(v, 4, printerror, false);
|
|
|
SQ_OPT_BOOL(v, 5, show_warnings, false);
|
|
|
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;
|
|
|
- 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
|
|
|
{
|
|
|
- const SQChar *last_error = sq_getlasterror_str(self);
|
|
|
+ const SQChar *last_error = sq_getlasterror_str(svm);
|
|
|
if(last_error) {
|
|
|
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);
|
|
|
}
|
|
|
}
|
|
|
- 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;
|
|
|
}
|
|
|
|
|
|
+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
|
|
|
extern "C" {
|
|
|
#endif
|
|
|
@@ -337,7 +659,7 @@ extern "C" {
|
|
|
sq_pushstring(v,sq_slave_vm_TAG, -1);
|
|
|
sq_newclass(v, SQFalse);
|
|
|
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("close"), sq_slave_vm_close, 1, _SC("x"), 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("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("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("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
|
|
|
return 0;
|