From cf480e499c6080a1f155077e9fbca9fc602473be Mon Sep 17 00:00:00 2001 From: "roberto@quantal64" Date: Fri, 7 Sep 2012 19:09:22 +0200 Subject: [PATCH] implemented psgi cleanup handlers, and fixed a leak in rpc call --- plugins/php/php_plugin.c | 2 ++ plugins/psgi/psgi_plugin.c | 58 ++++++++++++++++++++++++++++----- plugins/psgi/uwsgi_plmodule.c | 2 ++ plugins/python/uwsgi_pymodule.c | 2 ++ plugins/rack/rack_api.c | 3 +- test.psgi | 24 ++++++++++++++ 6 files changed, 81 insertions(+), 10 deletions(-) diff --git a/plugins/php/php_plugin.c b/plugins/php/php_plugin.c index d1694140..638fe339 100644 --- a/plugins/php/php_plugin.c +++ b/plugins/php/php_plugin.c @@ -498,6 +498,7 @@ PHP_FUNCTION(uwsgi_rpc) { argvs[i] = Z_STRLEN_P(z_current_obj); } + // response must always be freed char *response = uwsgi_do_rpc(node, func, num_args - 2, argv, argvs, &size); if (size > 0) { @@ -506,6 +507,7 @@ PHP_FUNCTION(uwsgi_rpc) { free(response); RETURN_STRING(ret, 0); } + free(response); clear: efree(varargs); diff --git a/plugins/psgi/psgi_plugin.c b/plugins/psgi/psgi_plugin.c index fbc0d3a2..7e6425a0 100644 --- a/plugins/psgi/psgi_plugin.c +++ b/plugins/psgi/psgi_plugin.c @@ -297,6 +297,12 @@ SV *build_psgi_env(struct wsgi_request *wsgi_req) { if (!hv_store(env, "psgix.harakiri", 14, newSViv(1), 0)) goto clear; } + if (!hv_store(env, "psgix.cleanup", 13, newSViv(1), 0)) goto clear; + // cleanup handlers array + av = newAV(); + if (!hv_store(env, "psgix.cleanup.handlers", 22, newRV_noinc((SV *)av ), 0)) goto clear; + + SV *pe = uwsgi_perl_obj_new("uwsgi::error", 12); if (!hv_store(env, "psgi.errors", 11, pe, 0)) goto clear; @@ -375,8 +381,6 @@ int uwsgi_perl_init(){ int uwsgi_perl_request(struct wsgi_request *wsgi_req) { - SV **harakiri; - #ifdef UWSGI_ASYNC if (wsgi_req->async_status == UWSGI_AGAIN) { return psgi_response(wsgi_req, wsgi_req->async_placeholder); @@ -457,13 +461,7 @@ int uwsgi_perl_request(struct wsgi_request *wsgi_req) { } clear2: - // check for psgix.harakiri - harakiri = hv_fetch((HV*)SvRV( (SV*)wsgi_req->async_environ), "psgix.harakiri.commit", 21, 0); - if (harakiri) { - if (SvTRUE(*harakiri)) wsgi_req->async_plagued = 1; - } - - SvREFCNT_dec(wsgi_req->async_environ); + // clear response SvREFCNT_dec(wsgi_req->async_result); clear: @@ -478,16 +476,58 @@ clear: return UWSGI_OK; } +static void psgi_call_cleanup_hook(SV *hook, SV *env) { + dSP; + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(env); + PUTBACK; + call_sv(hook, G_DISCARD); + if(SvTRUE(ERRSV)) { + uwsgi_log("[uwsgi-perl error] %s\n", SvPV_nolen(ERRSV)); + } + FREETMPS; + LEAVE; +} void uwsgi_perl_after_request(struct wsgi_request *wsgi_req) { log_request(wsgi_req); + // dereference %env + SV *env = SvRV((SV *) wsgi_req->async_environ); + + // check for cleanup handlers + if (hv_exists((HV *)env, "psgix.cleanup.handlers", 22)) { + SV **cleanup_handlers = hv_fetch((HV *)env, "psgix.cleanup.handlers", 22, 0); + if (SvROK(*cleanup_handlers)) { + if (SvTYPE(SvRV(*cleanup_handlers)) == SVt_PVAV) { + I32 n = av_len((AV *)SvRV(*cleanup_handlers)); + I32 i; + for(i=0;i<=n;i++) { + SV **hook = av_fetch((AV *)SvRV(*cleanup_handlers), i, 0); + psgi_call_cleanup_hook(*hook, (SV *) wsgi_req->async_environ); + } + } + } + } + + // check for psgix.harakiri + if (hv_exists((HV *)env, "psgix.harakiri.commit", 21)) { + SV **harakiri = hv_fetch((HV *)env, "psgix.harakiri.commit", 21, 0); + if (SvTRUE(*harakiri)) wsgi_req->async_plagued = 1; + } + + // async plagued could be defined in other areas... if (wsgi_req->async_plagued) { uwsgi_log("*** psgix.harakiri.commit requested ***\n"); goodbye_cruel_world(); } + // clear the env + SvREFCNT_dec(wsgi_req->async_environ); + } int uwsgi_perl_magic(char *mountpoint, char *lazy) { diff --git a/plugins/psgi/uwsgi_plmodule.c b/plugins/psgi/uwsgi_plmodule.c index 51081849..c1b3eba8 100644 --- a/plugins/psgi/uwsgi_plmodule.c +++ b/plugins/psgi/uwsgi_plmodule.c @@ -190,6 +190,7 @@ XS(XS_call) { argvs[i] = arg_len; } + // response must be always freed char *response = uwsgi_do_rpc(NULL, func, items-1, argv, argvs, &size); if (size > 0) { @@ -198,6 +199,7 @@ XS(XS_call) { free(response); XSRETURN(1); } + free(response); XSRETURN_UNDEF; } diff --git a/plugins/python/uwsgi_pymodule.c b/plugins/python/uwsgi_pymodule.c index 4210d550..49aae6b5 100644 --- a/plugins/python/uwsgi_pymodule.c +++ b/plugins/python/uwsgi_pymodule.c @@ -313,6 +313,7 @@ PyObject *py_uwsgi_call(PyObject * self, PyObject * args) { } UWSGI_RELEASE_GIL; + // response must always be freed char *response = uwsgi_do_rpc(NULL, func, argc - 1, argv, argvs, &size); UWSGI_GET_GIL; @@ -322,6 +323,7 @@ PyObject *py_uwsgi_call(PyObject * self, PyObject * args) { return ret; } + free(response); Py_INCREF(Py_None); return Py_None; diff --git a/plugins/rack/rack_api.c b/plugins/rack/rack_api.c index 003b2ef2..615d60da 100644 --- a/plugins/rack/rack_api.c +++ b/plugins/rack/rack_api.c @@ -654,6 +654,7 @@ VALUE uwsgi_ruby_do_rpc(int argc, VALUE *rpc_argv, VALUE *class) { argvs[i] = RSTRING_LEN(rpc_str); } + // response must always be freed char *response = uwsgi_do_rpc(node, func, argc - 2, argv, argvs, &size); if (size > 0) { @@ -661,7 +662,7 @@ VALUE uwsgi_ruby_do_rpc(int argc, VALUE *rpc_argv, VALUE *class) { free(response); return ret; } - + free(response); clear: diff --git a/test.psgi b/test.psgi index a04e982e..f40bb361 100644 --- a/test.psgi +++ b/test.psgi @@ -7,8 +7,32 @@ if ($rpc_value) { print "rpc value = ".$rpc_value."\n"; } +my $one = sub { + my $env = shift; + #sleep(1); + print "one\n"; +}; + +my $two = sub { + my $env = shift; + #sleep(1); + print "two\n"; +}; + +my $three = sub { + my $env = shift; + #sleep(1); + print "three\n"; +}; + my $app = sub { my $env = shift; + if ($env->{'psgix.cleanup'}) { + print "cleanup supported\n"; + push $env->{'psgix.cleanup.handlers'}, $one; + push $env->{'psgix.cleanup.handlers'}, $two; + push $env->{'psgix.cleanup.handlers'}, $three; + } uwsgi::cache_set("key1", "val1"); if ($rpc_value) { print uwsgi::call('hello')."\n";