diff --git a/src/ngx_http_lua_uthread.c b/src/ngx_http_lua_uthread.c index 453d3ebdef..2281a9cf62 100644 --- a/src/ngx_http_lua_uthread.c +++ b/src/ngx_http_lua_uthread.c @@ -24,7 +24,7 @@ static int ngx_http_lua_uthread_spawn(lua_State *L); static int ngx_http_lua_uthread_wait(lua_State *L); - +static int ngx_http_lua_uthread_kill(lua_State *L); void ngx_http_lua_inject_uthread_api(ngx_log_t *log, lua_State *L) @@ -38,6 +38,9 @@ ngx_http_lua_inject_uthread_api(ngx_log_t *log, lua_State *L) lua_pushcfunction(L, ngx_http_lua_uthread_wait); lua_setfield(L, -2, "wait"); + lua_pushcfunction(L, ngx_http_lua_uthread_kill); + lua_setfield(L, -2, "kill"); + lua_setfield(L, -2, "thread"); } @@ -196,4 +199,84 @@ ngx_http_lua_uthread_wait(lua_State *L) return lua_yield(L, 0); } + +static int +ngx_http_lua_uthread_kill(lua_State *L) +{ + int i, nargs; + int killed; + 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); + + killed = 0; + 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 + || sub_coctx->co_status == NGX_HTTP_LUA_CO_DEAD) + { + /* XXX The thread is dead, consider it a success and continue. */ + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "attempt to kill an already dead thread"); + killed++; + continue; + } + + if (!sub_coctx->is_uthread) { + return luaL_error(L, "attempt to kill a coroutine that is " + "not a user thread"); + } + + if (sub_coctx->parent_co_ctx != coctx) { + return luaL_error(L, "only the parent coroutine can kill the " + "thread"); + } + + if (sub_coctx->nsubreqs) { + /* XXX Don't kill threads with pending subrequests. */ + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "attempt to kill thread with pending subrequests"); + continue; + } + + if (sub_coctx->cleanup) { + sub_coctx->cleanup(sub_coctx); + sub_coctx->cleanup = NULL; + } + + if (ngx_http_lua_del_thread(r, L, ctx, sub_coctx) == NGX_OK) { + killed++; + ctx->uthreads--; + } + + } + + lua_pushinteger(L, killed); + return 1; +} + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index be99d927fc..5012540b5f 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -344,12 +344,12 @@ ngx_http_lua_new_thread(ngx_http_request_t *r, lua_State *L, int *ref) } -void +ngx_int_t ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L, ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t *coctx) { if (coctx->co_ref == LUA_NOREF) { - return; + return NGX_DECLINED; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -365,6 +365,8 @@ ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L, coctx->co_status = NGX_HTTP_LUA_CO_DEAD; lua_pop(L, 1); + + return NGX_OK; } diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index 0ade7933d1..874699c73b 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -192,7 +192,7 @@ ngx_int_t ngx_http_lua_run_posted_threads(ngx_connection_t *c, lua_State *L, ngx_int_t ngx_http_lua_post_thread(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t *coctx); -void ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L, +ngx_int_t ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L, ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t *coctx); void ngx_http_lua_rd_check_broken_connection(ngx_http_request_t *r);