Line data Source code
1 :
2 : /*
3 : * Copyright (C) Yichun Zhang (agentzh)
4 : */
5 :
6 :
7 : #ifndef DDEBUG
8 : #define DDEBUG 0
9 : #endif
10 : #include "ddebug.h"
11 :
12 :
13 : #include "ngx_http_lua_timer.h"
14 : #include "ngx_http_lua_util.h"
15 : #include "ngx_http_lua_contentby.h"
16 : #include "ngx_http_lua_probe.h"
17 :
18 :
19 : typedef struct {
20 : void **main_conf;
21 : void **srv_conf;
22 : void **loc_conf;
23 :
24 : lua_State *co;
25 :
26 : ngx_pool_t *pool;
27 :
28 : ngx_listening_t *listening;
29 : ngx_str_t client_addr_text;
30 :
31 : ngx_http_lua_main_conf_t *lmcf;
32 : ngx_http_lua_vm_state_t *vm_state;
33 :
34 : int co_ref;
35 : unsigned delay:31;
36 : unsigned premature:1;
37 : } ngx_http_lua_timer_ctx_t;
38 :
39 :
40 : static int ngx_http_lua_ngx_timer_at(lua_State *L);
41 : static int ngx_http_lua_ngx_timer_every(lua_State *L);
42 : static int ngx_http_lua_ngx_timer_helper(lua_State *L, int every);
43 : static int ngx_http_lua_ngx_timer_running_count(lua_State *L);
44 : static int ngx_http_lua_ngx_timer_pending_count(lua_State *L);
45 : static ngx_int_t ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx);
46 : static void ngx_http_lua_timer_handler(ngx_event_t *ev);
47 : static u_char *ngx_http_lua_log_timer_error(ngx_log_t *log, u_char *buf,
48 : size_t len);
49 : static void ngx_http_lua_abort_pending_timers(ngx_event_t *ev);
50 :
51 :
52 : void
53 18 : ngx_http_lua_inject_timer_api(lua_State *L)
54 : {
55 18 : lua_createtable(L, 0 /* narr */, 4 /* nrec */); /* ngx.timer. */
56 :
57 18 : lua_pushcfunction(L, ngx_http_lua_ngx_timer_at);
58 18 : lua_setfield(L, -2, "at");
59 :
60 18 : lua_pushcfunction(L, ngx_http_lua_ngx_timer_every);
61 18 : lua_setfield(L, -2, "every");
62 :
63 18 : lua_pushcfunction(L, ngx_http_lua_ngx_timer_running_count);
64 18 : lua_setfield(L, -2, "running_count");
65 :
66 18 : lua_pushcfunction(L, ngx_http_lua_ngx_timer_pending_count);
67 18 : lua_setfield(L, -2, "pending_count");
68 :
69 18 : lua_setfield(L, -2, "timer");
70 18 : }
71 :
72 :
73 : static int
74 0 : ngx_http_lua_ngx_timer_running_count(lua_State *L)
75 : {
76 : ngx_http_request_t *r;
77 : ngx_http_lua_main_conf_t *lmcf;
78 :
79 0 : r = ngx_http_lua_get_req(L);
80 0 : if (r == NULL) {
81 0 : return luaL_error(L, "no request");
82 : }
83 :
84 0 : lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
85 :
86 0 : lua_pushnumber(L, lmcf->running_timers);
87 :
88 0 : return 1;
89 : }
90 :
91 :
92 : static int
93 0 : ngx_http_lua_ngx_timer_pending_count(lua_State *L)
94 : {
95 : ngx_http_request_t *r;
96 : ngx_http_lua_main_conf_t *lmcf;
97 :
98 0 : r = ngx_http_lua_get_req(L);
99 0 : if (r == NULL) {
100 0 : return luaL_error(L, "no request");
101 : }
102 :
103 0 : lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
104 :
105 0 : lua_pushnumber(L, lmcf->pending_timers);
106 :
107 0 : return 1;
108 : }
109 :
110 :
111 : static int
112 0 : ngx_http_lua_ngx_timer_at(lua_State *L)
113 : {
114 0 : return ngx_http_lua_ngx_timer_helper(L, 0);
115 : }
116 :
117 :
118 : /*
119 : * TODO: return a timer handler instead which can be passed to
120 : * the ngx.timer.cancel method to cancel the timer.
121 : */
122 : static int
123 0 : ngx_http_lua_ngx_timer_every(lua_State *L)
124 : {
125 0 : return ngx_http_lua_ngx_timer_helper(L, 1);
126 : }
127 :
128 :
129 : static int
130 0 : ngx_http_lua_ngx_timer_helper(lua_State *L, int every)
131 : {
132 : int nargs, co_ref;
133 : u_char *p;
134 : lua_State *vm; /* the main thread */
135 : lua_State *co;
136 : ngx_msec_t delay;
137 0 : ngx_event_t *ev = NULL;
138 : ngx_http_request_t *r;
139 0 : ngx_connection_t *saved_c = NULL;
140 : ngx_http_lua_ctx_t *ctx;
141 : #if 0
142 : ngx_http_connection_t *hc;
143 : #endif
144 :
145 0 : ngx_http_lua_timer_ctx_t *tctx = NULL;
146 : ngx_http_lua_main_conf_t *lmcf;
147 : #if 0
148 : ngx_http_core_main_conf_t *cmcf;
149 : #endif
150 :
151 0 : nargs = lua_gettop(L);
152 0 : if (nargs < 2) {
153 0 : return luaL_error(L, "expecting at least 2 arguments but got %d",
154 : nargs);
155 : }
156 :
157 0 : delay = (ngx_msec_t) (luaL_checknumber(L, 1) * 1000);
158 :
159 0 : if (every && delay == 0) {
160 0 : return luaL_error(L, "delay cannot be zero");
161 : }
162 :
163 0 : luaL_argcheck(L, lua_isfunction(L, 2) && !lua_iscfunction(L, 2), 2,
164 : "Lua function expected");
165 :
166 0 : r = ngx_http_lua_get_req(L);
167 0 : if (r == NULL) {
168 0 : return luaL_error(L, "no request");
169 : }
170 :
171 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
172 :
173 0 : if (ngx_exiting && delay > 0) {
174 0 : lua_pushnil(L);
175 0 : lua_pushliteral(L, "process exiting");
176 0 : return 2;
177 : }
178 :
179 0 : lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
180 :
181 0 : if (lmcf->pending_timers >= lmcf->max_pending_timers) {
182 0 : lua_pushnil(L);
183 0 : lua_pushliteral(L, "too many pending timers");
184 0 : return 2;
185 : }
186 :
187 0 : if (lmcf->watcher == NULL) {
188 : /* create the watcher fake connection */
189 :
190 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
191 : "lua creating fake watcher connection");
192 :
193 0 : if (ngx_cycle->files) {
194 0 : saved_c = ngx_cycle->files[0];
195 : }
196 :
197 0 : lmcf->watcher = ngx_get_connection(0, ngx_cycle->log);
198 :
199 0 : if (ngx_cycle->files) {
200 0 : ngx_cycle->files[0] = saved_c;
201 : }
202 :
203 0 : if (lmcf->watcher == NULL) {
204 0 : return luaL_error(L, "no memory");
205 : }
206 :
207 : /* to work around the -1 check in ngx_worker_process_cycle: */
208 0 : lmcf->watcher->fd = (ngx_socket_t) -2;
209 :
210 0 : lmcf->watcher->idle = 1;
211 0 : lmcf->watcher->read->handler = ngx_http_lua_abort_pending_timers;
212 0 : lmcf->watcher->data = lmcf;
213 : }
214 :
215 0 : vm = ngx_http_lua_get_lua_vm(r, ctx);
216 :
217 0 : co = lua_newthread(vm);
218 :
219 : /* L stack: time func [args] */
220 :
221 : ngx_http_lua_probe_user_coroutine_create(r, L, co);
222 :
223 0 : lua_createtable(co, 0, 0); /* the new globals table */
224 :
225 : /* co stack: global_tb */
226 :
227 0 : lua_createtable(co, 0, 1); /* the metatable */
228 0 : ngx_http_lua_get_globals_table(co);
229 0 : lua_setfield(co, -2, "__index");
230 0 : lua_setmetatable(co, -2);
231 :
232 : /* co stack: global_tb */
233 :
234 0 : ngx_http_lua_set_globals_table(co);
235 :
236 : /* co stack: <empty> */
237 :
238 : dd("stack top: %d", lua_gettop(L));
239 :
240 0 : lua_xmove(vm, L, 1); /* move coroutine from main thread to L */
241 :
242 : /* L stack: time func [args] thread */
243 : /* vm stack: empty */
244 :
245 0 : lua_pushvalue(L, 2); /* copy entry function to top of L*/
246 :
247 : /* L stack: time func [args] thread func */
248 :
249 0 : lua_xmove(L, co, 1); /* move entry function from L to co */
250 :
251 : /* L stack: time func [args] thread */
252 : /* co stack: func */
253 :
254 0 : ngx_http_lua_get_globals_table(co);
255 0 : lua_setfenv(co, -2);
256 :
257 : /* co stack: func */
258 :
259 0 : lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key);
260 0 : lua_rawget(L, LUA_REGISTRYINDEX);
261 :
262 : /* L stack: time func [args] thread coroutines */
263 :
264 0 : lua_pushvalue(L, -2);
265 :
266 : /* L stack: time func [args] thread coroutines thread */
267 :
268 0 : co_ref = luaL_ref(L, -2);
269 0 : lua_pop(L, 1);
270 :
271 : /* L stack: time func [args] thread */
272 :
273 0 : if (nargs > 2) {
274 0 : lua_pop(L, 1); /* L stack: time func [args] */
275 0 : lua_xmove(L, co, nargs - 2); /* L stack: time func */
276 :
277 : /* co stack: func [args] */
278 : }
279 :
280 0 : p = ngx_alloc(sizeof(ngx_event_t) + sizeof(ngx_http_lua_timer_ctx_t),
281 0 : r->connection->log);
282 0 : if (p == NULL) {
283 0 : goto nomem;
284 : }
285 :
286 0 : ev = (ngx_event_t *) p;
287 :
288 0 : ngx_memzero(ev, sizeof(ngx_event_t));
289 :
290 0 : p += sizeof(ngx_event_t);
291 :
292 0 : tctx = (ngx_http_lua_timer_ctx_t *) p;
293 :
294 0 : tctx->delay = every ? delay : 0;
295 :
296 0 : tctx->premature = 0;
297 0 : tctx->co_ref = co_ref;
298 0 : tctx->co = co;
299 0 : tctx->main_conf = r->main_conf;
300 0 : tctx->srv_conf = r->srv_conf;
301 0 : tctx->loc_conf = r->loc_conf;
302 0 : tctx->lmcf = lmcf;
303 :
304 0 : tctx->pool = ngx_create_pool(128, ngx_cycle->log);
305 0 : if (tctx->pool == NULL) {
306 0 : goto nomem;
307 : }
308 :
309 0 : if (r->connection) {
310 0 : tctx->listening = r->connection->listening;
311 :
312 : } else {
313 0 : tctx->listening = NULL;
314 : }
315 :
316 0 : if (r->connection->addr_text.len) {
317 0 : tctx->client_addr_text.data = ngx_palloc(tctx->pool,
318 0 : r->connection->addr_text.len);
319 0 : if (tctx->client_addr_text.data == NULL) {
320 0 : goto nomem;
321 : }
322 :
323 0 : ngx_memcpy(tctx->client_addr_text.data, r->connection->addr_text.data,
324 : r->connection->addr_text.len);
325 0 : tctx->client_addr_text.len = r->connection->addr_text.len;
326 :
327 : } else {
328 0 : tctx->client_addr_text.len = 0;
329 0 : tctx->client_addr_text.data = NULL;
330 : }
331 :
332 0 : if (ctx && ctx->vm_state) {
333 0 : tctx->vm_state = ctx->vm_state;
334 0 : tctx->vm_state->count++;
335 :
336 : } else {
337 0 : tctx->vm_state = NULL;
338 : }
339 :
340 0 : ev->handler = ngx_http_lua_timer_handler;
341 0 : ev->data = tctx;
342 0 : ev->log = ngx_cycle->log;
343 :
344 0 : lmcf->pending_timers++;
345 :
346 0 : ngx_add_timer(ev, delay);
347 :
348 0 : lua_pushinteger(L, 1);
349 0 : return 1;
350 :
351 0 : nomem:
352 :
353 0 : if (tctx && tctx->pool) {
354 0 : ngx_destroy_pool(tctx->pool);
355 : }
356 :
357 0 : if (ev) {
358 0 : ngx_free(ev);
359 : }
360 :
361 0 : lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key);
362 0 : lua_rawget(L, LUA_REGISTRYINDEX);
363 0 : luaL_unref(L, -1, co_ref);
364 :
365 0 : return luaL_error(L, "no memory");
366 : }
367 :
368 :
369 : static ngx_int_t
370 0 : ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx)
371 : {
372 : int nargs, co_ref, i;
373 : u_char *p;
374 : lua_State *vm; /* the main thread */
375 : lua_State *co;
376 : lua_State *L;
377 0 : ngx_event_t *ev = NULL;
378 0 : ngx_http_lua_timer_ctx_t *tctx = NULL;
379 : ngx_http_lua_main_conf_t *lmcf;
380 :
381 : /* L stack: func [args] */
382 0 : L = old_tctx->co;
383 :
384 0 : lmcf = old_tctx->lmcf;
385 :
386 0 : vm = old_tctx->vm_state ? old_tctx->vm_state->vm : lmcf->lua;
387 :
388 0 : co = lua_newthread(vm);
389 :
390 0 : lua_createtable(co, 0, 0); /* the new globals table */
391 :
392 : /* co stack: global_tb */
393 :
394 0 : lua_createtable(co, 0, 1); /* the metatable */
395 0 : ngx_http_lua_get_globals_table(co);
396 0 : lua_setfield(co, -2, "__index");
397 0 : lua_setmetatable(co, -2);
398 :
399 : /* co stack: global_tb */
400 :
401 0 : ngx_http_lua_set_globals_table(co);
402 :
403 : /* co stack: <empty> */
404 :
405 : dd("stack top: %d", lua_gettop(L));
406 :
407 0 : lua_xmove(vm, L, 1); /* move coroutine from main thread to L */
408 :
409 : /* L stack: func [args] thread */
410 : /* vm stack: empty */
411 :
412 0 : lua_pushvalue(L, 1); /* copy entry function to top of L*/
413 :
414 : /* L stack: func [args] thread func */
415 :
416 0 : lua_xmove(L, co, 1); /* move entry function from L to co */
417 :
418 : /* L stack: func [args] thread */
419 : /* co stack: func */
420 :
421 0 : ngx_http_lua_get_globals_table(co);
422 0 : lua_setfenv(co, -2);
423 :
424 : /* co stack: func */
425 :
426 0 : lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key);
427 0 : lua_rawget(L, LUA_REGISTRYINDEX);
428 :
429 : /* L stack: func [args] thread coroutines */
430 :
431 0 : lua_pushvalue(L, -2);
432 :
433 : /* L stack: func [args] thread coroutines thread */
434 :
435 0 : co_ref = luaL_ref(L, -2);
436 0 : lua_pop(L, 2);
437 :
438 : /* L stack: func [args] */
439 :
440 0 : nargs = lua_gettop(L);
441 0 : if (nargs > 1) {
442 0 : for (i = 2; i <= nargs; i++) {
443 0 : lua_pushvalue(L, i);
444 : }
445 :
446 : /* L stack: func [args] [args] */
447 :
448 0 : lua_xmove(L, co, nargs - 1);
449 :
450 : /* L stack: func [args] */
451 : /* co stack: func [args] */
452 : }
453 :
454 0 : p = ngx_alloc(sizeof(ngx_event_t) + sizeof(ngx_http_lua_timer_ctx_t),
455 0 : ngx_cycle->log);
456 0 : if (p == NULL) {
457 0 : goto nomem;
458 : }
459 :
460 0 : ev = (ngx_event_t *) p;
461 :
462 0 : ngx_memzero(ev, sizeof(ngx_event_t));
463 :
464 0 : p += sizeof(ngx_event_t);
465 :
466 0 : tctx = (ngx_http_lua_timer_ctx_t *) p;
467 :
468 0 : ngx_memcpy(tctx, old_tctx, sizeof(ngx_http_lua_timer_ctx_t));
469 :
470 0 : tctx->co_ref = co_ref;
471 0 : tctx->co = co;
472 :
473 0 : tctx->pool = ngx_create_pool(128, ngx_cycle->log);
474 0 : if (tctx->pool == NULL) {
475 0 : goto nomem;
476 : }
477 :
478 0 : if (tctx->client_addr_text.len) {
479 0 : tctx->client_addr_text.data = ngx_palloc(tctx->pool,
480 : tctx->client_addr_text.len);
481 0 : if (tctx->client_addr_text.data == NULL) {
482 0 : goto nomem;
483 : }
484 :
485 0 : ngx_memcpy(tctx->client_addr_text.data, old_tctx->client_addr_text.data,
486 : tctx->client_addr_text.len);
487 : }
488 :
489 0 : if (tctx->vm_state) {
490 0 : tctx->vm_state->count++;
491 : }
492 :
493 0 : ev->handler = ngx_http_lua_timer_handler;
494 0 : ev->data = tctx;
495 0 : ev->log = ngx_cycle->log;
496 :
497 0 : lmcf->pending_timers++;
498 :
499 0 : ngx_add_timer(ev, tctx->delay);
500 :
501 0 : return NGX_OK;
502 :
503 0 : nomem:
504 :
505 0 : if (tctx && tctx->pool) {
506 0 : ngx_destroy_pool(tctx->pool);
507 : }
508 :
509 0 : if (ev) {
510 0 : ngx_free(ev);
511 : }
512 :
513 : /* L stack: func [args] */
514 :
515 0 : lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key);
516 0 : lua_rawget(L, LUA_REGISTRYINDEX);
517 0 : luaL_unref(L, -1, co_ref);
518 :
519 : /* L stack: func [args] coroutines */
520 :
521 0 : lua_pop(L, 1);
522 :
523 0 : return NGX_ERROR;
524 : }
525 :
526 :
527 : static void
528 0 : ngx_http_lua_timer_handler(ngx_event_t *ev)
529 : {
530 : int n;
531 : lua_State *L;
532 : ngx_int_t rc;
533 0 : ngx_connection_t *c = NULL;
534 0 : ngx_http_request_t *r = NULL;
535 : ngx_http_lua_ctx_t *ctx;
536 : ngx_http_cleanup_t *cln;
537 : ngx_pool_cleanup_t *pcln;
538 :
539 : ngx_http_lua_timer_ctx_t tctx;
540 : ngx_http_lua_main_conf_t *lmcf;
541 : ngx_http_core_loc_conf_t *clcf;
542 :
543 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
544 : "lua ngx.timer expired");
545 :
546 0 : ngx_memcpy(&tctx, ev->data, sizeof(ngx_http_lua_timer_ctx_t));
547 0 : ngx_free(ev);
548 :
549 0 : lmcf = tctx.lmcf;
550 :
551 0 : lmcf->pending_timers--;
552 :
553 0 : if (!ngx_exiting && tctx.delay > 0) {
554 0 : rc = ngx_http_lua_timer_copy(&tctx);
555 0 : if (rc != NGX_OK) {
556 0 : ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
557 : "failed to create the next timer of delay %ud ms",
558 : (unsigned) tctx.delay);
559 : }
560 : }
561 :
562 0 : if (lmcf->running_timers >= lmcf->max_running_timers) {
563 0 : ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
564 : "%i lua_max_running_timers are not enough",
565 : lmcf->max_running_timers);
566 0 : goto failed;
567 : }
568 :
569 0 : c = ngx_http_lua_create_fake_connection(tctx.pool);
570 0 : if (c == NULL) {
571 0 : goto failed;
572 : }
573 :
574 0 : c->log->handler = ngx_http_lua_log_timer_error;
575 0 : c->log->data = c;
576 :
577 0 : c->listening = tctx.listening;
578 0 : c->addr_text = tctx.client_addr_text;
579 :
580 0 : r = ngx_http_lua_create_fake_request(c);
581 0 : if (r == NULL) {
582 0 : goto failed;
583 : }
584 :
585 0 : r->main_conf = tctx.main_conf;
586 0 : r->srv_conf = tctx.srv_conf;
587 0 : r->loc_conf = tctx.loc_conf;
588 :
589 0 : clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
590 :
591 : #if defined(nginx_version) && nginx_version >= 1003014
592 :
593 : # if nginx_version >= 1009000
594 :
595 0 : ngx_set_connection_log(r->connection, clcf->error_log);
596 :
597 : # else
598 :
599 : ngx_http_set_connection_log(r->connection, clcf->error_log);
600 :
601 : # endif
602 :
603 : #else
604 :
605 : c->log->file = clcf->error_log->file;
606 :
607 : if (!(c->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
608 : c->log->log_level = clcf->error_log->log_level;
609 : }
610 :
611 : #endif
612 :
613 : dd("lmcf: %p", lmcf);
614 :
615 0 : ctx = ngx_http_lua_create_ctx(r);
616 0 : if (ctx == NULL) {
617 0 : goto failed;
618 : }
619 :
620 0 : if (tctx.vm_state) {
621 0 : ctx->vm_state = tctx.vm_state;
622 :
623 0 : pcln = ngx_pool_cleanup_add(r->pool, 0);
624 0 : if (pcln == NULL) {
625 0 : goto failed;
626 : }
627 :
628 0 : pcln->handler = ngx_http_lua_cleanup_vm;
629 0 : pcln->data = tctx.vm_state;
630 : }
631 :
632 0 : ctx->cur_co_ctx = &ctx->entry_co_ctx;
633 :
634 0 : L = ngx_http_lua_get_lua_vm(r, ctx);
635 :
636 0 : cln = ngx_http_cleanup_add(r, 0);
637 0 : if (cln == NULL) {
638 0 : goto failed;
639 : }
640 :
641 0 : cln->handler = ngx_http_lua_request_cleanup_handler;
642 0 : cln->data = ctx;
643 0 : ctx->cleanup = &cln->handler;
644 :
645 0 : ctx->entered_content_phase = 1;
646 0 : ctx->context = NGX_HTTP_LUA_CONTEXT_TIMER;
647 :
648 0 : r->read_event_handler = ngx_http_block_reading;
649 :
650 0 : ctx->cur_co_ctx->co_ref = tctx.co_ref;
651 0 : ctx->cur_co_ctx->co = tctx.co;
652 0 : ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_RUNNING;
653 :
654 : dd("r connection: %p, log %p", r->connection, r->connection->log);
655 :
656 : /* save the request in coroutine globals table */
657 0 : ngx_http_lua_set_req(tctx.co, r);
658 :
659 0 : lmcf->running_timers++;
660 :
661 0 : lua_pushboolean(tctx.co, tctx.premature);
662 :
663 0 : n = lua_gettop(tctx.co);
664 0 : if (n > 2) {
665 0 : lua_insert(tctx.co, 2);
666 : }
667 :
668 : #ifdef NGX_LUA_USE_ASSERT
669 0 : ctx->cur_co_ctx->co_top = 1;
670 : #endif
671 :
672 0 : rc = ngx_http_lua_run_thread(L, r, ctx, n - 1);
673 :
674 : dd("timer lua run thread: %d", (int) rc);
675 :
676 0 : if (rc == NGX_ERROR || rc >= NGX_OK) {
677 : /* do nothing */
678 :
679 0 : } else if (rc == NGX_AGAIN) {
680 0 : rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 0);
681 :
682 0 : } else if (rc == NGX_DONE) {
683 0 : rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 1);
684 :
685 : } else {
686 0 : rc = NGX_OK;
687 : }
688 :
689 0 : ngx_http_lua_finalize_request(r, rc);
690 0 : return;
691 :
692 0 : failed:
693 :
694 0 : if (tctx.co_ref && tctx.co) {
695 0 : lua_pushlightuserdata(tctx.co, &ngx_http_lua_coroutines_key);
696 0 : lua_rawget(tctx.co, LUA_REGISTRYINDEX);
697 0 : luaL_unref(tctx.co, -1, tctx.co_ref);
698 0 : lua_settop(tctx.co, 0);
699 : }
700 :
701 0 : if (tctx.vm_state) {
702 0 : ngx_http_lua_cleanup_vm(tctx.vm_state);
703 : }
704 :
705 0 : if (c) {
706 0 : ngx_http_lua_close_fake_connection(c);
707 :
708 0 : } else if (tctx.pool) {
709 0 : ngx_destroy_pool(tctx.pool);
710 : }
711 : }
712 :
713 :
714 : static u_char *
715 0 : ngx_http_lua_log_timer_error(ngx_log_t *log, u_char *buf, size_t len)
716 : {
717 : u_char *p;
718 : ngx_connection_t *c;
719 :
720 0 : if (log->action) {
721 0 : p = ngx_snprintf(buf, len, " while %s", log->action);
722 0 : len -= p - buf;
723 0 : buf = p;
724 : }
725 :
726 0 : c = log->data;
727 :
728 : dd("ctx = %p", c);
729 :
730 0 : p = ngx_snprintf(buf, len, ", context: ngx.timer");
731 0 : len -= p - buf;
732 0 : buf = p;
733 :
734 0 : if (c->addr_text.len) {
735 0 : p = ngx_snprintf(buf, len, ", client: %V", &c->addr_text);
736 0 : len -= p - buf;
737 0 : buf = p;
738 : }
739 :
740 0 : if (c && c->listening && c->listening->addr_text.len) {
741 0 : p = ngx_snprintf(buf, len, ", server: %V", &c->listening->addr_text);
742 : /* len -= p - buf; */
743 0 : buf = p;
744 : }
745 :
746 0 : return buf;
747 : }
748 :
749 :
750 : static void
751 0 : ngx_http_lua_abort_pending_timers(ngx_event_t *ev)
752 : {
753 : ngx_int_t i, n;
754 : ngx_event_t **events;
755 0 : ngx_connection_t *c, *saved_c = NULL;
756 : ngx_rbtree_node_t *cur, *prev, *next, *sentinel, *temp;
757 : ngx_http_lua_timer_ctx_t *tctx;
758 : ngx_http_lua_main_conf_t *lmcf;
759 :
760 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
761 : "lua abort pending timers");
762 :
763 0 : c = ev->data;
764 0 : lmcf = c->data;
765 :
766 : dd("lua connection fd: %d", (int) c->fd);
767 :
768 0 : if (!c->close) {
769 0 : return;
770 : }
771 :
772 0 : c->read->closed = 1;
773 0 : c->write->closed = 1;
774 :
775 : /* we temporarily use a valid fd (0) to make ngx_free_connection happy */
776 :
777 0 : c->fd = 0;
778 :
779 0 : if (ngx_cycle->files) {
780 0 : saved_c = ngx_cycle->files[0];
781 : }
782 :
783 0 : ngx_free_connection(c);
784 :
785 0 : c->fd = (ngx_socket_t) -1;
786 :
787 0 : if (ngx_cycle->files) {
788 0 : ngx_cycle->files[0] = saved_c;
789 : }
790 :
791 0 : if (lmcf->pending_timers == 0) {
792 0 : return;
793 : }
794 :
795 : /* expire pending timers immediately */
796 :
797 0 : sentinel = ngx_event_timer_rbtree.sentinel;
798 :
799 0 : cur = ngx_event_timer_rbtree.root;
800 :
801 : /* XXX nginx does not guarantee the parent of root is meaningful,
802 : * so we temporarily override it to simplify tree traversal. */
803 0 : temp = cur->parent;
804 0 : cur->parent = NULL;
805 :
806 0 : prev = NULL;
807 :
808 0 : events = ngx_pcalloc(ngx_cycle->pool,
809 0 : lmcf->pending_timers * sizeof(ngx_event_t));
810 0 : if (events == NULL) {
811 0 : return;
812 : }
813 :
814 0 : n = 0;
815 :
816 : dd("root: %p, root parent: %p, sentinel: %p", cur, cur->parent, sentinel);
817 :
818 0 : while (n < lmcf->pending_timers) {
819 0 : if (cur == sentinel || cur == NULL) {
820 0 : ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
821 : "lua pending timer counter got out of sync: %i",
822 : lmcf->pending_timers);
823 0 : break;
824 : }
825 :
826 : dd("prev: %p, cur: %p, cur parent: %p, cur left: %p, cur right: %p",
827 : prev, cur, cur->parent, cur->left, cur->right);
828 :
829 0 : if (prev == cur->parent) {
830 : /* neither of the children has been accessed yet */
831 :
832 0 : next = cur->left;
833 0 : if (next == sentinel) {
834 0 : ev = (ngx_event_t *)
835 : ((char *) cur - offsetof(ngx_event_t, timer));
836 :
837 0 : if (ev->handler == ngx_http_lua_timer_handler) {
838 : dd("found node: %p", cur);
839 0 : events[n++] = ev;
840 : }
841 :
842 0 : next = (cur->right != sentinel) ? cur->right : cur->parent;
843 : }
844 :
845 0 : } else if (prev == cur->left) {
846 : /* just accessed the left child */
847 :
848 0 : ev = (ngx_event_t *)
849 : ((char *) cur - offsetof(ngx_event_t, timer));
850 :
851 0 : if (ev->handler == ngx_http_lua_timer_handler) {
852 : dd("found node 2: %p", cur);
853 0 : events[n++] = ev;
854 : }
855 :
856 0 : next = (cur->right != sentinel) ? cur->right : cur->parent;
857 :
858 0 : } else if (prev == cur->right) {
859 : /* already accessed both children */
860 0 : next = cur->parent;
861 :
862 : } else {
863 : /* not reacheable */
864 0 : next = NULL;
865 : }
866 :
867 0 : prev = cur;
868 0 : cur = next;
869 : }
870 :
871 : /* restore the old tree root's parent */
872 0 : ngx_event_timer_rbtree.root->parent = temp;
873 :
874 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
875 : "lua found %i pending timers to be aborted prematurely",
876 : n);
877 :
878 0 : for (i = 0; i < n; i++) {
879 0 : ev = events[i];
880 :
881 0 : ngx_rbtree_delete(&ngx_event_timer_rbtree, &ev->timer);
882 :
883 : #if (NGX_DEBUG)
884 0 : ev->timer.left = NULL;
885 0 : ev->timer.right = NULL;
886 0 : ev->timer.parent = NULL;
887 : #endif
888 :
889 0 : ev->timer_set = 0;
890 :
891 0 : ev->timedout = 1;
892 :
893 0 : tctx = ev->data;
894 0 : tctx->premature = 1;
895 :
896 : dd("calling timer handler prematurely");
897 0 : ev->handler(ev);
898 : }
899 :
900 : #if 0
901 : if (pending_timers) {
902 : ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
903 : "lua pending timer counter got out of sync: %i",
904 : pending_timers);
905 : }
906 : #endif
907 : }
908 :
909 : /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|