[ANN] nginx-perl

Alexandr Gomoliako zzz на zzz.org.ua
Вт Ноя 1 17:50:59 UTC 2011


> На всякий случай прикладываю и в виде патча.

Патч.
-------------- next part --------------
diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm
--- a/src/http/modules/perl/nginx.pm
+++ b/src/http/modules/perl/nginx.pm
@@ -1,14 +1,37 @@
 package nginx;
 
-use 5.006001;
 use strict;
 use warnings;
 
 require Exporter;
+our @ISA    = qw(Exporter);
+our @EXPORT = qw(
 
-our @ISA = qw(Exporter);
+    ngx_timer
+    ngx_connector
+    ngx_reader
+    ngx_writer
+    ngx_read
+    ngx_write
+    ngx_close
+    ngx_noop
 
-our @EXPORT = qw(
+    NGX_READ
+    NGX_WRITE
+    NGX_CLOSE
+    NGX_NOOP
+    NGX_EOF
+    NGX_EINVAL
+    NGX_ENOMEM
+    NGX_ETIMEDOUT
+    NGX_EBADE
+    NGX_EBADF
+
+    NGX_DONE
+    NGX_OK
+    NGX_HTTP_LAST
+
+
     OK
     DECLINED
 
@@ -53,54 +76,6 @@
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
 
-# Preloaded methods go here.
-
-use constant OK                             => 0;
-use constant DECLINED                       => -5;
-
-use constant HTTP_OK                        => 200;
-use constant HTTP_CREATED                   => 201;
-use constant HTTP_ACCEPTED                  => 202;
-use constant HTTP_NO_CONTENT                => 204;
-use constant HTTP_PARTIAL_CONTENT           => 206;
-
-use constant HTTP_MOVED_PERMANENTLY         => 301;
-use constant HTTP_MOVED_TEMPORARILY         => 302;
-use constant HTTP_REDIRECT                  => 302;
-use constant HTTP_NOT_MODIFIED              => 304;
-
-use constant HTTP_BAD_REQUEST               => 400;
-use constant HTTP_UNAUTHORIZED              => 401;
-use constant HTTP_PAYMENT_REQUIRED          => 402;
-use constant HTTP_FORBIDDEN                 => 403;
-use constant HTTP_NOT_FOUND                 => 404;
-use constant HTTP_NOT_ALLOWED               => 405;
-use constant HTTP_NOT_ACCEPTABLE            => 406;
-use constant HTTP_REQUEST_TIME_OUT          => 408;
-use constant HTTP_CONFLICT                  => 409;
-use constant HTTP_GONE                      => 410;
-use constant HTTP_LENGTH_REQUIRED           => 411;
-use constant HTTP_REQUEST_ENTITY_TOO_LARGE  => 413;
-use constant HTTP_REQUEST_URI_TOO_LARGE     => 414;
-use constant HTTP_UNSUPPORTED_MEDIA_TYPE    => 415;
-use constant HTTP_RANGE_NOT_SATISFIABLE     => 416;
-
-use constant HTTP_INTERNAL_SERVER_ERROR     => 500;
-use constant HTTP_SERVER_ERROR              => 500;
-use constant HTTP_NOT_IMPLEMENTED           => 501;
-use constant HTTP_BAD_GATEWAY               => 502;
-use constant HTTP_SERVICE_UNAVAILABLE       => 503;
-use constant HTTP_GATEWAY_TIME_OUT          => 504;
-use constant HTTP_INSUFFICIENT_STORAGE      => 507;
-
-
-sub rflush {
-    my $r = shift;
-
-    $r->flush;
-}
-
-
 1;
 __END__
 
diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs
--- a/src/http/modules/perl/nginx.xs
+++ b/src/http/modules/perl/nginx.xs
@@ -93,9 +93,62 @@
     return ngx_http_output_filter(r, &out);
 }
 
+#define ci(stash, a, b)   newCONSTSUB (stash, a, newSViv(b))
 
 MODULE = nginx    PACKAGE = nginx
 
+BOOT:
+    HV *stash = gv_stashpv ("nginx", 1);
+    ci (stash, "NGX_DONE",                       NGX_DONE);
+    ci (stash, "NGX_HTTP_LAST",                  NGX_HTTP_LAST);
+    ci (stash, "NGX_OK",                         NGX_OK);
+    ci (stash, "NGX_DECLINED",                   NGX_DECLINED);
+    ci (stash, "NGX_NOOP",                       NGX_PERL_NOOP);
+    ci (stash, "NGX_READ",                       NGX_PERL_READ);
+    ci (stash, "NGX_WRITE",                      NGX_PERL_WRITE);
+    ci (stash, "NGX_CLOSE",                      NGX_PERL_CLOSE);
+    ci (stash, "NGX_EOF",                        NGX_PERL_EOF);
+    ci (stash, "NGX_EINVAL",                     NGX_PERL_EINVAL);
+    ci (stash, "NGX_ENOMEM",                     NGX_PERL_ENOMEM);
+    ci (stash, "NGX_EBADF",                      NGX_PERL_EBADF);
+    ci (stash, "NGX_EBADE",                      NGX_PERL_EBADE);
+    ci (stash, "NGX_ETIMEDOUT",                  NGX_PERL_ETIMEDOUT);
+    ci (stash, "OK",                             0);
+    ci (stash, "DECLINED",                       -5);
+    ci (stash, "HTTP_OK",                        200);
+    ci (stash, "HTTP_CREATED",                   201);
+    ci (stash, "HTTP_ACCEPTED",                  202);
+    ci (stash, "HTTP_NO_CONTENT",                204);
+    ci (stash, "HTTP_PARTIAL_CONTENT",           206);
+    ci (stash, "HTTP_MOVED_PERMANENTLY",         301);
+    ci (stash, "HTTP_MOVED_TEMPORARILY",         302);
+    ci (stash, "HTTP_REDIRECT",                  302);
+    ci (stash, "HTTP_NOT_MODIFIED",              304);
+    ci (stash, "HTTP_BAD_REQUEST",               400);
+    ci (stash, "HTTP_UNAUTHORIZED",              401);
+    ci (stash, "HTTP_PAYMENT_REQUIRED",          402);
+    ci (stash, "HTTP_FORBIDDEN",                 403);
+    ci (stash, "HTTP_NOT_FOUND",                 404);
+    ci (stash, "HTTP_NOT_ALLOWED",               405);
+    ci (stash, "HTTP_NOT_ACCEPTABLE",            406);
+    ci (stash, "HTTP_REQUEST_TIME_OUT",          408);
+    ci (stash, "HTTP_CONFLICT",                  409);
+    ci (stash, "HTTP_GONE",                      410);
+    ci (stash, "HTTP_LENGTH_REQUIRED",           411);
+    ci (stash, "HTTP_REQUEST_ENTITY_TOO_LARGE",  413);
+    ci (stash, "HTTP_REQUEST_URI_TOO_LARGE",     414);
+    ci (stash, "HTTP_UNSUPPORTED_MEDIA_TYPE",    415);
+    ci (stash, "HTTP_RANGE_NOT_SATISFIABLE",     416);
+    ci (stash, "HTTP_INTERNAL_SERVER_ERROR",     500);
+    ci (stash, "HTTP_SERVER_ERROR",              500);
+    ci (stash, "HTTP_NOT_IMPLEMENTED",           501);
+    ci (stash, "HTTP_BAD_GATEWAY",               502);
+    ci (stash, "HTTP_SERVICE_UNAVAILABLE",       503);
+    ci (stash, "HTTP_GATEWAY_TIME_OUT",          504);
+    ci (stash, "HTTP_INSUFFICIENT_STORAGE",      507);
+
+PROTOTYPES: DISABLE
+
 
 void
 status(r, code)
@@ -696,6 +749,9 @@
 
 void
 flush(r)
+    ALIAS:
+    rflush = 1
+
     CODE:
 
     ngx_http_request_t  *r;
@@ -983,3 +1039,147 @@
     p = (u_char *) SvPV(msg, len);
 
     ngx_log_error(NGX_LOG_ERR, r->connection->log, e, "perl: %s", p);
+
+
+void
+main_count_inc(r)
+    CODE:
+
+    ngx_http_request_t   *r;
+
+    ngx_http_perl_set_request(r);
+
+    r->main->count++;
+
+
+void
+finalize_request(r, rc)
+    ALIAS:
+    send_special = 1
+    CODE:
+
+    ngx_http_request_t   *r;
+
+    ngx_http_perl_set_request(r);
+
+    switch (ix) {
+	case 1:
+	    ngx_http_send_special(r, SvIV(ST(1)));
+	    break;
+	default:
+	    ngx_http_finalize_request(r, SvIV(ST(1)));
+	    break;
+    }
+
+
+SV *
+ngx_timer(after, repeat, cb)
+    PROTOTYPE: $$&
+    CODE:
+
+    ngx_connection_t *c;
+
+    c = ngx_perl_timer((ngx_int_t)SvIV(ST(0)), ST(1), ST(2));
+    if (c == NULL) {
+	croak("ngx_perl_timer returned NULL");
+    }
+
+    RETVAL = newSViv(PTR2IV(c));
+
+    OUTPUT:
+    RETVAL
+
+
+void
+ngx_timer_clear(timer)
+    CODE:
+
+    ngx_connection_t  *c;
+
+    c = INT2PTR(ngx_connection_t *, SvIV(ST(0)));
+    ngx_perl_timer_clear(c);
+
+
+void
+ngx_connector(address, port, timeout, cb)
+    PROTOTYPE: $$$&
+    CODE:
+
+    ngx_perl_connector(ST(0), ST(1), ST(2), ST(3));
+
+
+void
+ngx_reader(c, buf, min, max, timeout, cb)
+    PROTOTYPE: $$$$$&
+    CODE:
+
+    ngx_connection_t  *c;
+
+    c = INT2PTR(ngx_connection_t *, SvIV(ST(0)));
+
+    ngx_perl_reader(c, ST(1), ST(2), ST(3), ST(4), ST(5));
+
+
+void
+ngx_writer(c, buf, timeout, cb)
+    PROTOTYPE: $$$&
+    CODE:
+
+    ngx_connection_t  *c;
+
+    c = INT2PTR(ngx_connection_t *, SvIV(ST(0)));
+
+    ngx_perl_writer(c, ST(1), ST(2), ST(3));
+
+
+void
+ngx_close(c)
+    PROTOTYPE: $
+    CODE:
+
+    ngx_connection_t  *c;
+
+    c = INT2PTR(ngx_connection_t *, SvIV(ST(0)));
+
+    ngx_perl_close(c);
+
+
+void
+ngx_read(c)
+    PROTOTYPE: $
+    CODE:
+
+    ngx_connection_t  *c;
+
+    c = INT2PTR(ngx_connection_t *, SvIV(ST(0)));
+
+    ngx_perl_read(c);
+
+
+void
+ngx_write(c)
+    PROTOTYPE: $
+    CODE:
+
+    ngx_connection_t  *c;
+
+    c = INT2PTR(ngx_connection_t *, SvIV(ST(0)));
+
+    ngx_perl_write(c);
+    if (c->write->ready) {
+        c->write->handler(c->write);
+    }
+
+
+void
+ngx_noop(c)
+    PROTOTYPE: $
+    CODE:
+
+    ngx_connection_t  *c;
+
+    c = INT2PTR(ngx_connection_t *, SvIV(ST(0)));
+
+    ngx_perl_noop(c);
+
+
diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c
--- a/src/http/modules/perl/ngx_http_perl_module.c
+++ b/src/http/modules/perl/ngx_http_perl_module.c
@@ -11,8 +11,6 @@
 
 
 typedef struct {
-    PerlInterpreter   *perl;
-    HV                *nginx;
     ngx_array_t       *modules;
     ngx_array_t       *requires;
 } ngx_http_perl_main_conf_t;
@@ -42,7 +40,7 @@
 static ngx_int_t ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires,
     ngx_log_t *log);
 static ngx_int_t ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r,
-    HV *nginx, SV *sub, SV **args, ngx_str_t *handler, ngx_str_t *rv);
+    SV *sub, SV **args, ngx_str_t *handler, ngx_str_t *rv);
 static void ngx_http_perl_eval_anon_sub(pTHX_ ngx_str_t *handler, SV **sv);
 
 static ngx_int_t ngx_http_perl_preconfiguration(ngx_conf_t *cf);
@@ -54,13 +52,16 @@
 static char *ngx_http_perl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 static char *ngx_http_perl_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 
-#if (NGX_HAVE_PERL_MULTIPLICITY)
-static void ngx_http_perl_cleanup_perl(void *data);
-#endif
-
 static ngx_int_t ngx_http_perl_init_worker(ngx_cycle_t *cycle);
 static void ngx_http_perl_exit(ngx_cycle_t *cycle);
 
+static void ngx_perl_timer_callback(ngx_event_t *ev);
+static void ngx_perl_connection_cleanup(void *data);
+static void ngx_perl_connect_handler(ngx_event_t *ev);
+static void ngx_perl_dummy_handler(ngx_event_t *ev);
+static void ngx_perl_read_handler(ngx_event_t *ev);
+static void ngx_perl_write_handler(ngx_event_t *ev);
+
 
 static ngx_command_t  ngx_http_perl_commands[] = {
 
@@ -148,12 +149,9 @@
 
 static ngx_str_t         ngx_null_name = ngx_null_string;
 static HV               *nginx_stash;
-
-#if (NGX_HAVE_PERL_MULTIPLICITY)
-static ngx_uint_t        ngx_perl_term;
-#else
-static PerlInterpreter  *perl;
-#endif
+static PerlInterpreter  *my_perl;
+
+static ngx_log_t        *ngx_perl_log; 
 
 
 static void
@@ -170,8 +168,12 @@
 {
     r->main->count++;
 
+    /* ngx_perl_log = r->connection->log; */
+
     ngx_http_perl_handle_request(r);
 
+    /* ngx_perl_log = ngx_cycle->log; */
+
     return NGX_DONE;
 }
 
@@ -184,7 +186,6 @@
     ngx_str_t                   uri, args, *handler;
     ngx_http_perl_ctx_t        *ctx;
     ngx_http_perl_loc_conf_t   *plcf;
-    ngx_http_perl_main_conf_t  *pmcf;
 
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "perl handler");
 
@@ -200,28 +201,18 @@
         ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
     }
 
-    pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
-
-    {
-
-    dTHXa(pmcf->perl);
-    PERL_SET_CONTEXT(pmcf->perl);
 
     if (ctx->next == NULL) {
         plcf = ngx_http_get_module_loc_conf(r, ngx_http_perl_module);
         sub = plcf->sub;
         handler = &plcf->handler;
-
     } else {
         sub = ctx->next;
         handler = &ngx_null_name;
         ctx->next = NULL;
     }
 
-    rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sub, NULL, handler,
-                                    NULL);
-
-    }
+    rc = ngx_http_perl_call_handler(aTHX_ r, sub, NULL, handler, NULL);
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "perl handler done: %i", rc);
@@ -297,7 +288,6 @@
     ngx_int_t                   rc;
     ngx_str_t                   value;
     ngx_http_perl_ctx_t        *ctx;
-    ngx_http_perl_main_conf_t  *pmcf;
 
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "perl variable handler");
@@ -313,20 +303,11 @@
         ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
     }
 
-    pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
-
     value.data = NULL;
 
-    {
-
-    dTHXa(pmcf->perl);
-    PERL_SET_CONTEXT(pmcf->perl);
-
-    rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, pv->sub, NULL,
+    rc = ngx_http_perl_call_handler(aTHX_ r, pv->sub, NULL,
                                     &pv->handler, &value);
 
-    }
-
     if (value.data) {
         v->len = value.len;
         v->valid = 1;
@@ -359,7 +340,6 @@
     ngx_str_t                  *handler, **args;
     ngx_uint_t                  i;
     ngx_http_perl_ctx_t        *ctx;
-    ngx_http_perl_main_conf_t  *pmcf;
 
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "perl ssi handler");
@@ -375,18 +355,11 @@
         ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
     }
 
-    pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
-
     ctx->ssi = ssi_ctx;
 
     handler = params[NGX_HTTP_PERL_SSI_SUB];
     handler->data[handler->len] = '\0';
 
-    {
-
-    dTHXa(pmcf->perl);
-    PERL_SET_CONTEXT(pmcf->perl);
-
 #if 0
 
     /* the code is disabled to force the precompiled perl code using only */
@@ -430,13 +403,11 @@
         asv = NULL;
     }
 
-    rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sv, asv, handler,
+    rc = ngx_http_perl_call_handler(aTHX_ r, sv, asv, handler,
                                     NULL);
 
     SvREFCNT_dec(sv);
 
-    }
-
     ctx->filename.data = NULL;
     ctx->redirect_uri.len = 0;
     ctx->ssi = NULL;
@@ -454,15 +425,6 @@
 {
     ngx_str_t           *m;
     ngx_uint_t           i;
-#if (NGX_HAVE_PERL_MULTIPLICITY)
-    ngx_pool_cleanup_t  *cln;
-
-    cln = ngx_pool_cleanup_add(cf->pool, 0);
-    if (cln == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-#endif
 
 #ifdef NGX_PERL_MODULES
     if (pmcf->modules == NGX_CONF_UNSET_PTR) {
@@ -490,9 +452,7 @@
         }
     }
 
-#if !(NGX_HAVE_PERL_MULTIPLICITY)
-
-    if (perl) {
+    if (my_perl) {
 
         if (ngx_set_environment(cf->cycle, NULL) == NULL) {
             return NGX_CONF_ERROR;
@@ -504,37 +464,20 @@
             return NGX_CONF_ERROR;
         }
 
-        pmcf->perl = perl;
-        pmcf->nginx = nginx_stash;
-
         return NGX_CONF_OK;
     }
 
-#endif
 
     if (nginx_stash == NULL) {
         PERL_SYS_INIT(&ngx_argc, &ngx_argv);
     }
 
-    pmcf->perl = ngx_http_perl_create_interpreter(cf, pmcf);
-
-    if (pmcf->perl == NULL) {
+    my_perl = ngx_http_perl_create_interpreter(cf, pmcf);
+
+    if (my_perl == NULL) {
         return NGX_CONF_ERROR;
     }
 
-    pmcf->nginx = nginx_stash;
-
-#if (NGX_HAVE_PERL_MULTIPLICITY)
-
-    cln->handler = ngx_http_perl_cleanup_perl;
-    cln->data = pmcf->perl;
-
-#else
-
-    perl = pmcf->perl;
-
-#endif
-
     return NGX_CONF_OK;
 }
 
@@ -549,7 +492,6 @@
     char              *ver, **embedding;
     ngx_str_t         *m;
     ngx_uint_t         i;
-    PerlInterpreter   *perl;
 
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "create perl interpreter");
 
@@ -557,18 +499,17 @@
         return NULL;
     }
 
-    perl = perl_alloc();
-    if (perl == NULL) {
+    my_perl = perl_alloc();
+    if (my_perl == NULL) {
         ngx_log_error(NGX_LOG_ALERT, cf->log, 0, "perl_alloc() failed");
         return NULL;
     }
 
     {
 
-    dTHXa(perl);
-    PERL_SET_CONTEXT(perl);
-
-    perl_construct(perl);
+    perl_construct(my_perl);
+
+    PL_origalen = 1;
 
 #ifdef PERL_EXIT_DESTRUCT_END
     PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
@@ -595,7 +536,7 @@
     embedding[n++] = "-e";
     embedding[n++] = "0";
 
-    n = perl_parse(perl, ngx_http_perl_xs_init, n, embedding, NULL);
+    n = perl_parse(my_perl, ngx_http_perl_xs_init, n, embedding, NULL);
 
     if (n != 0) {
         ngx_log_error(NGX_LOG_ALERT, cf->log, 0, "perl_parse() failed: %d", n);
@@ -618,13 +559,13 @@
 
     }
 
-    return perl;
+    return my_perl;
 
 fail:
 
-    (void) perl_destruct(perl);
-
-    perl_free(perl);
+    (void) perl_destruct(my_perl);
+
+    perl_free(my_perl);
 
     return NULL;
 }
@@ -665,7 +606,7 @@
 
 
 static ngx_int_t
-ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, HV *nginx, SV *sub,
+ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, SV *sub,
     SV **args, ngx_str_t *handler, ngx_str_t *rv)
 {
     SV                *sv;
@@ -685,7 +626,7 @@
 
     PUSHMARK(sp);
 
-    sv = sv_2mortal(sv_bless(newRV_noinc(newSViv(PTR2IV(r))), nginx));
+    sv = sv_2mortal(sv_bless(newRV_noinc(newSViv(PTR2IV(r))), nginx_stash));
     XPUSHs(sv);
 
     if (args) {
@@ -808,7 +749,7 @@
 {
     ngx_http_perl_main_conf_t *pmcf = conf;
 
-    if (pmcf->perl == NULL) {
+    if (my_perl == NULL) {
         if (ngx_http_perl_init_interpreter(cf, pmcf) != NGX_CONF_OK) {
             return NGX_CONF_ERROR;
         }
@@ -818,28 +759,6 @@
 }
 
 
-#if (NGX_HAVE_PERL_MULTIPLICITY)
-
-static void
-ngx_http_perl_cleanup_perl(void *data)
-{
-    PerlInterpreter  *perl = data;
-
-    PERL_SET_CONTEXT(perl);
-
-    (void) perl_destruct(perl);
-
-    perl_free(perl);
-
-    if (ngx_perl_term) {
-        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "perl term");
-
-        PERL_SYS_TERM();
-    }
-}
-
-#endif
-
 
 static ngx_int_t
 ngx_http_perl_preconfiguration(ngx_conf_t *cf)
@@ -922,7 +841,7 @@
 
     pmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_perl_module);
 
-    if (pmcf->perl == NULL) {
+    if (my_perl == NULL) {
         if (ngx_http_perl_init_interpreter(cf, pmcf) != NGX_CONF_OK) {
             return NGX_CONF_ERROR;
         }
@@ -930,11 +849,6 @@
 
     plcf->handler = value[1];
 
-    {
-
-    dTHXa(pmcf->perl);
-    PERL_SET_CONTEXT(pmcf->perl);
-
     ngx_http_perl_eval_anon_sub(aTHX_ &value[1], &plcf->sub);
 
     if (plcf->sub == &PL_sv_undef) {
@@ -947,8 +861,6 @@
         plcf->sub = newSVpvn((char *) value[1].data, value[1].len);
     }
 
-    }
-
     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
     clcf->handler = ngx_http_perl_handler;
 
@@ -993,7 +905,7 @@
 
     pmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_perl_module);
 
-    if (pmcf->perl == NULL) {
+    if (my_perl == NULL) {
         if (ngx_http_perl_init_interpreter(cf, pmcf) != NGX_CONF_OK) {
             return NGX_CONF_ERROR;
         }
@@ -1003,9 +915,6 @@
 
     {
 
-    dTHXa(pmcf->perl);
-    PERL_SET_CONTEXT(pmcf->perl);
-
     ngx_http_perl_eval_anon_sub(aTHX_ &value[2], &pv->sub);
 
     if (pv->sub == &PL_sv_undef) {
@@ -1035,14 +944,14 @@
     pmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_perl_module);
 
     if (pmcf) {
-        dTHXa(pmcf->perl);
-        PERL_SET_CONTEXT(pmcf->perl);
 
         /* set worker's $$ */
 
         sv_setiv(GvSV(gv_fetchpv("$", TRUE, SVt_PV)), (I32) ngx_pid);
     }
 
+    ngx_perl_log = ngx_cycle->log;
+
     return NGX_OK;
 }
 
@@ -1050,26 +959,977 @@
 static void
 ngx_http_perl_exit(ngx_cycle_t *cycle)
 {
-#if (NGX_HAVE_PERL_MULTIPLICITY)
-
-    /*
-     * the master exit hook is run before global pool cleanup,
-     * therefore just set flag here
-     */
-
-    ngx_perl_term = 1;
-
-#else
 
     if (nginx_stash) {
         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cycle->log, 0, "perl term");
 
-        (void) perl_destruct(perl);
-
-        perl_free(perl);
+        (void) perl_destruct(my_perl);
+
+        perl_free(my_perl);
 
         PERL_SYS_TERM();
     }
-
-#endif
 }
+
+
+ngx_connection_t *
+ngx_perl_timer(ngx_int_t after, SV *repeat, SV *cb) 
+{
+    ngx_connection_t  *c;
+    ngx_perl_timer_t  *t;
+
+    c = ngx_get_connection((ngx_socket_t) 0, ngx_cycle->log);
+    if (c == NULL) {
+        return NULL;
+    }
+ 
+    Newz(0, t, 1, ngx_perl_timer_t);
+    if (t == NULL) {
+        return NULL;
+    }
+
+    c->read->handler = ngx_perl_timer_callback;
+    c->read->active  = 1;
+    c->read->log     = ngx_cycle->log;
+
+    c->data = (void *) t;
+
+    t->after  = after;
+    t->repeat = repeat;
+    t->cb     = cb; 
+    
+    SvREFCNT_inc(t->repeat);
+    SvREFCNT_inc(t->cb);
+
+    ngx_add_timer(c->read, t->after * 1000);
+
+    return c;
+}
+
+
+void
+ngx_perl_timer_clear(ngx_connection_t *c) 
+{
+    ngx_perl_timer_t  *t;
+
+    if (c->destroyed) {
+        ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
+                      "ngx_perl_timer_clear: connection already destroyed");
+        return;
+    }
+
+    t = (ngx_perl_timer_t *) c->data;
+
+    SvREFCNT_dec(t->repeat);
+    SvREFCNT_dec(t->cb);
+
+    if (c->read->timer_set) {
+        ngx_del_timer(c->read);
+    }
+
+    safefree(t);
+    ngx_free_connection(c);
+
+    return;
+}
+
+
+static void 
+ngx_perl_timer_callback(ngx_event_t *ev) 
+{
+    ngx_connection_t  *c;
+    ngx_perl_timer_t  *t;
+    dSP;
+
+    c = (ngx_connection_t *) ev->data;
+    t = (ngx_perl_timer_t *) c->data;
+
+    ENTER;
+    SAVETMPS;
+
+    PUSHMARK(SP);
+    XPUSHs(sv_2mortal(newSViv(PTR2IV(c))));
+    PUTBACK;
+
+    call_sv(t->cb, G_VOID|G_DISCARD);
+
+    FREETMPS;
+    LEAVE;
+
+    if (SvIV(t->repeat) > 0) {
+        ngx_add_timer(ev, SvIV(t->repeat) * 1000);
+    } else {
+        ngx_perl_timer_clear(c);
+    }
+
+    return;
+}
+
+
+void
+ngx_perl_connector(SV *address, SV *port, SV *timeout, SV *cb) 
+{
+    in_addr_t               inaddr;
+    in_port_t               inport;
+    ngx_pool_t             *pool;
+    struct sockaddr_in     *sin;
+    ngx_peer_connection_t  *peer;
+    ngx_perl_connection_t  *plc;
+    ngx_pool_cleanup_t     *plccln;
+    ngx_connection_t       *c;
+    ngx_int_t               rc;
+    dSP;
+
+    if (!SvOK(address) || !SvOK(port) || !SvOK(timeout)) {
+        ngx_log_error(NGX_LOG_ERR, ngx_perl_log, 0,
+                      "ngx_perl_connector: incorrect argument(s)");
+        errno = NGX_PERL_EINVAL;
+        goto FATAL;
+    }
+
+    inport = (in_port_t) SvIV(port);
+
+    inaddr = ngx_inet_addr((u_char *) SvPV_nolen(address), SvCUR(address));
+
+    if (inaddr == INADDR_NONE) {
+        ngx_log_error(NGX_LOG_ERR, ngx_perl_log, 0,
+                      "ngx_perl_connector: incorrect address");
+        errno = NGX_PERL_EINVAL;
+        goto FATAL;
+    }
+
+    pool = ngx_create_pool(1024, ngx_perl_log);
+
+    if (pool == NULL) {
+        errno = NGX_PERL_ENOMEM;
+        goto FATAL;
+    }
+
+    sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in));
+
+    if (sin == NULL) {
+        ngx_log_error(NGX_LOG_ERR, pool->log, 0,
+                      "ngx_perl_connector: ngx_pcalloc() failed");
+        ngx_destroy_pool(pool);
+        errno = NGX_PERL_ENOMEM;
+        goto FATAL;
+    }
+
+    sin->sin_family      = AF_INET;
+    sin->sin_addr.s_addr = inaddr;
+    sin->sin_port        = htons(inport);
+
+
+
+    plc = ngx_pcalloc(pool, sizeof(ngx_perl_connection_t));
+
+    if (plc == NULL) {
+        ngx_log_error(NGX_LOG_ERR, pool->log, 0,
+                      "ngx_perl_connector: ngx_pcalloc() failed");
+        ngx_destroy_pool(pool);
+        errno = NGX_PERL_ENOMEM;
+        goto FATAL;
+    }
+
+    plccln = ngx_pool_cleanup_add(pool, 0);
+
+    if (plccln == NULL) {
+        ngx_log_error(NGX_LOG_ERR, pool->log, 0,
+                      "ngx_perl_connector: ngx_pool_cleanup_add() failed");
+        ngx_destroy_pool(pool);
+        errno = NGX_PERL_ENOMEM;
+        goto FATAL;
+    }
+
+    plccln->data    = (void *) plc;
+    plccln->handler = ngx_perl_connection_cleanup;
+
+
+
+    peer = ngx_pcalloc(pool, sizeof(ngx_peer_connection_t));
+
+    if (peer == NULL) {
+        ngx_log_error(NGX_LOG_ERR, pool->log, 0,
+                      "ngx_perl_connector: ngx_pcalloc() failed");
+        ngx_destroy_pool(pool);
+        errno = NGX_PERL_ENOMEM;
+        goto FATAL;
+    }
+
+    peer->sockaddr  = (struct sockaddr *) sin;
+    peer->socklen   = sizeof(struct sockaddr_in);
+    peer->get       = ngx_event_get_peer;
+    peer->log       = pool->log;
+    peer->log_error = NGX_ERROR_ERR;
+
+
+    peer->name = ngx_pcalloc(pool, sizeof(ngx_str_t));
+
+    if (peer->name == NULL) {
+        ngx_log_error(NGX_LOG_ERR, peer->log, 0,
+                      "ngx_perl_connector: ngx_pcalloc() failed");
+        ngx_destroy_pool(pool);
+        errno = NGX_PERL_ENOMEM;
+        goto FATAL;
+    }
+
+    peer->name->data = ngx_pcalloc(pool, SvCUR(address));
+
+    if (peer->name->data == NULL) {
+        ngx_log_error(NGX_LOG_ERR, peer->log, 0,
+                      "ngx_perl_connector: ngx_pcalloc() failed");
+        ngx_destroy_pool(pool);
+        errno = NGX_PERL_ENOMEM;
+        goto FATAL;
+    }
+
+    ngx_memcpy(peer->name->data, SvPVX(address), SvCUR(address));
+    peer->name->len = SvCUR(address);
+
+
+
+    rc = ngx_event_connect_peer(peer);
+
+    if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
+        ngx_log_error(NGX_LOG_ERR, peer->log, 0,
+                      "ngx_perl_connector: ngx_event_connect_peer() failed");
+
+        if (peer->connection) 
+            ngx_close_connection(peer->connection);
+
+        ngx_destroy_pool(pool);
+
+        errno = NGX_PERL_EBADF;
+        goto FATAL;
+    }
+
+
+    c = peer->connection;
+
+    if (c == NULL) {
+        ngx_log_error(NGX_LOG_ERR, pool->log, 0,
+                      "ngx_perl_connector: no peer->connection");
+        ngx_destroy_pool(pool);
+        errno = NGX_PERL_EBADF;
+        goto FATAL;
+    }
+
+    c->pool = pool;
+    c->log  = pool->log;
+    c->data = (void *) plc;
+
+    plc->connect_cb = cb;
+    SvREFCNT_inc(cb);
+
+    c->write->handler = ngx_perl_connect_handler;
+    c->read->handler  = ngx_perl_connect_handler;
+
+    ngx_add_timer(c->write, SvOK(timeout) && SvIV(timeout) 
+                                ? SvIV(timeout) * 1000 : 15000);
+
+    if (rc == NGX_OK) {
+        c->write->handler(c->write);
+        return;
+    } 
+
+    return;
+
+FATAL:
+
+    SvREFCNT_inc(cb);
+
+    ENTER;
+    SAVETMPS;
+
+    PUSHMARK(SP);
+    PUTBACK;
+
+    call_sv(cb, G_VOID|G_DISCARD); 
+
+    FREETMPS;
+    LEAVE;
+
+    SvREFCNT_dec(cb);
+    errno = 0;
+
+    return;
+}
+
+
+void
+ngx_perl_reader(ngx_connection_t *c, SV *buf, SV *min, SV *max, 
+        SV *timeout, SV *cb) 
+{
+    ngx_perl_connection_t  *plc;
+
+    plc = (ngx_perl_connection_t *) c->data;
+
+    if (plc->read_min) {
+        SvREFCNT_dec(plc->read_min);
+        plc->read_min = NULL;
+    }
+
+    if (plc->read_max) {
+        SvREFCNT_dec(plc->read_max);
+        plc->read_max = NULL;
+    }
+
+    if (plc->read_timeout) {
+        SvREFCNT_dec(plc->read_timeout);
+        plc->read_timeout = NULL;
+    }
+
+    if (plc->read_buffer) {
+        SvREFCNT_dec(plc->read_buffer);
+        plc->read_buffer = NULL;
+    }
+
+    if (plc->read_cb) {
+        SvREFCNT_dec(plc->read_cb);
+        plc->read_cb = NULL;
+    }
+
+    plc->read_min     = min;
+    plc->read_max     = max;
+    plc->read_buffer  = buf;
+    plc->read_timeout = timeout;
+    plc->read_cb      = cb;
+
+    SvREFCNT_inc(min);
+    SvREFCNT_inc(max);
+    SvREFCNT_inc(buf);
+    SvREFCNT_inc(timeout);
+    SvREFCNT_inc(cb);
+
+    return;
+}
+
+
+void
+ngx_perl_writer(ngx_connection_t *c, SV *buf, SV *timeout, SV *cb) 
+{
+    ngx_perl_connection_t  *plc;
+
+    plc = (ngx_perl_connection_t *) c->data;
+
+    if (plc->write_timeout) {
+        SvREFCNT_dec(plc->write_timeout);
+        plc->write_timeout = NULL;
+    }
+
+    if (plc->write_buffer) {
+        SvREFCNT_dec(plc->write_buffer);
+        plc->write_buffer = NULL;
+    }
+
+    if (plc->write_cb) {
+        SvREFCNT_dec(plc->write_cb);
+        plc->write_cb = NULL;
+    }
+
+    plc->write_buffer  = buf;
+    plc->write_timeout = timeout;
+    plc->write_cb      = cb;
+
+    SvREFCNT_inc(buf);
+    SvREFCNT_inc(timeout);
+    SvREFCNT_inc(cb);
+
+    return;
+}
+
+static void
+ngx_perl_connection_cleanup(void *data)
+{
+    ngx_perl_connection_t  *plc;
+
+    plc = (ngx_perl_connection_t *) data;
+
+
+    if (plc->connect_cb) {
+        SvREFCNT_dec(plc->connect_cb);
+        plc->connect_cb = NULL;
+    }
+
+
+    if (plc->read_min) {
+        SvREFCNT_dec(plc->read_min);
+        plc->read_min = NULL;
+    }
+
+    if (plc->read_max) {
+        SvREFCNT_dec(plc->read_max);
+        plc->read_max = NULL;
+    }
+
+    if (plc->read_timeout) {
+        SvREFCNT_dec(plc->read_timeout);
+        plc->read_timeout = NULL;
+    }
+
+    if (plc->read_buffer) {
+        SvREFCNT_dec(plc->read_buffer);
+        plc->read_buffer = NULL;
+    }
+
+    if (plc->read_cb) {
+        SvREFCNT_dec(plc->read_cb);
+        plc->read_cb = NULL;
+    }
+
+
+    if (plc->write_timeout) {
+        SvREFCNT_dec(plc->write_timeout);
+        plc->write_timeout = NULL;
+    }
+
+    if (plc->write_buffer) {
+        SvREFCNT_dec(plc->write_buffer);
+        plc->write_buffer = NULL;
+    }
+
+    if (plc->write_cb) {
+        SvREFCNT_dec(plc->write_cb);
+        plc->write_cb = NULL;
+    }
+
+
+    return;
+}
+
+
+void
+ngx_perl_close(ngx_connection_t *c) 
+{
+    ngx_pool_t  *pool;
+
+    if (c->destroyed) {
+        ngx_log_error(NGX_LOG_ERR, c->log, 0,
+            "ngx_perl_close: "
+            "connection already destroyed");
+        return;
+    }
+
+    pool = c->pool; 
+
+    ngx_close_connection(c);
+    ngx_destroy_pool(pool);
+
+    return;
+}
+
+
+void
+ngx_perl_read(ngx_connection_t *c) 
+{
+    ngx_perl_connection_t  *plc;
+
+    plc = (ngx_perl_connection_t *) c->data;
+   
+    if (c->read->timer_set) {
+        ngx_del_timer(c->read);
+    }
+
+    c->read->handler  = ngx_perl_read_handler;
+    c->write->handler = ngx_perl_dummy_handler;
+
+    if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
+
+        if (c->read->error == 0) 
+            c->read->error = 1;
+
+        c->read->handler(c->read);
+        return;
+    }
+
+    if (!c->read->timer_set) {
+
+        if (plc->read_timeout != NULL  && 
+            SvOK  (plc->read_timeout)  && 
+            SvIV  (plc->read_timeout) >= 0) 
+        {
+            ngx_add_timer(c->read, SvIV(plc->read_timeout) * 1000);
+
+        } else {
+
+            ngx_log_error(NGX_LOG_ERR, c->log, 0,
+                "ngx_perl_read: "
+                "incorrent read timeout, using 15 s instead");
+
+            ngx_add_timer(c->read, 15000);
+        }
+    }
+
+    return;
+}
+
+
+void
+ngx_perl_write(ngx_connection_t *c) 
+{
+    ngx_perl_connection_t  *plc;
+
+    plc = (ngx_perl_connection_t *) c->data;
+
+    plc->write_offset = 0;
+
+    if (c->write->timer_set) {
+        ngx_del_timer(c->write);
+    }
+
+    c->read->handler  = ngx_perl_read_handler;
+    c->write->handler = ngx_perl_write_handler;
+
+    if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
+
+        if (c->write->error == 0) 
+            c->write->error = 1;
+
+        c->write->handler(c->write);
+        return;
+    }
+
+    if (!c->write->timer_set) {
+
+        if (plc->write_timeout != NULL  && 
+            SvOK  (plc->write_timeout)  && 
+            SvIV  (plc->write_timeout) >= 0) 
+        {
+            ngx_add_timer(c->write, SvIV(plc->write_timeout) * 1000);
+
+        } else {
+
+            ngx_log_error(NGX_LOG_ERR, c->log, 0,
+                "ngx_perl_write: "
+                "incorrent write timeout, using 15 s instead");
+
+            ngx_add_timer(c->write, 15000);
+        }
+    }
+
+    return;
+}
+
+
+void
+ngx_perl_noop(ngx_connection_t *c) 
+{
+
+    c->read->handler  = ngx_perl_dummy_handler;
+    c->write->handler = ngx_perl_dummy_handler;
+
+    return;
+}
+
+
+static void
+ngx_perl_dummy_handler(ngx_event_t *ev) 
+{
+    ngx_connection_t  *c;
+
+    c = (ngx_connection_t *) ev->data;
+
+    ngx_log_debug(NGX_LOG_DEBUG, c->log, 0,
+        "ngx_perl_dummy_handler called");
+
+    return;
+}
+
+
+static void
+ngx_perl_connect_handler(ngx_event_t *ev) 
+{
+    ngx_connection_t       *c;
+    ngx_perl_connection_t  *plc;
+    ngx_int_t               cmd, count;
+    dSP;
+
+    c   = (ngx_connection_t *)      ev->data;
+    plc = (ngx_perl_connection_t *) c->data;
+
+    c->read->handler  = ngx_perl_dummy_handler;
+    c->write->handler = ngx_perl_dummy_handler;
+
+    if (ev->timer_set) {
+        ngx_del_timer(ev);
+    }
+
+    if (ev->timedout) {
+        errno = NGX_PERL_ETIMEDOUT;
+        goto CALLBACK;
+    }
+
+    if (ev->error || c->error) {
+        errno = NGX_PERL_EBADE;
+        goto CALLBACK;
+    }
+
+    errno = 0;
+
+CALLBACK:
+
+    SvREFCNT_inc(plc->connect_cb);
+
+    ENTER;
+    SAVETMPS;
+
+    PUSHMARK(SP);
+    XPUSHs(sv_2mortal(newSViv(PTR2IV(c)))); 
+    PUTBACK;
+
+    count = call_sv(plc->connect_cb, G_VOID|G_SCALAR); 
+
+    if (count != 1) {
+        ngx_log_error(NGX_LOG_ERR, c->log, 0,
+            "ngx_perl_connect_handler: "
+            "call_sv returned wrong count = %i",
+            count);
+    }
+
+    SPAGAIN;
+    cmd = POPi;
+    PUTBACK;
+
+    FREETMPS;
+    LEAVE;
+
+    SvREFCNT_dec(plc->connect_cb);
+    errno = 0;
+
+    if ((ev->error || c->error) && cmd != NGX_PERL_CLOSE) {
+        ngx_log_error(NGX_LOG_ERR, c->log, 0,
+            "ngx_perl_connect_handler: "
+            "NGX_CLOSE required on error, forcing");
+        ngx_perl_close(c);
+        return;
+    }
+
+    switch (cmd) {
+        case NGX_PERL_CLOSE:
+            ngx_perl_close(c);
+            break;
+        case NGX_PERL_READ:
+            ngx_perl_read(c);
+            if (c->read->ready) {
+                c->read->handler(c->read);
+            }
+            break;
+        case NGX_PERL_WRITE:
+            ngx_perl_write(c);
+            if (c->write->ready) {
+                c->write->handler(c->write);
+            }
+            break;
+        case NGX_PERL_NOOP:
+            ngx_perl_noop(c);
+            break;
+    }
+
+    return;
+}
+
+
+static void
+ngx_perl_read_handler(ngx_event_t *ev)
+{
+    ssize_t                 n;
+    ngx_connection_t       *c;
+    ngx_perl_connection_t  *plc;
+    SV                     *sv, *cb;
+    U32                     min, max;
+    ngx_int_t               cmd, count;
+    dSP;
+
+    c   = (ngx_connection_t *) ev->data;
+    plc = (ngx_perl_connection_t *) c->data;
+
+    if (ev->timer_set) {
+        ngx_del_timer(ev);
+    }
+
+    if (ev->timedout) {
+        errno = NGX_PERL_ETIMEDOUT;
+        goto CALLBACK;
+    }
+
+AGAIN:
+
+    if (ev->error || c->error) {
+        errno = NGX_PERL_EBADE;
+        goto CALLBACK;
+    }
+
+
+    min = 0;
+    max = 0;
+
+    if (  SvOK ( plc->read_min ) && 
+          SvIV ( plc->read_min )     ) 
+        min = SvIV ( plc->read_min );
+
+    if (  SvOK ( plc->read_max ) && 
+          SvIV ( plc->read_max )     ) 
+        max = SvIV ( plc->read_max );
+
+
+    sv = plc->read_buffer;
+
+    SvPOK_on(sv);
+
+    if ( SvLEN(sv) - SvCUR(sv) < 1500) {
+        if ( max ) {
+            if ( SvLEN(sv) < max + 1 ) {
+                SvGROW(sv, ( SvCUR(sv) * 2 ) + 1500);
+            } else {
+                if ( SvCUR(sv) >= max ) {
+                    goto CALLBACK;
+                }
+            }
+        } else {
+            SvGROW(sv, ( SvCUR(sv) * 2 ) + 1500);
+        }
+    }
+
+    
+    for ( ;; ) {
+
+        ngx_socket_errno = 0;
+
+        n = c->recv(c, (u_char *) SvPVX (sv) + SvCUR (sv), 
+                       ( max && SvLEN (sv) > max 
+                               ? max + 1 : SvLEN (sv) ) - SvCUR (sv) - 1);
+
+        if (n == NGX_AGAIN) {
+
+            if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
+                errno = NGX_PERL_EBADE;
+                goto CALLBACK;
+            }
+
+            return;
+        }
+
+        if (n == 0) {
+            errno = NGX_PERL_EOF;
+            goto CALLBACK;
+        }
+
+        if (n == NGX_ERROR) {
+            errno = ngx_socket_errno ? ngx_socket_errno : NGX_PERL_EBADE;
+            goto CALLBACK;
+        }
+
+        SvCUR_set (sv, SvCUR (sv) + n);
+
+        if ( SvCUR (sv) < min ) {
+            continue;
+        }
+
+        break;
+    }
+
+    errno = 0;
+
+CALLBACK:
+
+    cb = plc->read_cb;
+
+    SvREFCNT_inc(cb);
+
+    ENTER;
+    SAVETMPS;
+
+    PUSHMARK(SP);
+    XPUSHs(sv_2mortal(newSViv(PTR2IV(c)))); 
+    PUTBACK;
+
+    ngx_log_debug(NGX_LOG_DEBUG, c->log, 0,
+        "ngx_perl_read_handler: "
+        "ev->eof = %i, ev->error = %i, c->error = %i",
+        ev->eof, ev->error, c->error);
+
+    count = call_sv(cb, G_VOID|G_SCALAR); 
+
+    if (count != 1) {
+        ngx_log_error(NGX_LOG_ERR, c->log, 0,
+            "ngx_perl_read_handler: "
+            "call_sv returned wrong count = %i",
+            count);
+    }
+
+    SPAGAIN;
+    cmd = POPi;
+    PUTBACK;
+
+    FREETMPS;
+    LEAVE;
+
+    SvREFCNT_dec(cb);
+    errno = 0;
+
+    if ((ev->error || c->error) && cmd != NGX_PERL_CLOSE) {
+        ngx_log_error(NGX_LOG_ERR, c->log, 0,
+            "ngx_perl_read_handler: "
+            "NGX_CLOSE required on error, forcing");
+        ngx_perl_close(c);
+        return;
+    }
+
+    switch (cmd) {
+        case NGX_PERL_CLOSE:
+            ngx_perl_close(c);
+            break;
+        case NGX_PERL_READ:
+            ngx_perl_read(c);
+            if (c->read->ready) {
+                goto AGAIN;
+            }
+            break;
+        case NGX_PERL_WRITE:
+            ngx_perl_write(c);
+            if (c->write->ready) {
+                c->write->handler(c->write);
+            }
+            break;
+        case NGX_PERL_NOOP:
+            ngx_perl_noop(c);
+            break;
+    }
+
+    return;
+}
+
+
+static void
+ngx_perl_write_handler(ngx_event_t *ev)
+{
+    ssize_t                 n;
+    ngx_connection_t       *c;
+    ngx_perl_connection_t  *plc;
+    SV                     *sv, *cb;
+    ngx_int_t               cmd, count;
+    dSP;
+
+    c   = (ngx_connection_t *) ev->data;
+    plc = (ngx_perl_connection_t *) c->data;
+
+    if (ev->timer_set) {
+        ngx_del_timer(ev);
+    }
+
+    if (ev->timedout) {
+        errno = NGX_PERL_ETIMEDOUT;
+        goto CALLBACK;
+    }
+
+AGAIN:
+
+    if (ev->error || c->error) {
+        errno = NGX_PERL_EBADE;
+        goto CALLBACK;
+    }
+
+    sv = plc->write_buffer;
+
+    for ( ;; ) {
+
+        ngx_socket_errno = 0;
+
+        n = c->send(c, (u_char *) SvPV_nolen (sv) + plc->write_offset, 
+                                  SvCUR (sv) - plc->write_offset); 
+
+        if (n == NGX_AGAIN) {
+
+            if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
+                errno = NGX_PERL_EBADE;
+                goto CALLBACK;
+            }
+
+            return;
+        }
+
+        if (n == 0) {
+            errno = NGX_PERL_EOF;
+            goto CALLBACK;
+        }
+
+        if (n == NGX_ERROR) {
+            errno = ngx_socket_errno ? ngx_socket_errno : NGX_PERL_EBADE;
+            goto CALLBACK;
+        }
+
+        plc->write_offset += n;
+
+        if (SvCUR(sv) - plc->write_offset > 0) {
+            continue;
+        }
+
+        break;
+    }
+
+    errno = 0;
+
+CALLBACK:
+
+    plc->write_offset = 0;
+
+    cb = plc->write_cb;
+
+    SvREFCNT_inc(cb);
+
+    ENTER;
+    SAVETMPS;
+
+    PUSHMARK(SP);
+    XPUSHs(sv_2mortal(newSViv(PTR2IV(c)))); 
+    PUTBACK;
+
+    count = call_sv(cb, G_VOID|G_SCALAR); 
+
+    if (count != 1) {
+        ngx_log_error(NGX_LOG_ERR, c->log, 0,
+            "ngx_perl_write_handler: "
+            "call_sv returned wrong count = %i",
+            count);
+    }
+
+    SPAGAIN;
+    cmd = POPi;
+    PUTBACK;
+
+    FREETMPS;
+    LEAVE;
+
+    SvREFCNT_dec(cb);
+    errno = 0;
+
+    if ((ev->error || c->error) && cmd != NGX_PERL_CLOSE) {
+        ngx_log_error(NGX_LOG_ERR, c->log, 0,
+            "ngx_perl_write_handler: "
+            "NGX_CLOSE required on error, forcing");
+        ngx_perl_close(c);
+        return;
+    }
+
+    switch (cmd) {
+        case NGX_PERL_CLOSE:
+            ngx_perl_close(c);
+            break;
+        case NGX_PERL_READ:
+            ngx_perl_read(c);
+            break;
+        case NGX_PERL_WRITE:
+            ngx_perl_write(c);
+            if (c->write->ready) {
+                goto AGAIN;
+            }
+            break;
+        case NGX_PERL_NOOP:
+            ngx_perl_noop(c);
+            break;
+    }
+
+    return;
+}
+
+
diff --git a/src/http/modules/perl/ngx_http_perl_module.h b/src/http/modules/perl/ngx_http_perl_module.h
--- a/src/http/modules/perl/ngx_http_perl_module.h
+++ b/src/http/modules/perl/ngx_http_perl_module.h
@@ -51,8 +51,8 @@
  * when building with perl 5.6.1
  */
 #ifndef PERL_IMPLICIT_CONTEXT
-#undef  dTHXa
-#define dTHXa(a)
+#  undef  dTHXa
+#  define dTHXa(a)
 #endif
 
 
@@ -63,4 +63,55 @@
 void ngx_http_perl_sleep_handler(ngx_http_request_t *r);
 
 
+
+typedef struct {
+    ngx_int_t   after;
+    SV         *repeat;
+    SV         *cb;
+} ngx_perl_timer_t;
+
+ngx_connection_t *ngx_perl_timer(ngx_int_t after, SV *repeat, SV *cb);
+void ngx_perl_timer_clear(ngx_connection_t *c);
+
+
+#define NGX_PERL_NOOP        0
+#define NGX_PERL_READ        1
+#define NGX_PERL_WRITE       2
+#define NGX_PERL_CONNECT     4
+#define NGX_PERL_CLOSE       8
+
+#ifndef EBADE
+#  define  EBADE  52
+#endif
+
+#define NGX_PERL_EOF         42   /* ENOMSG */
+#define NGX_PERL_EINVAL      EINVAL
+#define NGX_PERL_ENOMEM      ENOMEM
+#define NGX_PERL_EBADE       EBADE
+#define NGX_PERL_EBADF       EBADF
+#define NGX_PERL_ETIMEDOUT   ETIMEDOUT
+
+typedef struct {
+    SV       *connect_cb;
+    SV       *read_buffer;
+    SV       *read_min;
+    SV       *read_max;
+    SV       *read_timeout;
+    SV       *read_cb;
+    SV       *write_buffer;
+    ssize_t   write_offset;
+    SV       *write_timeout;
+    SV       *write_cb;
+} ngx_perl_connection_t;
+
+void ngx_perl_connector(SV *address, SV *port, SV *timeout, SV *cb);
+void ngx_perl_writer(ngx_connection_t *c, SV *buf, SV *timeout, SV *cb);
+void ngx_perl_reader(ngx_connection_t *c, SV *buf, SV *min, SV *max, 
+        SV *timeout, SV *cb);
+void ngx_perl_close(ngx_connection_t *c);
+void ngx_perl_read(ngx_connection_t *c);
+void ngx_perl_write(ngx_connection_t *c);
+void ngx_perl_noop(ngx_connection_t *c);
+
+
 #endif /* _NGX_HTTP_PERL_MODULE_H_INCLUDED_ */


Подробная информация о списке рассылки nginx-ru