On Wed, 16 Aug 2000, Geoffrey Young wrote:
> ack... so the alias only goes one way? I guess it makes sense that we
> can't know at run time what the Init handler stands for, but how come
> get_handlers('PerlInitHandler') comes up blank? Isn't it just a table
> entry?
it's not in the get/set handler lookup table. just use
PostReadRequest/HeaderParser for now, we'll see about making Init do the
right thing with get/set handlers later.
> well, it got the handler ok, but I couldn't set it properly:
>
> #!/usr/bin/perl
>
> my $r = shift;
> $r->set_handlers(PerlCleanupHandler => [\&cleanup]);
> $r->send_http_header('text/plain');
> print "done";
>
> sub cleanup {
> warn "hi";
> }
>
> is a no go. same with using ['My::Cleanup'] as the arg...
ok, fixed, problem described in new Apache.xs comment:
/* since register_cleanups are fifo, and the already registered
* mod_perl_end_cleanup() runs PerlCleanupHandlers, PerlCleanupHandler
* needs to maintain the refcnt itself
*/
> I also noticed that the patch didn't fix the get_handlers() coderef bug:
>
> #!/usr/bin/perl
>
> my $r = shift;
> $r->push_handlers(PerlCleanupHandler => sub { warn "hi"; });
> #my $handlers = $r->get_handlers('PerlCleanupHandler');
> $r->send_http_header('text/plain');
> print "done";
>
> uncomment the get_handlers() line and the cleanup handler never runs and you
> get "Attempt to free unreferenced scalar"
i see the problem, perl_handler_merge_avs() did not increment the
reference counts during av_push(). below is the current patch against cvs
which fixes both problems. thanks for testing geoff!
Index: src/modules/perl/Apache.xs
===================================================================
RCS file: /home/cvs/modperl/src/modules/perl/Apache.xs,v
retrieving revision 1.103
diff -u -r1.103 Apache.xs
--- src/modules/perl/Apache.xs 2000/08/15 19:36:32 1.103
+++ src/modules/perl/Apache.xs 2000/08/21 22:33:32
@@ -73,12 +73,6 @@
void (*set_func) (void *, void *, SV *);
} perl_handler_table;
-typedef struct {
- I32 fill;
- AV *av;
- AV **ptr;
-} perl_save_av;
-
static void set_handler_dir (perl_handler_table *tab, request_rec *r, SV *sv);
static void set_handler_srv (perl_handler_table *tab, request_rec *r, SV *sv);
@@ -101,77 +95,78 @@
{HandlerDirEntry("PerlFixupHandler", PerlFixupHandler)},
{HandlerDirEntry("PerlHandler", PerlHandler)},
{HandlerDirEntry("PerlLogHandler", PerlLogHandler)},
+ {HandlerDirEntry("PerlCleanupHandler", PerlCleanupHandler)},
{ FALSE, NULL }
};
-static void perl_restore_av(void *data)
-{
- perl_save_av *save_av = (perl_save_av *)data;
-
- if(save_av->fill != DONE) {
- AvFILLp(*save_av->ptr) = save_av->fill;
- }
- else if(save_av->av != Nullav) {
- *save_av->ptr = save_av->av;
- }
-}
-
static void perl_handler_merge_avs(char *hook, AV **dest)
{
int i = 0;
HV *hv = perl_get_hv("Apache::PerlStackedHandlers", FALSE);
SV **svp = hv_fetch(hv, hook, strlen(hook), FALSE);
AV *base;
-
+
if(!(svp && SvROK(*svp)))
return;
base = (AV*)SvRV(*svp);
for(i=0; i<=AvFILL(base); i++) {
SV *sv = *av_fetch(base, i, FALSE);
- av_push(*dest, sv);
+ av_push(*dest, SvREFCNT_inc(sv));
}
}
+#define avptr_from_offset(ptr, tab) \
+(AV **)((char *)ptr + (int)(long)tab->offset)
+
static void set_handler_base(void *ptr, perl_handler_table *tab, pool *p, SV *sv)
{
- AV **av = (AV **)((char *)ptr + (int)(long)tab->offset);
+ int do_register_cleanup = 0;
+ AV **av = avptr_from_offset(ptr, tab);
- perl_save_av *save_av =
- (perl_save_av *)palloc(p, sizeof(perl_save_av));
-
- save_av->fill = DONE;
- save_av->av = Nullav;
-
- if((sv == &sv_undef) || (SvIOK(sv) && SvIV(sv) == DONE)) {
- if(AvTRUE(*av)) {
- save_av->fill = AvFILL(*av);
- AvFILLp(*av) = -1;
- }
- }
- else if(SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV) {
- if(AvTRUE(*av))
- save_av->av = av_copy_array(*av);
- *av = (AV*)SvRV(sv);
- ++SvREFCNT(*av);
+ if ((sv == &sv_undef) || (SvIOK(sv) && SvIV(sv) == DONE)) {
+ if (!*av) {
+ do_register_cleanup = 1;
+ }
+ if (*av && SvREFCNT(*av)) {
+ SvREFCNT_dec(*av);
+ }
+ *av = newAV();
+ }
+ else if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV) {
+ *av = (AV*)SvRV(sv);
+ ++SvREFCNT(*av);
+ do_register_cleanup = 1;
}
else {
- croak("Can't set_handler with that value");
+ croak("Can't set_handler with that value");
+ }
+
+ /* since register_cleanups are fifo, and the already registered
+ * mod_perl_end_cleanup() runs PerlCleanupHandlers, PerlCleanupHandler
+ * needs to maintain the refcnt itself
+ */
+ if (do_register_cleanup && strNE(tab->name, "PerlCleanupHandler")) {
+ register_cleanup(p, (void*)*av, mod_perl_cleanup_av, mod_perl_noop);
}
- save_av->ptr = av;
- register_cleanup(p, save_av, perl_restore_av, mod_perl_noop);
}
-static void set_handler_dir(perl_handler_table *tab, request_rec *r, SV *sv)
+void set_handler_dir(perl_handler_table *tab, request_rec *r, SV *sv)
{
- dPPDIR;
- set_handler_base((void*)cld, tab, r->pool, sv);
+ dPPREQ;
+ if (!cfg->dir_cfg) {
+ cfg->dir_cfg = perl_create_dir_config(r->pool, r->uri);
+ }
+ set_handler_base((void*)cfg->dir_cfg, tab, r->pool, sv);
}
static void set_handler_srv(perl_handler_table *tab, request_rec *r, SV *sv)
{
- dPSRV(r->server);
- set_handler_base((void*)cls, tab, r->pool, sv);
+ dPPREQ;
+ if (!cfg->srv_cfg) {
+ cfg->srv_cfg = perl_create_server_config(r->pool, NULL);
+ }
+ set_handler_base((void*)cfg->srv_cfg, tab, r->pool, sv);
}
static perl_handler_table *perl_handler_lookup(char *name)
@@ -185,29 +180,45 @@
return NULL;
}
-
static SV *get_handlers(request_rec *r, char *hook)
{
AV *avcopy;
AV **av;
+ dPPREQ;
dPPDIR;
dPSRV(r->server);
void *ptr;
perl_handler_table *tab = perl_handler_lookup(hook);
- if(!tab) return Nullsv;
+ if (!tab) {
+ return Nullsv;
+ }
- if(tab->type == PER_DIR_CONFIG)
- ptr = (void*)cld;
- else
- ptr = (void*)cls;
+ if (tab->type == PER_DIR_CONFIG) {
+ if (cfg->dir_cfg && *avptr_from_offset(cfg->dir_cfg, tab)) {
+ ptr = (void*)cfg->dir_cfg;
+ }
+ else {
+ ptr = (void*)cld;
+ }
+ }
+ else {
+ if (cfg->srv_cfg && *avptr_from_offset(cfg->srv_cfg, tab)) {
+ ptr = (void*)cfg->srv_cfg;
+ }
+ else {
+ ptr = (void*)cls;
+ }
+ }
- av = (AV **)((char *)ptr + (int)(long)tab->offset);
+ av = avptr_from_offset(ptr, tab);
- if(*av)
+ if (*av) {
avcopy = av_copy_array(*av);
- else
- avcopy = newAV();
+ }
+ else {
+ avcopy = newAV();
+ }
perl_handler_merge_avs(hook, &avcopy);
Index: src/modules/perl/mod_perl.c
===================================================================
RCS file: /home/cvs/modperl/src/modules/perl/mod_perl.c,v
retrieving revision 1.124
diff -u -r1.124 mod_perl.c
--- src/modules/perl/mod_perl.c 2000/08/15 19:36:33 1.124
+++ src/modules/perl/mod_perl.c 2000/08/21 22:33:32
@@ -891,7 +891,8 @@
}
cfg->setup_env = 1;
- PERL_CALLBACK("PerlHandler", cld->PerlHandler);
+ PERL_CALLBACK("PerlHandler",
+ PERL_REQ_DIR_HANDLER(cfg, cld, PerlHandler));
cfg->setup_env = 0;
FREETMPS;
@@ -965,16 +966,21 @@
{
dSTATUS;
dPSRV(r->server);
+ dPPREQ;
+
#if MODULE_MAGIC_NUMBER > 19980270
if(r->parsed_uri.scheme && r->parsed_uri.hostname && do_proxy(r)) {
r->proxyreq = 1;
r->uri = r->unparsed_uri;
}
#endif
+
#ifdef PERL_INIT
- PERL_CALLBACK("PerlInitHandler", cls->PerlInitHandler);
+ PERL_CALLBACK("PerlInitHandler",
+ PERL_REQ_SRV_HANDLER(cfg, cls, PerlInitHandler));
#endif
- PERL_CALLBACK("PerlPostReadRequestHandler", cls->PerlPostReadRequestHandler);
+ PERL_CALLBACK("PerlPostReadRequestHandler",
+ PERL_REQ_SRV_HANDLER(cfg, cls, PerlPostReadRequestHandler));
return status;
}
#endif
@@ -984,7 +990,9 @@
{
dSTATUS;
dPSRV(r->server);
- PERL_CALLBACK("PerlTransHandler", cls->PerlTransHandler);
+ dPPREQ;
+ PERL_CALLBACK("PerlTransHandler",
+ PERL_REQ_SRV_HANDLER(cfg, cls, PerlTransHandler));
return status;
}
#endif
@@ -994,12 +1002,13 @@
{
dSTATUS;
dPPDIR;
+ dPPREQ;
#ifdef PERL_INIT
PERL_CALLBACK("PerlInitHandler",
- cld->PerlInitHandler);
+ PERL_REQ_DIR_HANDLER(cfg, cld, PerlInitHandler));
#endif
PERL_CALLBACK("PerlHeaderParserHandler",
- cld->PerlHeaderParserHandler);
+ PERL_REQ_DIR_HANDLER(cfg, cld, PerlHeaderParserHandler));
return status;
}
#endif
@@ -1009,7 +1018,9 @@
{
dSTATUS;
dPPDIR;
- PERL_CALLBACK("PerlAuthenHandler", cld->PerlAuthenHandler);
+ dPPREQ;
+ PERL_CALLBACK("PerlAuthenHandler",
+ PERL_REQ_DIR_HANDLER(cfg, cld, PerlAuthenHandler));
return status;
}
#endif
@@ -1019,7 +1030,9 @@
{
dSTATUS;
dPPDIR;
- PERL_CALLBACK("PerlAuthzHandler", cld->PerlAuthzHandler);
+ dPPREQ;
+ PERL_CALLBACK("PerlAuthzHandler",
+ PERL_REQ_DIR_HANDLER(cfg, cld, PerlAuthzHandler));
return status;
}
#endif
@@ -1029,7 +1042,9 @@
{
dSTATUS;
dPPDIR;
- PERL_CALLBACK("PerlAccessHandler", cld->PerlAccessHandler);
+ dPPREQ;
+ PERL_CALLBACK("PerlAccessHandler",
+ PERL_REQ_DIR_HANDLER(cfg, cld, PerlAccessHandler));
return status;
}
#endif
@@ -1039,7 +1054,9 @@
{
dSTATUS;
dPPDIR;
- PERL_CALLBACK("PerlTypeHandler", cld->PerlTypeHandler);
+ dPPREQ;
+ PERL_CALLBACK("PerlTypeHandler",
+ PERL_REQ_DIR_HANDLER(cfg, cld, PerlTypeHandler));
return status;
}
#endif
@@ -1049,7 +1066,9 @@
{
dSTATUS;
dPPDIR;
- PERL_CALLBACK("PerlFixupHandler", cld->PerlFixupHandler);
+ dPPREQ;
+ PERL_CALLBACK("PerlFixupHandler",
+ PERL_REQ_DIR_HANDLER(cfg, cld, PerlFixupHandler));
return status;
}
#endif
@@ -1059,7 +1078,9 @@
{
dSTATUS;
dPPDIR;
- PERL_CALLBACK("PerlLogHandler", cld->PerlLogHandler);
+ dPPREQ;
+ PERL_CALLBACK("PerlLogHandler",
+ PERL_REQ_DIR_HANDLER(cfg, cld, PerlLogHandler));
return status;
}
#endif
@@ -1117,9 +1138,14 @@
request_rec *r = (request_rec *)data;
dSTATUS;
dPPDIR;
+ dPPREQ;
#ifdef PERL_CLEANUP
- PERL_CALLBACK("PerlCleanupHandler", CleanupHandler);
+ PERL_CALLBACK("PerlCleanupHandler",
+ PERL_REQ_DIR_HANDLER(cfg, cld, PerlCleanupHandler));
+ if (PERL_HAS_REQ_DIR_HANDLER(cfg, PerlCleanupHandler)) {
+ SvREFCNT_dec((SV*)cfg->dir_cfg->PerlCleanupHandler);
+ }
#endif
MP_TRACE_g(fprintf(stderr, "perl_end_cleanup..."));
Index: src/modules/perl/mod_perl.h
===================================================================
RCS file: /home/cvs/modperl/src/modules/perl/mod_perl.h,v
retrieving revision 1.102
diff -u -r1.102 mod_perl.h
--- src/modules/perl/mod_perl.h 2000/08/15 19:36:33 1.102
+++ src/modules/perl/mod_perl.h 2000/08/21 22:33:33
@@ -1058,7 +1058,21 @@
HV *pnotes;
int setup_env;
array_header *sigsave;
+ perl_dir_config *dir_cfg;
+ perl_server_config *srv_cfg;
} perl_request_config;
+
+#define PERL_HAS_REQ_DIR_HANDLER(cfg, h) \
+(cfg && cfg->dir_cfg && cfg->dir_cfg->h)
+
+#define PERL_HAS_REQ_SRV_HANDLER(cfg, h) \
+(cfg && cfg->srv_cfg && cfg->srv_cfg->h)
+
+#define PERL_REQ_DIR_HANDLER(cfg, cld, h) \
+(PERL_HAS_REQ_DIR_HANDLER(cfg,h) ? cfg->dir_cfg->h : cld->h)
+
+#define PERL_REQ_SRV_HANDLER(cfg, cls, h) \
+(PERL_HAS_REQ_SRV_HANDLER(cfg, h) ? cfg->srv_cfg->h : cls->h)
typedef struct {
int is_method;