feature: added new Lua API, ngx.timer.at(time, callback), for defining timers that can run the user callback as a Lua "light thread" (detached from the current request) after the time (in seconds) specified. also added new configure directives lua_max_pending_timers and lua_max_running_timers for limiting the number of pending timers and "running" timers.
This commit is contained in:
Родитель
664d74ed7f
Коммит
2ac8d89439
|
@ -149,8 +149,10 @@ tre
|
|||
src/phase.[ch]
|
||||
src/probe.h
|
||||
src/uthread.[ch]
|
||||
src/timer.[ch]
|
||||
*.plist
|
||||
lua
|
||||
ttimer
|
||||
Makefile
|
||||
tsubreq
|
||||
tthread
|
||||
|
|
2
config
2
config
|
@ -221,6 +221,7 @@ NGX_ADDON_SRCS="$NGX_ADDON_SRCS \
|
|||
$ngx_addon_dir/src/ngx_http_lua_req_method.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_phase.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_uthread.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_timer.c \
|
||||
"
|
||||
|
||||
NGX_ADDON_DEPS="$NGX_ADDON_DEPS \
|
||||
|
@ -270,6 +271,7 @@ NGX_ADDON_DEPS="$NGX_ADDON_DEPS \
|
|||
$ngx_addon_dir/src/ngx_http_lua_phase.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_probe.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_uthread.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_timer.h \
|
||||
"
|
||||
|
||||
CFLAGS="$CFLAGS -DNDK_SET_VAR"
|
||||
|
|
|
@ -326,7 +326,7 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r)
|
|||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
ngx_http_finalize_request(r, NGX_DONE);
|
||||
ngx_http_lua_finalize_request(r, NGX_DONE);
|
||||
|
||||
rc = ngx_http_lua_run_posted_threads(c, L, r, ctx);
|
||||
|
||||
|
|
|
@ -42,6 +42,8 @@ ngx_http_lua_ngx_req_set_uri_args(lua_State *L) {
|
|||
return luaL_error(L, "no request object found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request(L, r);
|
||||
|
||||
switch (lua_type(L, 1)) {
|
||||
case LUA_TNUMBER:
|
||||
case LUA_TSTRING:
|
||||
|
@ -113,6 +115,8 @@ ngx_http_lua_ngx_req_get_uri_args(lua_State *L) {
|
|||
return luaL_error(L, "no request object found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request(L, r);
|
||||
|
||||
lua_createtable(L, 0, 4);
|
||||
|
||||
/* we copy r->args over to buf to simplify
|
||||
|
@ -171,8 +175,10 @@ ngx_http_lua_ngx_req_get_post_args(lua_State *L)
|
|||
return luaL_error(L, "no request object found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request(L, r);
|
||||
|
||||
if (r->discard_body) {
|
||||
lua_createtable(L, 0, 4);
|
||||
lua_createtable(L, 0, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -77,6 +77,7 @@ typedef struct {
|
|||
#define NGX_HTTP_LUA_CONTEXT_LOG 0x10
|
||||
#define NGX_HTTP_LUA_CONTEXT_HEADER_FILTER 0x20
|
||||
#define NGX_HTTP_LUA_CONTEXT_BODY_FILTER 0x40
|
||||
#define NGX_HTTP_LUA_CONTEXT_TIMER 0x80
|
||||
|
||||
|
||||
typedef struct ngx_http_lua_main_conf_s ngx_http_lua_main_conf_t;
|
||||
|
@ -100,6 +101,12 @@ struct ngx_http_lua_main_conf_s {
|
|||
|
||||
ngx_pool_t *pool;
|
||||
|
||||
ngx_int_t max_pending_timers;
|
||||
ngx_int_t pending_timers;
|
||||
|
||||
ngx_int_t max_running_timers;
|
||||
ngx_int_t running_timers;
|
||||
|
||||
#if (NGX_PCRE)
|
||||
ngx_int_t regex_cache_entries;
|
||||
ngx_int_t regex_cache_max_entries;
|
||||
|
@ -271,10 +278,6 @@ struct ngx_http_lua_co_ctx_s {
|
|||
|
||||
|
||||
typedef struct ngx_http_lua_ctx_s {
|
||||
uint8_t context; /* the current running directive context
|
||||
(or running phase) for the current
|
||||
Lua chunk */
|
||||
|
||||
ngx_http_handler_pt resume_handler;
|
||||
|
||||
ngx_http_lua_co_ctx_t *cur_co_ctx; /* co ctx for the current coroutine */
|
||||
|
@ -326,6 +329,10 @@ typedef struct ngx_http_lua_ctx_s {
|
|||
|
||||
ngx_http_lua_posted_thread_t *posted_threads;
|
||||
|
||||
uint16_t context; /* the current running directive context
|
||||
(or running phase) for the current
|
||||
Lua chunk */
|
||||
|
||||
unsigned run_post_subrequest:1; /* whether it has run
|
||||
post_subrequest
|
||||
(for subrequests only) */
|
||||
|
|
|
@ -19,8 +19,6 @@
|
|||
|
||||
|
||||
static void ngx_http_lua_content_phase_post_read(ngx_http_request_t *r);
|
||||
static ngx_int_t ngx_http_lua_content_run_posted_threads(lua_State *L,
|
||||
ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, int n);
|
||||
|
||||
|
||||
ngx_int_t
|
||||
|
@ -220,7 +218,7 @@ ngx_http_lua_content_phase_post_read(ngx_http_request_t *r)
|
|||
|
||||
if (ctx->waiting_more_body) {
|
||||
ctx->waiting_more_body = 0;
|
||||
ngx_http_finalize_request(r, ngx_http_lua_content_handler(r));
|
||||
ngx_http_lua_finalize_request(r, ngx_http_lua_content_handler(r));
|
||||
|
||||
} else {
|
||||
r->main->count--;
|
||||
|
@ -313,13 +311,15 @@ ngx_http_lua_content_handler_inline(ngx_http_request_t *r)
|
|||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_int_t
|
||||
ngx_http_lua_content_run_posted_threads(lua_State *L, ngx_http_request_t *r,
|
||||
ngx_http_lua_ctx_t *ctx, int n)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
ngx_http_lua_posted_thread_t *pt;
|
||||
|
||||
dd("run posted threads: %p", ctx->posted_threads);
|
||||
|
||||
for ( ;; ) {
|
||||
pt = ctx->posted_threads;
|
||||
if (pt == NULL) {
|
||||
|
@ -331,6 +331,8 @@ ngx_http_lua_content_run_posted_threads(lua_State *L, ngx_http_request_t *r,
|
|||
ngx_http_lua_probe_run_posted_thread(r, pt->co_ctx->co,
|
||||
(int) pt->co_ctx->co_status);
|
||||
|
||||
dd("posted thread status: %d", pt->co_ctx->co_status);
|
||||
|
||||
if (pt->co_ctx->co_status != NGX_HTTP_LUA_CO_RUNNING) {
|
||||
continue;
|
||||
}
|
||||
|
@ -350,7 +352,7 @@ ngx_http_lua_content_run_posted_threads(lua_State *L, ngx_http_request_t *r,
|
|||
|
||||
if (rc == NGX_OK) {
|
||||
while (n > 0) {
|
||||
ngx_http_finalize_request(r, NGX_DONE);
|
||||
ngx_http_lua_finalize_request(r, NGX_DONE);
|
||||
n--;
|
||||
}
|
||||
|
||||
|
@ -375,7 +377,7 @@ done:
|
|||
/* n > 1 */
|
||||
|
||||
do {
|
||||
ngx_http_finalize_request(r, NGX_DONE);
|
||||
ngx_http_lua_finalize_request(r, NGX_DONE);
|
||||
} while (--n > 1);
|
||||
|
||||
return NGX_DONE;
|
||||
|
|
|
@ -17,6 +17,8 @@ void ngx_http_lua_content_wev_handler(ngx_http_request_t *r);
|
|||
ngx_int_t ngx_http_lua_content_handler_file(ngx_http_request_t *r);
|
||||
ngx_int_t ngx_http_lua_content_handler_inline(ngx_http_request_t *r);
|
||||
ngx_int_t ngx_http_lua_content_handler(ngx_http_request_t *r);
|
||||
ngx_int_t ngx_http_lua_content_run_posted_threads(lua_State *L,
|
||||
ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, int n);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_CONTENT_BY_H_INCLUDED_ */
|
||||
|
|
|
@ -317,7 +317,8 @@ ngx_http_lua_ngx_exit(lua_State *L)
|
|||
|
||||
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_CONTENT
|
||||
| NGX_HTTP_LUA_CONTEXT_TIMER);
|
||||
|
||||
rc = (ngx_int_t) luaL_checkinteger(L, 1);
|
||||
|
||||
|
@ -378,6 +379,8 @@ ngx_http_lua_on_abort(lua_State *L)
|
|||
return luaL_error(L, "no request ctx found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request2(L, r, ctx);
|
||||
|
||||
if (ctx->on_abort_co_ctx) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "duplicate call");
|
||||
|
|
|
@ -74,7 +74,8 @@ ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r,
|
|||
|
||||
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_CONTENT
|
||||
| NGX_HTTP_LUA_CONTEXT_TIMER);
|
||||
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
mt = lmcf->lua;
|
||||
|
@ -142,7 +143,8 @@ ngx_http_lua_coroutine_resume(lua_State *L)
|
|||
|
||||
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_CONTENT
|
||||
| NGX_HTTP_LUA_CONTEXT_TIMER);
|
||||
|
||||
p_coctx = ctx->cur_co_ctx;
|
||||
if (p_coctx == NULL) {
|
||||
|
@ -204,7 +206,8 @@ ngx_http_lua_coroutine_yield(lua_State *L)
|
|||
|
||||
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_CONTENT
|
||||
| NGX_HTTP_LUA_CONTEXT_TIMER);
|
||||
|
||||
coctx = ctx->cur_co_ctx;
|
||||
|
||||
|
@ -323,7 +326,8 @@ ngx_http_lua_coroutine_status(lua_State *L)
|
|||
|
||||
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_CONTENT
|
||||
| NGX_HTTP_LUA_CONTEXT_TIMER);
|
||||
|
||||
coctx = ngx_http_lua_get_co_ctx(co, ctx);
|
||||
if (coctx == NULL) {
|
||||
|
|
|
@ -41,6 +41,8 @@ ngx_http_lua_ngx_req_http_version(lua_State *L)
|
|||
return luaL_error(L, "no request object found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request(L, r);
|
||||
|
||||
switch (r->http_version) {
|
||||
case NGX_HTTP_VERSION_9:
|
||||
lua_pushnumber(L, 0.9);
|
||||
|
@ -91,6 +93,8 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L)
|
|||
return luaL_error(L, "no request object found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request(L, r);
|
||||
|
||||
hc = r->main->http_connection;
|
||||
|
||||
if (hc->nbusy) {
|
||||
|
@ -277,6 +281,8 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) {
|
|||
return luaL_error(L, "no request object found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request(L, r);
|
||||
|
||||
lua_createtable(L, 0, 4);
|
||||
|
||||
if (!raw) {
|
||||
|
@ -352,6 +358,8 @@ ngx_http_lua_ngx_header_get(lua_State *L)
|
|||
return luaL_error(L, "no request object found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request(L, r);
|
||||
|
||||
/* we skip the first argument that is the table */
|
||||
p = (u_char *) luaL_checklstring(L, 2, &len);
|
||||
|
||||
|
@ -407,6 +415,11 @@ ngx_http_lua_ngx_header_set(lua_State *L)
|
|||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no ctx");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request2(L, r, ctx);
|
||||
|
||||
if (ctx->headers_sent) {
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "attempt to "
|
||||
|
@ -562,6 +575,8 @@ ngx_http_lua_ngx_req_header_set_helper(lua_State *L)
|
|||
return luaL_error(L, "no request object found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request(L, r);
|
||||
|
||||
p = (u_char *) luaL_checklstring(L, 1, &len);
|
||||
|
||||
dd("key: %.*s, len %d", (int) len, p, (int) len);
|
||||
|
|
|
@ -57,6 +57,7 @@ ngx_http_lua_ngx_get(lua_State *L)
|
|||
if (len == sizeof("status") - 1
|
||||
&& ngx_strncmp(p, "status", sizeof("status") - 1) == 0)
|
||||
{
|
||||
ngx_http_lua_check_fake_request(L, r);
|
||||
lua_pushnumber(L, (lua_Number) r->headers_out.status);
|
||||
return 1;
|
||||
}
|
||||
|
@ -78,6 +79,11 @@ ngx_http_lua_ngx_get(lua_State *L)
|
|||
&& ngx_strncmp(p, "headers_sent", sizeof("headers_sent") - 1) == 0)
|
||||
{
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no ctx");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request2(L, r, ctx);
|
||||
|
||||
dd("headers sent: %d", ctx->headers_sent);
|
||||
|
||||
|
@ -124,6 +130,8 @@ ngx_http_lua_ngx_set(lua_State *L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request2(L, r, ctx);
|
||||
|
||||
/* get the value */
|
||||
r->headers_out.status = (ngx_uint_t) luaL_checknumber(L, 3);
|
||||
return 0;
|
||||
|
|
|
@ -47,6 +47,20 @@ static ngx_conf_post_t ngx_http_lua_lowat_post =
|
|||
|
||||
static ngx_command_t ngx_http_lua_cmds[] = {
|
||||
|
||||
{ ngx_string("lua_max_running_timers"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_num_slot,
|
||||
NGX_HTTP_MAIN_CONF_OFFSET,
|
||||
offsetof(ngx_http_lua_main_conf_t, max_running_timers),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("lua_max_pending_timers"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_num_slot,
|
||||
NGX_HTTP_MAIN_CONF_OFFSET,
|
||||
offsetof(ngx_http_lua_main_conf_t, max_pending_timers),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("lua_shared_dict"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE2,
|
||||
ngx_http_lua_shared_dict,
|
||||
|
@ -489,6 +503,8 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf)
|
|||
* lmcf->lua = NULL;
|
||||
* lmcf->lua_path = { 0, NULL };
|
||||
* lmcf->lua_cpath = { 0, NULL };
|
||||
* lmcf->pending_timers = 0;
|
||||
* lmcf->running_timers = 0;
|
||||
* lmcf->regex_cache_entries = 0;
|
||||
* lmcf->shm_zones = NULL;
|
||||
* lmcf->init_handler = NULL;
|
||||
|
@ -505,6 +521,8 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf)
|
|||
*/
|
||||
|
||||
lmcf->pool = cf->pool;
|
||||
lmcf->max_pending_timers = NGX_CONF_UNSET;
|
||||
lmcf->max_running_timers = NGX_CONF_UNSET;
|
||||
#if (NGX_PCRE)
|
||||
lmcf->regex_cache_max_entries = NGX_CONF_UNSET;
|
||||
#endif
|
||||
|
@ -519,14 +537,22 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf)
|
|||
static char *
|
||||
ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf)
|
||||
{
|
||||
#if (NGX_PCRE)
|
||||
ngx_http_lua_main_conf_t *lmcf = conf;
|
||||
|
||||
#if (NGX_PCRE)
|
||||
if (lmcf->regex_cache_max_entries == NGX_CONF_UNSET) {
|
||||
lmcf->regex_cache_max_entries = 1024;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (lmcf->max_pending_timers == NGX_CONF_UNSET) {
|
||||
lmcf->max_pending_timers = 1024;
|
||||
}
|
||||
|
||||
if (lmcf->max_running_timers == NGX_CONF_UNSET) {
|
||||
lmcf->max_running_timers = 256;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -713,14 +713,14 @@ ngx_http_lua_flush_resume_helper(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx)
|
|||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
ngx_http_finalize_request(r, NGX_DONE);
|
||||
ngx_http_lua_finalize_request(r, NGX_DONE);
|
||||
return ngx_http_lua_run_posted_threads(c, lmcf->lua, r, ctx);
|
||||
}
|
||||
|
||||
/* rc == NGX_ERROR || rc >= NGX_OK */
|
||||
|
||||
if (ctx->entered_content_phase) {
|
||||
ngx_http_finalize_request(r, rc);
|
||||
ngx_http_lua_finalize_request(r, rc);
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
|
|
|
@ -226,6 +226,8 @@ ngx_http_lua_ngx_req_discard_body(lua_State *L)
|
|||
return luaL_error(L, "request object not found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request(L, r);
|
||||
|
||||
rc = ngx_http_discard_request_body(r);
|
||||
|
||||
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
|
@ -261,6 +263,8 @@ ngx_http_lua_ngx_req_get_body_data(lua_State *L)
|
|||
return luaL_error(L, "request object not found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request(L, r);
|
||||
|
||||
if (r->request_body == NULL
|
||||
|| r->request_body->temp_file
|
||||
|| r->request_body->bufs == NULL)
|
||||
|
@ -330,6 +334,8 @@ ngx_http_lua_ngx_req_get_body_file(lua_State *L)
|
|||
return luaL_error(L, "request object not found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request(L, r);
|
||||
|
||||
if (r->request_body == NULL || r->request_body->temp_file == NULL) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
|
@ -382,6 +388,8 @@ ngx_http_lua_ngx_req_set_body_data(lua_State *L)
|
|||
return luaL_error(L, "request object not found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request(L, r);
|
||||
|
||||
if (r->discard_body) {
|
||||
return luaL_error(L, "request body already discarded asynchronously");
|
||||
}
|
||||
|
@ -543,6 +551,8 @@ ngx_http_lua_ngx_req_init_body(lua_State *L)
|
|||
r = lua_touserdata(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
ngx_http_lua_check_fake_request(L, r);
|
||||
|
||||
if (r->discard_body) {
|
||||
return luaL_error(L, "request body already discarded asynchronously");
|
||||
}
|
||||
|
@ -641,6 +651,8 @@ ngx_http_lua_ngx_req_append_body(lua_State *L)
|
|||
r = lua_touserdata(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
ngx_http_lua_check_fake_request(L, r);
|
||||
|
||||
if (r->request_body == NULL
|
||||
|| r->request_body->buf == NULL
|
||||
|| r->request_body->bufs == NULL)
|
||||
|
@ -702,6 +714,12 @@ ngx_http_lua_ngx_req_body_finish(lua_State *L)
|
|||
r = lua_touserdata(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request(L, r);
|
||||
|
||||
if (r->request_body == NULL
|
||||
|| r->request_body->buf == NULL
|
||||
|| r->request_body->bufs == NULL)
|
||||
|
@ -832,6 +850,8 @@ ngx_http_lua_ngx_req_set_body_file(lua_State *L)
|
|||
return luaL_error(L, "request object not found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request(L, r);
|
||||
|
||||
if (r->discard_body) {
|
||||
return luaL_error(L, "request body already discarded asynchronously");
|
||||
}
|
||||
|
@ -1131,12 +1151,12 @@ ngx_http_lua_read_body_resume(ngx_http_request_t *r)
|
|||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
ngx_http_finalize_request(r, NGX_DONE);
|
||||
ngx_http_lua_finalize_request(r, NGX_DONE);
|
||||
return ngx_http_lua_run_posted_threads(c, lmcf->lua, r, ctx);
|
||||
}
|
||||
|
||||
if (ctx->entered_content_phase) {
|
||||
ngx_http_finalize_request(r, rc);
|
||||
ngx_http_lua_finalize_request(r, rc);
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,8 @@ ngx_http_lua_ngx_req_get_method(lua_State *L)
|
|||
return luaL_error(L, "request object not found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request(L, r);
|
||||
|
||||
lua_pushlstring(L, (char *) r->method_name.data, r->method_name.len);
|
||||
return 1;
|
||||
}
|
||||
|
@ -78,6 +80,8 @@ ngx_http_lua_ngx_req_set_method(lua_State *L)
|
|||
return luaL_error(L, "request object not found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request(L, r);
|
||||
|
||||
r->method = method;
|
||||
|
||||
switch (method) {
|
||||
|
|
|
@ -322,7 +322,7 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r)
|
|||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
ngx_http_finalize_request(r, 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) {
|
||||
|
|
|
@ -175,12 +175,12 @@ ngx_http_lua_sleep_resume(ngx_http_request_t *r)
|
|||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
ngx_http_finalize_request(r, NGX_DONE);
|
||||
ngx_http_lua_finalize_request(r, NGX_DONE);
|
||||
return ngx_http_lua_run_posted_threads(c, lmcf->lua, r, ctx);
|
||||
}
|
||||
|
||||
if (ctx->entered_content_phase) {
|
||||
ngx_http_finalize_request(r, rc);
|
||||
ngx_http_lua_finalize_request(r, rc);
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
|
|
|
@ -237,7 +237,8 @@ ngx_http_lua_socket_tcp(lua_State *L)
|
|||
|
||||
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_CONTENT
|
||||
| NGX_HTTP_LUA_CONTEXT_TIMER);
|
||||
|
||||
lua_createtable(L, 3 /* narr */, 1 /* nrec */);
|
||||
lua_pushlightuserdata(L, &ngx_http_lua_tcp_socket_metatable_key);
|
||||
|
@ -297,7 +298,8 @@ ngx_http_lua_socket_tcp_connect(lua_State *L)
|
|||
|
||||
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_CONTENT
|
||||
| NGX_HTTP_LUA_CONTEXT_TIMER);
|
||||
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
|
||||
|
@ -3008,7 +3010,7 @@ ngx_http_lua_req_socket(lua_State *L)
|
|||
|
||||
if (lua_gettop(L) != 0) {
|
||||
return luaL_error(L, "expecting zero arguments, but got %d",
|
||||
lua_gettop(L));
|
||||
lua_gettop(L));
|
||||
}
|
||||
|
||||
lua_pushlightuserdata(L, &ngx_http_lua_request_key);
|
||||
|
@ -4005,12 +4007,12 @@ ngx_http_lua_socket_tcp_resume(ngx_http_request_t *r)
|
|||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
ngx_http_finalize_request(r, NGX_DONE);
|
||||
ngx_http_lua_finalize_request(r, NGX_DONE);
|
||||
return ngx_http_lua_run_posted_threads(c,lmcf->lua, r, ctx);
|
||||
}
|
||||
|
||||
if (ctx->entered_content_phase) {
|
||||
ngx_http_finalize_request(r, rc);
|
||||
ngx_http_lua_finalize_request(r, rc);
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
|
|
|
@ -134,7 +134,8 @@ ngx_http_lua_socket_udp(lua_State *L)
|
|||
|
||||
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_CONTENT
|
||||
| NGX_HTTP_LUA_CONTEXT_TIMER);
|
||||
|
||||
lua_createtable(L, 3 /* narr */, 1 /* nrec */);
|
||||
lua_pushlightuserdata(L, &ngx_http_lua_socket_udp_metatable_key);
|
||||
|
@ -197,7 +198,8 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L)
|
|||
|
||||
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_CONTENT
|
||||
| NGX_HTTP_LUA_CONTEXT_TIMER);
|
||||
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
|
||||
|
@ -1494,12 +1496,12 @@ ngx_http_lua_socket_udp_resume(ngx_http_request_t *r)
|
|||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
ngx_http_finalize_request(r, NGX_DONE);
|
||||
ngx_http_lua_finalize_request(r, NGX_DONE);
|
||||
return ngx_http_lua_run_posted_threads(c, lmcf->lua, r, ctx);
|
||||
}
|
||||
|
||||
if (ctx->entered_content_phase) {
|
||||
ngx_http_finalize_request(r, rc);
|
||||
ngx_http_lua_finalize_request(r, rc);
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
|
|
|
@ -1511,14 +1511,14 @@ ngx_http_lua_subrequest_resume(ngx_http_request_t *r)
|
|||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
ngx_http_finalize_request(r, NGX_DONE);
|
||||
ngx_http_lua_finalize_request(r, NGX_DONE);
|
||||
return ngx_http_lua_run_posted_threads(c, lmcf->lua, r, ctx);
|
||||
}
|
||||
|
||||
/* rc == NGX_ERROR || rc >= NGX_OK */
|
||||
|
||||
if (ctx->entered_content_phase) {
|
||||
ngx_http_finalize_request(r, rc);
|
||||
ngx_http_lua_finalize_request(r, rc);
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,470 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_timer.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
#include "ngx_http_lua_contentby.h"
|
||||
#include "ngx_http_lua_probe.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
int co_ref;
|
||||
lua_State *co;
|
||||
|
||||
void **main_conf;
|
||||
void **srv_conf;
|
||||
void **loc_conf;
|
||||
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
} ngx_http_lua_timer_t;
|
||||
|
||||
|
||||
static int ngx_http_lua_ngx_timer_at(lua_State *L);
|
||||
static void ngx_http_lua_timer_handler(ngx_event_t *ev);
|
||||
static u_char * ngx_http_lua_log_timer_error(ngx_log_t *log, u_char *buf,
|
||||
size_t len);
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_inject_timer_api(lua_State *L)
|
||||
{
|
||||
lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* ngx.timer. */
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_ngx_timer_at);
|
||||
lua_setfield(L, -2, "at");
|
||||
|
||||
lua_setfield(L, -2, "timer");
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_ngx_timer_at(lua_State *L)
|
||||
{
|
||||
int co_ref;
|
||||
u_char *p;
|
||||
lua_State *mt; /* the main thread */
|
||||
lua_State *co;
|
||||
ngx_msec_t delay;
|
||||
ngx_event_t *ev;
|
||||
ngx_http_request_t *r;
|
||||
ngx_http_lua_timer_t *timer;
|
||||
#if 0
|
||||
ngx_http_connection_t *hc;
|
||||
#endif
|
||||
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
#if 0
|
||||
ngx_http_core_main_conf_t *cmcf;
|
||||
#endif
|
||||
|
||||
if (lua_gettop(L) != 2) {
|
||||
return luaL_error(L, "expecting 2 arguments but got %d",
|
||||
lua_gettop(L));
|
||||
}
|
||||
|
||||
delay = (ngx_msec_t) (luaL_checknumber(L, 1) * 1000);
|
||||
|
||||
luaL_argcheck(L, lua_isfunction(L, 2) && !lua_iscfunction(L, 2), 2,
|
||||
"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");
|
||||
}
|
||||
|
||||
if (ngx_exiting) {
|
||||
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;
|
||||
}
|
||||
|
||||
mt = lmcf->lua;
|
||||
|
||||
co = lua_newthread(mt);
|
||||
|
||||
/* stack: time func 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(mt, L, 1); /* move coroutine from main thread to L */
|
||||
|
||||
/* L stack: time func thread */
|
||||
/* mt stack: empty */
|
||||
|
||||
lua_pushvalue(L, 2); /* copy entry function to top of L*/
|
||||
|
||||
/* L stack: time func thread func */
|
||||
|
||||
lua_xmove(L, co, 1); /* move entry function from L to co */
|
||||
|
||||
/* L stack: time func thread */
|
||||
/* co stack: func */
|
||||
|
||||
lua_pushvalue(co, LUA_GLOBALSINDEX);
|
||||
lua_setfenv(co, -2);
|
||||
|
||||
/* co stack: thread */
|
||||
|
||||
lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
|
||||
/* L stack: time func thread corountines */
|
||||
|
||||
lua_pushvalue(L, -2);
|
||||
|
||||
/* L stack: time func thread coroutines thread */
|
||||
|
||||
co_ref = luaL_ref(L, -2);
|
||||
lua_pop(L, 1);
|
||||
|
||||
/* L stack: time func thread */
|
||||
|
||||
p = ngx_alloc(sizeof(ngx_event_t) + sizeof(ngx_http_lua_timer_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);
|
||||
|
||||
timer = (ngx_http_lua_timer_t *) p;
|
||||
|
||||
timer->co_ref = co_ref;
|
||||
timer->co = co;
|
||||
timer->main_conf = r->main_conf;
|
||||
timer->srv_conf = r->srv_conf;
|
||||
timer->loc_conf = r->loc_conf;
|
||||
timer->lmcf = lmcf;
|
||||
|
||||
ev->handler = ngx_http_lua_timer_handler;
|
||||
ev->data = timer;
|
||||
ev->log = ngx_cycle->log;
|
||||
|
||||
lmcf->pending_timers++;
|
||||
|
||||
ngx_add_timer(ev, delay);
|
||||
|
||||
lua_pushinteger(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_lua_timer_handler(ngx_event_t *ev)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_int_t rc;
|
||||
ngx_log_t *log;
|
||||
ngx_connection_t *c = NULL, *saved_c = NULL;
|
||||
ngx_http_request_t *r = NULL;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_cleanup_t *cln;
|
||||
ngx_http_log_ctx_t *logctx;
|
||||
ngx_http_lua_timer_t timer;
|
||||
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
ngx_http_core_loc_conf_t *clcf;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
|
||||
"lua ngx.timer expired");
|
||||
|
||||
ngx_memcpy(&timer, ev->data, sizeof(ngx_http_lua_timer_t));
|
||||
ngx_free(ev);
|
||||
ev = NULL;
|
||||
|
||||
lmcf = timer.lmcf;
|
||||
|
||||
lmcf->pending_timers--;
|
||||
|
||||
if (lmcf->running_timers >= lmcf->max_running_timers) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
|
||||
"%i lua_max_running_timers are not enough",
|
||||
lmcf->max_running_timers);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
/* create the fake connection (we temporarily use a valid fd (0) to make
|
||||
ngx_get_connection happy) */
|
||||
|
||||
if (ngx_cycle->files) {
|
||||
saved_c = ngx_cycle->files[0];
|
||||
}
|
||||
|
||||
c = ngx_get_connection(0, ngx_cycle->log);
|
||||
|
||||
if (ngx_cycle->files) {
|
||||
ngx_cycle->files[0] = saved_c;
|
||||
}
|
||||
|
||||
if (c == NULL) {
|
||||
goto abort;
|
||||
}
|
||||
|
||||
c->fd = -1;
|
||||
|
||||
c->pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, c->log);
|
||||
if (c->pool == NULL) {
|
||||
goto abort;
|
||||
}
|
||||
|
||||
log = ngx_pcalloc(c->pool, sizeof(ngx_log_t));
|
||||
if (log == NULL) {
|
||||
goto abort;
|
||||
}
|
||||
|
||||
logctx = ngx_palloc(c->pool, sizeof(ngx_http_log_ctx_t));
|
||||
if (logctx == NULL) {
|
||||
goto abort;
|
||||
}
|
||||
|
||||
dd("c pool allocated: %d", (int) (sizeof(ngx_log_t)
|
||||
+ sizeof(ngx_http_log_ctx_t) + sizeof(ngx_http_request_t)));
|
||||
|
||||
logctx->connection = c;
|
||||
logctx->request = NULL;
|
||||
logctx->current_request = NULL;
|
||||
|
||||
c->log = log;
|
||||
c->log->connection = c->number;
|
||||
c->log->handler = ngx_http_lua_log_timer_error;
|
||||
c->log->data = logctx;
|
||||
c->log->action = NULL;
|
||||
|
||||
c->log_error = NGX_ERROR_INFO;
|
||||
|
||||
#if 0
|
||||
c->buffer = ngx_create_temp_buf(c->pool, 2);
|
||||
if (c->buffer == NULL) {
|
||||
goto abort;
|
||||
}
|
||||
|
||||
c->buffer->start[0] = CR;
|
||||
c->buffer->start[1] = LF;
|
||||
#endif
|
||||
|
||||
/* create the fake request */
|
||||
|
||||
r = ngx_pcalloc(c->pool, sizeof(ngx_http_request_t));
|
||||
if (r == NULL) {
|
||||
goto abort;
|
||||
}
|
||||
|
||||
c->requests++;
|
||||
logctx->request = r;
|
||||
logctx->current_request = r;
|
||||
|
||||
r->pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, c->log);
|
||||
if (r->pool == NULL) {
|
||||
goto abort;
|
||||
}
|
||||
|
||||
dd("r pool allocated: %d", (int) (sizeof(ngx_http_lua_ctx_t)
|
||||
+ sizeof(void *) * ngx_http_max_module + sizeof(ngx_http_cleanup_t)));
|
||||
|
||||
#if 0
|
||||
hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t));
|
||||
if (hc == NULL) {
|
||||
goto abort;
|
||||
}
|
||||
|
||||
r->header_in = c->buffer;
|
||||
r->header_end = c->buffer->start;
|
||||
|
||||
if (ngx_list_init(&r->headers_out.headers, r->pool, 0,
|
||||
sizeof(ngx_table_elt_t))
|
||||
!= NGX_OK)
|
||||
{
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (ngx_list_init(&r->headers_in.headers, r->pool, 0,
|
||||
sizeof(ngx_table_elt_t))
|
||||
!= NGX_OK)
|
||||
{
|
||||
goto abort;
|
||||
}
|
||||
#endif
|
||||
|
||||
r->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module);
|
||||
if (r->ctx == NULL) {
|
||||
goto abort;
|
||||
}
|
||||
|
||||
#if 0
|
||||
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
|
||||
|
||||
r->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts
|
||||
* sizeof(ngx_http_variable_value_t));
|
||||
if (r->variables == NULL) {
|
||||
goto abort;
|
||||
}
|
||||
#endif
|
||||
|
||||
ctx = ngx_http_lua_create_ctx(r);
|
||||
if (ctx == NULL) {
|
||||
goto abort;
|
||||
}
|
||||
|
||||
r->headers_in.content_length_n = 0;
|
||||
c->data = r;
|
||||
#if 0
|
||||
hc->request = r;
|
||||
r->http_connection = hc;
|
||||
#endif
|
||||
r->signature = NGX_HTTP_MODULE;
|
||||
r->connection = c;
|
||||
r->main = r;
|
||||
r->count = 1;
|
||||
|
||||
r->method = NGX_HTTP_UNKNOWN;
|
||||
|
||||
r->headers_in.keep_alive_n = -1;
|
||||
r->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1;
|
||||
r->subrequests = NGX_HTTP_MAX_SUBREQUESTS + 1;
|
||||
|
||||
r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE;
|
||||
r->discard_body = 1;
|
||||
|
||||
r->main_conf = timer.main_conf;
|
||||
r->srv_conf = timer.srv_conf;
|
||||
r->loc_conf = timer.loc_conf;
|
||||
|
||||
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
|
||||
c->log->file = clcf->error_log->file;
|
||||
if (!(c->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
|
||||
c->log->log_level = clcf->error_log->log_level;
|
||||
}
|
||||
|
||||
c->error = 1;
|
||||
|
||||
ctx->cur_co_ctx = &ctx->entry_co_ctx;
|
||||
|
||||
L = lmcf->lua;
|
||||
|
||||
cln = ngx_http_cleanup_add(r, 0);
|
||||
if (cln == NULL) {
|
||||
goto abort;
|
||||
}
|
||||
|
||||
cln->handler = ngx_http_lua_request_cleanup;
|
||||
cln->data = r;
|
||||
ctx->cleanup = &cln->handler;
|
||||
|
||||
ctx->entered_content_phase = 1;
|
||||
ctx->context = NGX_HTTP_LUA_CONTEXT_TIMER;
|
||||
|
||||
r->read_event_handler = ngx_http_block_reading;
|
||||
|
||||
ctx->cur_co_ctx->co_ref = timer.co_ref;
|
||||
ctx->cur_co_ctx->co = timer.co;
|
||||
ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_RUNNING;
|
||||
|
||||
dd("r connection: %p, log %p", r->connection, r->connection->log);
|
||||
|
||||
/* save the request in coroutine globals table */
|
||||
lua_pushvalue(timer.co, LUA_GLOBALSINDEX);
|
||||
lua_pushlightuserdata(timer.co, &ngx_http_lua_request_key);
|
||||
lua_pushlightuserdata(timer.co, r);
|
||||
lua_rawset(timer.co, -3);
|
||||
lua_pop(timer.co, 1);
|
||||
/* }}} */
|
||||
|
||||
lmcf->running_timers++;
|
||||
|
||||
rc = ngx_http_lua_run_thread(L, r, ctx, 0);
|
||||
|
||||
dd("timer lua run thread: %d", (int) rc);
|
||||
|
||||
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;
|
||||
|
||||
abort:
|
||||
if (timer.co_ref && timer.co) {
|
||||
lua_pushlightuserdata(timer.co, &ngx_http_lua_coroutines_key);
|
||||
lua_rawget(timer.co, LUA_REGISTRYINDEX);
|
||||
luaL_unref(timer.co, -1, timer.co_ref);
|
||||
lua_settop(timer.co, 0);
|
||||
}
|
||||
|
||||
if (r && r->pool) {
|
||||
ngx_destroy_pool(r->pool);
|
||||
}
|
||||
|
||||
if (c) {
|
||||
ngx_http_lua_close_fake_connection(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static u_char *
|
||||
ngx_http_lua_log_timer_error(ngx_log_t *log, u_char *buf, size_t len)
|
||||
{
|
||||
u_char *p;
|
||||
|
||||
if (log->action) {
|
||||
p = ngx_snprintf(buf, len, " while %s", log->action);
|
||||
len -= p - buf;
|
||||
buf = p;
|
||||
}
|
||||
|
||||
return ngx_snprintf(buf, len, ", context: ngx.timer");
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_TIMER_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_TIMER_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
void ngx_http_lua_inject_timer_api(lua_State *L);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_TIMER_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -47,6 +47,8 @@ ngx_http_lua_ngx_req_set_uri(lua_State *L)
|
|||
r = lua_touserdata(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
ngx_http_lua_check_fake_request(L, r);
|
||||
|
||||
if (n == 2) {
|
||||
|
||||
luaL_checktype(L, 2, LUA_TBOOLEAN);
|
||||
|
|
|
@ -127,7 +127,8 @@ ngx_http_lua_uthread_wait(lua_State *L)
|
|||
|
||||
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_CONTENT
|
||||
| NGX_HTTP_LUA_CONTEXT_TIMER);
|
||||
|
||||
coctx = ctx->cur_co_ctx;
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "ngx_http_lua_probe.h"
|
||||
#include "ngx_http_lua_uthread.h"
|
||||
#include "ngx_http_lua_contentby.h"
|
||||
#include "ngx_http_lua_timer.h"
|
||||
|
||||
|
||||
#if 1
|
||||
|
@ -93,6 +94,8 @@ static ngx_int_t ngx_http_lua_post_zombie_thread(ngx_http_request_t *r,
|
|||
static void ngx_http_lua_cleanup_zombie_child_uthreads(ngx_http_request_t *r,
|
||||
lua_State *L, ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t *coctx);
|
||||
static ngx_int_t ngx_http_lua_on_abort_resume(ngx_http_request_t *r);
|
||||
static void ngx_http_lua_close_fake_request(ngx_http_request_t *r);
|
||||
static void ngx_http_lua_free_fake_request(ngx_http_request_t *r);
|
||||
|
||||
|
||||
#ifndef LUA_PATH_SEP
|
||||
|
@ -744,7 +747,7 @@ ngx_http_lua_inject_ngx_api(ngx_conf_t *cf, lua_State *L)
|
|||
|
||||
lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module);
|
||||
|
||||
lua_createtable(L, 0 /* narr */, 85 /* nrec */); /* ngx.* */
|
||||
lua_createtable(L, 0 /* narr */, 86 /* nrec */); /* ngx.* */
|
||||
|
||||
ngx_http_lua_inject_arg_api(L);
|
||||
|
||||
|
@ -771,6 +774,7 @@ ngx_http_lua_inject_ngx_api(ngx_conf_t *cf, lua_State *L)
|
|||
ngx_http_lua_inject_socket_tcp_api(cf->log, L);
|
||||
ngx_http_lua_inject_socket_udp_api(cf->log, L);
|
||||
ngx_http_lua_inject_uthread_api(cf->log, L);
|
||||
ngx_http_lua_inject_timer_api(L);
|
||||
|
||||
ngx_http_lua_inject_misc_api(L);
|
||||
|
||||
|
@ -931,6 +935,13 @@ ngx_http_lua_request_cleanup(void *data)
|
|||
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
|
||||
#if 1
|
||||
if (r->connection->fd == -1) {
|
||||
/* being a fake request */
|
||||
lmcf->running_timers--;
|
||||
}
|
||||
#endif
|
||||
|
||||
L = lmcf->lua;
|
||||
|
||||
/* we cannot release the ngx.ctx table if we have log_by_lua* hooks
|
||||
|
@ -1447,7 +1458,7 @@ no_parent:
|
|||
return ctx->headers_sent ? NGX_ERROR : NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
|
||||
done:
|
||||
if (ctx->entered_content_phase) {
|
||||
if (ctx->entered_content_phase && r->connection->fd != -1) {
|
||||
rc = ngx_http_lua_send_chain_link(r, ctx,
|
||||
NULL /* last_buf */);
|
||||
|
||||
|
@ -1494,7 +1505,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r)
|
|||
c->timedout = 1;
|
||||
|
||||
if (ctx->entered_content_phase) {
|
||||
ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
|
||||
ngx_http_lua_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
|
||||
}
|
||||
|
||||
return NGX_HTTP_REQUEST_TIME_OUT;
|
||||
|
@ -1508,7 +1519,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r)
|
|||
|
||||
if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) {
|
||||
if (ctx->entered_content_phase) {
|
||||
ngx_http_finalize_request(r, NGX_ERROR);
|
||||
ngx_http_lua_finalize_request(r, NGX_ERROR);
|
||||
}
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
@ -1528,7 +1539,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r)
|
|||
|
||||
if (rc == NGX_ERROR || rc > NGX_OK) {
|
||||
if (ctx->entered_content_phase) {
|
||||
ngx_http_finalize_request(r, rc);
|
||||
ngx_http_lua_finalize_request(r, rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
@ -1559,7 +1570,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r)
|
|||
|
||||
if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) {
|
||||
if (ctx->entered_content_phase) {
|
||||
ngx_http_finalize_request(r, NGX_ERROR);
|
||||
ngx_http_lua_finalize_request(r, NGX_ERROR);
|
||||
}
|
||||
|
||||
return NGX_ERROR;
|
||||
|
@ -2890,14 +2901,14 @@ ngx_http_lua_run_posted_threads(ngx_connection_t *c, lua_State *L,
|
|||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
ngx_http_finalize_request(r, NGX_DONE);
|
||||
ngx_http_lua_finalize_request(r, NGX_DONE);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* rc == NGX_ERROR || rc >= NGX_OK */
|
||||
|
||||
if (ctx->entered_content_phase) {
|
||||
ngx_http_finalize_request(r, rc);
|
||||
ngx_http_lua_finalize_request(r, rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
@ -3150,7 +3161,7 @@ ngx_http_lua_rd_check_broken_connection(ngx_http_request_t *r)
|
|||
if (ctx->on_abort_co_ctx == NULL) {
|
||||
r->connection->error = 1;
|
||||
ngx_http_lua_request_cleanup(r);
|
||||
ngx_http_finalize_request(r, rc);
|
||||
ngx_http_lua_finalize_request(r, rc);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3163,7 +3174,8 @@ ngx_http_lua_rd_check_broken_connection(ngx_http_request_t *r)
|
|||
if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && rev->active) {
|
||||
if (ngx_del_event(rev, NGX_READ_EVENT, 0) != NGX_OK) {
|
||||
ngx_http_lua_request_cleanup(r);
|
||||
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
ngx_http_lua_finalize_request(r,
|
||||
NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -3226,12 +3238,12 @@ ngx_http_lua_on_abort_resume(ngx_http_request_t *r)
|
|||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
ngx_http_finalize_request(r, NGX_DONE);
|
||||
ngx_http_lua_finalize_request(r, NGX_DONE);
|
||||
return ngx_http_lua_run_posted_threads(c,lmcf->lua, r, ctx);
|
||||
}
|
||||
|
||||
if (ctx->entered_content_phase) {
|
||||
ngx_http_finalize_request(r, rc);
|
||||
ngx_http_lua_finalize_request(r, rc);
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
|
@ -3280,4 +3292,159 @@ ngx_http_lua_test_expect(ngx_http_request_t *r)
|
|||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
|
||||
{
|
||||
if (r->connection->fd != -1) {
|
||||
ngx_http_finalize_request(r, rc);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_http_lua_finalize_fake_request(r, rc);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_finalize_fake_request(ngx_http_request_t *r, ngx_int_t rc)
|
||||
{
|
||||
ngx_connection_t *c;
|
||||
|
||||
c = r->connection;
|
||||
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
||||
"http lua finalize fake request: %d, a:%d, c:%d",
|
||||
rc, r == c->data, r->main->count);
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
ngx_http_lua_close_fake_request(r);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
ngx_http_lua_close_fake_request(r);
|
||||
return;
|
||||
}
|
||||
|
||||
if (c->read->timer_set) {
|
||||
ngx_del_timer(c->read);
|
||||
}
|
||||
|
||||
if (c->write->timer_set) {
|
||||
c->write->delayed = 0;
|
||||
ngx_del_timer(c->write);
|
||||
}
|
||||
|
||||
ngx_http_lua_close_fake_request(r);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_lua_close_fake_request(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_connection_t *c;
|
||||
|
||||
r = r->main;
|
||||
c = r->connection;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
||||
"http lua fake request count:%d", r->count);
|
||||
|
||||
if (r->count == 0) {
|
||||
ngx_log_error(NGX_LOG_ALERT, c->log, 0, "http lua fake request "
|
||||
"count is zero");
|
||||
}
|
||||
|
||||
r->count--;
|
||||
|
||||
if (r->count) {
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_http_lua_free_fake_request(r);
|
||||
ngx_http_lua_close_fake_connection(c);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_lua_free_fake_request(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_log_t *log;
|
||||
ngx_http_cleanup_t *cln;
|
||||
ngx_http_log_ctx_t *ctx;
|
||||
|
||||
log = r->connection->log;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http lua close fake "
|
||||
"request");
|
||||
|
||||
if (r->pool == NULL) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, 0, "http lua fake request "
|
||||
"already closed");
|
||||
return;
|
||||
}
|
||||
|
||||
for (cln = r->cleanup; cln; cln = cln->next) {
|
||||
if (cln->handler) {
|
||||
cln->handler(cln->data);
|
||||
}
|
||||
}
|
||||
|
||||
/* the various request strings were allocated from r->pool */
|
||||
ctx = log->data;
|
||||
ctx->request = NULL;
|
||||
|
||||
r->request_line.len = 0;
|
||||
|
||||
r->connection->destroyed = 1;
|
||||
|
||||
ngx_destroy_pool(r->pool);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_close_fake_connection(ngx_connection_t *c)
|
||||
{
|
||||
ngx_pool_t *pool;
|
||||
ngx_connection_t *saved_c = NULL;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
||||
"http lua close fake http connection");
|
||||
|
||||
c->destroyed = 1;
|
||||
|
||||
pool = c->pool;
|
||||
|
||||
if (c->read->timer_set) {
|
||||
ngx_del_timer(c->read);
|
||||
}
|
||||
|
||||
if (c->write->timer_set) {
|
||||
ngx_del_timer(c->write);
|
||||
}
|
||||
|
||||
c->read->closed = 1;
|
||||
c->write->closed = 1;
|
||||
|
||||
/* we temporarily use a valid fd (0) to make ngx_free_connection happy */
|
||||
|
||||
c->fd = 0;
|
||||
|
||||
if (ngx_cycle->files) {
|
||||
saved_c = ngx_cycle->files[0];
|
||||
}
|
||||
|
||||
ngx_free_connection(c);
|
||||
|
||||
c->fd = -1;
|
||||
|
||||
if (ngx_cycle->files) {
|
||||
ngx_cycle->files[0] = saved_c;
|
||||
}
|
||||
|
||||
if (pool) {
|
||||
ngx_destroy_pool(pool);
|
||||
}
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
||||
|
|
|
@ -61,6 +61,7 @@ extern char ngx_http_lua_req_get_headers_metatable_key;
|
|||
: (c) == NGX_HTTP_LUA_CONTEXT_CONTENT ? "content_by_lua*" \
|
||||
: (c) == NGX_HTTP_LUA_CONTEXT_LOG ? "log_by_lua*" \
|
||||
: (c) == NGX_HTTP_LUA_CONTEXT_HEADER_FILTER ? "header_filter_by_lua*" \
|
||||
: (c) == NGX_HTTP_LUA_CONTEXT_TIMER ? "ngx.timer" \
|
||||
: "(unknown)")
|
||||
|
||||
|
||||
|
@ -71,6 +72,19 @@ extern char ngx_http_lua_req_get_headers_metatable_key;
|
|||
}
|
||||
|
||||
|
||||
#define ngx_http_lua_check_fake_request(L, r) \
|
||||
if ((r)->connection->fd == -1) { \
|
||||
return luaL_error(L, "API disabled in the current context"); \
|
||||
}
|
||||
|
||||
|
||||
#define ngx_http_lua_check_fake_request2(L, r, ctx) \
|
||||
if ((r)->connection->fd == -1) { \
|
||||
return luaL_error(L, "API disabled in the context of %s", \
|
||||
ngx_http_lua_context_name((ctx)->context)); \
|
||||
}
|
||||
|
||||
|
||||
lua_State * ngx_http_lua_new_state(ngx_conf_t *cf,
|
||||
ngx_http_lua_main_conf_t *lmcf);
|
||||
|
||||
|
@ -150,6 +164,13 @@ ngx_int_t ngx_http_lua_test_expect(ngx_http_request_t *r);
|
|||
ngx_int_t ngx_http_lua_check_broken_connection(ngx_http_request_t *r,
|
||||
ngx_event_t *ev);
|
||||
|
||||
void ngx_http_lua_finalize_request(ngx_http_request_t *r, ngx_int_t rc);
|
||||
|
||||
void ngx_http_lua_finalize_fake_request(ngx_http_request_t *r,
|
||||
ngx_int_t rc);
|
||||
|
||||
void ngx_http_lua_close_fake_connection(ngx_connection_t *c);
|
||||
|
||||
|
||||
#define ngx_http_lua_check_if_abortable(L, ctx) \
|
||||
if ((ctx)->no_abort) { \
|
||||
|
|
|
@ -69,6 +69,8 @@ ngx_http_lua_var_get(lua_State *L)
|
|||
return luaL_error(L, "no request object found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request(L, r);
|
||||
|
||||
#if (NGX_PCRE)
|
||||
if (lua_type(L, -1) == LUA_TNUMBER) {
|
||||
/* it is a regex capturing variable */
|
||||
|
@ -157,6 +159,8 @@ ngx_http_lua_var_set(lua_State *L)
|
|||
return luaL_error(L, "no request object found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request(L, r);
|
||||
|
||||
/* we skip the first argument that is the table */
|
||||
|
||||
/* we read the variable name */
|
||||
|
|
|
@ -35,7 +35,7 @@ __DATA__
|
|||
--- request
|
||||
GET /test
|
||||
--- response_body
|
||||
ngx: 85
|
||||
ngx: 86
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
@ -56,7 +56,7 @@ ngx: 85
|
|||
--- request
|
||||
GET /test
|
||||
--- response_body
|
||||
85
|
||||
86
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
@ -84,7 +84,7 @@ GET /test
|
|||
--- request
|
||||
GET /test
|
||||
--- response_body
|
||||
n = 85
|
||||
n = 86
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
@ -301,5 +301,25 @@ GET /t
|
|||
--- response_body_like: 404 Not Found
|
||||
--- error_code: 404
|
||||
--- error_log
|
||||
ngx. entry count: 85
|
||||
ngx. entry count: 86
|
||||
|
||||
|
||||
|
||||
=== TEST 14: entries under ngx.timer
|
||||
--- config
|
||||
location = /test {
|
||||
content_by_lua '
|
||||
local n = 0
|
||||
for k, v in pairs(ngx.timer) do
|
||||
n = n + 1
|
||||
end
|
||||
ngx.say("n = ", n)
|
||||
';
|
||||
}
|
||||
--- request
|
||||
GET /test
|
||||
--- response_body
|
||||
n = 1
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -260,10 +260,12 @@ F(ngx_http_lua_del_all_threads) {
|
|||
println("del all threads")
|
||||
}
|
||||
|
||||
/*
|
||||
M(http-lua-info) {
|
||||
msg = user_string($arg1)
|
||||
printf("lua info: %s\n", msg)
|
||||
}
|
||||
*/
|
||||
|
||||
M(http-lua-user-thread-wait) {
|
||||
p = gen_id($arg1)
|
||||
|
|
Загрузка…
Ссылка в новой задаче