/* initialize lua coroutine for fetching cached session */ static ngx_int_t ngx_http_lua_ssl_sess_fetch_by_chunk(lua_State *L, ngx_http_request_t *r) { int co_ref; ngx_int_t rc; lua_State *co; ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { rc = NGX_ERROR; ngx_http_lua_finalize_request(r, rc); return rc; } } else { dd("reset ctx"); ngx_http_lua_reset_ctx(r, L, ctx); } ctx->entered_content_phase = 1; /* {{{ new coroutine to handle request */ co = ngx_http_lua_new_thread(r, L, &co_ref); if (co == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua: failed to create new coroutine to handle request"); rc = NGX_ERROR; ngx_http_lua_finalize_request(r, rc); return rc; } /* move code closure to new coroutine */ lua_xmove(L, co, 1); /* set closure's env table to new coroutine's globals table */ ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); /* save nginx request in coroutine globals table */ ngx_http_lua_set_req(co, r); ctx->cur_co_ctx = &ctx->entry_co_ctx; ctx->cur_co_ctx->co = co; ctx->cur_co_ctx->co_ref = co_ref; #ifdef NGX_LUA_USE_ASSERT ctx->cur_co_ctx->co_top = 1; #endif /* register request cleanup hooks */ if (ctx->cleanup == NULL) { cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { rc = NGX_ERROR; ngx_http_lua_finalize_request(r, rc); return rc; } cln->handler = ngx_http_lua_request_cleanup_handler; cln->data = ctx; ctx->cleanup = &cln->handler; } ctx->context = NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH; rc = ngx_http_lua_run_thread(L, r, ctx, 0); if (rc == NGX_ERROR || rc >= NGX_OK) { /* do nothing */ } else if (rc == NGX_AGAIN) { rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 0); } else if (rc == NGX_DONE) { rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 1); } else { rc = NGX_OK; } ngx_http_lua_finalize_request(r, rc); return rc; }
ngx_int_t ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) { int cc_ref; lua_State *cc; ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; dd("content by chunk"); ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_ctx_t)); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } dd("setting new ctx, ctx = %p", ctx); ctx->cc_ref = LUA_NOREF; ctx->ctx_ref = LUA_NOREF; ngx_http_set_ctx(r, ctx, ngx_http_lua_module); } else { dd("reset ctx"); ngx_http_lua_reset_ctx(r, L, ctx); } ctx->entered_content_phase = 1; /* {{{ new coroutine to handle request */ cc = ngx_http_lua_new_thread(r, L, &cc_ref); if (cc == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "(lua-content-by-chunk) failed to create new coroutine " "to handle request"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } /* move code closure to new coroutine */ lua_xmove(L, cc, 1); /* set closure's env table to new coroutine's globals table */ lua_pushvalue(cc, LUA_GLOBALSINDEX); lua_setfenv(cc, -2); /* save reference of code to ease forcing stopping */ lua_pushvalue(cc, -1); lua_setglobal(cc, GLOBALS_SYMBOL_RUNCODE); /* save nginx request in coroutine globals table */ lua_pushlightuserdata(cc, r); lua_setglobal(cc, GLOBALS_SYMBOL_REQUEST); /* }}} */ ctx->cc = cc; ctx->cc_ref = cc_ref; /* {{{ register request cleanup hooks */ if (ctx->cleanup == NULL) { cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cln->handler = ngx_http_lua_request_cleanup; cln->data = r; ctx->cleanup = &cln->handler; } /* }}} */ return ngx_http_lua_run_thread(L, r, ctx, 0); }
ngx_int_t ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) { int co_ref; ngx_int_t rc; lua_State *co; ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; dd("content by chunk"); ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } } else { dd("reset ctx"); ngx_http_lua_reset_ctx(r, L, ctx); } ctx->entered_content_phase = 1; /* {{{ new coroutine to handle request */ co = ngx_http_lua_new_thread(r, L, &co_ref); if (co == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua: failed to create new coroutine to handle request"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } /* move code closure to new coroutine */ lua_xmove(L, co, 1); /* set closure's env table to new coroutine's globals table */ lua_pushvalue(co, LUA_GLOBALSINDEX); lua_setfenv(co, -2); /* save nginx request in coroutine globals table */ lua_pushlightuserdata(co, &ngx_http_lua_request_key); lua_pushlightuserdata(co, r); lua_rawset(co, LUA_GLOBALSINDEX); /* }}} */ ctx->cur_co_ctx = &ctx->entry_co_ctx; ctx->cur_co_ctx->co = co; ctx->cur_co_ctx->co_ref = co_ref; /* {{{ register request cleanup hooks */ if (ctx->cleanup == NULL) { cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cln->handler = ngx_http_lua_request_cleanup; cln->data = r; ctx->cleanup = &cln->handler; } /* }}} */ ctx->context = NGX_HTTP_LUA_CONTEXT_CONTENT; rc = ngx_http_lua_run_thread(L, r, ctx, 0); if (rc == NGX_ERROR || rc >= NGX_OK) { return rc; } if (rc == NGX_AGAIN) { return ngx_http_lua_content_run_posted_threads(L, r, ctx, 0); } if (rc == NGX_DONE) { return ngx_http_lua_content_run_posted_threads(L, r, ctx, 1); } return NGX_OK; }
static int emit (lua_State *L) { lyaml_emitter *emitter; int yaml_ok = 0; int finalize = 0; luaL_argcheck (L, lua_istable (L, 1), 1, "expected table"); emitter = (lyaml_emitter *) lua_touserdata (L, lua_upvalueindex (1)); { const char *type; RAWGET_STRDUP (type); lua_pop (L, 1); if (type == NULL) { emitter->error++; luaL_addstring (&emitter->errbuff, "no type field in event table"); } #define MENTRY(_s) (STREQ (type, #_s)) { yaml_ok = emit_##_s (L, emitter); } /* Minimize comparisons by putting more common types earlier. */ else if MENTRY( SCALAR ) else if MENTRY( MAPPING_START ) else if MENTRY( MAPPING_END ) else if MENTRY( SEQUENCE_START ) else if MENTRY( SEQUENCE_END ) else if MENTRY( DOCUMENT_START ) else if MENTRY( DOCUMENT_END ) else if MENTRY( STREAM_START ) else if MENTRY( STREAM_END ) else if MENTRY( ALIAS ) #undef MENTRY else { emitter->error++; luaL_addsize (&emitter->errbuff, sprintf (luaL_prepbuffer (&emitter->errbuff), "invalid event type '%s'", type)); } /* If the stream has finished, finalize the YAML output. */ if (type && STREQ (type, "STREAM_END")) finalize = 1; if (type) free ((void *) type); } /* Copy any yaml_emitter_t errors into the error buffer. */ if (!emitter->error && !yaml_ok) { if (emitter->emitter.problem) luaL_addstring (&emitter->errbuff, emitter->emitter.problem); else luaL_addstring (&emitter->errbuff, "LibYAML call failed"); emitter->error++; } /* Report errors back to the caller as `false, "error message"`. */ if (emitter->error != 0) { assert (emitter->error == 1); /* bail on uncaught additional errors */ lua_pushboolean (L, 0); luaL_pushresult (&emitter->errbuff); lua_xmove (emitter->errL, L, 1); return 2; } /* Return `true, "YAML string"` after accepting a STREAM_END event. */ if (finalize) { lua_pushboolean (L, 1); luaL_pushresult (&emitter->yamlbuff); lua_xmove (emitter->outputL, L, 1); return 2; } /* Otherwise, just report success to the caller as `true`. */ lua_pushboolean (L, 1); return 1; }
/* * Arguments: evq_udata, * obj_udata | signal (number), * events (string: "r", "w") | event_flags (number), * callback (function | coroutine), * [timeout (milliseconds), one_shot (boolean)] * Returns: [ev_ludata] */ static int levq_add (lua_State *L) { struct event_queue *evq = checkudata(L, 1, EVQ_TYPENAME); unsigned int ev_flags = lua_tointeger(L, 3) | (lua_toboolean(L, 6) ? EVENT_ONESHOT : 0); const msec_t timeout = lua_isnoneornil(L, 5) ? TIMEOUT_INFINITE : (msec_t) lua_tointeger(L, 5); struct event *ev; int res; #undef ARG_LAST #define ARG_LAST 4 ev = levq_new_event(evq); if (!(ev_flags & EVENT_TIMER)) { fd_t *fdp = lua_touserdata(L, 2); ev->fd = fdp ? *fdp : (fd_t) lua_tointeger(L, 2); /* signo */ } if (!(ev_flags & (EVENT_READ | EVENT_WRITE))) { const char *evstr = lua_tostring(L, 3); ev_flags |= (!evstr || evstr[0] == 'r') ? EVENT_READ : EVENT_WRITE; } switch (lua_type(L, 4)) { case LUA_TFUNCTION: ev_flags |= EVENT_CALLBACK; break; case LUA_TTHREAD: ev_flags |= EVENT_CALLBACK | EVENT_CALLBACK_CORO; break; } ev->flags = ev_flags; /* reserve place for timeout_queue */ if (!evq->ev_free) evq->ev_free = levq_new_event(evq); if (ev_flags & EVENT_TIMER) { res = evq_add_timer(evq, ev, timeout); } else { if (ev_flags & EVENT_DIRWATCH) { const char *path = luaL_checkstring(L, 2); res = evq_add_dirwatch(evq, ev, path); } else { res = evq_add(evq, ev); } if (!res && timeout != TIMEOUT_INFINITE) { evq_set_timeout(ev, timeout); } } if (!res) { lua_State *NL = evq->L; const int ev_id = ev->ev_id; /* cb_fun */ if (ev_flags & EVENT_CALLBACK) { lua_settop(L, 4); lua_xmove(L, NL, 1); lua_rawseti(NL, EVQ_CORO_CALLBACK, ev_id); } /* obj_udata */ lua_settop(L, 2); lua_xmove(L, NL, 1); lua_rawseti(NL, EVQ_CORO_UDATA, ev_id); lua_pushlightuserdata(L, ev); return 1; } levq_del_event(evq, ev); return sys_seterror(L, 0); }
/* * open() * * argument 1: uri to connect to */ static int bus_open(lua_State *T) { const char *uri; DBusError err; DBusConnection *conn; struct bus_object *obj; lua_State *S; uri = luaL_checkstring(T, 1); lem_debug("opening %s", uri); dbus_error_init(&err); conn = dbus_connection_open_private(uri, &err); if (dbus_error_is_set(&err)) { lua_pushnil(T); lua_pushstring(T, err.message); dbus_error_free(&err); return 2; } if (conn == NULL) { lua_pushnil(T); lua_pushliteral(T, "error opening connection"); return 2; } dbus_connection_set_exit_on_disconnect(conn, FALSE); /* set watch functions */ if (!dbus_connection_set_watch_functions(conn, watch_add, watch_remove, watch_toggle, conn, NULL)) { dbus_connection_close(conn); dbus_connection_unref(conn); lua_pushnil(T); lua_pushliteral(T, "error setting watch functions"); return 2; } /* set timout functions */ if (!dbus_connection_set_timeout_functions(conn, timeout_add, timeout_remove, timeout_toggle, conn, NULL)) { dbus_connection_close(conn); dbus_connection_unref(conn); lua_pushnil(T); lua_pushliteral(T, "error setting timeout functions"); return 2; } /* create new userdata for the bus */ obj = lua_newuserdata(T, sizeof(struct bus_object)); obj->conn = conn; /* set the metatable */ lua_pushvalue(T, lua_upvalueindex(1)); lua_setmetatable(T, -2); /* create fenv table */ lua_createtable(T, 2, 0); /* create signal handler thread */ S = lua_newthread(T); lua_rawseti(T, -2, 1); /* put a reference to bus object and * message metatable on thread */ lua_pushvalue(T, -2); lua_pushvalue(T, lua_upvalueindex(2)); lua_xmove(T, S, 2); /* create signal handler table */ lua_newtable(S); lua_pushvalue(S, -1); lua_xmove(S, T, 1); lua_rawseti(T, -2, 2); /* create object path table */ lua_newtable(S); lua_pushvalue(S, -1); lua_xmove(S, T, 1); lua_rawseti(T, -2, 3); /* set fenv table */ lua_setfenv(T, -2); /* set the message filter */ if (!dbus_connection_add_filter(conn, message_filter, S, NULL)) { dbus_connection_close(conn); dbus_connection_unref(conn); lua_pushnil(T); lua_pushliteral(T, "out of memory"); return 2; } /* return the bus object */ return 1; }
// Помещает на верхушку стека значенее из реестра void LuaScript::GetFromRegistry( lua_State* L, LuaRegRef r ) { lua_rawgeti( Lst, LUA_REGISTRYINDEX, r ); lua_xmove( Lst, L, 1 ); }
static int ngx_http_lua_ngx_timer_at(lua_State *L) { int nargs, co_ref; u_char *p; lua_State *vm; /* the main thread */ lua_State *co; ngx_msec_t delay; ngx_event_t *ev; ngx_http_request_t *r; ngx_connection_t *saved_c = NULL; ngx_http_lua_ctx_t *ctx; #if 0 ngx_http_connection_t *hc; #endif ngx_http_lua_timer_ctx_t *tctx; ngx_http_lua_main_conf_t *lmcf; #if 0 ngx_http_core_main_conf_t *cmcf; #endif nargs = lua_gettop(L); if (nargs < 2) { return luaL_error(L, "expecting at least 2 arguments but got %d", nargs); } delay = (ngx_msec_t) (luaL_checknumber(L, 1) * 1000); luaL_argcheck(L, lua_isfunction(L, 2) && !lua_iscfunction(L, 2), 2, "Lua function expected"); r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request"); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ngx_exiting && delay > 0) { lua_pushnil(L); lua_pushliteral(L, "process exiting"); return 2; } lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); if (lmcf->pending_timers >= lmcf->max_pending_timers) { lua_pushnil(L); lua_pushliteral(L, "too many pending timers"); return 2; } if (lmcf->watcher == NULL) { /* create the watcher fake connection */ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "lua creating fake watcher connection"); if (ngx_cycle->files) { saved_c = ngx_cycle->files[0]; } lmcf->watcher = ngx_get_connection(0, ngx_cycle->log); if (ngx_cycle->files) { ngx_cycle->files[0] = saved_c; } if (lmcf->watcher == NULL) { return luaL_error(L, "no memory"); } /* to work around the -1 check in ngx_worker_process_cycle: */ lmcf->watcher->fd = (ngx_socket_t) -2; lmcf->watcher->idle = 1; lmcf->watcher->read->handler = ngx_http_lua_abort_pending_timers; lmcf->watcher->data = lmcf; } vm = ngx_http_lua_get_lua_vm(r, ctx); co = lua_newthread(vm); /* L stack: time func [args] thread */ ngx_http_lua_probe_user_coroutine_create(r, L, co); lua_createtable(co, 0, 0); /* the new global table */ /* co stack: global_tb */ lua_createtable(co, 0, 1); /* the metatable */ lua_pushvalue(co, LUA_GLOBALSINDEX); lua_setfield(co, -2, "__index"); lua_setmetatable(co, -2); /* co stack: global_tb */ lua_replace(co, LUA_GLOBALSINDEX); /* co stack: <empty> */ dd("stack top: %d", lua_gettop(L)); lua_xmove(vm, L, 1); /* move coroutine from main thread to L */ /* L stack: time func [args] thread */ /* vm stack: empty */ lua_pushvalue(L, 2); /* copy entry function to top of L*/ /* L stack: time func [args] thread func */ lua_xmove(L, co, 1); /* move entry function from L to co */ /* L stack: time func [args] thread */ /* co stack: func */ lua_pushvalue(co, LUA_GLOBALSINDEX); lua_setfenv(co, -2); /* co stack: func */ lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); /* L stack: time func [args] thread corountines */ lua_pushvalue(L, -2); /* L stack: time func [args] thread coroutines thread */ co_ref = luaL_ref(L, -2); lua_pop(L, 1); /* L stack: time func [args] thread */ if (nargs > 2) { lua_pop(L, 1); /* L stack: time func [args] */ lua_xmove(L, co, nargs - 2); /* L stack: time func */ /* co stack: func [args] */ } p = ngx_alloc(sizeof(ngx_event_t) + sizeof(ngx_http_lua_timer_ctx_t), r->connection->log); if (p == NULL) { lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); luaL_unref(L, -1, co_ref); return luaL_error(L, "no memory"); } ev = (ngx_event_t *) p; ngx_memzero(ev, sizeof(ngx_event_t)); p += sizeof(ngx_event_t); tctx = (ngx_http_lua_timer_ctx_t *) p; tctx->premature = 0; tctx->co_ref = co_ref; tctx->co = co; tctx->main_conf = r->main_conf; tctx->srv_conf = r->srv_conf; tctx->loc_conf = r->loc_conf; tctx->lmcf = lmcf; if (ctx && ctx->vm_state) { tctx->vm_state = ctx->vm_state; tctx->vm_state->count++; } else { tctx->vm_state = NULL; } ev->handler = ngx_http_lua_timer_handler; ev->data = tctx; ev->log = ngx_cycle->log; lmcf->pending_timers++; ngx_add_timer(ev, delay); lua_pushinteger(L, 1); return 1; }
/* * Arguments: dpool_udata, [timeout (milliseconds)] * Returns: data_items (any) ... */ static int dpool_get (lua_State *L) { struct sys_thread *td = sys_thread_get(); struct data_pool *dp = checkudata(L, 1, DPOOL_TYPENAME); const msec_t timeout = lua_isnoneornil(L, 2) ? TIMEOUT_INFINITE : (msec_t) lua_tointeger(L, 2); int nput; if (!td) luaL_argerror(L, 0, "Threading not initialized"); lua_settop(L, 1); lua_getfenv(L, 1); /* storage */ lua_insert(L, 1); if ((dp->flags & DPOOL_GETONEMPTY) && !dp->n) { lua_rawgetp(L, 1, (void *) DPOOL_GETONEMPTY); lua_insert(L, 2); lua_call(L, 1, LUA_MULTRET); nput = lua_gettop(L) - 1; if (nput) return nput; } for (; ; ) { /* get from storage */ if (dp->n) { const int idx = dp->idx + 1; int i; lua_rawgeti(L, 1, idx); nput = lua_tointeger(L, -1); lua_pushnil(L); lua_rawseti(L, 1, idx); dp->idx = idx + nput; for (i = dp->idx; i > idx; --i) { lua_rawgeti(L, 1, i); lua_pushnil(L); lua_rawseti(L, 1, i); } if (dp->idx == dp->top) dp->idx = dp->top = 0; if (dp->n-- == dp->max) { thread_event_signal(&dp->tev); } return nput; } /* wait signal */ { int res; dp->nwaits++; res = thread_event_wait(&dp->tev, td, timeout); dp->nwaits--; sys_thread_check(td); if (res) { if (res == 1) { lua_pushboolean(L, 0); return 1; /* timed out */ } return sys_seterror(L, 0); } } /* get directly from another thread */ nput = dp->nput; if (nput) { dp->nput = 0; luaL_checkstack(L, nput, NULL); lua_xmove(dp->td->L, L, nput); return nput; } } }
/* * Arguments: function, [arguments (any) ...] * Returns: [thread_ludata] */ static int thread_run (lua_State *L) { struct sys_thread *vmtd = sys_get_thread(); lua_State *NL; struct sys_thread *td; #ifndef _WIN32 pthread_attr_t attr; int res = 0; #else HANDLE hThr; const int res = 0; #endif if (!vmtd) luaL_argerror(L, 0, "Threading not initialized"); luaL_checktype(L, 1, LUA_TFUNCTION); NL = lua_newthread(L); if (!NL) goto err; td = lua_newuserdata(L, sizeof(struct sys_thread)); memset(td, 0, sizeof(struct sys_thread)); td->mutex = vmtd->mutex; td->L = NL; td->vmtd = vmtd->vmtd; #ifndef _WIN32 if ((res = pthread_attr_init(&attr)) || (res = pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE))) goto err; pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); res = pthread_create(&td->tid, &attr, (thread_func_t) thread_start, td); pthread_attr_destroy(&attr); if (!res) { #else hThr = (HANDLE) _beginthreadex(NULL, THREAD_STACK_SIZE, (thread_func_t) thread_start, td, 0, &td->tid); if (hThr) { CloseHandle(hThr); #endif thread_settable(L, NL, td->tid); /* save thread to avoid GC */ lua_xmove(L, NL, lua_gettop(L)); /* move function and args to NL */ lua_pushlightuserdata(L, td); return 1; } err: return sys_seterror(L, res); } /* * Arguments: function, master (thread_ludata), * [arguments (string | number | boolean | lightuserdata) ...], * thread, thread_udata */ static THREAD_FUNC_API thread_startvm (struct sys_thread *td) { lua_State *L = td->L; thread_settable(L, L, td->tid); sys_set_thread(td); sys_vm2_enter(td); if (lua_pcall(L, lua_gettop(L) - 1, 0, 0)) { if (td->interrupted && lua_touserdata(L, -1) == &g_TLSIndex) lua_pop(L, 1); else lua_error(L); } /* notify event_queue */ if (td->trigger) sys_trigger_notify(&td->trigger, SYS_EVEOF | SYS_EVDEL); lua_close(L); return 0; }
static void *cothread( void *arg ) { lpthread_t *th = (lpthread_t*)arg; lua_State *L = lua_newthread( th->L ); int ref = lstate_ref( th->L ); lua_State *task = th->task.L; th->join = 0; // wakeup parent pthread_cond_signal( &CREATION_COND ); lpth_lock( th ); WAIT_COTHREAD: pthread_cond_wait( &th->cond, &th->mutex ); if( !th->join ) { lua_State *co = NULL; lua_State *eco = NULL; int argc = 0; CHECK_TASK: lpth_task_lock( th ); // get task if( lua_gettop( task ) ) { lua_pushvalue( task, 1 ); lua_xmove( task, L, 1 ); lua_remove( task, 1 ); co = lua_tothread( L, -1 ); argc = lua_gettop( co ); // create error thread if( argc > 1 && lua_type( co, 2 ) == LUA_TFUNCTION ) { if( ( eco = lua_newthread( L ) ) ) { int i = 2; for(; i <= argc; i++ ){ lua_pushvalue( co, i ); } lua_xmove( co, eco, argc - 1 ); } // remove error function lua_remove( co, 2 ); } } lpth_task_unlock( th ); if( co ) { switch( lua_resume( co, lua_gettop( co ) - 1 ) ) { case LUA_YIELD: case LUA_ERRRUN: case LUA_ERRSYNTAX: case LUA_ERRMEM: case LUA_ERRERR: if( eco ){ lua_xmove( co, eco, 1 ); lua_insert( eco, 2 ); lua_resume( eco, argc - 1 ); } break; } // remove coroutine lua_settop( L, 0 ); if( !th->join ){ co = eco = NULL; goto CHECK_TASK; } } else if( !th->join ){ goto WAIT_COTHREAD; } } lpth_unlock( th ); lstate_unref( th->L, ref ); return NULL; }
static int db_getinfo (lua_State *L) { lua_Debug ar; int arg; //add by cuiwei 07.8.30 int i; char aparms[1024] = {0}; //add end lua_State *L1 = getthread(L, &arg); const char *options = luaL_optstring(L, arg+2, "flnSu"); if (lua_isnumber(L, arg+1)) { if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) { lua_pushnil(L); /* level out of range */ return 1; } } else if (lua_isfunction(L, arg+1)) { lua_pushfstring(L, ">%s", options); options = lua_tostring(L, -1); lua_pushvalue(L, arg+1); lua_xmove(L, L1, 1); } else return luaL_argerror(L, arg+1, "function or level expected"); if (!lua_getinfo(L1, options, &ar)) return luaL_argerror(L, arg+2, "invalid option"); lua_createtable(L, 0, 2); if (strchr(options, 'S')) { settabss(L, "source", ar.source); settabss(L, "short_src", ar.short_src); settabsi(L, "linedefined", ar.linedefined); settabsi(L, "lastlinedefined", ar.lastlinedefined); settabss(L, "what", ar.what); } if (strchr(options, 'l')) settabsi(L, "currentline", ar.currentline); if (strchr(options, 'u')) { settabsi(L, "nups", ar.nups); //add by cuiwei 07.8.30 if (ar.what != "C" ) { settabsi(L, "npars", ar.npars); settabsi(L, "has3dot", ar.has3dot?1:0); for ( i = 1; i <= ar.npars; i++ ) { strcat(aparms, ar.parms[i-1]); if ( i != ar.npars || ar.has3dot) { strcat(aparms, ","); } } if ( ar.has3dot ) { strcat(aparms, "..."); } settabss(L, "strparms", aparms); } //add end } if (strchr(options, 'n')) { settabss(L, "name", ar.name); settabss(L, "namewhat", ar.namewhat); } if (strchr(options, 'L')) treatstackoption(L, L1, "activelines"); if (strchr(options, 'f')) treatstackoption(L, L1, "func"); return 1; /* return table */ }
void LuaInstance::MoveTo(LuaInstance* instance, int n) const { lua_xmove(m_state, instance->m_state, n); }
static int ngx_http_lua_uthread_wait(lua_State *L) { int i, nargs, nrets; lua_State *sub_co; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx, *sub_coctx; r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no request ctx found"); } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER); coctx = ctx->cur_co_ctx; nargs = lua_gettop(L); for (i = 1; i <= nargs; i++) { sub_co = lua_tothread(L, i); luaL_argcheck(L, sub_co, i, "lua thread expected"); sub_coctx = ngx_http_lua_get_co_ctx(sub_co, ctx); if (sub_coctx == NULL) { goto found_dead; } if (!sub_coctx->is_uthread) { return luaL_error(L, "attempt to wait on a coroutine that is " "not a user thread"); } if (sub_coctx->parent_co_ctx != coctx) { return luaL_error(L, "only the parent coroutine can wait on the " "thread"); } switch (sub_coctx->co_status) { case NGX_HTTP_LUA_CO_ZOMBIE: ngx_http_lua_probe_info("found zombie child"); nrets = lua_gettop(sub_coctx->co); dd("child retval count: %d, %s: %s", (int) nrets, luaL_typename(sub_coctx->co, -1), lua_tostring(sub_coctx->co, -1)); if (nrets) { lua_xmove(sub_coctx->co, L, nrets); } #if 1 ngx_http_lua_del_thread(r, L, ctx, sub_coctx); ctx->uthreads--; #endif return nrets; case NGX_HTTP_LUA_CO_DEAD: dd("uthread already waited: %p (parent %p)", sub_coctx, coctx); found_dead: if (i < nargs) { /* just ignore it if it is not the last one */ continue; } /* being the last one */ lua_pushnil(L); lua_pushliteral(L, "already waited"); return 2; default: dd("uthread %p still alive, status: %d, parent %p", sub_coctx, sub_coctx->co_status, coctx); break; } ngx_http_lua_probe_user_thread_wait(L, sub_coctx->co); sub_coctx->waited_by_parent = 1; } return lua_yield(L, 0); }
int ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t **pcoctx) { lua_State *vm; /* the Lua VM */ lua_State *co; /* new coroutine to be created */ ngx_http_lua_co_ctx_t *coctx; /* co ctx for the new coroutine */ luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, "Lua function expected"); ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER | NGX_HTTP_LUA_CONTEXT_SSL_CERT); vm = ngx_http_lua_get_lua_vm(r, ctx); /* create new coroutine on root Lua state, so it always yields * to main Lua thread */ co = lua_newthread(vm); ngx_http_lua_probe_user_coroutine_create(r, L, co); coctx = ngx_http_lua_get_co_ctx(co, ctx); if (coctx == NULL) { coctx = ngx_http_lua_create_co_ctx(r, ctx); if (coctx == NULL) { return luaL_error(L, "no memory"); } } else { ngx_memzero(coctx, sizeof(ngx_http_lua_co_ctx_t)); coctx->co_ref = LUA_NOREF; } coctx->co = co; coctx->co_status = NGX_HTTP_LUA_CO_SUSPENDED; /* make new coroutine share globals of the parent coroutine. * NOTE: globals don't have to be separated! */ ngx_http_lua_get_globals_table(L); lua_xmove(L, co, 1); ngx_http_lua_set_globals_table(co); lua_xmove(vm, L, 1); /* move coroutine from main thread to L */ lua_pushvalue(L, 1); /* copy entry function to top of L*/ lua_xmove(L, co, 1); /* move entry function from L to co */ if (pcoctx) { *pcoctx = coctx; } #ifdef NGX_LUA_USE_ASSERT coctx->co_top = 1; #endif return 1; /* return new coroutine to Lua */ }
int ravaL_thread_once(rava_thread_t* self) { if (!QUEUE_EMPTY(&self->rouse)) { QUEUE* q; rava_fiber_t* fiber; q = QUEUE_HEAD(&self->rouse); fiber = QUEUE_DATA(q, rava_fiber_t, queue); QUEUE_REMOVE(q); TRACE("[%p] rouse fiber: %p\n", self, fiber); if (fiber->flags & RAVA_STATE_DEAD) { TRACE("[%p] fiber is dead: %p\n", self, fiber); luaL_error(self->L, "cannot resume a dead fiber"); } else { int stat, narg; narg = lua_gettop(fiber->L); if (!(fiber->flags & RAVA_STATE_START)) { /* first entry, ignore function arg */ fiber->flags |= RAVA_STATE_START; --narg; } self->curr = (rava_state_t*)fiber; TRACE("[%p] calling lua_resume on: %p\n", self, fiber); stat = lua_resume(fiber->L, narg); TRACE("resume returned\n"); self->curr = (rava_state_t*)self; switch (stat) { case LUA_YIELD: TRACE("[%p] seen LUA_YIELD\n", self); /* if called via coroutine.yield() then we're still in the queue */ if (fiber->flags & RAVA_STATE_READY) { TRACE("%p is still ready, back in the queue\n", fiber); QUEUE_INSERT_TAIL(&self->rouse, &fiber->queue); } break; case 0: { /* normal exit, wake up joining states */ int i, narg; narg = lua_gettop(fiber->L); TRACE("[%p] normal exit - fiber: %p, narg: %i\n", self, fiber, narg); QUEUE* q; rava_state_t* s; while (!QUEUE_EMPTY(&fiber->rouse)) { q = QUEUE_HEAD(&fiber->rouse); s = QUEUE_DATA(q, rava_state_t, join); QUEUE_REMOVE(q); TRACE("calling ravaL_state_ready(%p)\n", s); ravaL_state_ready(s); if (s->type == RAVA_STATE_TYPE_FIBER) { lua_checkstack(fiber->L, 1); lua_checkstack(s->L, narg); for (i = 1; i <= narg; i++) { lua_pushvalue(fiber->L, i); lua_xmove(fiber->L, s->L, 1); } } } TRACE("closing fiber %p\n", fiber); ravaL_fiber_close(fiber); break; } default: TRACE("ERROR: in fiber\n"); lua_pushvalue(fiber->L, -1); /* error message */ lua_xmove(fiber->L, self->L, 1); ravaL_fiber_close(fiber); lua_error(self->L); } } } return !QUEUE_EMPTY(&self->rouse); }
static int l_load_music_async_callback(lua_State *L) { load_music_async_t *async = (load_music_async_t*)lua_touserdata(L, 1); // Replace light UD with full UD lua_pushvalue(L, 1); lua_gettable(L, LUA_REGISTRYINDEX); lua_insert(L, 1); lua_pushnil(L); lua_settable(L, LUA_REGISTRYINDEX); // Get CB state and function lua_pushvalue(L, 1); lua_gettable(L, LUA_REGISTRYINDEX); lua_rawgeti(L, -1, 1); lua_State *cbL = lua_tothread(L, -1); // NB: cbL may equal L, or it may not lua_pop(L, 1); lua_rawgeti(L, -1, 2); if(L != cbL) lua_xmove(L, cbL, 1); // Push CB arg int nargs = 1; if(async->music == NULL) { lua_pushnil(cbL); if(async->err) { if(*async->err) { lua_pushstring(cbL, async->err); nargs = 2; } free(async->err); } } else { lua_rawgeti(L, 2, 3); if(L != cbL) lua_xmove(L, cbL, 1); music_t* pLMusic = (music_t*)lua_touserdata(cbL, -1); pLMusic->pMusic = async->music; pLMusic->pRWop = async->rwop; async->music = NULL; async->rwop = NULL; } // Finish cleanup if(async->rwop) SDL_FreeRW(async->rwop); lua_pushvalue(L, 1); lua_pushnil(L); lua_settable(L, LUA_REGISTRYINDEX); // Callback if(cbL == L) { lua_call(cbL, nargs, 0); return 0; } if(lua_pcall(cbL, nargs, 0, 0) != 0) { lua_pushliteral(L, "Error in async music load callback: "); lua_xmove(cbL, L, 1); lua_tostring(L, -1); lua_concat(L, 2); lua_error(L); } return 0; }
static int l_mainloop(lua_State *L) { luaL_checktype(L, 1, LUA_TTHREAD); lua_State *dispatcher = lua_tothread(L, 1); fps_ctrl *fps_control = (fps_ctrl*)lua_touserdata(L, luaT_upvalueindex(1)); SDL_TimerID timer = SDL_AddTimer(30, timer_frame_callback, NULL); SDL_Event e; while(SDL_WaitEvent(&e) != 0) { bool do_frame = false; bool do_timer = false; do { int nargs; switch(e.type) { case SDL_QUIT: goto leave_loop; case SDL_KEYDOWN: lua_pushliteral(dispatcher, "keydown"); lua_pushstring(dispatcher, SDL_GetKeyName(e.key.keysym.sym)); l_push_modifiers_table(dispatcher, e.key.keysym.mod); lua_pushboolean(dispatcher, e.key.repeat != 0); nargs = 4; break; case SDL_KEYUP: lua_pushliteral(dispatcher, "keyup"); lua_pushstring(dispatcher, SDL_GetKeyName(e.key.keysym.sym)); nargs = 2; break; case SDL_TEXTINPUT: lua_pushliteral(dispatcher, "textinput"); lua_pushstring(dispatcher, e.text.text); nargs = 2; break; case SDL_TEXTEDITING: lua_pushliteral(dispatcher, "textediting"); lua_pushstring(dispatcher, e.edit.text); lua_pushinteger(dispatcher, e.edit.start); lua_pushinteger(dispatcher, e.edit.length); nargs = 4; break; case SDL_MOUSEBUTTONDOWN: lua_pushliteral(dispatcher, "buttondown"); lua_pushinteger(dispatcher, e.button.button); lua_pushinteger(dispatcher, e.button.x); lua_pushinteger(dispatcher, e.button.y); nargs = 4; break; case SDL_MOUSEBUTTONUP: lua_pushliteral(dispatcher, "buttonup"); lua_pushinteger(dispatcher, e.button.button); lua_pushinteger(dispatcher, e.button.x); lua_pushinteger(dispatcher, e.button.y); nargs = 4; break; case SDL_MOUSEWHEEL: lua_pushliteral(dispatcher, "mousewheel"); lua_pushinteger(dispatcher, e.wheel.x); lua_pushinteger(dispatcher, e.wheel.y); nargs = 3; break; case SDL_MOUSEMOTION: lua_pushliteral(dispatcher, "motion"); lua_pushinteger(dispatcher, e.motion.x); lua_pushinteger(dispatcher, e.motion.y); lua_pushinteger(dispatcher, e.motion.xrel); lua_pushinteger(dispatcher, e.motion.yrel); nargs = 5; break; case SDL_WINDOWEVENT: switch (e.window.event) { case SDL_WINDOWEVENT_FOCUS_GAINED: lua_pushliteral(dispatcher, "active"); lua_pushinteger(dispatcher, 1); nargs = 2; break; case SDL_WINDOWEVENT_FOCUS_LOST: lua_pushliteral(dispatcher, "active"); lua_pushinteger(dispatcher, 0); nargs = 2; break; default: nargs = 0; break; } break; case SDL_USEREVENT_MUSIC_OVER: lua_pushliteral(dispatcher, "music_over"); nargs = 1; break; case SDL_USEREVENT_CPCALL: if(luaT_cpcall(L, (lua_CFunction)e.user.data1, e.user.data2)) { SDL_RemoveTimer(timer); lua_pushliteral(L, "callback"); return 2; } nargs = 0; break; case SDL_USEREVENT_TICK: do_timer = true; nargs = 0; break; case SDL_USEREVENT_MOVIE_OVER: lua_pushliteral(dispatcher, "movie_over"); nargs = 1; break; case SDL_USEREVENT_SOUND_OVER: lua_pushliteral(dispatcher, "sound_over"); lua_pushinteger(dispatcher, *(static_cast<int*>(e.user.data1))); nargs = 2; break; default: nargs = 0; break; } if(nargs != 0) { if(luaT_resume(dispatcher, dispatcher, nargs) != LUA_YIELD) { goto leave_loop; } do_frame = do_frame || (lua_toboolean(dispatcher, 1) != 0); lua_settop(dispatcher, 0); } } while(SDL_PollEvent(&e) != 0); if(do_timer) { lua_pushliteral(dispatcher, "timer"); if(luaT_resume(dispatcher, dispatcher, 1) != LUA_YIELD) { break; } do_frame = do_frame || (lua_toboolean(dispatcher, 1) != 0); lua_settop(dispatcher, 0); } if(do_frame || !fps_control->limit_fps) { do { if(fps_control->track_fps) { fps_control->count_frame(); } lua_pushliteral(dispatcher, "frame"); if(luaT_resume(dispatcher, dispatcher, 1) != LUA_YIELD) { goto leave_loop; } lua_settop(dispatcher, 0); } while(fps_control->limit_fps == false && SDL_PollEvent(NULL) == 0); } // No events pending - a good time to do a bit of garbage collection lua_gc(L, LUA_GCSTEP, 2); } leave_loop: SDL_RemoveTimer(timer); int n = lua_gettop(dispatcher); if(lua_status(dispatcher) >= LUA_ERRRUN) { n = 1; } lua_checkstack(L, n); lua_xmove(dispatcher, L, n); return n; }
static ngx_int_t ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) { int co_ref; lua_State *co; ngx_int_t rc; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; ngx_http_lua_loc_conf_t *llcf; /* {{{ new coroutine to handle request */ co = ngx_http_lua_new_thread(r, L, &co_ref); if (co == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua: failed to create new coroutine to handle request"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } /* move code closure to new coroutine */ lua_xmove(L, co, 1); /* set closure's env table to new coroutine's globals table */ ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); /* save nginx request in coroutine globals table */ ngx_http_lua_set_req(co, r); /* {{{ initialize request context */ ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); dd("ctx = %p", ctx); if (ctx == NULL) { return NGX_ERROR; } ngx_http_lua_reset_ctx(r, L, ctx); ctx->entered_rewrite_phase = 1; ctx->cur_co_ctx = &ctx->entry_co_ctx; ctx->cur_co_ctx->co = co; ctx->cur_co_ctx->co_ref = co_ref; #ifdef NGX_LUA_USE_ASSERT ctx->cur_co_ctx->co_top = 1; #endif /* }}} */ /* {{{ register request cleanup hooks */ if (ctx->cleanup == NULL) { cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cln->handler = ngx_http_lua_request_cleanup_handler; cln->data = ctx; ctx->cleanup = &cln->handler; } /* }}} */ ctx->context = NGX_HTTP_LUA_CONTEXT_REWRITE; llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->check_client_abort) { r->read_event_handler = ngx_http_lua_rd_check_broken_connection; } else { r->read_event_handler = ngx_http_block_reading; } rc = ngx_http_lua_run_thread(L, r, ctx, 0); if (rc == NGX_ERROR || rc > NGX_OK) { return rc; } c = r->connection; if (rc == NGX_AGAIN) { rc = ngx_http_lua_run_posted_threads(c, L, r, ctx); } else if (rc == NGX_DONE) { ngx_http_lua_finalize_request(r, NGX_DONE); rc = ngx_http_lua_run_posted_threads(c, L, r, ctx); } if (rc == NGX_OK || rc == NGX_DECLINED) { if (r->header_sent) { dd("header already sent"); /* response header was already generated in access_by_lua*, * so it is no longer safe to proceed to later phases * which may generate responses again */ if (!ctx->eof) { dd("eof not yet sent"); rc = ngx_http_lua_send_chain_link(r, ctx, NULL /* indicate last_buf */); if (rc == NGX_ERROR || rc > NGX_OK) { return rc; } } return NGX_HTTP_OK; } return NGX_DECLINED; } return rc; }
/* * Arguments: evq_udata, [timeout (milliseconds), once (boolean), * fetch (boolean)] * Returns: [evq_udata | timeout (false)] * | * Returns: [ev_ludata, obj_udata, event (string: "r", "w", "t", "e"), * eof_status (number)] */ static int levq_loop (lua_State *L) { struct event_queue *evq = checkudata(L, 1, EVQ_TYPENAME); const msec_t timeout = (lua_type(L, 2) != LUA_TNUMBER) ? TIMEOUT_INFINITE : (msec_t) lua_tointeger(L, 2); const int once = lua_toboolean(L, 3); const int fetch = lua_toboolean(L, 4); #undef ARG_LAST #define ARG_LAST 1 lua_settop(L, ARG_LAST); { lua_State *NL = evq->L; lua_pushvalue(NL, EVQ_CORO_CALLBACK); lua_pushvalue(NL, EVQ_CORO_UDATA); lua_xmove(NL, L, 2); } #ifdef EVQ_POST_INIT if (evq->ev_post) { evq_post_init(evq->ev_post); evq->ev_post = NULL; } #endif while (!evq_is_empty(evq)) { struct event *ev; if (evq->stop) { evq->stop = 0; break; } /* process synchronous operations */ if (evq->sync_op) { struct evq_sync_op *op = evq->sync_op; evq->sync_op = NULL; levq_sync_process(L, evq, op); } if (!evq->ev_ready) { const int res = evq_wait(evq, timeout); if (res == EVQ_TIMEOUT) { lua_pushboolean(L, 0); return 1; } if (res == EVQ_FAILED) return sys_seterror(L, 0); } ev = evq->ev_ready; if (!ev) continue; do { const unsigned int ev_flags = ev->flags; /* clear EVENT_ACTIVE and EVENT_*_RES flags */ ev->flags &= EVENT_MASK; evq->ev_ready = ev->next_ready; if (ev_flags & EVENT_DELETE) { /* postponed deletion of active event */ levq_del_event(evq, ev); } else { if ((ev_flags & EVENT_CALLBACK) || fetch) { const int ev_id = ev->ev_id; /* callback function */ lua_rawgeti(L, ARG_LAST+1, ev_id); /* arguments */ if (!(ev_flags & EVENT_CALLBACK_SCHED)) { lua_pushvalue(L, 1); /* evq_udata */ lua_pushlightuserdata(L, ev); /* ev_ludata */ lua_rawgeti(L, ARG_LAST+2, ev_id); /* obj_udata */ } if (ev_flags & EVENT_EOF_MASK_RES) { lua_pushliteral(L, "e"); lua_pushinteger(L, (int) ev_flags >> EVENT_EOF_SHIFT_RES); } else { lua_pushstring(L, (ev_flags & EVENT_TIMEOUT_RES) ? "t" : (ev_flags & EVENT_WRITE_RES) ? "w" : "r"); lua_pushnil(L); } } if ((ev_flags & EVENT_ONESHOT) && !event_deleted(ev)) evq_del(ev, 1); if (event_deleted(ev)) levq_del_event(evq, ev); /* deletion of oneshot event */ #ifdef EVQ_POST_INIT else evq->ev_post = ev; #endif if (ev_flags & EVENT_CALLBACK_SCHED) { /* callback function: coroutine */ lua_State *co = lua_tothread(L, ARG_LAST+3); lua_xmove(L, co, 2); lua_pop(L, 1); /* pop coroutine */ sys_sched_event_ready(co, ev); } else if (ev_flags & EVENT_CALLBACK_CORO) { lua_State *co = lua_tothread(L, ARG_LAST+3); lua_xmove(L, co, 5); lua_pop(L, 1); /* pop coroutine */ switch (lua_resume(co, L, 5)) { case 0: lua_settop(co, 0); if (!event_deleted(ev)) { evq_del(ev, 0); levq_del_event(evq, ev); #ifdef EVQ_POST_INIT evq->ev_post = NULL; #endif } break; case LUA_YIELD: lua_settop(co, 0); break; default: lua_xmove(co, L, 1); /* error message */ lua_error(L); } } else if (ev_flags & EVENT_CALLBACK) lua_call(L, 5, 0); else if (fetch) return 4; #ifdef EVQ_POST_INIT if (evq->ev_post) { evq_post_init(evq->ev_post); evq->ev_post = NULL; } #endif } ev = evq->ev_ready; } while (ev);
static ngx_int_t ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) { int cc_ref; lua_State *cc; ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; ngx_int_t rc; /* {{{ new coroutine to handle request */ cc = ngx_http_lua_new_thread(r, L, &cc_ref); if (cc == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua: failed to create new coroutine to handle request"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } /* move code closure to new coroutine */ lua_xmove(L, cc, 1); /* set closure's env table to new coroutine's globals table */ lua_pushvalue(cc, LUA_GLOBALSINDEX); lua_setfenv(cc, -2); /* save reference of code to ease forcing stopping */ lua_pushvalue(cc, -1); lua_setglobal(cc, GLOBALS_SYMBOL_RUNCODE); /* save nginx request in coroutine globals table */ lua_pushlightuserdata(cc, r); lua_setglobal(cc, GLOBALS_SYMBOL_REQUEST); /* }}} */ /* {{{ initialize request context */ ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); dd("ctx = %p", ctx); if (ctx == NULL) { return NGX_ERROR; } ngx_http_lua_reset_ctx(r, L, ctx); ctx->entered_rewrite_phase = 1; ctx->cc = cc; ctx->cc_ref = cc_ref; /* }}} */ /* {{{ register request cleanup hooks */ if (ctx->cleanup == NULL) { cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cln->handler = ngx_http_lua_request_cleanup; cln->data = r; ctx->cleanup = &cln->handler; } /* }}} */ rc = ngx_http_lua_run_thread(L, r, ctx, 0); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } if (rc == NGX_AGAIN) { return NGX_DONE; } if (rc == NGX_DONE) { ngx_http_finalize_request(r, NGX_DONE); return NGX_DONE; } if (rc >= NGX_HTTP_OK && rc < NGX_HTTP_SPECIAL_RESPONSE) { return rc; } return NGX_DECLINED; }
ngx_int_t ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) { int co_ref; ngx_int_t rc; lua_State *co; ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; ngx_http_lua_loc_conf_t *llcf; dd("content by chunk"); ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } } else { dd("reset ctx"); ngx_http_lua_reset_ctx(r, L, ctx); } ctx->entered_content_phase = 1; /* {{{ new coroutine to handle request */ co = ngx_http_lua_new_thread(r, L, &co_ref); if (co == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua: failed to create new coroutine to handle request"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } /* move code closure to new coroutine */ lua_xmove(L, co, 1); /* set closure's env table to new coroutine's globals table */ ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); /* save nginx request in coroutine globals table */ ngx_http_lua_set_req(co, r); ctx->cur_co_ctx = &ctx->entry_co_ctx; ctx->cur_co_ctx->co = co; ctx->cur_co_ctx->co_ref = co_ref; #ifdef ngx_http_lua_assert ctx->cur_co_ctx->co_top = 1; #endif /* {{{ register request cleanup hooks */ if (ctx->cleanup == NULL) { cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cln->handler = ngx_http_lua_request_cleanup_handler; cln->data = ctx; ctx->cleanup = &cln->handler; } /* }}} */ ctx->context = NGX_HTTP_LUA_CONTEXT_CONTENT; llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->check_client_abort) { r->read_event_handler = ngx_http_lua_rd_check_broken_connection; } else { r->read_event_handler = ngx_http_block_reading; } rc = ngx_http_lua_run_thread(L, r, ctx, 0); if (rc == NGX_ERROR || rc >= NGX_OK) { return rc; } if (rc == NGX_AGAIN) { return ngx_http_lua_content_run_posted_threads(L, r, ctx, 0); } if (rc == NGX_DONE) { return ngx_http_lua_content_run_posted_threads(L, r, ctx, 1); } return NGX_OK; }
int ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t **pr, ngx_http_lua_ctx_t **pctx, ngx_http_lua_co_ctx_t **pcoctx) { lua_State *mt; /* the main thread */ lua_State *co; /* new coroutine to be created */ ngx_http_request_t *r; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx; /* co ctx for the new coroutine */ luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, "Lua function expected"); lua_pushlightuserdata(L, &ngx_http_lua_request_key); lua_rawget(L, LUA_GLOBALSINDEX); r = lua_touserdata(L, -1); lua_pop(L, 1); if (r == NULL) { return luaL_error(L, "no request found"); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no request ctx found"); } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); mt = lmcf->lua; /* create new coroutine on root Lua state, so it always yields * to main Lua thread */ co = lua_newthread(mt); ngx_http_lua_probe_user_coroutine_create(r, L, co); coctx = ngx_http_lua_create_co_ctx(r, ctx); if (coctx == NULL) { return luaL_error(L, "out of memory"); } coctx->co = co; coctx->co_status = NGX_HTTP_LUA_CO_SUSPENDED; /* make new coroutine share globals of the parent coroutine. * NOTE: globals don't have to be separated! */ lua_pushvalue(L, LUA_GLOBALSINDEX); lua_xmove(L, co, 1); lua_replace(co, LUA_GLOBALSINDEX); lua_xmove(mt, L, 1); /* move coroutine from main thread to L */ lua_pushvalue(L, 1); /* copy entry function to top of L*/ lua_xmove(L, co, 1); /* move entry function from L to co */ if (pcoctx) { *pcoctx = coctx; } if (pctx) { *pctx = ctx; } if (pr) { *pr = r; } return 1; /* return new coroutine to Lua */ }
static int ngx_http_lua_uthread_wait(lua_State *L) { int i, nargs, nrets; lua_State *sub_co; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx, *sub_coctx; lua_pushlightuserdata(L, &ngx_http_lua_request_key); lua_rawget(L, LUA_GLOBALSINDEX); r = lua_touserdata(L, -1); lua_pop(L, 1); if (r == NULL) { return luaL_error(L, "no request found"); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no request ctx found"); } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); coctx = ctx->cur_co_ctx; nargs = lua_gettop(L); for (i = 1; i <= nargs; i++) { sub_co = lua_tothread(L, i); luaL_argcheck(L, sub_co, i, "lua thread expected"); sub_coctx = ngx_http_lua_get_co_ctx(sub_co, ctx); if (sub_coctx == NULL) { return luaL_error(L, "no co ctx found for the ngx.thread " "instance given"); } if (!sub_coctx->is_uthread) { return luaL_error(L, "attempt to wait on a coroutine that is " "not a user thread"); } if (sub_coctx->parent_co_ctx != coctx) { return luaL_error(L, "only the parent coroutine can wait on the " "thread"); } switch (sub_coctx->co_status) { case NGX_HTTP_LUA_CO_ZOMBIE: ngx_http_lua_probe_info("found zombie child"); nrets = lua_gettop(sub_coctx->co); dd("child retval count: %d, %s: %s", n, luaL_typename(sub_coctx->co, -1), lua_tostring(sub_coctx->co, -1)); if (nrets) { lua_xmove(sub_coctx->co, L, nrets); } #if 1 ngx_http_lua_del_thread(r, L, ctx, sub_coctx); ctx->uthreads--; #endif return nrets; default: /* still alive */ break; } sub_coctx->waited_by_parent = 1; } return lua_yield(L, 0); }
bool EmbeddedGamePanel::loadLua() { // Create state m_L = luaL_newstate(); lua_atpanic(m_L, _l_panic); // Save a pointer to ourselves in the registry lua_pushliteral(m_L, "wxWindow"); lua_pushlightuserdata(m_L, reinterpret_cast<wxWindow*>(this)); lua_settable(m_L, LUA_REGISTRYINDEX); // Open default libraries, and override appropriate bits luaL_openlibs(m_L); luaT_execute(m_L, "print = ...", _l_print); // Set _MAP_EDITOR to true, to allow scripts to notice that they are // running inside this component, rather than standalone. luaT_execute(m_L, "_MAP_EDITOR = true"); // Load CorsixTH.lua and perform other initialisation needed by it lua_settop(m_L, 0); lua_pushcfunction(m_L, CorsixTH_lua_stacktrace); lua_pushcfunction(m_L, CorsixTH_lua_main_no_eval); lua_checkstack(m_L, wxTheApp->argc); for(int i = 0; i < wxTheApp->argc; ++ i) lua_pushstring(m_L, wxTheApp->argv[i]); if(lua_pcall(m_L, wxTheApp->argc, 1, 1)) { if(m_pPrintTarget) { m_pPrintTarget->AppendText(L"Error initialising Lua: "); m_pPrintTarget->AppendText(lua_tostring(m_L, -1)); m_pPrintTarget->AppendText(L"\n"); } return false; } // NB: CorsixTH_lua_main_no_eval will have loaded CorsixTH.lua and left it // as the top value on the stack, but will not have executed it. // The stack will hence have two things on it: the stacktrace function, // and the loaded CorsixTH.lua // Overwrite what CorsixTH_lua_main_no_eval registered for require("sdl") // with our own function that uses wxWidgets to do what SDL would have. luaT_execute(m_L, "package.preload.sdl = ...", _l_open_sdl); // Replace the Surface:endFrame() function with our own lua_getglobal(m_L, "require"); lua_pushliteral(m_L, "TH"); lua_call(m_L, 1, 1); lua_getfield(m_L, -1, "surface"); lua_getfield(m_L, -1, "endFrame"); lua_pushcclosure(m_L, _l_end_frame, 1); lua_setfield(m_L, -2, "endFrame"); lua_pop(m_L, 2); // Perform extra initialisation if(m_fnExtraLuaInit) { if(lua_cpcall(m_L, m_fnExtraLuaInit, m_pExtraLuaInitArg) != 0) lua_pop(m_L, 1); } // Execute CorsixTH.lua in a coroutine lua_getglobal(m_L, "coroutine"); lua_getfield(m_L, -1, "create"); lua_replace(m_L, -2); lua_insert(m_L, -2); lua_call(m_L, 1, 1); lua_State *L = lua_tothread(m_L, -1); if(lua_resume(L, 0) != LUA_YIELD) { if(m_pPrintTarget) { // Push debug.traceback onto m_L lua_getglobal(m_L, "debug"); lua_getfield(m_L, -1, "traceback"); lua_replace(m_L, -2); // Push the thread onto m_L lua_pushvalue(m_L, -2); // Push tostring(errmsg) onto m_L lua_getglobal(m_L, "tostring"); lua_xmove(L, m_L, 1); lua_call(m_L, 1, 1); // Push constant 1 onto m_L lua_pushinteger(m_L, 1); // Call debug.traceback(thread, tostring(err), 1) lua_call(m_L, 3, 1); // Display resulting string and pop it m_pPrintTarget->AppendText(L"Error initialising Lua: "); m_pPrintTarget->AppendText(lua_tostring(m_L, -1)); m_pPrintTarget->AppendText(L"\n"); lua_pop(m_L, 1); } return false; } lua_settop(L, 1); m_Lthread = L; // The stack of the Lua states is now as follows: // m_L: stacktrace function, m_Lthread <top // m_Lthread: event dispatch coroutine <top return true; }