Line data Source code
1 :
2 : /*
3 : * Copyright (C) Xiaozhe Wang (chaoslawful)
4 : * Copyright (C) Yichun Zhang (agentzh)
5 : */
6 :
7 :
8 : #ifndef DDEBUG
9 : #define DDEBUG 0
10 : #endif
11 : #include "ddebug.h"
12 :
13 :
14 : #include "ngx_http_lua_util.h"
15 : #include "ngx_http_lua_sleep.h"
16 : #include "ngx_http_lua_contentby.h"
17 :
18 :
19 : static int ngx_http_lua_ngx_sleep(lua_State *L);
20 : static void ngx_http_lua_sleep_handler(ngx_event_t *ev);
21 : static void ngx_http_lua_sleep_cleanup(void *data);
22 : static ngx_int_t ngx_http_lua_sleep_resume(ngx_http_request_t *r);
23 :
24 :
25 : static int
26 0 : ngx_http_lua_ngx_sleep(lua_State *L)
27 : {
28 : int n;
29 : ngx_int_t delay; /* in msec */
30 : ngx_http_request_t *r;
31 : ngx_http_lua_ctx_t *ctx;
32 : ngx_http_lua_co_ctx_t *coctx;
33 :
34 0 : n = lua_gettop(L);
35 0 : if (n != 1) {
36 0 : return luaL_error(L, "attempt to pass %d arguments, but accepted 1", n);
37 : }
38 :
39 0 : r = ngx_http_lua_get_req(L);
40 0 : if (r == NULL) {
41 0 : return luaL_error(L, "no request found");
42 : }
43 :
44 0 : delay = (ngx_int_t) (luaL_checknumber(L, 1) * 1000);
45 :
46 0 : if (delay < 0) {
47 0 : return luaL_error(L, "invalid sleep duration \"%d\"", delay);
48 : }
49 :
50 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
51 0 : if (ctx == NULL) {
52 0 : return luaL_error(L, "no request ctx found");
53 : }
54 :
55 0 : ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE
56 : | NGX_HTTP_LUA_CONTEXT_ACCESS
57 : | NGX_HTTP_LUA_CONTEXT_CONTENT
58 : | NGX_HTTP_LUA_CONTEXT_TIMER
59 : | NGX_HTTP_LUA_CONTEXT_SSL_CERT
60 : | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH);
61 :
62 0 : coctx = ctx->cur_co_ctx;
63 0 : if (coctx == NULL) {
64 0 : return luaL_error(L, "no co ctx found");
65 : }
66 :
67 0 : ngx_http_lua_cleanup_pending_operation(coctx);
68 0 : coctx->cleanup = ngx_http_lua_sleep_cleanup;
69 0 : coctx->data = r;
70 :
71 0 : coctx->sleep.handler = ngx_http_lua_sleep_handler;
72 0 : coctx->sleep.data = coctx;
73 0 : coctx->sleep.log = r->connection->log;
74 :
75 0 : if (delay == 0) {
76 : #ifdef HAVE_POSTED_DELAYED_EVENTS_PATCH
77 : dd("posting 0 sec sleep event to head of delayed queue");
78 :
79 0 : coctx->sleep.delayed = 1;
80 0 : ngx_post_event(&coctx->sleep, &ngx_posted_delayed_events);
81 : #else
82 : ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "ngx.sleep(0)"
83 : " called without delayed events patch, this will"
84 : " hurt performance");
85 : ngx_add_timer(&coctx->sleep, (ngx_msec_t) delay);
86 : #endif
87 :
88 : } else {
89 : dd("adding timer with delay %lu ms, r:%.*s", (unsigned long) delay,
90 : (int) r->uri.len, r->uri.data);
91 :
92 0 : ngx_add_timer(&coctx->sleep, (ngx_msec_t) delay);
93 : }
94 :
95 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
96 : "lua ready to sleep for %d ms", delay);
97 :
98 0 : return lua_yield(L, 0);
99 : }
100 :
101 :
102 : void
103 0 : ngx_http_lua_sleep_handler(ngx_event_t *ev)
104 : {
105 : ngx_connection_t *c;
106 : ngx_http_request_t *r;
107 : ngx_http_lua_ctx_t *ctx;
108 : ngx_http_log_ctx_t *log_ctx;
109 : ngx_http_lua_co_ctx_t *coctx;
110 :
111 0 : coctx = ev->data;
112 :
113 0 : r = coctx->data;
114 0 : c = r->connection;
115 :
116 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
117 :
118 0 : if (ctx == NULL) {
119 0 : return;
120 : }
121 :
122 0 : if (c->fd != (ngx_socket_t) -1) { /* not a fake connection */
123 0 : log_ctx = c->log->data;
124 0 : log_ctx->current_request = r;
125 : }
126 :
127 0 : coctx->cleanup = NULL;
128 :
129 0 : ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
130 : "lua sleep timer expired: \"%V?%V\"", &r->uri, &r->args);
131 :
132 0 : ctx->cur_co_ctx = coctx;
133 :
134 0 : if (ctx->entered_content_phase) {
135 0 : (void) ngx_http_lua_sleep_resume(r);
136 :
137 : } else {
138 0 : ctx->resume_handler = ngx_http_lua_sleep_resume;
139 0 : ngx_http_core_run_phases(r);
140 : }
141 :
142 0 : ngx_http_run_posted_requests(c);
143 : }
144 :
145 :
146 : void
147 18 : ngx_http_lua_inject_sleep_api(lua_State *L)
148 : {
149 18 : lua_pushcfunction(L, ngx_http_lua_ngx_sleep);
150 18 : lua_setfield(L, -2, "sleep");
151 18 : }
152 :
153 :
154 : static void
155 0 : ngx_http_lua_sleep_cleanup(void *data)
156 : {
157 0 : ngx_http_lua_co_ctx_t *coctx = data;
158 :
159 0 : if (coctx->sleep.timer_set) {
160 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
161 : "lua clean up the timer for pending ngx.sleep");
162 :
163 0 : ngx_del_timer(&coctx->sleep);
164 : }
165 :
166 : #ifdef HAVE_POSTED_DELAYED_EVENTS_PATCH
167 0 : if (coctx->sleep.posted) {
168 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
169 : "lua clean up the posted event for pending ngx.sleep");
170 :
171 0 : ngx_delete_posted_event(&coctx->sleep);
172 : }
173 : #endif
174 0 : }
175 :
176 :
177 : static ngx_int_t
178 0 : ngx_http_lua_sleep_resume(ngx_http_request_t *r)
179 : {
180 : lua_State *vm;
181 : ngx_connection_t *c;
182 : ngx_int_t rc;
183 : ngx_uint_t nreqs;
184 : ngx_http_lua_ctx_t *ctx;
185 :
186 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
187 0 : if (ctx == NULL) {
188 0 : return NGX_ERROR;
189 : }
190 :
191 0 : ctx->resume_handler = ngx_http_lua_wev_handler;
192 :
193 0 : c = r->connection;
194 0 : vm = ngx_http_lua_get_lua_vm(r, ctx);
195 0 : nreqs = c->requests;
196 :
197 0 : rc = ngx_http_lua_run_thread(vm, r, ctx, 0);
198 :
199 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
200 : "lua run thread returned %d", rc);
201 :
202 0 : if (rc == NGX_AGAIN) {
203 0 : return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs);
204 : }
205 :
206 0 : if (rc == NGX_DONE) {
207 0 : ngx_http_lua_finalize_request(r, NGX_DONE);
208 0 : return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs);
209 : }
210 :
211 0 : if (ctx->entered_content_phase) {
212 0 : ngx_http_lua_finalize_request(r, rc);
213 0 : return NGX_DONE;
214 : }
215 :
216 0 : return rc;
217 : }
218 :
219 : /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|