blob: 0acd89d86ea784f4df30bc665c23e735491ed406 [file] [log] [blame] [raw]
/*
* Copyright (C) Xiaozhe Wang (chaoslawful)
* Copyright (C) Yichun Zhang (agentzh)
*/
#ifndef DDEBUG
#define DDEBUG 0
#endif
#include "ddebug.h"
#include "ngx_http_lua_util.h"
#include "ngx_http_lua_sleep.h"
#include "ngx_http_lua_contentby.h"
static int ngx_http_lua_ngx_sleep(lua_State *L);
static void ngx_http_lua_sleep_handler(ngx_event_t *ev);
static void ngx_http_lua_sleep_cleanup(void *data);
static ngx_int_t ngx_http_lua_sleep_resume(ngx_http_request_t *r);
static int
ngx_http_lua_ngx_sleep(lua_State *L)
{
int n;
ngx_int_t delay; /* in msec */
ngx_http_request_t *r;
ngx_http_lua_ctx_t *ctx;
ngx_http_lua_co_ctx_t *coctx;
n = lua_gettop(L);
if (n != 1) {
return luaL_error(L, "attempt to pass %d arguments, but accepted 1", n);
}
r = ngx_http_lua_get_req(L);
if (r == NULL) {
return luaL_error(L, "no request found");
}
delay = (ngx_int_t) (luaL_checknumber(L, 1) * 1000);
if (delay < 0) {
return luaL_error(L, "invalid sleep duration \"%d\"", delay);
}
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;
if (coctx == NULL) {
return luaL_error(L, "no co ctx found");
}
coctx->data = r;
coctx->sleep.handler = ngx_http_lua_sleep_handler;
coctx->sleep.data = coctx;
coctx->sleep.log = r->connection->log;
dd("adding timer with delay %lu ms, r:%.*s", (unsigned long) delay,
(int) r->uri.len, r->uri.data);
ngx_add_timer(&coctx->sleep, (ngx_msec_t) delay);
coctx->cleanup = ngx_http_lua_sleep_cleanup;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"lua ready to sleep for %d ms", delay);
return lua_yield(L, 0);
}
void
ngx_http_lua_sleep_handler(ngx_event_t *ev)
{
ngx_connection_t *c;
ngx_http_request_t *r;
ngx_http_lua_ctx_t *ctx;
ngx_http_log_ctx_t *log_ctx;
ngx_http_lua_co_ctx_t *coctx;
coctx = ev->data;
r = coctx->data;
c = r->connection;
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
if (ctx == NULL) {
return;
}
log_ctx = c->log->data;
log_ctx->current_request = r;
coctx->cleanup = NULL;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
"lua sleep timer expired: \"%V?%V\"", &r->uri, &r->args);
ctx->cur_co_ctx = coctx;
if (ctx->entered_content_phase) {
(void) ngx_http_lua_sleep_resume(r);
} else {
ctx->resume_handler = ngx_http_lua_sleep_resume;
ngx_http_core_run_phases(r);
}
ngx_http_run_posted_requests(c);
}
void
ngx_http_lua_inject_sleep_api(lua_State *L)
{
lua_pushcfunction(L, ngx_http_lua_ngx_sleep);
lua_setfield(L, -2, "sleep");
}
static void
ngx_http_lua_sleep_cleanup(void *data)
{
ngx_http_lua_co_ctx_t *coctx = data;
if (coctx->sleep.timer_set) {
dd("cleanup: deleting timer for ngx.sleep");
ngx_del_timer(&coctx->sleep);
}
}
static ngx_int_t
ngx_http_lua_sleep_resume(ngx_http_request_t *r)
{
lua_State *vm;
ngx_connection_t *c;
ngx_int_t rc;
ngx_http_lua_ctx_t *ctx;
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
if (ctx == NULL) {
return NGX_ERROR;
}
ctx->resume_handler = ngx_http_lua_wev_handler;
c = r->connection;
vm = ngx_http_lua_get_lua_vm(r, ctx);
rc = ngx_http_lua_run_thread(vm, r, ctx, 0);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"lua run thread returned %d", rc);
if (rc == NGX_AGAIN) {
return ngx_http_lua_run_posted_threads(c, vm, r, ctx);
}
if (rc == NGX_DONE) {
ngx_http_lua_finalize_request(r, NGX_DONE);
return ngx_http_lua_run_posted_threads(c, vm, r, ctx);
}
if (ctx->entered_content_phase) {
ngx_http_lua_finalize_request(r, rc);
return NGX_DONE;
}
return rc;
}
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */