// actor_obj = start_actor(callable) int ActorStart(lua_State *L) { // Get the global state lua_pushstring(L, RIDX_RUNTIMESTATE); lua_gettable(L, LUA_REGISTRYINDEX); TenshiRuntimeState s = (TenshiRuntimeState)lua_topointer(L, -1); lua_pop(L, 1); // Create an actor // TODO(rqou): Hope calling ActorCreate doesn't somehow introduce a subtle // bug of some sort. TenshiActorState a = ActorCreate(s); if (!a) { lua_pushstring(L, "could not create new actor object!"); lua_error(L); } // Move our callable onto the new actor state. lua_xmove(L, a->L, 1); // Append the new callable to the run queue ActorSetRunnable(a, 0); // our stack is empty // The object we want can be looked up in the global taskset. // TODO(rqou): This is not the most efficient. lua_pushcfunction(L, ActorFindInTaskset); // TODO(rqou): Is there a better way than doing this and then transplanting // the data back? lua_pushthread(a->L); lua_xmove(a->L, L, 1); lua_call(L, 1, 1); // stack is new actor object return 1; }
int main(int argc, char **argv) { printf("Hello world!\n"); TenshiRuntimeState s = TenshiRuntimeInit(); printf("Allocated state: %p\n", s); TenshiRegisterCFunctions(s, testprogram_runtimeentries); const char studentcode[] = "sensor = get_device('stestsensor')\n" "actuator = get_device('atestactuator')\n" "sensor_sampled = triggers.sampled(sensor)\n" "\n" "while true do\n" " local val = sensor_sampled:recv()\n" " print('sensor is ' .. tostring(val))\n" " actuator:send({val})\n" "end"; TenshiActorState a; int ret = LoadStudentcode(s, studentcode, strlen(studentcode), &a); printf("LoadStudentcode: %d, TenshiActorState: %p\n", ret, a); ret = ActorSetRunnable(a, 1); printf("ActorSetRunnable: %d\n", ret); int i = 0; while (i < 100) { printf("-----> Sent into sensor: %d\n", i); global_sensor_data = i; ret = TenshiFlagSensor(s, hax_dev_sensor); printf("TenshiFlagSensor: %d\n", ret); ret = TenshiRunQuanta(s); printf("Ran quanta %d, ret = %d\n", i, ret); i++; } TenshiRuntimeDeinit(s); printf("Done!\n"); return 0; }
int TenshiRunQuanta(TenshiRuntimeState s) { int ops_left = QUANTA_OPCODES; while (ops_left > 0) { TenshiActorState a; int ret = ActorDequeueHead(s, &a); if (ret != LUA_OK) return ret; if (!a) { printf("NOTHING TO RUN!\n"); return LUA_OK; } ret = threading_run_ops(a->L, ops_left, &ops_left); if (ret == THREADING_ERROR) { printf("THERE WAS AN ERROR!\n"); const char *msg = lua_tostring(a->L, -1); if (msg) /* is error object a string? */ luaL_traceback(a->L, a->L, msg, 0); /* use standard traceback */ else if (!lua_isnoneornil(a->L, -1)) { /* non-string error object? */ /* try its 'tostring' metamethod */ if (!luaL_callmeta(a->L, -1, "__tostring")) lua_pushliteral(a->L, "(no error message)"); } /* else no error object, does nothing */ const char *err_w_traceback = lua_tostring(a->L, -1); printf("%s\n", err_w_traceback); return LUA_ERRRUN; } if (ret == THREADING_EXITED) { printf("Thread exited!\n"); ActorDestroy(a); } else if (ret == THREADING_YIELD) { printf("Thread yielded (blocked)!\n"); ret = ActorSetBlocked(a); if (ret != LUA_OK) return ret; } else if (ret == THREADING_PREEMPT) { // Requeue it printf("Thread preempted!\n"); ret = ActorSetRunnable(a, 0); if (ret != LUA_OK) return ret; } } return LUA_OK; }
int TenshiRunQuanta(TenshiRuntimeState s) { // Do timeouts ActorProcessTimeouts(s); // Run the sensor actor // Dup the function first, as it disappears when we exit // TODO(rqou): Will we have a problem with the hardcoded op limit? lua_pushvalue(s->sensor_actor->L, -1); int ret = threading_run_ops(s->sensor_actor->L, 1000, NULL); if (ret != THREADING_EXITED) { printf("There was an error running the sensor actor!\n"); print_traceback(s->sensor_actor->L); return ret; } // Run the main code int ops_left = QUANTA_OPCODES; while (ops_left > 0) { TenshiActorState a; ret = ActorDequeueHead(s, &a); if (ret != LUA_OK) return ret; if (!a) { break; } ret = threading_run_ops(a->L, ops_left, &ops_left); if (ret == THREADING_ERROR) { printf("THERE WAS AN ERROR!\n"); print_traceback(a->L); return LUA_ERRRUN; } if (ret == THREADING_EXITED) { printf("Thread exited!\n"); ActorDestroy(a); } else if (ret == THREADING_YIELD) { printf("Thread yielded (blocked)!\n"); ret = ActorSetBlocked(a); if (ret != LUA_OK) return ret; } else if (ret == THREADING_PREEMPT) { // Requeue it ret = ActorSetRunnable(a, 0); if (ret != LUA_OK) return ret; } } // Run the actuator actor // Dup the function first, as it disappears when we exit lua_pushvalue(s->actuator_actor->L, -1); ret = threading_run_ops(s->actuator_actor->L, 1000, NULL); if (ret != THREADING_EXITED) { printf("There was an error running the actuator actor!\n"); print_traceback(s->actuator_actor->L); return ret; } lua_gc(s->L, LUA_GCCOLLECT, 0); return LUA_OK; }